diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2010-06-25 14:02:49 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-08-10 17:35:38 -0400 |
commit | 0d436b425e07f9e4b0fe571cec061f5d136f1d8b (patch) | |
tree | f1ebf7929aaf1b4b5e96e1182085e8924e2d0d50 /drivers | |
parent | ff2f07874362d34684296f2bd5547a099f33c6d4 (diff) |
USB: UHCI: add support for Intel's wakeup flags
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/host/uhci-hcd.c | 30 | ||||
-rw-r--r-- | drivers/usb/host/uhci-hcd.h | 7 |
2 files changed, 23 insertions, 14 deletions
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 9d4d81248f96..b04506036b64 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c | |||
@@ -176,6 +176,8 @@ static void check_and_reset_hc(struct uhci_hcd *uhci) | |||
176 | */ | 176 | */ |
177 | static void configure_hc(struct uhci_hcd *uhci) | 177 | static void configure_hc(struct uhci_hcd *uhci) |
178 | { | 178 | { |
179 | struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci)); | ||
180 | |||
179 | /* Set the frame length to the default: 1 ms exactly */ | 181 | /* Set the frame length to the default: 1 ms exactly */ |
180 | outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF); | 182 | outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF); |
181 | 183 | ||
@@ -191,8 +193,11 @@ static void configure_hc(struct uhci_hcd *uhci) | |||
191 | mb(); | 193 | mb(); |
192 | 194 | ||
193 | /* Enable PIRQ */ | 195 | /* Enable PIRQ */ |
194 | pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, | 196 | pci_write_config_word(pdev, USBLEGSUP, USBLEGSUP_DEFAULT); |
195 | USBLEGSUP_DEFAULT); | 197 | |
198 | /* Disable platform-specific non-PME# wakeup */ | ||
199 | if (pdev->vendor == PCI_VENDOR_ID_INTEL) | ||
200 | pci_write_config_byte(pdev, USBRES_INTEL, 0); | ||
196 | } | 201 | } |
197 | 202 | ||
198 | 203 | ||
@@ -791,6 +796,7 @@ static int uhci_rh_resume(struct usb_hcd *hcd) | |||
791 | static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) | 796 | static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) |
792 | { | 797 | { |
793 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); | 798 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); |
799 | struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci)); | ||
794 | int rc = 0; | 800 | int rc = 0; |
795 | 801 | ||
796 | dev_dbg(uhci_dev(uhci), "%s\n", __func__); | 802 | dev_dbg(uhci_dev(uhci), "%s\n", __func__); |
@@ -808,11 +814,15 @@ static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) | |||
808 | /* All PCI host controllers are required to disable IRQ generation | 814 | /* All PCI host controllers are required to disable IRQ generation |
809 | * at the source, so we must turn off PIRQ. | 815 | * at the source, so we must turn off PIRQ. |
810 | */ | 816 | */ |
811 | pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0); | 817 | pci_write_config_word(pdev, USBLEGSUP, 0); |
812 | mb(); | ||
813 | clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); | 818 | clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); |
814 | 819 | ||
815 | /* FIXME: Enable non-PME# remote wakeup? */ | 820 | /* Enable platform-specific non-PME# wakeup */ |
821 | if (do_wakeup) { | ||
822 | if (pdev->vendor == PCI_VENDOR_ID_INTEL) | ||
823 | pci_write_config_byte(pdev, USBRES_INTEL, | ||
824 | USBPORT1EN | USBPORT2EN); | ||
825 | } | ||
816 | 826 | ||
817 | done_okay: | 827 | done_okay: |
818 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | 828 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); |
@@ -831,7 +841,6 @@ static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated) | |||
831 | * even if the controller was dead. | 841 | * even if the controller was dead. |
832 | */ | 842 | */ |
833 | set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | 843 | set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); |
834 | mb(); | ||
835 | 844 | ||
836 | spin_lock_irq(&uhci->lock); | 845 | spin_lock_irq(&uhci->lock); |
837 | 846 | ||
@@ -839,8 +848,6 @@ static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated) | |||
839 | if (hibernated) | 848 | if (hibernated) |
840 | uhci_hc_died(uhci); | 849 | uhci_hc_died(uhci); |
841 | 850 | ||
842 | /* FIXME: Disable non-PME# remote wakeup? */ | ||
843 | |||
844 | /* The firmware or a boot kernel may have changed the controller | 851 | /* The firmware or a boot kernel may have changed the controller |
845 | * settings during a system wakeup. Check it and reconfigure | 852 | * settings during a system wakeup. Check it and reconfigure |
846 | * to avoid problems. | 853 | * to avoid problems. |
@@ -850,12 +857,9 @@ static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated) | |||
850 | /* If the controller was dead before, it's back alive now */ | 857 | /* If the controller was dead before, it's back alive now */ |
851 | configure_hc(uhci); | 858 | configure_hc(uhci); |
852 | 859 | ||
853 | if (uhci->rh_state == UHCI_RH_RESET) { | 860 | /* Tell the core if the controller had to be reset */ |
854 | 861 | if (uhci->rh_state == UHCI_RH_RESET) | |
855 | /* The controller had to be reset */ | ||
856 | usb_root_hub_lost_power(hcd->self.root_hub); | 862 | usb_root_hub_lost_power(hcd->self.root_hub); |
857 | suspend_rh(uhci, UHCI_RH_SUSPENDED); | ||
858 | } | ||
859 | 863 | ||
860 | spin_unlock_irq(&uhci->lock); | 864 | spin_unlock_irq(&uhci->lock); |
861 | 865 | ||
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 26bd1b2bcbfc..49bf2790f9c2 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h | |||
@@ -67,12 +67,17 @@ | |||
67 | #define USBPORTSC_RES3 0x4000 /* reserved, write zeroes */ | 67 | #define USBPORTSC_RES3 0x4000 /* reserved, write zeroes */ |
68 | #define USBPORTSC_RES4 0x8000 /* reserved, write zeroes */ | 68 | #define USBPORTSC_RES4 0x8000 /* reserved, write zeroes */ |
69 | 69 | ||
70 | /* Legacy support register */ | 70 | /* PCI legacy support register */ |
71 | #define USBLEGSUP 0xc0 | 71 | #define USBLEGSUP 0xc0 |
72 | #define USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */ | 72 | #define USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */ |
73 | #define USBLEGSUP_RWC 0x8f00 /* the R/WC bits */ | 73 | #define USBLEGSUP_RWC 0x8f00 /* the R/WC bits */ |
74 | #define USBLEGSUP_RO 0x5040 /* R/O and reserved bits */ | 74 | #define USBLEGSUP_RO 0x5040 /* R/O and reserved bits */ |
75 | 75 | ||
76 | /* PCI Intel-specific resume-enable register */ | ||
77 | #define USBRES_INTEL 0xc4 | ||
78 | #define USBPORT1EN 0x01 | ||
79 | #define USBPORT2EN 0x02 | ||
80 | |||
76 | #define UHCI_PTR_BITS cpu_to_le32(0x000F) | 81 | #define UHCI_PTR_BITS cpu_to_le32(0x000F) |
77 | #define UHCI_PTR_TERM cpu_to_le32(0x0001) | 82 | #define UHCI_PTR_TERM cpu_to_le32(0x0001) |
78 | #define UHCI_PTR_QH cpu_to_le32(0x0002) | 83 | #define UHCI_PTR_QH cpu_to_le32(0x0002) |