A host driver that is its own SVC, such as a software SVC, injects requests like MODULE_REMOVED through greybus_data_rcvd(). The core acts on them asynchronously: the request handler runs on the connection workqueue and queues the actual work on svc->wq. The response is sent before that work runs, so it cannot tell the driver that the module is gone.
Add gb_svc_flush() to wait until every request received so far has been fully processed. It flushes the connection workqueue, then svc->wq.
Signed-off-by: Ayush Singh ayush@beagleboard.org --- drivers/greybus/svc.c | 14 ++++++++++++++ include/linux/greybus/svc.h | 1 + 2 files changed, 15 insertions(+)
diff --git a/drivers/greybus/svc.c b/drivers/greybus/svc.c index 490577731a19..788d95b4b87b 100644 --- a/drivers/greybus/svc.c +++ b/drivers/greybus/svc.c @@ -1381,6 +1381,20 @@ static void gb_svc_remove_modules(struct gb_svc *svc) } }
+/** + * gb_svc_flush - wait for received SVC requests to be processed + * @svc: the SVC + * + * Requests pass through the connection workqueue on their way to svc->wq, so + * both have to be flushed, in this order. + */ +void gb_svc_flush(struct gb_svc *svc) +{ + flush_workqueue(svc->connection->wq); + flush_workqueue(svc->wq); +} +EXPORT_SYMBOL_GPL(gb_svc_flush); + void gb_svc_del(struct gb_svc *svc) { gb_connection_disable_rx(svc->connection); diff --git a/include/linux/greybus/svc.h b/include/linux/greybus/svc.h index da547fb9071b..ced5fc3a9c6b 100644 --- a/include/linux/greybus/svc.h +++ b/include/linux/greybus/svc.h @@ -63,6 +63,7 @@ struct gb_svc *gb_svc_create(struct gb_host_device *hd); int gb_svc_add(struct gb_svc *svc); void gb_svc_del(struct gb_svc *svc); void gb_svc_put(struct gb_svc *svc); +void gb_svc_flush(struct gb_svc *svc);
int gb_svc_pwrmon_intf_sample_get(struct gb_svc *svc, u8 intf_id, u8 measurement_type, u32 *value);