Commit e40d15fc authored by Tony Lindgren's avatar Tony Lindgren Committed by Greg Kroah-Hartman

usb: musb: Fix host mode error -71 regression

commit 407788b5 upstream.

Commit 467d5c98 ("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 9298b4aa ("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: 467d5c98 ("usb: musb: Implement session bit based runtime PM for musb-core")
Reported-by: default avatarBin Liu <b-liu@ti.com>
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
Signed-off-by: default avatarBin Liu <b-liu@ti.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent cbd819e7
...@@ -578,11 +578,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, ...@@ -578,11 +578,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
| MUSB_PORT_STAT_RESUME; | MUSB_PORT_STAT_RESUME;
musb->rh_timer = jiffies musb->rh_timer = jiffies
+ msecs_to_jiffies(USB_RESUME_TIMEOUT); + msecs_to_jiffies(USB_RESUME_TIMEOUT);
musb->need_finish_resume = 1;
musb->xceiv->otg->state = OTG_STATE_A_HOST; musb->xceiv->otg->state = OTG_STATE_A_HOST;
musb->is_active = 1; musb->is_active = 1;
musb_host_resume_root_hub(musb); musb_host_resume_root_hub(musb);
schedule_delayed_work(&musb->finish_resume_work,
msecs_to_jiffies(USB_RESUME_TIMEOUT));
break; break;
case OTG_STATE_B_WAIT_ACON: case OTG_STATE_B_WAIT_ACON:
musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
...@@ -2691,11 +2691,6 @@ static int musb_resume(struct device *dev) ...@@ -2691,11 +2691,6 @@ static int musb_resume(struct device *dev)
mask = MUSB_DEVCTL_BDEVICE | MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV; mask = MUSB_DEVCTL_BDEVICE | MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV;
if ((devctl & mask) != (musb->context.devctl & mask)) if ((devctl & mask) != (musb->context.devctl & mask))
musb->port1_status = 0; musb->port1_status = 0;
if (musb->need_finish_resume) {
musb->need_finish_resume = 0;
schedule_delayed_work(&musb->finish_resume_work,
msecs_to_jiffies(USB_RESUME_TIMEOUT));
}
/* /*
* The USB HUB code expects the device to be in RPM_ACTIVE once it came * The USB HUB code expects the device to be in RPM_ACTIVE once it came
...@@ -2747,12 +2742,6 @@ static int musb_runtime_resume(struct device *dev) ...@@ -2747,12 +2742,6 @@ static int musb_runtime_resume(struct device *dev)
musb_restore_context(musb); musb_restore_context(musb);
if (musb->need_finish_resume) {
musb->need_finish_resume = 0;
schedule_delayed_work(&musb->finish_resume_work,
msecs_to_jiffies(USB_RESUME_TIMEOUT));
}
spin_lock_irqsave(&musb->lock, flags); spin_lock_irqsave(&musb->lock, flags);
error = musb_run_resume_work(musb); error = musb_run_resume_work(musb);
if (error) if (error)
......
...@@ -410,7 +410,6 @@ struct musb { ...@@ -410,7 +410,6 @@ struct musb {
/* is_suspended means USB B_PERIPHERAL suspend */ /* is_suspended means USB B_PERIPHERAL suspend */
unsigned is_suspended:1; unsigned is_suspended:1;
unsigned need_finish_resume :1;
/* may_wakeup means remote wakeup is enabled */ /* may_wakeup means remote wakeup is enabled */
unsigned may_wakeup:1; unsigned may_wakeup:1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment