--- /dev/null
+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)