OSDN Git Service

usb: gadget: gsi: Use drain_workqueue instead of flush_workqueue
authorMayank Rana <mrana@codeaurora.org>
Thu, 12 May 2016 00:57:45 +0000 (17:57 -0700)
committerJeevan Shriram <jshriram@codeaurora.org>
Wed, 18 May 2016 20:41:23 +0000 (13:41 -0700)
USB GSI function driver uses usb_ipa_w work to queue different events
like EVT_CONNECTED, EVT_DISCONNECTED and more. ipa_event_handler()
uses those events as inputs to make necessary decision about performing
connect and disconnect with IPA driver. It is required that before USB
GSI driver calls ipa_usb_deinit_teth_prot(), it has invoked IPA
disconnect API ipa_usb_xdci_disconnect() if it has called
ipa_usb_xdci_connect() API. Current code is making sure that any
running usb_ipa_w work is being completed before calling
ipa_usb_deinit_teth_prot() but if work is not scheduled and pending,
ipa_usb_xdci_connect() is not called (i.e. later when usb_ipw_w work is
scheduled, EVT_DISCONNECTED is being processed but gsi_unbind() has
changed sm_state as STATE_UNINITIALIZED which results into no-ops.)
which results into USB and IPA driver go out of sync in terms of
expected state machine. Hence calling ipa_usb_init_teth_prot() on next
USB cable connect from gsi_bind_config() fails which results into no
USB GSI functionality. Fix this issue by using drain_workqueue() instead
of flush_workqueue() which makes sure that re-queue work is flushed.

CRs-Fixed: 1005018
Change-Id: I64ff559b85f901688a4abd0110ebb32a5317e34d
Signed-off-by: Mayank Rana <mrana@codeaurora.org>
drivers/usb/gadget/function/f_gsi.c

index 4274d69..57e2ba5 100644 (file)
@@ -2551,11 +2551,14 @@ static void gsi_unbind(struct usb_configuration *c, struct usb_function *f)
        u32 len;
 
        /*
-        * call flush_workqueue to make sure that any pending
-        * disconnect_work() is being flushed before calling
-        * ipa_usb_deinit_teth_prot ipa
+        * Use drain_workqueue to accomplish below conditions:
+        * 1. Make sure that any running work completed
+        * 2. Make sure to wait until all pending work completed i.e. workqueue
+        * is not having any pending work.
+        * Above conditions are making sure that ipa_usb_deinit_teth_prot()
+        * with ipa driver shall not fail due to unexpected state.
         */
-       flush_workqueue(gsi->d_port.ipa_usb_wq);
+       drain_workqueue(gsi->d_port.ipa_usb_wq);
        ipa_usb_deinit_teth_prot(gsi->prot_id);
 
        if (gsi->prot_id == IPA_USB_RNDIS) {