From 5d59d11198960bb39f5755f28273903e39cddb0d Mon Sep 17 00:00:00 2001 From: Benoit Goby Date: Wed, 22 Sep 2010 18:34:42 -0700 Subject: [PATCH] mdm6600: Wait for pending urbs on suspend On suspend, while we are killing read urbs, some of the urbs might succeed. Don't re-submit them and wait for the workqueue to process them. Fixed urbs ref count Change-Id: I3c69926b0bec8d5425ed8bc403b8c040db5ab435 Signed-off-by: Benoit Goby --- drivers/usb/serial/mdm6600.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/mdm6600.c b/drivers/usb/serial/mdm6600.c index 9b9805d7090e..6ea24e2efb8b 100644 --- a/drivers/usb/serial/mdm6600.c +++ b/drivers/usb/serial/mdm6600.c @@ -673,12 +673,25 @@ static void mdm6600_read_bulk_work(struct work_struct *work) size_t c; struct urb *u; struct tty_struct *tty; + unsigned long flags; struct mdm6600_port *modem = container_of(work, struct mdm6600_port, read.work); + struct usb_anchor *anchor = &modem->read.pending; dbg("%s", __func__); - while ((u = usb_get_from_anchor(&modem->read.pending))) { + while (true) { + spin_lock_irqsave(&anchor->lock, flags); + if (list_empty(&anchor->urb_list)) { + spin_unlock_irqrestore(&anchor->lock, flags); + return; + } + + u = list_entry(anchor->urb_list.next, struct urb, + anchor_list); + usb_get_urb(u); + spin_unlock_irqrestore(&anchor->lock, flags); + dbg("%s: processing urb %p len %u", __func__, u, u->actual_length); usb_serial_debug_data(debug_data, &modem->port->dev, __func__, @@ -697,7 +710,14 @@ static void mdm6600_read_bulk_work(struct work_struct *work) tty_kref_put(tty); next: + usb_unanchor_urb(u); + if (modem->susp_count) { + usb_put_urb(u); + continue; + } + usb_anchor_urb(u, &modem->read.in_flight); + usb_put_urb(u); rc = usb_submit_urb(u, GFP_KERNEL); if (rc) { pr_err("%s: Error %d re-submitting read urb %p\n", @@ -759,6 +779,8 @@ static int mdm6600_suspend(struct usb_interface *intf, pm_message_t message) spin_unlock_irq(&modem->susp_lock); dbg("%s: kill urbs", __func__); mdm6600_kill_urbs(modem); + if (!usb_wait_anchor_empty_timeout(&modem->read.pending, 1000)) + usb_scuttle_anchored_urbs(&modem->read.pending); return 0; } @@ -788,6 +810,7 @@ static int mdm6600_resume(struct usb_interface *intf) while ((u = usb_get_from_anchor(&modem->write.delayed))) { usb_anchor_urb(u, &modem->write.in_flight); + usb_put_urb(u); rc = usb_submit_urb(u, GFP_KERNEL); if (rc < 0) { usb_unanchor_urb(u); -- 2.34.1