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>
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) {