[PATCH v3 4/4] usb: ohci: add AMD remote wakeup quirk into ohci driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The following patch is required to resolve remote wake issues with
certain devices.

Issue description:
If the remote wake is issued from the device in a specific timing
condition while the system is entering sleep state then it may cause
system to auto wake on subsequent sleep cycle.

Root cause:
Host controller rebroadcasts the Resume signal > 100 µseconds after
receiving the original resume event from the device. For proper
function, some devices may require the rebroadcast of resume event
within the USB spec of 100µS.

Workaroud:
1. Filter the special platforms, then judge of all the usb devices are
mouse or not. And get out the port id which attached a mouse with Pixart
controller.
2. Then reset the port which attached issue device during system resume
from S3.

[Q] Why the special devices are only mice? Would high speed devices
such as 3G modem or USB Bluetooth adapter trigger this issue?
- Current this sensitivity is only confined to devices that use Pixart
  controllers. This controller is designed for use with LS mouse
devices only. We have not observed any other devices failing. There
may be a small risk for other devices also but this patch (reset
device in resume phase) will cover the cases if required.

[Q] Shouldn’t the resume signal be sent within 100 us for every
device?
- The Host controller may not send the resume signal within 100us,
  this our host controller specification change. This is why we
require the patch to prevent side effects on certain known devices.

[Q] Why would clicking mouse INTENSELY to wake the system up trigger
this issue?
- This behavior is specific to the devices that use Pixart controller.
  It is timing dependent on when the resume event is triggered during
the sleep state.

[Q] Is it a host controller issue or mouse?
- It is the host controller behavior during resume that triggers the
  device incorrect behavior on the next resume.

This patch is for OHCI driver to add AMD remote wakeup fix.

Signed-off-by: Huang Rui <ray.huang@xxxxxxx>
---
 drivers/usb/host/ohci-hub.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/host/ohci-pci.c | 14 ++++++++++++++
 drivers/usb/host/ohci.h     | 23 ++++++++++++-----------
 3 files changed, 71 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 2347ab8..5a95c75 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -41,6 +41,7 @@
 
 static void dl_done_list (struct ohci_hcd *);
 static void finish_unlinks (struct ohci_hcd *, u16);
+static inline int root_port_reset (struct ohci_hcd *, unsigned);
 
 #ifdef	CONFIG_PM
 static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop)
@@ -293,6 +294,47 @@ static int ohci_bus_suspend (struct usb_hcd *hcd)
 	return rc;
 }
 
+/*
+ * Reset port which attached with an issue device.
+ *
+ * If the remote wake is issued from the device in a specific timing
+ * condition while the system is entering sleep state then it may
+ * cause system to auto wake on subsequent sleep cycle.
+ *
+ * Host controller rebroadcasts the Resume signal > 100 µseconds after
+ * receiving the original resume event from the device. For proper
+ * function, some devices may require the rebroadcast of resume event
+ * within the USB spec of 100µS.
+ *
+ * Without this quirk, some usb mouse controller would react
+ * differently to this unexpected event from some AMD host controller
+ * and will result in the mouse to assert a resume event on the
+ * subsequent S3 sleep even if the user does not initiate the wake
+ * event by clicking on the mouse. So it should reset the port which
+ * attached with issue mouse during S3 reusme phase.
+ */
+static int ohci_reset_port_by_amd_remote_wakeup(struct ohci_hcd *ohci)
+{
+	u32 temp;
+	struct usb_device *hdev, *child;
+	int port1, wIndex;
+
+	hdev = hcd_to_bus(ohci_to_hcd(ohci))->root_hub;
+
+	usb_hub_for_each_child(hdev, port1, child) {
+		wIndex = port1 - 1;
+		temp = roothub_portstatus(ohci, wIndex);
+		dbg_port(ohci, "Get port status", wIndex, temp);
+		if (is_issue_device_for_amd_quirk(child)) {
+			ohci_dbg(ohci, "Connencted issue device on port %d.\n", 
+					wIndex);
+			root_port_reset(ohci, wIndex);
+		}
+	}
+
+	return 0;
+}
+
 static int ohci_bus_resume (struct usb_hcd *hcd)
 {
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
@@ -309,6 +351,9 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
 		rc = ohci_rh_resume (ohci);
 	spin_unlock_irq (&ohci->lock);
 
+	if (ohci->flags & OHCI_QUIRK_AMD_REMOTE_WAKEUP)
+		ohci_reset_port_by_amd_remote_wakeup(ohci);
+
 	/* poll until we know a device is connected or we autostop */
 	if (rc == 0)
 		usb_hcd_poll_rh_status(hcd);
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 767a5ee..12881fa 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -175,6 +175,16 @@ static int ohci_quirk_amd700(struct usb_hcd *hcd)
 	return 0;
 }
 
+static int ohci_quirk_remote_wakeup(struct usb_hcd *hcd)
+{
+	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+	if (usb_amd_remote_wakeup_quirk())
+		ohci->flags |= OHCI_QUIRK_AMD_REMOTE_WAKEUP;
+
+	return 0;
+}
+
 /* List of quirks for OHCI */
 static const struct pci_device_id ohci_pci_quirks[] = {
 	{
@@ -225,6 +235,10 @@ static const struct pci_device_id ohci_pci_quirks[] = {
 		PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4399),
 		.driver_data = (unsigned long)ohci_quirk_amd700,
 	},
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x7807),
+		.driver_data = (unsigned long)ohci_quirk_remote_wakeup,
+	},
 
 	/* FIXME for some of the early AMD 760 southbridges, OHCI
 	 * won't work at all.  blacklist them.
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index e2e5faa..0d53f32 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -394,17 +394,18 @@ struct ohci_hcd {
 	unsigned		autostop:1;	/* rh auto stopping/stopped */
 
 	unsigned long		flags;		/* for HC bugs */
-#define	OHCI_QUIRK_AMD756	0x01			/* erratum #4 */
-#define	OHCI_QUIRK_SUPERIO	0x02			/* natsemi */
-#define	OHCI_QUIRK_INITRESET	0x04			/* SiS, OPTi, ... */
-#define	OHCI_QUIRK_BE_DESC	0x08			/* BE descriptors */
-#define	OHCI_QUIRK_BE_MMIO	0x10			/* BE registers */
-#define	OHCI_QUIRK_ZFMICRO	0x20			/* Compaq ZFMicro chipset*/
-#define	OHCI_QUIRK_NEC		0x40			/* lost interrupts */
-#define	OHCI_QUIRK_FRAME_NO	0x80			/* no big endian frame_no shift */
-#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_AMD756		0x01		/* erratum #4 */
+#define	OHCI_QUIRK_SUPERIO		0x02		/* natsemi */
+#define	OHCI_QUIRK_INITRESET		0x04		/* SiS, OPTi, ... */
+#define	OHCI_QUIRK_BE_DESC		0x08		/* BE descriptors */
+#define	OHCI_QUIRK_BE_MMIO		0x10		/* BE registers */
+#define	OHCI_QUIRK_ZFMICRO		0x20		/* Compaq ZFMicro chipset*/
+#define	OHCI_QUIRK_NEC			0x40		/* lost interrupts */
+#define	OHCI_QUIRK_FRAME_NO		0x80		/* no big endian frame_no shift */
+#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_AMD_REMOTE_WAKEUP	0x800		/* AMD remote wakeup quirk */
 	// there are also chip quirks/bugs in init logic
 
 	struct work_struct	nec_work;	/* Worker for NEC quirk */
-- 
1.7.11.7


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux