USB: UHCI: add support for Intel's wakeup flags
authorAlan Stern <stern@rowland.harvard.edu>
Fri, 25 Jun 2010 18:02:49 +0000 (14:02 -0400)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 10 Aug 2010 21:35:38 +0000 (14:35 -0700)
This patch (as1396) adds code to uhci-hcd to support the
vendor-specific wakeup settings found in Intel's ICHx hardware.  A
couple of unnecessary memory barriers are removed.  And the root hub
isn't put back into the "suspended" state if power was lost during a
system sleep -- there's not much point in doing so because the root hub
will be resumed shortly.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

drivers/usb/host/uhci-hcd.c
drivers/usb/host/uhci-hcd.h

index 9d4d812..b045060 100644 (file)
@@ -176,6 +176,8 @@ static void check_and_reset_hc(struct uhci_hcd *uhci)
  */
 static void configure_hc(struct uhci_hcd *uhci)
 {
+       struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci));
+
        /* Set the frame length to the default: 1 ms exactly */
        outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF);
 
@@ -191,8 +193,11 @@ static void configure_hc(struct uhci_hcd *uhci)
        mb();
 
        /* Enable PIRQ */
-       pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
-                       USBLEGSUP_DEFAULT);
+       pci_write_config_word(pdev, USBLEGSUP, USBLEGSUP_DEFAULT);
+
+       /* Disable platform-specific non-PME# wakeup */
+       if (pdev->vendor == PCI_VENDOR_ID_INTEL)
+               pci_write_config_byte(pdev, USBRES_INTEL, 0);
 }
 
 
@@ -791,6 +796,7 @@ static int uhci_rh_resume(struct usb_hcd *hcd)
 static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
 {
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+       struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci));
        int rc = 0;
 
        dev_dbg(uhci_dev(uhci), "%s\n", __func__);
@@ -808,11 +814,15 @@ static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
        /* All PCI host controllers are required to disable IRQ generation
         * at the source, so we must turn off PIRQ.
         */
-       pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0);
-       mb();
+       pci_write_config_word(pdev, USBLEGSUP, 0);
        clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
 
-       /* FIXME: Enable non-PME# remote wakeup? */
+       /* Enable platform-specific non-PME# wakeup */
+       if (do_wakeup) {
+               if (pdev->vendor == PCI_VENDOR_ID_INTEL)
+                       pci_write_config_byte(pdev, USBRES_INTEL,
+                                       USBPORT1EN | USBPORT2EN);
+       }
 
 done_okay:
        clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
@@ -831,7 +841,6 @@ static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
         * even if the controller was dead.
         */
        set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-       mb();
 
        spin_lock_irq(&uhci->lock);
 
@@ -839,8 +848,6 @@ static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
        if (hibernated)
                uhci_hc_died(uhci);
 
-       /* FIXME: Disable non-PME# remote wakeup? */
-
        /* The firmware or a boot kernel may have changed the controller
         * settings during a system wakeup.  Check it and reconfigure
         * to avoid problems.
@@ -850,12 +857,9 @@ static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
        /* If the controller was dead before, it's back alive now */
        configure_hc(uhci);
 
-       if (uhci->rh_state == UHCI_RH_RESET) {
-
-               /* The controller had to be reset */
+       /* Tell the core if the controller had to be reset */
+       if (uhci->rh_state == UHCI_RH_RESET)
                usb_root_hub_lost_power(hcd->self.root_hub);
-               suspend_rh(uhci, UHCI_RH_SUSPENDED);
-       }
 
        spin_unlock_irq(&uhci->lock);
 
index 26bd1b2..49bf279 100644 (file)
 #define   USBPORTSC_RES3       0x4000  /* reserved, write zeroes */
 #define   USBPORTSC_RES4       0x8000  /* reserved, write zeroes */
 
-/* Legacy support register */
+/* PCI legacy support register */
 #define USBLEGSUP              0xc0
 #define   USBLEGSUP_DEFAULT    0x2000  /* only PIRQ enable set */
 #define   USBLEGSUP_RWC                0x8f00  /* the R/WC bits */
 #define   USBLEGSUP_RO         0x5040  /* R/O and reserved bits */
 
+/* PCI Intel-specific resume-enable register */
+#define USBRES_INTEL           0xc4
+#define   USBPORT1EN           0x01
+#define   USBPORT2EN           0x02
+
 #define UHCI_PTR_BITS          cpu_to_le32(0x000F)
 #define UHCI_PTR_TERM          cpu_to_le32(0x0001)
 #define UHCI_PTR_QH            cpu_to_le32(0x0002)