Commit baadd52f authored by Sebastian Andrzej Siewior's avatar Sebastian Andrzej Siewior Committed by Felipe Balbi

usb: musb: try a race-free wakeup

Attaching a keyboard, using it as a wakeup via
|for f in $(find /sys/devices/ocp.3/47400000.usb -name wakeup)
|do
|	echo enabled > $f
|done

going into standby
|  echo standby >  /sys/power/state

and now a wake up by a pressing a key.
What happens is that the system wakes up but the USB device is dead. The
USB stack tries to send a few control URBs but nothing comes back.
Eventually it gaves up and the device remains dead:
|[  632.559678] PM: Wakeup source USB1_PHY
|[  632.581074] PM: noirq resume of devices complete after 21.261 msecs
|[  632.607521] PM: early resume of devices complete after 10.360 msecs
|[  632.616854] net eth2: initializing cpsw version 1.12 (0)
|[  632.704126] net eth2: phy found : id is : 0x4dd074
|[  636.704048] libphy: 4a101000.mdio:00 - Link is Up - 1000/Full
|[  638.444620] usb 1-1: reset low-speed USB device number 2 using musb-hdrc
|[  653.713435] usb 1-1: device descriptor read/64, error -110
|[  669.093435] usb 1-1: device descriptor read/64, error -110
|[  669.473424] usb 1-1: reset low-speed USB device number 2 using musb-hdrc
|[  684.743436] usb 1-1: device descriptor read/64, error -110
|[  690.065097] PM: resume of devices complete after 57450.744 msecs
|[  690.076601] PM: Finishing wakeup.
|[  690.076627] Restarting tasks ...

It seems that since we got woken up via MUSB_INTR_RESUME the
musb_host_finish_resume() callback is executed before the
resume-callbacks of the PHY and glue layer are invoked. If I delay it
until the glue layer resumed then I don't see this problem.

I also move musb_host_resume_root_hub() into that callback since I don't
see any reason in doing anything resume-link if there are still pieces
not restored.
Signed-off-by: default avatarSebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent b87fd2f7
...@@ -478,13 +478,10 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, ...@@ -478,13 +478,10 @@ 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(20); + msecs_to_jiffies(20);
schedule_delayed_work( musb->need_finish_resume = 1;
&musb->finish_resume_work,
msecs_to_jiffies(20));
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);
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;
...@@ -2319,6 +2316,11 @@ static int musb_resume(struct device *dev) ...@@ -2319,6 +2316,11 @@ 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(20));
}
return 0; return 0;
} }
......
...@@ -390,6 +390,7 @@ struct musb { ...@@ -390,6 +390,7 @@ 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;
......
...@@ -72,6 +72,7 @@ void musb_host_finish_resume(struct work_struct *work) ...@@ -72,6 +72,7 @@ void musb_host_finish_resume(struct work_struct *work)
musb->xceiv->otg->state = OTG_STATE_A_HOST; musb->xceiv->otg->state = OTG_STATE_A_HOST;
spin_unlock_irqrestore(&musb->lock, flags); spin_unlock_irqrestore(&musb->lock, flags);
musb_host_resume_root_hub(musb);
} }
void musb_port_suspend(struct musb *musb, bool do_suspend) void musb_port_suspend(struct musb *musb, bool do_suspend)
......
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