]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.9-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 18 Jun 2018 08:04:52 +0000 (10:04 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 18 Jun 2018 08:04:52 +0000 (10:04 +0200)
added patches:
usb-musb-fix-remote-wakeup-racing-with-suspend.patch

queue-4.9/series
queue-4.9/usb-musb-fix-remote-wakeup-racing-with-suspend.patch [new file with mode: 0644]

index ab380667a0809cf46cd6e48e5831f4cb4b0c20e5..4a1a7c71056ec722a64d77d5ab3985737a0c03bd 100644 (file)
@@ -11,3 +11,4 @@ net-dsa-b53-add-bcm5389-support.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.9/usb-musb-fix-remote-wakeup-racing-with-suspend.patch b/queue-4.9/usb-musb-fix-remote-wakeup-racing-with-suspend.patch
new file mode 100644 (file)
index 0000000..c4ddce7
--- /dev/null
@@ -0,0 +1,126 @@
+From foo@baz Sun Jun 17 13:19:44 CEST 2018
+From: "Daniel Glöckner" <dg@emlix.com>
+Date: Mon, 14 May 2018 09:40:05 -0500
+Subject: usb: musb: fix remote wakeup racing with suspend
+
+From: "Daniel Glöckner" <dg@emlix.com>
+
+[ 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 <dg@emlix.com>
+Signed-off-by: Bin Liu <b-liu@ti.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -2554,8 +2554,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
+@@ -73,14 +73,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
+@@ -91,16 +91,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;
++                      }
+               }
+               musb_dbg(musb, "Root port suspended, power %02x", power);
+@@ -137,6 +141,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)