From 25e67d307809d92c9d6f142f398bc4e261caaa1a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 25 May 2012 04:28:41 +0900 Subject: [PATCH] 3.4-stable patches added patches: usb-add-usb_quirk_reset_resume-for-m-audio-88es.patch usb-gadget-fsl_udc_core-dtd-s-next-dtd-pointer-need-to-be-updated-once-written.patch usb-ohci-at91-add-a-reset-function-to-fix-race-condition.patch usb-remove-races-in-devio.c.patch usb-serial-ti_usb_3410_5052-add-support-for-the-fri2-serial-console.patch xhci-add-lynx-point-to-list-of-intel-switchable-hosts.patch xhci-keep-track-of-ports-being-resumed-and-indicate-in-hub_status_data.patch --- queue-3.4/series | 7 + ..._quirk_reset_resume-for-m-audio-88es.patch | 33 +++++ ...nter-need-to-be-updated-once-written.patch | 41 ++++++ ...reset-function-to-fix-race-condition.patch | 59 ++++++++ queue-3.4/usb-remove-races-in-devio.c.patch | 129 ++++++++++++++++++ ...-support-for-the-fri2-serial-console.patch | 71 ++++++++++ ...nt-to-list-of-intel-switchable-hosts.patch | 76 +++++++++++ ...umed-and-indicate-in-hub_status_data.patch | 126 +++++++++++++++++ 8 files changed, 542 insertions(+) create mode 100644 queue-3.4/usb-add-usb_quirk_reset_resume-for-m-audio-88es.patch create mode 100644 queue-3.4/usb-gadget-fsl_udc_core-dtd-s-next-dtd-pointer-need-to-be-updated-once-written.patch create mode 100644 queue-3.4/usb-ohci-at91-add-a-reset-function-to-fix-race-condition.patch create mode 100644 queue-3.4/usb-remove-races-in-devio.c.patch create mode 100644 queue-3.4/usb-serial-ti_usb_3410_5052-add-support-for-the-fri2-serial-console.patch create mode 100644 queue-3.4/xhci-add-lynx-point-to-list-of-intel-switchable-hosts.patch create mode 100644 queue-3.4/xhci-keep-track-of-ports-being-resumed-and-indicate-in-hub_status_data.patch diff --git a/queue-3.4/series b/queue-3.4/series index c075586b8d2..b1b386f7f21 100644 --- a/queue-3.4/series +++ b/queue-3.4/series @@ -48,3 +48,10 @@ usb-usbtest-two-super-speed-fixes-for-usbtest.patch usb-ehci-platform-remove-update_device.patch usb-ehci-omap-finish-ehci-omap-phy-reset-cycle-before-adding-hcd.patch usb-gpio_vbus-provide-an-appropriate-debounce-interval.patch +usb-ohci-at91-add-a-reset-function-to-fix-race-condition.patch +usb-remove-races-in-devio.c.patch +usb-serial-ti_usb_3410_5052-add-support-for-the-fri2-serial-console.patch +usb-gadget-fsl_udc_core-dtd-s-next-dtd-pointer-need-to-be-updated-once-written.patch +usb-add-usb_quirk_reset_resume-for-m-audio-88es.patch +xhci-add-lynx-point-to-list-of-intel-switchable-hosts.patch +xhci-keep-track-of-ports-being-resumed-and-indicate-in-hub_status_data.patch diff --git a/queue-3.4/usb-add-usb_quirk_reset_resume-for-m-audio-88es.patch b/queue-3.4/usb-add-usb_quirk_reset_resume-for-m-audio-88es.patch new file mode 100644 index 00000000000..199326a67d2 --- /dev/null +++ b/queue-3.4/usb-add-usb_quirk_reset_resume-for-m-audio-88es.patch @@ -0,0 +1,33 @@ +From 166cb70e97bd83d7ae9bbec6ae59a178fd9bb823 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Steffen=20M=C3=BCller?= +Date: Mon, 30 Apr 2012 13:05:34 +0200 +Subject: usb: add USB_QUIRK_RESET_RESUME for M-Audio 88es +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: =?UTF-8?q?Steffen=20M=C3=BCller?= + +commit 166cb70e97bd83d7ae9bbec6ae59a178fd9bb823 upstream. + +Tested-by: Steffen Müller +Signed-off-by: Steffen Müller +Signed-off-by: Stefan Seyfried +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/core/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -123,6 +123,9 @@ static const struct usb_device_id usb_qu + /* Guillemot Webcam Hercules Dualpix Exchange*/ + { USB_DEVICE(0x06f8, 0x3005), .driver_info = USB_QUIRK_RESET_RESUME }, + ++ /* Midiman M-Audio Keystation 88es */ ++ { USB_DEVICE(0x0763, 0x0192), .driver_info = USB_QUIRK_RESET_RESUME }, ++ + /* M-Systems Flash Disk Pioneers */ + { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, + diff --git a/queue-3.4/usb-gadget-fsl_udc_core-dtd-s-next-dtd-pointer-need-to-be-updated-once-written.patch b/queue-3.4/usb-gadget-fsl_udc_core-dtd-s-next-dtd-pointer-need-to-be-updated-once-written.patch new file mode 100644 index 00000000000..37c8f72e9f3 --- /dev/null +++ b/queue-3.4/usb-gadget-fsl_udc_core-dtd-s-next-dtd-pointer-need-to-be-updated-once-written.patch @@ -0,0 +1,41 @@ +From 4d0947dec4db1224354e2f6f00ae22ce38e62a43 Mon Sep 17 00:00:00 2001 +From: Peter Chen +Date: Sun, 1 Apr 2012 15:17:16 +0800 +Subject: usb: gadget: fsl_udc_core: dTD's next dtd pointer need to be updated once written + +From: Peter Chen + +commit 4d0947dec4db1224354e2f6f00ae22ce38e62a43 upstream. + +dTD's next dtd pointer need to be updated once CPU writes it, or this +request may not be handled by controller, then host will get NAK from +device forever. + +This problem occurs when there is a request is handling, we need to add +a new request to dTD list, if this new request is added before the current +one is finished, the new request is intended to added as next dtd pointer +at current dTD, but without wmb(), the dTD's next dtd pointer may not be +updated when the controller reads it. In that case, the controller will +still get Terminate Bit is 1 at dTD's next dtd pointer, that means there is +no next request, then this new request is missed by controller. + +Signed-off-by: Peter Chen +Acked-by: Li Yang +Signed-off-by: Felipe Balbi +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/gadget/fsl_udc_core.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/usb/gadget/fsl_udc_core.c ++++ b/drivers/usb/gadget/fsl_udc_core.c +@@ -736,6 +736,8 @@ static void fsl_queue_td(struct fsl_ep * + lastreq = list_entry(ep->queue.prev, struct fsl_req, queue); + lastreq->tail->next_td_ptr = + cpu_to_hc32(req->head->td_dma & DTD_ADDR_MASK); ++ /* Ensure dTD's next dtd pointer to be updated */ ++ wmb(); + /* Read prime bit, if 1 goto done */ + if (fsl_readl(&dr_regs->endpointprime) & bitmask) + return; diff --git a/queue-3.4/usb-ohci-at91-add-a-reset-function-to-fix-race-condition.patch b/queue-3.4/usb-ohci-at91-add-a-reset-function-to-fix-race-condition.patch new file mode 100644 index 00000000000..677c251d89f --- /dev/null +++ b/queue-3.4/usb-ohci-at91-add-a-reset-function-to-fix-race-condition.patch @@ -0,0 +1,59 @@ +From 07e4e556eff4938eb2edf2591de3aa7d7fb82b52 Mon Sep 17 00:00:00 2001 +From: Nicolas Ferre +Date: Wed, 9 May 2012 10:48:54 +0200 +Subject: USB: ohci-at91: add a reset function to fix race condition + +From: Nicolas Ferre + +commit 07e4e556eff4938eb2edf2591de3aa7d7fb82b52 upstream. + +A possible race condition appears because we are not initializing +the ohci->regs before calling usb_hcd_request_irqs(). +We move the call to ohci_init() in hcd->driver->reset() instead of +hcd->driver->start() to fix this. +This was experienced when we share the same IRQ line between OHCI and EHCI +controllers. + +Signed-off-by: Nicolas Ferre +Tested-by: Christian Eggers +Acked-by: Alan Stern +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/host/ohci-at91.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +--- a/drivers/usb/host/ohci-at91.c ++++ b/drivers/usb/host/ohci-at91.c +@@ -223,7 +223,7 @@ static void __devexit usb_hcd_at91_remov + /*-------------------------------------------------------------------------*/ + + static int __devinit +-ohci_at91_start (struct usb_hcd *hcd) ++ohci_at91_reset (struct usb_hcd *hcd) + { + struct at91_usbh_data *board = hcd->self.controller->platform_data; + struct ohci_hcd *ohci = hcd_to_ohci (hcd); +@@ -233,6 +233,14 @@ ohci_at91_start (struct usb_hcd *hcd) + return ret; + + ohci->num_ports = board->ports; ++ return 0; ++} ++ ++static int __devinit ++ohci_at91_start (struct usb_hcd *hcd) ++{ ++ struct ohci_hcd *ohci = hcd_to_ohci (hcd); ++ int ret; + + if ((ret = ohci_run(ohci)) < 0) { + err("can't start %s", hcd->self.bus_name); +@@ -418,6 +426,7 @@ static const struct hc_driver ohci_at91_ + /* + * basic lifecycle operations + */ ++ .reset = ohci_at91_reset, + .start = ohci_at91_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, diff --git a/queue-3.4/usb-remove-races-in-devio.c.patch b/queue-3.4/usb-remove-races-in-devio.c.patch new file mode 100644 index 00000000000..f539801fc0a --- /dev/null +++ b/queue-3.4/usb-remove-races-in-devio.c.patch @@ -0,0 +1,129 @@ +From 4e09dcf20f7b5358615514c2ec8584b248ab8874 Mon Sep 17 00:00:00 2001 +From: Huajun Li +Date: Fri, 18 May 2012 20:12:51 +0800 +Subject: USB: Remove races in devio.c + +From: Huajun Li + +commit 4e09dcf20f7b5358615514c2ec8584b248ab8874 upstream. + +There exist races in devio.c, below is one case, +and there are similar races in destroy_async() +and proc_unlinkurb(). Remove these races. + + cancel_bulk_urbs() async_completed() +------------------- ----------------------- + spin_unlock(&ps->lock); + + list_move_tail(&as->asynclist, + &ps->async_completed); + + wake_up(&ps->wait); + + Lead to free_async() be triggered, + then urb and 'as' will be freed. + + usb_unlink_urb(as->urb); + ===> refer to the freed 'as' + +Signed-off-by: Huajun Li +Cc: Alan Stern +Cc: Oncaphillis +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/core/devio.c | 33 +++++++++++++++++++++++++-------- + 1 file changed, 25 insertions(+), 8 deletions(-) + +--- a/drivers/usb/core/devio.c ++++ b/drivers/usb/core/devio.c +@@ -333,17 +333,14 @@ static struct async *async_getcompleted( + static struct async *async_getpending(struct dev_state *ps, + void __user *userurb) + { +- unsigned long flags; + struct async *as; + +- spin_lock_irqsave(&ps->lock, flags); + list_for_each_entry(as, &ps->async_pending, asynclist) + if (as->userurb == userurb) { + list_del_init(&as->asynclist); +- spin_unlock_irqrestore(&ps->lock, flags); + return as; + } +- spin_unlock_irqrestore(&ps->lock, flags); ++ + return NULL; + } + +@@ -398,6 +395,7 @@ static void cancel_bulk_urbs(struct dev_ + __releases(ps->lock) + __acquires(ps->lock) + { ++ struct urb *urb; + struct async *as; + + /* Mark all the pending URBs that match bulk_addr, up to but not +@@ -420,8 +418,11 @@ __acquires(ps->lock) + list_for_each_entry(as, &ps->async_pending, asynclist) { + if (as->bulk_status == AS_UNLINK) { + as->bulk_status = 0; /* Only once */ ++ urb = as->urb; ++ usb_get_urb(urb); + spin_unlock(&ps->lock); /* Allow completions */ +- usb_unlink_urb(as->urb); ++ usb_unlink_urb(urb); ++ usb_put_urb(urb); + spin_lock(&ps->lock); + goto rescan; + } +@@ -472,6 +473,7 @@ static void async_completed(struct urb * + + static void destroy_async(struct dev_state *ps, struct list_head *list) + { ++ struct urb *urb; + struct async *as; + unsigned long flags; + +@@ -479,10 +481,13 @@ static void destroy_async(struct dev_sta + while (!list_empty(list)) { + as = list_entry(list->next, struct async, asynclist); + list_del_init(&as->asynclist); ++ urb = as->urb; ++ usb_get_urb(urb); + + /* drop the spinlock so the completion handler can run */ + spin_unlock_irqrestore(&ps->lock, flags); +- usb_kill_urb(as->urb); ++ usb_kill_urb(urb); ++ usb_put_urb(urb); + spin_lock_irqsave(&ps->lock, flags); + } + spin_unlock_irqrestore(&ps->lock, flags); +@@ -1410,12 +1415,24 @@ static int proc_submiturb(struct dev_sta + + static int proc_unlinkurb(struct dev_state *ps, void __user *arg) + { ++ struct urb *urb; + struct async *as; ++ unsigned long flags; + ++ spin_lock_irqsave(&ps->lock, flags); + as = async_getpending(ps, arg); +- if (!as) ++ if (!as) { ++ spin_unlock_irqrestore(&ps->lock, flags); + return -EINVAL; +- usb_kill_urb(as->urb); ++ } ++ ++ urb = as->urb; ++ usb_get_urb(urb); ++ spin_unlock_irqrestore(&ps->lock, flags); ++ ++ usb_kill_urb(urb); ++ usb_put_urb(urb); ++ + return 0; + } + diff --git a/queue-3.4/usb-serial-ti_usb_3410_5052-add-support-for-the-fri2-serial-console.patch b/queue-3.4/usb-serial-ti_usb_3410_5052-add-support-for-the-fri2-serial-console.patch new file mode 100644 index 00000000000..f300896075f --- /dev/null +++ b/queue-3.4/usb-serial-ti_usb_3410_5052-add-support-for-the-fri2-serial-console.patch @@ -0,0 +1,71 @@ +From 975dc33b82cb887d75a29b1e3835c8eb063a8e99 Mon Sep 17 00:00:00 2001 +From: Darren Hart +Date: Fri, 11 May 2012 13:56:57 -0700 +Subject: USB: serial: ti_usb_3410_5052: Add support for the FRI2 serial console + +From: Darren Hart + +commit 975dc33b82cb887d75a29b1e3835c8eb063a8e99 upstream. + +The Kontron M2M development board, also known as the Fish River Island II, +has an optional daughter card providing access to the PCH_UART (EG20T) via +a ti_usb_3410_5052 uart to usb chip. + +http://us.kontron.com/products/systems+and+platforms/m2m/m2m+smart+services+developer+kit.html + +Signed-off-by: Darren Hart +CC: Al Borchers +CC: Peter Berger +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/ti_usb_3410_5052.c | 6 ++++-- + drivers/usb/serial/ti_usb_3410_5052.h | 1 + + 2 files changed, 5 insertions(+), 2 deletions(-) + +--- a/drivers/usb/serial/ti_usb_3410_5052.c ++++ b/drivers/usb/serial/ti_usb_3410_5052.c +@@ -165,7 +165,7 @@ static unsigned int product_5052_count; + /* the array dimension is the number of default entries plus */ + /* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */ + /* null entry */ +-static struct usb_device_id ti_id_table_3410[14+TI_EXTRA_VID_PID_COUNT+1] = { ++static struct usb_device_id ti_id_table_3410[15+TI_EXTRA_VID_PID_COUNT+1] = { + { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, + { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, + { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, +@@ -180,6 +180,7 @@ static struct usb_device_id ti_id_table_ + { USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) }, + { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) }, + { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) }, ++ { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) }, + }; + + static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = { +@@ -189,7 +190,7 @@ static struct usb_device_id ti_id_table_ + { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) }, + }; + +-static struct usb_device_id ti_id_table_combined[18+2*TI_EXTRA_VID_PID_COUNT+1] = { ++static struct usb_device_id ti_id_table_combined[19+2*TI_EXTRA_VID_PID_COUNT+1] = { + { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, + { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, + { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, +@@ -208,6 +209,7 @@ static struct usb_device_id ti_id_table_ + { USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) }, + { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) }, + { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) }, ++ { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) }, + { } + }; + +--- a/drivers/usb/serial/ti_usb_3410_5052.h ++++ b/drivers/usb/serial/ti_usb_3410_5052.h +@@ -37,6 +37,7 @@ + #define TI_5152_BOOT_PRODUCT_ID 0x5152 /* no EEPROM, no firmware */ + #define TI_5052_EEPROM_PRODUCT_ID 0x505A /* EEPROM, no firmware */ + #define TI_5052_FIRMWARE_PRODUCT_ID 0x505F /* firmware is running */ ++#define FRI2_PRODUCT_ID 0x5053 /* Fish River Island II */ + + /* Multi-Tech vendor and product ids */ + #define MTS_VENDOR_ID 0x06E0 diff --git a/queue-3.4/xhci-add-lynx-point-to-list-of-intel-switchable-hosts.patch b/queue-3.4/xhci-add-lynx-point-to-list-of-intel-switchable-hosts.patch new file mode 100644 index 00000000000..69b76113a95 --- /dev/null +++ b/queue-3.4/xhci-add-lynx-point-to-list-of-intel-switchable-hosts.patch @@ -0,0 +1,76 @@ +From 1c12443ab8eba71a658fae4572147e56d1f84f66 Mon Sep 17 00:00:00 2001 +From: Sarah Sharp +Date: Thu, 9 Feb 2012 15:55:13 -0800 +Subject: xhci: Add Lynx Point to list of Intel switchable hosts. + +From: Sarah Sharp + +commit 1c12443ab8eba71a658fae4572147e56d1f84f66 upstream. + +The upcoming Intel Lynx Point chipset includes an xHCI host controller +that can have ports switched from the EHCI host controller, just like +the Intel Panther Point xHCI host. This time, ports from both EHCI +hosts can be switched to the xHCI host controller. The PCI config +registers to do the port switching are in the exact same place in the +xHCI PCI configuration registers, with the same semantics. + +Hooray for shipping patches for next-gen hardware before the current gen +hardware is even available for purchase! + +This patch should be backported to stable kernels as old as 3.0, +that contain commit 69e848c2090aebba5698a1620604c7dccb448684 +"Intel xhci: Support EHCI/xHCI port switching." + +Signed-off-by: Sarah Sharp +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/host/ehci-pci.c | 4 +++- + drivers/usb/host/pci-quirks.c | 18 +++++++++++++++++- + 2 files changed, 20 insertions(+), 2 deletions(-) + +--- a/drivers/usb/host/ehci-pci.c ++++ b/drivers/usb/host/ehci-pci.c +@@ -368,7 +368,9 @@ static bool usb_is_intel_switchable_ehci + { + return pdev->class == PCI_CLASS_SERIAL_USB_EHCI && + pdev->vendor == PCI_VENDOR_ID_INTEL && +- pdev->device == 0x1E26; ++ (pdev->device == 0x1E26 || ++ pdev->device == 0x8C2D || ++ pdev->device == 0x8C26); + } + + static void ehci_enable_xhci_companion(void) +--- a/drivers/usb/host/pci-quirks.c ++++ b/drivers/usb/host/pci-quirks.c +@@ -712,12 +712,28 @@ static int handshake(void __iomem *ptr, + return -ETIMEDOUT; + } + +-bool usb_is_intel_switchable_xhci(struct pci_dev *pdev) ++#define PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI 0x8C31 ++ ++bool usb_is_intel_ppt_switchable_xhci(struct pci_dev *pdev) + { + return pdev->class == PCI_CLASS_SERIAL_USB_XHCI && + pdev->vendor == PCI_VENDOR_ID_INTEL && + pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI; + } ++ ++/* The Intel Lynx Point chipset also has switchable ports. */ ++bool usb_is_intel_lpt_switchable_xhci(struct pci_dev *pdev) ++{ ++ return pdev->class == PCI_CLASS_SERIAL_USB_XHCI && ++ pdev->vendor == PCI_VENDOR_ID_INTEL && ++ pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI; ++} ++ ++bool usb_is_intel_switchable_xhci(struct pci_dev *pdev) ++{ ++ return usb_is_intel_ppt_switchable_xhci(pdev) || ++ usb_is_intel_lpt_switchable_xhci(pdev); ++} + EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci); + + /* diff --git a/queue-3.4/xhci-keep-track-of-ports-being-resumed-and-indicate-in-hub_status_data.patch b/queue-3.4/xhci-keep-track-of-ports-being-resumed-and-indicate-in-hub_status_data.patch new file mode 100644 index 00000000000..2f03fc2f256 --- /dev/null +++ b/queue-3.4/xhci-keep-track-of-ports-being-resumed-and-indicate-in-hub_status_data.patch @@ -0,0 +1,126 @@ +From f370b9968a220a3d79d870dd7dee674cc0ff3d10 Mon Sep 17 00:00:00 2001 +From: Andiry Xu +Date: Sat, 14 Apr 2012 02:54:30 +0800 +Subject: xHCI: keep track of ports being resumed and indicate in hub_status_data + +From: Andiry Xu + +commit f370b9968a220a3d79d870dd7dee674cc0ff3d10 upstream. + +This commit adds a bit-array to xhci bus_state for keeping track of +which ports are undergoing a resume transition. If any of the bits +are set when xhci_hub_status_data() is called, the routine will return +a non-zero value even if no ports have any status changes pending. +This will allow usbcore to handle races between root-hub suspend and +port wakeup. + +This patch should be backported to kernels as old as 3.4, that contain +the commit 879d38e6bc36d73b0ac40ec9b0d839fda9fa8b1a "USB: fix race +between root-hub suspend and remote wakeup". + +Signed-off-by: Andiry Xu +Signed-off-by: Sarah Sharp +Cc: Alan Stern +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/host/xhci-hub.c | 22 ++++++++++++---------- + drivers/usb/host/xhci-ring.c | 1 + + drivers/usb/host/xhci.c | 12 ++++++++++-- + drivers/usb/host/xhci.h | 2 ++ + 4 files changed, 25 insertions(+), 12 deletions(-) + +--- a/drivers/usb/host/xhci-hub.c ++++ b/drivers/usb/host/xhci-hub.c +@@ -558,6 +558,7 @@ int xhci_hub_control(struct usb_hcd *hcd + xhci_dbg(xhci, "Resume USB2 port %d\n", + wIndex + 1); + bus_state->resume_done[wIndex] = 0; ++ clear_bit(wIndex, &bus_state->resuming_ports); + xhci_set_link_state(xhci, port_array, wIndex, + XDEV_U0); + xhci_dbg(xhci, "set port %d resume\n", +@@ -845,7 +846,12 @@ int xhci_hub_status_data(struct usb_hcd + /* Initial status is no changes */ + retval = (max_ports + 8) / 8; + memset(buf, 0, retval); +- status = 0; ++ ++ /* ++ * Inform the usbcore about resume-in-progress by returning ++ * a non-zero value even if there are no status changes. ++ */ ++ status = bus_state->resuming_ports; + + mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC; + +@@ -885,15 +891,11 @@ int xhci_bus_suspend(struct usb_hcd *hcd + spin_lock_irqsave(&xhci->lock, flags); + + if (hcd->self.root_hub->do_remote_wakeup) { +- port_index = max_ports; +- while (port_index--) { +- if (bus_state->resume_done[port_index] != 0) { +- spin_unlock_irqrestore(&xhci->lock, flags); +- xhci_dbg(xhci, "suspend failed because " +- "port %d is resuming\n", +- port_index + 1); +- return -EBUSY; +- } ++ if (bus_state->resuming_ports) { ++ spin_unlock_irqrestore(&xhci->lock, flags); ++ xhci_dbg(xhci, "suspend failed because " ++ "a port is resuming\n"); ++ return -EBUSY; + } + } + +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -1377,6 +1377,7 @@ static void handle_port_status(struct xh + xhci_dbg(xhci, "resume HS port %d\n", port_id); + bus_state->resume_done[faked_port_index] = jiffies + + msecs_to_jiffies(20); ++ set_bit(faked_port_index, &bus_state->resuming_ports); + mod_timer(&hcd->rh_timer, + bus_state->resume_done[faked_port_index]); + /* Do the rest in GetPortStatus */ +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -152,7 +152,7 @@ int xhci_reset(struct xhci_hcd *xhci) + { + u32 command; + u32 state; +- int ret; ++ int ret, i; + + state = xhci_readl(xhci, &xhci->op_regs->status); + if ((state & STS_HALT) == 0) { +@@ -175,7 +175,15 @@ int xhci_reset(struct xhci_hcd *xhci) + * xHCI cannot write to any doorbells or operational registers other + * than status until the "Controller Not Ready" flag is cleared. + */ +- return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000); ++ ret = handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000); ++ ++ for (i = 0; i < 2; ++i) { ++ xhci->bus_state[i].port_c_suspend = 0; ++ xhci->bus_state[i].suspended_ports = 0; ++ xhci->bus_state[i].resuming_ports = 0; ++ } ++ ++ return ret; + } + + #ifdef CONFIG_PCI +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1362,6 +1362,8 @@ struct xhci_bus_state { + u32 suspended_ports; + u32 port_remote_wakeup; + unsigned long resume_done[USB_MAXCHILDREN]; ++ /* which ports have started to resume */ ++ unsigned long resuming_ports; + }; + + static inline unsigned int hcd_index(struct usb_hcd *hcd) -- 2.47.3