aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/xhci-hub.c
diff options
context:
space:
mode:
authorAndiry Xu <andiry.xu@amd.com>2010-10-14 10:23:00 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-10-22 13:22:13 -0400
commit561925318725a41189a69f36ebe99199b3fb84c4 (patch)
treee84c72692f8fd9ed67c298db17d26ccb9970a7a8 /drivers/usb/host/xhci-hub.c
parentbe88fe4f4dda93e3264a887745123b1e6c4a6845 (diff)
USB: xHCI: port remote wakeup implementation
This commit implements port remote wakeup. When a port is in U3 state and resume signaling is detected from a device, the port transitions to the Resume state, and the xHC generates a Port Status Change Event. For USB3 port, software write a '0' to the PLS field to complete the resume signaling. For USB2 port, the resume should be signaling for at least 20ms, irq handler set a timer for port remote wakeup, and then finishes process in hub_control GetPortStatus. Some codes are borrowed from EHCI code. Signed-off-by: Andiry Xu <andiry.xu@amd.com> Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/xhci-hub.c')
-rw-r--r--drivers/usb/host/xhci-hub.c44
1 files changed, 39 insertions, 5 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 14b48b261e06..8163f17e7043 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -123,7 +123,7 @@ static unsigned int xhci_port_speed(unsigned int port_status)
123 * writing a 0 clears the bit and writing a 1 sets the bit (RWS). 123 * writing a 0 clears the bit and writing a 1 sets the bit (RWS).
124 * For all other types (RW1S, RW1CS, RW, and RZ), writing a '0' has no effect. 124 * For all other types (RW1S, RW1CS, RW, and RZ), writing a '0' has no effect.
125 */ 125 */
126static u32 xhci_port_state_to_neutral(u32 state) 126u32 xhci_port_state_to_neutral(u32 state)
127{ 127{
128 /* Save read-only status and port state */ 128 /* Save read-only status and port state */
129 return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS); 129 return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS);
@@ -132,7 +132,7 @@ static u32 xhci_port_state_to_neutral(u32 state)
132/* 132/*
133 * find slot id based on port number. 133 * find slot id based on port number.
134 */ 134 */
135static int xhci_find_slot_id_by_port(struct xhci_hcd *xhci, u16 port) 135int xhci_find_slot_id_by_port(struct xhci_hcd *xhci, u16 port)
136{ 136{
137 int slot_id; 137 int slot_id;
138 int i; 138 int i;
@@ -210,7 +210,7 @@ command_cleanup:
210/* 210/*
211 * Ring device, it rings the all doorbells unconditionally. 211 * Ring device, it rings the all doorbells unconditionally.
212 */ 212 */
213static void xhci_ring_device(struct xhci_hcd *xhci, int slot_id) 213void xhci_ring_device(struct xhci_hcd *xhci, int slot_id)
214{ 214{
215 int i; 215 int i;
216 216
@@ -276,7 +276,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
276 struct xhci_hcd *xhci = hcd_to_xhci(hcd); 276 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
277 int ports; 277 int ports;
278 unsigned long flags; 278 unsigned long flags;
279 u32 temp, status; 279 u32 temp, temp1, status;
280 int retval = 0; 280 int retval = 0;
281 u32 __iomem *addr; 281 u32 __iomem *addr;
282 int slot_id; 282 int slot_id;
@@ -315,6 +315,34 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
315 if ((temp & PORT_PLS_MASK) == XDEV_U3 315 if ((temp & PORT_PLS_MASK) == XDEV_U3
316 && (temp & PORT_POWER)) 316 && (temp & PORT_POWER))
317 status |= 1 << USB_PORT_FEAT_SUSPEND; 317 status |= 1 << USB_PORT_FEAT_SUSPEND;
318 if ((temp & PORT_PLS_MASK) == XDEV_RESUME) {
319 if ((temp & PORT_RESET) || !(temp & PORT_PE))
320 goto error;
321 if (!DEV_SUPERSPEED(temp) && time_after_eq(jiffies,
322 xhci->resume_done[wIndex])) {
323 xhci_dbg(xhci, "Resume USB2 port %d\n",
324 wIndex + 1);
325 xhci->resume_done[wIndex] = 0;
326 temp1 = xhci_port_state_to_neutral(temp);
327 temp1 &= ~PORT_PLS_MASK;
328 temp1 |= PORT_LINK_STROBE | XDEV_U0;
329 xhci_writel(xhci, temp1, addr);
330
331 xhci_dbg(xhci, "set port %d resume\n",
332 wIndex + 1);
333 slot_id = xhci_find_slot_id_by_port(xhci,
334 wIndex + 1);
335 if (!slot_id) {
336 xhci_dbg(xhci, "slot_id is zero\n");
337 goto error;
338 }
339 xhci_ring_device(xhci, slot_id);
340 xhci->port_c_suspend[wIndex >> 5] |=
341 1 << (wIndex & 31);
342 xhci->suspended_ports[wIndex >> 5] &=
343 ~(1 << (wIndex & 31));
344 }
345 }
318 if ((temp & PORT_PLS_MASK) == XDEV_U0 346 if ((temp & PORT_PLS_MASK) == XDEV_U0
319 && (temp & PORT_POWER) 347 && (temp & PORT_POWER)
320 && (xhci->suspended_ports[wIndex >> 5] & 348 && (xhci->suspended_ports[wIndex >> 5] &
@@ -500,6 +528,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
500{ 528{
501 unsigned long flags; 529 unsigned long flags;
502 u32 temp, status; 530 u32 temp, status;
531 u32 mask;
503 int i, retval; 532 int i, retval;
504 struct xhci_hcd *xhci = hcd_to_xhci(hcd); 533 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
505 int ports; 534 int ports;
@@ -512,13 +541,18 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
512 memset(buf, 0, retval); 541 memset(buf, 0, retval);
513 status = 0; 542 status = 0;
514 543
544 mask = PORT_CSC | PORT_PEC | PORT_OCC;
545
515 spin_lock_irqsave(&xhci->lock, flags); 546 spin_lock_irqsave(&xhci->lock, flags);
516 /* For each port, did anything change? If so, set that bit in buf. */ 547 /* For each port, did anything change? If so, set that bit in buf. */
517 for (i = 0; i < ports; i++) { 548 for (i = 0; i < ports; i++) {
518 addr = &xhci->op_regs->port_status_base + 549 addr = &xhci->op_regs->port_status_base +
519 NUM_PORT_REGS*i; 550 NUM_PORT_REGS*i;
520 temp = xhci_readl(xhci, addr); 551 temp = xhci_readl(xhci, addr);
521 if (temp & (PORT_CSC | PORT_PEC | PORT_OCC)) { 552 if ((temp & mask) != 0 ||
553 (xhci->port_c_suspend[i >> 5] & 1 << (i & 31)) ||
554 (xhci->resume_done[i] && time_after_eq(
555 jiffies, xhci->resume_done[i]))) {
522 buf[(i + 1) / 8] |= 1 << (i + 1) % 8; 556 buf[(i + 1) / 8] |= 1 << (i + 1) % 8;
523 status = 1; 557 status = 1;
524 } 558 }