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.

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

This should be backported to kernels as old as 3.9, that contrain the
commit 3f5eb14135ba9d97ba4b8514fc7ef5e0dac2abf4 "usb: add
find_raw_port_number callback to struct hc_driver()" and the last
patch that AMD remote wakeup quirk for xhci.

Cc: <[email protected]>
Signed-off-by: Huang Rui <[email protected]>
---
 drivers/usb/host/ohci-hub.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/host/ohci-pci.c | 13 +++++++++++++
 drivers/usb/host/ohci.h     | 23 ++++++++++++-----------
 3 files changed, 67 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 2347ab8..0af45e3 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,44 @@ static int ohci_bus_suspend (struct usb_hcd *hcd)
        return rc;
 }
 
+/*
+ * Reset port which attached with mouse.
+ *
+ * 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 AMD platform doesn't hold the resume right
+ * away when there is a resume signal from LS device like mouse. So it
+ * should reset the port which attached with mouse.
+ */
+static int ohci_reset_port_by_mouse(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_usb_mouse(child)) {
+                       ohci_dbg(ohci, "Connencted mouse on port1%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 +348,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_mouse(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 08613e2..f69e2f3 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -175,6 +175,15 @@ 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 +234,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 stable" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to