diff options
author | Lu Baolu <baolu.lu@linux.intel.com> | 2014-11-18 04:27:14 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-11-22 10:34:20 -0500 |
commit | a1377e5397ab321e21b793ec8cd2b6f12bd3c718 (patch) | |
tree | 9b8ded8851235754d797cd012df13b53d7ff9df6 /drivers/usb | |
parent | 8e71a322fdb127814bcba423a512914ca5bc6cf5 (diff) |
usb: xhci: rework root port wake bits if controller isn't allowed to wakeup
When system is being suspended, if host device is not allowed to do wakeup,
xhci_suspend() needs to clear all root port wake on bits. Otherwise, some
platforms may generate spurious wakeup, even if PCI PME# is disabled.
The initial commit ff8cbf250b44 ("xhci: clear root port wake on bits"),
which also got into stable, turned out to not work correctly and had to
be reverted, and is now rewritten.
Cc: stable <stable@vger.kernel.org> # v3.2+
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Suggested-by: Alan Stern <stern@rowland.harvard.edu>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
[Mathias Nyman: reword commit message]
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/host/xhci-pci.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/xhci-plat.c | 10 | ||||
-rw-r--r-- | drivers/usb/host/xhci.c | 42 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 2 |
4 files changed, 52 insertions, 4 deletions
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 9a69b1f1b300..142b601f9563 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c | |||
@@ -281,7 +281,7 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) | |||
281 | if (xhci->quirks & XHCI_COMP_MODE_QUIRK) | 281 | if (xhci->quirks & XHCI_COMP_MODE_QUIRK) |
282 | pdev->no_d3cold = true; | 282 | pdev->no_d3cold = true; |
283 | 283 | ||
284 | return xhci_suspend(xhci); | 284 | return xhci_suspend(xhci, do_wakeup); |
285 | } | 285 | } |
286 | 286 | ||
287 | static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) | 287 | static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) |
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 3d78b0cd674b..646300cbe5f7 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c | |||
@@ -204,7 +204,15 @@ static int xhci_plat_suspend(struct device *dev) | |||
204 | struct usb_hcd *hcd = dev_get_drvdata(dev); | 204 | struct usb_hcd *hcd = dev_get_drvdata(dev); |
205 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | 205 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
206 | 206 | ||
207 | return xhci_suspend(xhci); | 207 | /* |
208 | * xhci_suspend() needs `do_wakeup` to know whether host is allowed | ||
209 | * to do wakeup during suspend. Since xhci_plat_suspend is currently | ||
210 | * only designed for system suspend, device_may_wakeup() is enough | ||
211 | * to dertermine whether host is allowed to do wakeup. Need to | ||
212 | * reconsider this when xhci_plat_suspend enlarges its scope, e.g., | ||
213 | * also applies to runtime suspend. | ||
214 | */ | ||
215 | return xhci_suspend(xhci, device_may_wakeup(dev)); | ||
208 | } | 216 | } |
209 | 217 | ||
210 | static int xhci_plat_resume(struct device *dev) | 218 | static int xhci_plat_resume(struct device *dev) |
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 4d0d2407b71c..033b46c470bd 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c | |||
@@ -35,6 +35,8 @@ | |||
35 | #define DRIVER_AUTHOR "Sarah Sharp" | 35 | #define DRIVER_AUTHOR "Sarah Sharp" |
36 | #define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver" | 36 | #define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver" |
37 | 37 | ||
38 | #define PORT_WAKE_BITS (PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E) | ||
39 | |||
38 | /* Some 0.95 hardware can't handle the chain bit on a Link TRB being cleared */ | 40 | /* Some 0.95 hardware can't handle the chain bit on a Link TRB being cleared */ |
39 | static int link_quirk; | 41 | static int link_quirk; |
40 | module_param(link_quirk, int, S_IRUGO | S_IWUSR); | 42 | module_param(link_quirk, int, S_IRUGO | S_IWUSR); |
@@ -851,13 +853,47 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci) | |||
851 | xhci_set_cmd_ring_deq(xhci); | 853 | xhci_set_cmd_ring_deq(xhci); |
852 | } | 854 | } |
853 | 855 | ||
856 | static void xhci_disable_port_wake_on_bits(struct xhci_hcd *xhci) | ||
857 | { | ||
858 | int port_index; | ||
859 | __le32 __iomem **port_array; | ||
860 | unsigned long flags; | ||
861 | u32 t1, t2; | ||
862 | |||
863 | spin_lock_irqsave(&xhci->lock, flags); | ||
864 | |||
865 | /* disble usb3 ports Wake bits*/ | ||
866 | port_index = xhci->num_usb3_ports; | ||
867 | port_array = xhci->usb3_ports; | ||
868 | while (port_index--) { | ||
869 | t1 = readl(port_array[port_index]); | ||
870 | t1 = xhci_port_state_to_neutral(t1); | ||
871 | t2 = t1 & ~PORT_WAKE_BITS; | ||
872 | if (t1 != t2) | ||
873 | writel(t2, port_array[port_index]); | ||
874 | } | ||
875 | |||
876 | /* disble usb2 ports Wake bits*/ | ||
877 | port_index = xhci->num_usb2_ports; | ||
878 | port_array = xhci->usb2_ports; | ||
879 | while (port_index--) { | ||
880 | t1 = readl(port_array[port_index]); | ||
881 | t1 = xhci_port_state_to_neutral(t1); | ||
882 | t2 = t1 & ~PORT_WAKE_BITS; | ||
883 | if (t1 != t2) | ||
884 | writel(t2, port_array[port_index]); | ||
885 | } | ||
886 | |||
887 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
888 | } | ||
889 | |||
854 | /* | 890 | /* |
855 | * Stop HC (not bus-specific) | 891 | * Stop HC (not bus-specific) |
856 | * | 892 | * |
857 | * This is called when the machine transition into S3/S4 mode. | 893 | * This is called when the machine transition into S3/S4 mode. |
858 | * | 894 | * |
859 | */ | 895 | */ |
860 | int xhci_suspend(struct xhci_hcd *xhci) | 896 | int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) |
861 | { | 897 | { |
862 | int rc = 0; | 898 | int rc = 0; |
863 | unsigned int delay = XHCI_MAX_HALT_USEC; | 899 | unsigned int delay = XHCI_MAX_HALT_USEC; |
@@ -868,6 +904,10 @@ int xhci_suspend(struct xhci_hcd *xhci) | |||
868 | xhci->shared_hcd->state != HC_STATE_SUSPENDED) | 904 | xhci->shared_hcd->state != HC_STATE_SUSPENDED) |
869 | return -EINVAL; | 905 | return -EINVAL; |
870 | 906 | ||
907 | /* Clear root port wake on bits if wakeup not allowed. */ | ||
908 | if (!do_wakeup) | ||
909 | xhci_disable_port_wake_on_bits(xhci); | ||
910 | |||
871 | /* Don't poll the roothubs on bus suspend. */ | 911 | /* Don't poll the roothubs on bus suspend. */ |
872 | xhci_dbg(xhci, "%s: stopping port polling.\n", __func__); | 912 | xhci_dbg(xhci, "%s: stopping port polling.\n", __func__); |
873 | clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); | 913 | clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); |
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index df76d642e719..d745715a1e2f 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h | |||
@@ -1746,7 +1746,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks); | |||
1746 | void xhci_init_driver(struct hc_driver *drv, int (*setup_fn)(struct usb_hcd *)); | 1746 | void xhci_init_driver(struct hc_driver *drv, int (*setup_fn)(struct usb_hcd *)); |
1747 | 1747 | ||
1748 | #ifdef CONFIG_PM | 1748 | #ifdef CONFIG_PM |
1749 | int xhci_suspend(struct xhci_hcd *xhci); | 1749 | int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup); |
1750 | int xhci_resume(struct xhci_hcd *xhci, bool hibernated); | 1750 | int xhci_resume(struct xhci_hcd *xhci, bool hibernated); |
1751 | #else | 1751 | #else |
1752 | #define xhci_suspend NULL | 1752 | #define xhci_suspend NULL |