Patchwork [3.11.y.z,extended,stable] Patch "USB: OHCI: fix problem with global suspend on ATI controllers" has been added to staging queue

mail settings
Submitter Luis Henriques
Date May 14, 2014, 2:57 p.m.
Message ID <>
Download mbox | patch
Permalink /patch/348824/
State New
Headers show


Luis Henriques - May 14, 2014, 2:57 p.m.
This is a note to let you know that I have just added a patch titled

    USB: OHCI: fix problem with global suspend on ATI controllers

to the linux-3.11.y-queue branch of the 3.11.y.z extended stable tree 
which can be found at:;a=shortlog;h=refs/heads/linux-3.11.y-queue

If you, or anyone else, feels it should not be added to this tree, please 
reply to this email.

For more information about the 3.11.y.z tree, see



From 22cb96d42ecafcfc3f3e9b0b0ae36124b22a0b6b Mon Sep 17 00:00:00 2001
From: Alan Stern <>
Date: Thu, 1 May 2014 15:21:42 -0400
Subject: USB: OHCI: fix problem with global suspend on ATI controllers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

commit c1db30a2a79eb59997b13b8cabf2a50bea9f04e1 upstream.

Some OHCI controllers from ATI/AMD seem to have difficulty with
"global" USB suspend, that is, suspending an entire USB bus without
setting the suspend feature for each port connected to a device.  When
we try to resume the child devices, the controller gives timeout
errors on the unsuspended ports, requiring resets, and can even cause
ohci-hcd to hang; see

and the following messages.

This patch fixes the problem by adding a new quirk flag to ohci-hcd.
The flag causes the ohci_rh_suspend() routine to suspend each
unsuspended, enabled port before suspending the root hub.  This
effectively converts the "global" suspend to an ordinary root-hub
suspend.  There is no need to unsuspend these ports when the root hub
is resumed, because the child devices will be resumed anyway in the
course of a normal system resume ("global" suspend is never used for
runtime PM).

This patch should be applied to all stable kernels which include
commit 0aa2832dd0d9 (USB: use "global suspend" for system sleep on
USB-2 buses) or a backported version thereof.

Signed-off-by: Alan Stern <>
Reported-by: Peter Münster <>
Tested-by: Peter Münster <>
Signed-off-by: Greg Kroah-Hartman <>
[ luis: backported to 3.11: adjusted context ]
Signed-off-by: Luis Henriques <>
 drivers/usb/host/ohci-hub.c | 18 ++++++++++++++++++
 drivers/usb/host/ohci-pci.c |  1 +
 drivers/usb/host/ohci.h     |  2 ++
 3 files changed, 21 insertions(+)



diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 2347ab8..dcf5708 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -90,6 +90,24 @@  __acquires(ohci->lock)
 	dl_done_list (ohci);
 	finish_unlinks (ohci, ohci_frame_no(ohci));

+	/*
+	 * Some controllers don't handle "global" suspend properly if
+	 * there are unsuspended ports.  For these controllers, put all
+	 * the enabled ports into suspend before suspending the root hub.
+	 */
+	if (ohci->flags & OHCI_QUIRK_GLOBAL_SUSPEND) {
+		__hc32 __iomem	*portstat = ohci->regs->roothub.portstatus;
+		int		i;
+		unsigned	temp;
+		for (i = 0; i < ohci->num_ports; (++i, ++portstat)) {
+			temp = ohci_readl(ohci, portstat);
+			if ((temp & (RH_PS_PES | RH_PS_PSS)) ==
+					RH_PS_PES)
+				ohci_writel(ohci, RH_PS_PSS, portstat);
+		}
+	}
 	/* maybe resume can wake root hub */
 	if (ohci_to_hcd(ohci)->self.root_hub->do_remote_wakeup || autostop) {
 		ohci->hc_control |= OHCI_CTRL_RWE;
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index ec337c2..32a2e6a 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -171,6 +171,7 @@  static int ohci_quirk_amd700(struct usb_hcd *hcd)

 	amd_smbus_dev = NULL;

 	return 0;
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index e2e5faa..0b2e58c 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -405,6 +405,8 @@  struct ohci_hcd {
 #define	OHCI_QUIRK_HUB_POWER	0x100			/* distrust firmware power/oc setup */
 #define	OHCI_QUIRK_AMD_PLL	0x200			/* AMD PLL quirk*/
 #define	OHCI_QUIRK_AMD_PREFETCH	0x400			/* pre-fetch for ISO transfer */
+#define	OHCI_QUIRK_GLOBAL_SUSPEND	0x800		/* must suspend ports */
 	// there are also chip quirks/bugs in init logic

 	struct work_struct	nec_work;	/* Worker for NEC quirk */