aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2013-08-05 16:36:00 -0400
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2013-10-09 19:26:55 -0400
commitf217c980ca980e3a645b7485ea5eae9a747f4945 (patch)
tree2bdcd262303c7cdd014fa019d142f4c769546b4e
parentd0e639c9e06d44e713170031fe05fb60ebe680af (diff)
xhci: Don't enable/disable RWE on bus suspend/resume.
The RWE bit of the USB 2.0 PORTPMSC register is supposed to enable remote wakeup for devices in the lower power link state L1. It has nothing to do with the device suspend remote wakeup from L2. The RWE bit is designed to be set once (when USB 2.0 LPM is enabled for the port) and cleared only when USB 2.0 LPM is disabled for the port. The xHCI bus suspend method was setting the RWE bit erroneously, and the bus resume method was clearing it. The xHCI 1.0 specification with errata up to Aug 12, 2012 says in section 4.23.5.1.1.1 "Hardware Controlled LPM": "While Hardware USB2 LPM is enabled, software shall not modify the HIRDBESL or RWE fields of the USB2 PORTPMSC register..." If we have previously enabled USB 2.0 LPM for a device, that means when the USB 2.0 bus is resumed, we violate the xHCI specification by clearing RWE. It also means that after a bus resume, the host would think remote wakeup is disabled from L1 for ports with USB 2.0 Link PM enabled, which is not what we want. This patch should be backported to kernels as old as 3.2, that contain the commit 65580b4321eb36f16ae8b5987bfa1bb948fc5112 "xHCI: set USB2 hardware LPM". That was the first kernel that supported USB 2.0 Link PM. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Cc: stable@vger.kernel.org
-rw-r--r--drivers/usb/host/xhci-hub.c26
1 files changed, 0 insertions, 26 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 773a6b28c4f1..e8b4c56dcf62 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -1157,18 +1157,6 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
1157 t1 = xhci_port_state_to_neutral(t1); 1157 t1 = xhci_port_state_to_neutral(t1);
1158 if (t1 != t2) 1158 if (t1 != t2)
1159 xhci_writel(xhci, t2, port_array[port_index]); 1159 xhci_writel(xhci, t2, port_array[port_index]);
1160
1161 if (hcd->speed != HCD_USB3) {
1162 /* enable remote wake up for USB 2.0 */
1163 __le32 __iomem *addr;
1164 u32 tmp;
1165
1166 /* Get the port power control register address. */
1167 addr = port_array[port_index] + PORTPMSC;
1168 tmp = xhci_readl(xhci, addr);
1169 tmp |= PORT_RWE;
1170 xhci_writel(xhci, tmp, addr);
1171 }
1172 } 1160 }
1173 hcd->state = HC_STATE_SUSPENDED; 1161 hcd->state = HC_STATE_SUSPENDED;
1174 bus_state->next_statechange = jiffies + msecs_to_jiffies(10); 1162 bus_state->next_statechange = jiffies + msecs_to_jiffies(10);
@@ -1247,20 +1235,6 @@ int xhci_bus_resume(struct usb_hcd *hcd)
1247 xhci_ring_device(xhci, slot_id); 1235 xhci_ring_device(xhci, slot_id);
1248 } else 1236 } else
1249 xhci_writel(xhci, temp, port_array[port_index]); 1237 xhci_writel(xhci, temp, port_array[port_index]);
1250
1251 if (hcd->speed != HCD_USB3) {
1252 /* disable remote wake up for USB 2.0 */
1253 __le32 __iomem *addr;
1254 u32 tmp;
1255
1256 /* Add one to the port status register address to get
1257 * the port power control register address.
1258 */
1259 addr = port_array[port_index] + PORTPMSC;
1260 tmp = xhci_readl(xhci, addr);
1261 tmp &= ~PORT_RWE;
1262 xhci_writel(xhci, tmp, addr);
1263 }
1264 } 1238 }
1265 1239
1266 (void) xhci_readl(xhci, &xhci->op_regs->command); 1240 (void) xhci_readl(xhci, &xhci->op_regs->command);