From def3ba14d7231805d93a1c6e2f2d1054383e4262 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 18 Jun 2018 10:04:34 +0200 Subject: [PATCH] 4.4-stable patches added patches: usb-musb-fix-remote-wakeup-racing-with-suspend.patch --- queue-4.4/series | 1 + ...ix-remote-wakeup-racing-with-suspend.patch | 126 ++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 queue-4.4/usb-musb-fix-remote-wakeup-racing-with-suspend.patch diff --git a/queue-4.4/series b/queue-4.4/series index c6a4537cbe4..46a01f071f2 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -7,3 +7,4 @@ net-sonic-use-dma_mapping_error.patch revert-btrfs-fix-scrub-to-repair-raid6-corruption.patch tcp-do-not-overshoot-window_clamp-in-tcp_rcv_space_adjust.patch btrfs-make-raid6-rebuild-retry-more.patch +usb-musb-fix-remote-wakeup-racing-with-suspend.patch diff --git a/queue-4.4/usb-musb-fix-remote-wakeup-racing-with-suspend.patch b/queue-4.4/usb-musb-fix-remote-wakeup-racing-with-suspend.patch new file mode 100644 index 00000000000..f7c73426412 --- /dev/null +++ b/queue-4.4/usb-musb-fix-remote-wakeup-racing-with-suspend.patch @@ -0,0 +1,126 @@ +From foo@baz Sun Jun 17 13:19:44 CEST 2018 +From: "Daniel Glöckner" +Date: Mon, 14 May 2018 09:40:05 -0500 +Subject: usb: musb: fix remote wakeup racing with suspend + +From: "Daniel Glöckner" + +[ Upstream commit ebc3dd688cd988754a304147753b13e58de1b5a1 ] + +It has been observed that writing 0xF2 to the power register while it +reads as 0xF4 results in the register having the value 0xF0, i.e. clearing +RESUME and setting SUSPENDM in one go does not work. It might also violate +the USB spec to transition directly from resume to suspend, especially +when not taking T_DRSMDN into account. But this is what happens when a +remote wakeup occurs between SetPortFeature USB_PORT_FEAT_SUSPEND on the +root hub and musb_bus_suspend being called. + +This commit returns -EBUSY when musb_bus_suspend is called while remote +wakeup is signalled and thus avoids to reset the RESUME bit. Ignoring +this error when musb_port_suspend is called from musb_hub_control is ok. + +Signed-off-by: Daniel Glöckner +Signed-off-by: Bin Liu +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/musb/musb_host.c | 5 ++++- + drivers/usb/musb/musb_host.h | 7 +++++-- + drivers/usb/musb/musb_virthub.c | 25 +++++++++++++++---------- + 3 files changed, 24 insertions(+), 13 deletions(-) + +--- a/drivers/usb/musb/musb_host.c ++++ b/drivers/usb/musb/musb_host.c +@@ -2580,8 +2580,11 @@ static int musb_bus_suspend(struct usb_h + { + struct musb *musb = hcd_to_musb(hcd); + u8 devctl; ++ int ret; + +- musb_port_suspend(musb, true); ++ ret = musb_port_suspend(musb, true); ++ if (ret) ++ return ret; + + if (!is_host_active(musb)) + return 0; +--- a/drivers/usb/musb/musb_host.h ++++ b/drivers/usb/musb/musb_host.h +@@ -92,7 +92,7 @@ extern void musb_host_rx(struct musb *, + extern void musb_root_disconnect(struct musb *musb); + extern void musb_host_resume_root_hub(struct musb *musb); + extern void musb_host_poke_root_hub(struct musb *musb); +-extern void musb_port_suspend(struct musb *musb, bool do_suspend); ++extern int musb_port_suspend(struct musb *musb, bool do_suspend); + extern void musb_port_reset(struct musb *musb, bool do_reset); + extern void musb_host_finish_resume(struct work_struct *work); + #else +@@ -124,7 +124,10 @@ static inline void musb_root_disconnect( + static inline void musb_host_resume_root_hub(struct musb *musb) {} + static inline void musb_host_poll_rh_status(struct musb *musb) {} + static inline void musb_host_poke_root_hub(struct musb *musb) {} +-static inline void musb_port_suspend(struct musb *musb, bool do_suspend) {} ++static inline int musb_port_suspend(struct musb *musb, bool do_suspend) ++{ ++ return 0; ++} + static inline void musb_port_reset(struct musb *musb, bool do_reset) {} + static inline void musb_host_finish_resume(struct work_struct *work) {} + #endif +--- a/drivers/usb/musb/musb_virthub.c ++++ b/drivers/usb/musb/musb_virthub.c +@@ -74,14 +74,14 @@ void musb_host_finish_resume(struct work + spin_unlock_irqrestore(&musb->lock, flags); + } + +-void musb_port_suspend(struct musb *musb, bool do_suspend) ++int musb_port_suspend(struct musb *musb, bool do_suspend) + { + struct usb_otg *otg = musb->xceiv->otg; + u8 power; + void __iomem *mbase = musb->mregs; + + if (!is_host_active(musb)) +- return; ++ return 0; + + /* NOTE: this doesn't necessarily put PHY into low power mode, + * turning off its clock; that's a function of PHY integration and +@@ -92,16 +92,20 @@ void musb_port_suspend(struct musb *musb + if (do_suspend) { + int retries = 10000; + +- power &= ~MUSB_POWER_RESUME; +- power |= MUSB_POWER_SUSPENDM; +- musb_writeb(mbase, MUSB_POWER, power); ++ if (power & MUSB_POWER_RESUME) ++ return -EBUSY; ++ ++ if (!(power & MUSB_POWER_SUSPENDM)) { ++ power |= MUSB_POWER_SUSPENDM; ++ musb_writeb(mbase, MUSB_POWER, power); + +- /* Needed for OPT A tests */ +- power = musb_readb(mbase, MUSB_POWER); +- while (power & MUSB_POWER_SUSPENDM) { ++ /* Needed for OPT A tests */ + power = musb_readb(mbase, MUSB_POWER); +- if (retries-- < 1) +- break; ++ while (power & MUSB_POWER_SUSPENDM) { ++ power = musb_readb(mbase, MUSB_POWER); ++ if (retries-- < 1) ++ break; ++ } + } + + dev_dbg(musb->controller, "Root port suspended, power %02x\n", power); +@@ -138,6 +142,7 @@ void musb_port_suspend(struct musb *musb + schedule_delayed_work(&musb->finish_resume_work, + msecs_to_jiffies(USB_RESUME_TIMEOUT)); + } ++ return 0; + } + + void musb_port_reset(struct musb *musb, bool do_reset) -- 2.47.3