USB: ks_bridge: Abort suspend when data is received during unlink
All the submitted URBs are unlinked during suspend. Abort suspend
if data is received during unlink. This avoids unnecessary suspend
and resume of remaining interfaces.
CRs-Fixed: 449097
Change-Id: Ia4009775ec29df0222b475581649c3a9f4f1899f
Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org>
diff --git a/drivers/usb/misc/ks_bridge.c b/drivers/usb/misc/ks_bridge.c
index 33280db..2a3594d 100644
--- a/drivers/usb/misc/ks_bridge.c
+++ b/drivers/usb/misc/ks_bridge.c
@@ -490,6 +490,7 @@
{
struct data_pkt *pkt = urb->context;
struct ks_bridge *ksb = pkt->ctxt;
+ bool wakeup = true;
dbg_log_event(ksb, "C RX_URB", urb->status, urb->actual_length);
@@ -497,8 +498,15 @@
urb->actual_length);
/*non zero len of data received while unlinking urb*/
- if (urb->status == -ENOENT && urb->actual_length > 0)
+ if (urb->status == -ENOENT && (urb->actual_length > 0)) {
+ /*
+ * If we wakeup the reader process now, it may
+ * queue the URB before its reject flag gets
+ * cleared.
+ */
+ wakeup = false;
goto add_to_list;
+ }
if (urb->status < 0) {
if (urb->status != -ESHUTDOWN && urb->status != -ENOENT
@@ -521,7 +529,8 @@
spin_unlock(&ksb->lock);
/* wake up read thread */
- wake_up(&ksb->ks_wait_q);
+ if (wakeup)
+ wake_up(&ksb->ks_wait_q);
done:
atomic_dec(&ksb->rx_pending_cnt);
wake_up(&ksb->pending_urb_wait);
@@ -703,11 +712,26 @@
static int ksb_usb_suspend(struct usb_interface *ifc, pm_message_t message)
{
struct ks_bridge *ksb = usb_get_intfdata(ifc);
+ unsigned long flags;
dbg_log_event(ksb, "SUSPEND", 0, 0);
usb_kill_anchored_urbs(&ksb->submitted);
+ spin_lock_irqsave(&ksb->lock, flags);
+ if (!list_empty(&ksb->to_ks_list)) {
+ spin_unlock_irqrestore(&ksb->lock, flags);
+ dbg_log_event(ksb, "SUSPEND ABORT", 0, 0);
+ /*
+ * Now wakeup the reader process and queue
+ * Rx URBs for more data.
+ */
+ wake_up(&ksb->ks_wait_q);
+ queue_work(ksb->wq, &ksb->start_rx_work);
+ return -EBUSY;
+ }
+ spin_unlock_irqrestore(&ksb->lock, flags);
+
return 0;
}