diff options
author | Tony Lindgren <tony@atomide.com> | 2017-01-24 10:18:57 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-01-25 05:02:29 -0500 |
commit | 407788b51db6f6aab499d02420082f436abf3238 (patch) | |
tree | b2fb3c885baf47cd2bd8ee0429f423b352e11905 | |
parent | 7a308bb3016f57e5be11a677d15b821536419d36 (diff) |
usb: musb: Fix host mode error -71 regression
Commit 467d5c980709 ("usb: musb: Implement session bit based runtime PM for
musb-core") started implementing musb generic runtime PM support by
introducing devctl register session bit based state control.
This caused a regression where if a USB mass storage device is connected
to a USB hub, we can get:
usb 1-1: reset high-speed USB device number 2 using musb-hdrc
usb 1-1: device descriptor read/64, error -71
usb 1-1.1: new high-speed USB device number 4 using musb-hdrc
This is because before the USB storage device is connected, musb is
in OTG_STATE_A_SUSPEND. And we currently only set need_finish_resume
in musb_stage0_irq() and the related code calling finish_resume_work
in musb_resume() and musb_runtime_resume() never gets called.
To fix the issue, we can call schedule_delayed_work() directly in
musb_stage0_irq() to have finish_resume_work run.
And we should no longer never get interrupts when when suspended.
We have changed musb to no longer need pm_runtime_irqsafe().
The need_finish_resume flag was added in commit 9298b4aad37e ("usb:
musb: fix device hotplug behind hub") and no longer applies as far
as I can tell. So let's just remove the earlier code that no longer
is needed.
Fixes: 467d5c980709 ("usb: musb: Implement session bit based runtime PM for musb-core")
Reported-by: Bin Liu <b-liu@ti.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Bin Liu <b-liu@ti.com>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/usb/musb/musb_core.c | 15 | ||||
-rw-r--r-- | drivers/usb/musb/musb_core.h | 1 |
2 files changed, 2 insertions, 14 deletions
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index fca288bbc800..cd40467be3c5 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c | |||
@@ -594,11 +594,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, | |||
594 | | MUSB_PORT_STAT_RESUME; | 594 | | MUSB_PORT_STAT_RESUME; |
595 | musb->rh_timer = jiffies | 595 | musb->rh_timer = jiffies |
596 | + msecs_to_jiffies(USB_RESUME_TIMEOUT); | 596 | + msecs_to_jiffies(USB_RESUME_TIMEOUT); |
597 | musb->need_finish_resume = 1; | ||
598 | |||
599 | musb->xceiv->otg->state = OTG_STATE_A_HOST; | 597 | musb->xceiv->otg->state = OTG_STATE_A_HOST; |
600 | musb->is_active = 1; | 598 | musb->is_active = 1; |
601 | musb_host_resume_root_hub(musb); | 599 | musb_host_resume_root_hub(musb); |
600 | schedule_delayed_work(&musb->finish_resume_work, | ||
601 | msecs_to_jiffies(USB_RESUME_TIMEOUT)); | ||
602 | break; | 602 | break; |
603 | case OTG_STATE_B_WAIT_ACON: | 603 | case OTG_STATE_B_WAIT_ACON: |
604 | musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; | 604 | musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; |
@@ -2710,11 +2710,6 @@ static int musb_resume(struct device *dev) | |||
2710 | mask = MUSB_DEVCTL_BDEVICE | MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV; | 2710 | mask = MUSB_DEVCTL_BDEVICE | MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV; |
2711 | if ((devctl & mask) != (musb->context.devctl & mask)) | 2711 | if ((devctl & mask) != (musb->context.devctl & mask)) |
2712 | musb->port1_status = 0; | 2712 | musb->port1_status = 0; |
2713 | if (musb->need_finish_resume) { | ||
2714 | musb->need_finish_resume = 0; | ||
2715 | schedule_delayed_work(&musb->finish_resume_work, | ||
2716 | msecs_to_jiffies(USB_RESUME_TIMEOUT)); | ||
2717 | } | ||
2718 | 2713 | ||
2719 | /* | 2714 | /* |
2720 | * The USB HUB code expects the device to be in RPM_ACTIVE once it came | 2715 | * The USB HUB code expects the device to be in RPM_ACTIVE once it came |
@@ -2766,12 +2761,6 @@ static int musb_runtime_resume(struct device *dev) | |||
2766 | 2761 | ||
2767 | musb_restore_context(musb); | 2762 | musb_restore_context(musb); |
2768 | 2763 | ||
2769 | if (musb->need_finish_resume) { | ||
2770 | musb->need_finish_resume = 0; | ||
2771 | schedule_delayed_work(&musb->finish_resume_work, | ||
2772 | msecs_to_jiffies(USB_RESUME_TIMEOUT)); | ||
2773 | } | ||
2774 | |||
2775 | spin_lock_irqsave(&musb->lock, flags); | 2764 | spin_lock_irqsave(&musb->lock, flags); |
2776 | error = musb_run_resume_work(musb); | 2765 | error = musb_run_resume_work(musb); |
2777 | if (error) | 2766 | if (error) |
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index ade902ea1221..ce5a18c98c6d 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h | |||
@@ -410,7 +410,6 @@ struct musb { | |||
410 | 410 | ||
411 | /* is_suspended means USB B_PERIPHERAL suspend */ | 411 | /* is_suspended means USB B_PERIPHERAL suspend */ |
412 | unsigned is_suspended:1; | 412 | unsigned is_suspended:1; |
413 | unsigned need_finish_resume :1; | ||
414 | 413 | ||
415 | /* may_wakeup means remote wakeup is enabled */ | 414 | /* may_wakeup means remote wakeup is enabled */ |
416 | unsigned may_wakeup:1; | 415 | unsigned may_wakeup:1; |