diff options
| author | Johan Hovold <jhovold@gmail.com> | 2014-05-26 13:23:48 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-05-27 18:04:10 -0400 |
| commit | b1d42efc217fdc1a6a704b344fd902ae52a012c8 (patch) | |
| tree | 8ecdc055e6f6c6b1c794d9b08b131840e0918568 | |
| parent | 89e54e4468338df5a4ab7627c5b8b10786ee43e8 (diff) | |
USB: cdc-acm: minimise no-suspend window during shutdown
Now that acm_set_control() handles runtime PM properly, the only
remaining reason for the PM operations in shutdown is to clear the
needs_remote_wakeup flag before the final put.
Note that this also means that we now need to grab the write_lock to
prevent racing with resume.
Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
| -rw-r--r-- | drivers/usb/class/cdc-acm.c | 17 |
1 files changed, 11 insertions, 6 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 91fdc293196f..f038f390db97 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
| @@ -590,13 +590,22 @@ static void acm_port_shutdown(struct tty_port *port) | |||
| 590 | struct urb *urb; | 590 | struct urb *urb; |
| 591 | struct acm_wb *wb; | 591 | struct acm_wb *wb; |
| 592 | int i; | 592 | int i; |
| 593 | int pm_err; | ||
| 594 | 593 | ||
| 595 | dev_dbg(&acm->control->dev, "%s\n", __func__); | 594 | dev_dbg(&acm->control->dev, "%s\n", __func__); |
| 596 | 595 | ||
| 597 | pm_err = usb_autopm_get_interface(acm->control); | ||
| 598 | acm_set_control(acm, acm->ctrlout = 0); | 596 | acm_set_control(acm, acm->ctrlout = 0); |
| 599 | 597 | ||
| 598 | /* | ||
| 599 | * Need to grab write_lock to prevent race with resume, but no need to | ||
| 600 | * hold it due to the tty-port initialised flag. | ||
| 601 | */ | ||
| 602 | spin_lock_irq(&acm->write_lock); | ||
| 603 | spin_unlock_irq(&acm->write_lock); | ||
| 604 | |||
| 605 | usb_autopm_get_interface_no_resume(acm->control); | ||
| 606 | acm->control->needs_remote_wakeup = 0; | ||
| 607 | usb_autopm_put_interface(acm->control); | ||
| 608 | |||
| 600 | for (;;) { | 609 | for (;;) { |
| 601 | urb = usb_get_from_anchor(&acm->delayed); | 610 | urb = usb_get_from_anchor(&acm->delayed); |
| 602 | if (!urb) | 611 | if (!urb) |
| @@ -611,10 +620,6 @@ static void acm_port_shutdown(struct tty_port *port) | |||
| 611 | usb_kill_urb(acm->wb[i].urb); | 620 | usb_kill_urb(acm->wb[i].urb); |
| 612 | for (i = 0; i < acm->rx_buflimit; i++) | 621 | for (i = 0; i < acm->rx_buflimit; i++) |
| 613 | usb_kill_urb(acm->read_urbs[i]); | 622 | usb_kill_urb(acm->read_urbs[i]); |
| 614 | |||
| 615 | acm->control->needs_remote_wakeup = 0; | ||
| 616 | if (!pm_err) | ||
| 617 | usb_autopm_put_interface(acm->control); | ||
| 618 | } | 623 | } |
| 619 | 624 | ||
| 620 | static void acm_tty_cleanup(struct tty_struct *tty) | 625 | static void acm_tty_cleanup(struct tty_struct *tty) |
