diff options
Diffstat (limited to 'drivers/usb/host/xhci-hub.c')
-rw-r--r-- | drivers/usb/host/xhci-hub.c | 419 |
1 files changed, 415 insertions, 4 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index a1a7a9795536..fef5a1f9d483 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c | |||
@@ -24,6 +24,10 @@ | |||
24 | 24 | ||
25 | #include "xhci.h" | 25 | #include "xhci.h" |
26 | 26 | ||
27 | #define PORT_WAKE_BITS (PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E) | ||
28 | #define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \ | ||
29 | PORT_RC | PORT_PLC | PORT_PE) | ||
30 | |||
27 | static void xhci_hub_descriptor(struct xhci_hcd *xhci, | 31 | static void xhci_hub_descriptor(struct xhci_hcd *xhci, |
28 | struct usb_hub_descriptor *desc) | 32 | struct usb_hub_descriptor *desc) |
29 | { | 33 | { |
@@ -123,12 +127,105 @@ 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). | 127 | * 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. | 128 | * For all other types (RW1S, RW1CS, RW, and RZ), writing a '0' has no effect. |
125 | */ | 129 | */ |
126 | static u32 xhci_port_state_to_neutral(u32 state) | 130 | u32 xhci_port_state_to_neutral(u32 state) |
127 | { | 131 | { |
128 | /* Save read-only status and port state */ | 132 | /* Save read-only status and port state */ |
129 | return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS); | 133 | return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS); |
130 | } | 134 | } |
131 | 135 | ||
136 | /* | ||
137 | * find slot id based on port number. | ||
138 | */ | ||
139 | int xhci_find_slot_id_by_port(struct xhci_hcd *xhci, u16 port) | ||
140 | { | ||
141 | int slot_id; | ||
142 | int i; | ||
143 | |||
144 | slot_id = 0; | ||
145 | for (i = 0; i < MAX_HC_SLOTS; i++) { | ||
146 | if (!xhci->devs[i]) | ||
147 | continue; | ||
148 | if (xhci->devs[i]->port == port) { | ||
149 | slot_id = i; | ||
150 | break; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | return slot_id; | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | * Stop device | ||
159 | * It issues stop endpoint command for EP 0 to 30. And wait the last command | ||
160 | * to complete. | ||
161 | * suspend will set to 1, if suspend bit need to set in command. | ||
162 | */ | ||
163 | static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend) | ||
164 | { | ||
165 | struct xhci_virt_device *virt_dev; | ||
166 | struct xhci_command *cmd; | ||
167 | unsigned long flags; | ||
168 | int timeleft; | ||
169 | int ret; | ||
170 | int i; | ||
171 | |||
172 | ret = 0; | ||
173 | virt_dev = xhci->devs[slot_id]; | ||
174 | cmd = xhci_alloc_command(xhci, false, true, GFP_NOIO); | ||
175 | if (!cmd) { | ||
176 | xhci_dbg(xhci, "Couldn't allocate command structure.\n"); | ||
177 | return -ENOMEM; | ||
178 | } | ||
179 | |||
180 | spin_lock_irqsave(&xhci->lock, flags); | ||
181 | for (i = LAST_EP_INDEX; i > 0; i--) { | ||
182 | if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue) | ||
183 | xhci_queue_stop_endpoint(xhci, slot_id, i, suspend); | ||
184 | } | ||
185 | cmd->command_trb = xhci->cmd_ring->enqueue; | ||
186 | list_add_tail(&cmd->cmd_list, &virt_dev->cmd_list); | ||
187 | xhci_queue_stop_endpoint(xhci, slot_id, 0, suspend); | ||
188 | xhci_ring_cmd_db(xhci); | ||
189 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
190 | |||
191 | /* Wait for last stop endpoint command to finish */ | ||
192 | timeleft = wait_for_completion_interruptible_timeout( | ||
193 | cmd->completion, | ||
194 | USB_CTRL_SET_TIMEOUT); | ||
195 | if (timeleft <= 0) { | ||
196 | xhci_warn(xhci, "%s while waiting for stop endpoint command\n", | ||
197 | timeleft == 0 ? "Timeout" : "Signal"); | ||
198 | spin_lock_irqsave(&xhci->lock, flags); | ||
199 | /* The timeout might have raced with the event ring handler, so | ||
200 | * only delete from the list if the item isn't poisoned. | ||
201 | */ | ||
202 | if (cmd->cmd_list.next != LIST_POISON1) | ||
203 | list_del(&cmd->cmd_list); | ||
204 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
205 | ret = -ETIME; | ||
206 | goto command_cleanup; | ||
207 | } | ||
208 | |||
209 | command_cleanup: | ||
210 | xhci_free_command(xhci, cmd); | ||
211 | return ret; | ||
212 | } | ||
213 | |||
214 | /* | ||
215 | * Ring device, it rings the all doorbells unconditionally. | ||
216 | */ | ||
217 | void xhci_ring_device(struct xhci_hcd *xhci, int slot_id) | ||
218 | { | ||
219 | int i; | ||
220 | |||
221 | for (i = 0; i < LAST_EP_INDEX + 1; i++) | ||
222 | if (xhci->devs[slot_id]->eps[i].ring && | ||
223 | xhci->devs[slot_id]->eps[i].ring->dequeue) | ||
224 | xhci_ring_ep_doorbell(xhci, slot_id, i, 0); | ||
225 | |||
226 | return; | ||
227 | } | ||
228 | |||
132 | static void xhci_disable_port(struct xhci_hcd *xhci, u16 wIndex, | 229 | static void xhci_disable_port(struct xhci_hcd *xhci, u16 wIndex, |
133 | u32 __iomem *addr, u32 port_status) | 230 | u32 __iomem *addr, u32 port_status) |
134 | { | 231 | { |
@@ -162,6 +259,10 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue, | |||
162 | status = PORT_PEC; | 259 | status = PORT_PEC; |
163 | port_change_bit = "enable/disable"; | 260 | port_change_bit = "enable/disable"; |
164 | break; | 261 | break; |
262 | case USB_PORT_FEAT_C_SUSPEND: | ||
263 | status = PORT_PLC; | ||
264 | port_change_bit = "suspend/resume"; | ||
265 | break; | ||
165 | default: | 266 | default: |
166 | /* Should never happen */ | 267 | /* Should never happen */ |
167 | return; | 268 | return; |
@@ -179,9 +280,10 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
179 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | 280 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
180 | int ports; | 281 | int ports; |
181 | unsigned long flags; | 282 | unsigned long flags; |
182 | u32 temp, status; | 283 | u32 temp, temp1, status; |
183 | int retval = 0; | 284 | int retval = 0; |
184 | u32 __iomem *addr; | 285 | u32 __iomem *addr; |
286 | int slot_id; | ||
185 | 287 | ||
186 | ports = HCS_MAX_PORTS(xhci->hcs_params1); | 288 | ports = HCS_MAX_PORTS(xhci->hcs_params1); |
187 | 289 | ||
@@ -211,9 +313,49 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
211 | if ((temp & PORT_OCC)) | 313 | if ((temp & PORT_OCC)) |
212 | status |= USB_PORT_STAT_C_OVERCURRENT << 16; | 314 | status |= USB_PORT_STAT_C_OVERCURRENT << 16; |
213 | /* | 315 | /* |
214 | * FIXME ignoring suspend, reset, and USB 2.1/3.0 specific | 316 | * FIXME ignoring reset and USB 2.1/3.0 specific |
215 | * changes | 317 | * changes |
216 | */ | 318 | */ |
319 | if ((temp & PORT_PLS_MASK) == XDEV_U3 | ||
320 | && (temp & PORT_POWER)) | ||
321 | status |= 1 << USB_PORT_FEAT_SUSPEND; | ||
322 | if ((temp & PORT_PLS_MASK) == XDEV_RESUME) { | ||
323 | if ((temp & PORT_RESET) || !(temp & PORT_PE)) | ||
324 | goto error; | ||
325 | if (!DEV_SUPERSPEED(temp) && time_after_eq(jiffies, | ||
326 | xhci->resume_done[wIndex])) { | ||
327 | xhci_dbg(xhci, "Resume USB2 port %d\n", | ||
328 | wIndex + 1); | ||
329 | xhci->resume_done[wIndex] = 0; | ||
330 | temp1 = xhci_port_state_to_neutral(temp); | ||
331 | temp1 &= ~PORT_PLS_MASK; | ||
332 | temp1 |= PORT_LINK_STROBE | XDEV_U0; | ||
333 | xhci_writel(xhci, temp1, addr); | ||
334 | |||
335 | xhci_dbg(xhci, "set port %d resume\n", | ||
336 | wIndex + 1); | ||
337 | slot_id = xhci_find_slot_id_by_port(xhci, | ||
338 | wIndex + 1); | ||
339 | if (!slot_id) { | ||
340 | xhci_dbg(xhci, "slot_id is zero\n"); | ||
341 | goto error; | ||
342 | } | ||
343 | xhci_ring_device(xhci, slot_id); | ||
344 | xhci->port_c_suspend[wIndex >> 5] |= | ||
345 | 1 << (wIndex & 31); | ||
346 | xhci->suspended_ports[wIndex >> 5] &= | ||
347 | ~(1 << (wIndex & 31)); | ||
348 | } | ||
349 | } | ||
350 | if ((temp & PORT_PLS_MASK) == XDEV_U0 | ||
351 | && (temp & PORT_POWER) | ||
352 | && (xhci->suspended_ports[wIndex >> 5] & | ||
353 | (1 << (wIndex & 31)))) { | ||
354 | xhci->suspended_ports[wIndex >> 5] &= | ||
355 | ~(1 << (wIndex & 31)); | ||
356 | xhci->port_c_suspend[wIndex >> 5] |= | ||
357 | 1 << (wIndex & 31); | ||
358 | } | ||
217 | if (temp & PORT_CONNECT) { | 359 | if (temp & PORT_CONNECT) { |
218 | status |= USB_PORT_STAT_CONNECTION; | 360 | status |= USB_PORT_STAT_CONNECTION; |
219 | status |= xhci_port_speed(temp); | 361 | status |= xhci_port_speed(temp); |
@@ -226,6 +368,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
226 | status |= USB_PORT_STAT_RESET; | 368 | status |= USB_PORT_STAT_RESET; |
227 | if (temp & PORT_POWER) | 369 | if (temp & PORT_POWER) |
228 | status |= USB_PORT_STAT_POWER; | 370 | status |= USB_PORT_STAT_POWER; |
371 | if (xhci->port_c_suspend[wIndex >> 5] & (1 << (wIndex & 31))) | ||
372 | status |= 1 << USB_PORT_FEAT_C_SUSPEND; | ||
229 | xhci_dbg(xhci, "Get port status returned 0x%x\n", status); | 373 | xhci_dbg(xhci, "Get port status returned 0x%x\n", status); |
230 | put_unaligned(cpu_to_le32(status), (__le32 *) buf); | 374 | put_unaligned(cpu_to_le32(status), (__le32 *) buf); |
231 | break; | 375 | break; |
@@ -238,6 +382,42 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
238 | temp = xhci_readl(xhci, addr); | 382 | temp = xhci_readl(xhci, addr); |
239 | temp = xhci_port_state_to_neutral(temp); | 383 | temp = xhci_port_state_to_neutral(temp); |
240 | switch (wValue) { | 384 | switch (wValue) { |
385 | case USB_PORT_FEAT_SUSPEND: | ||
386 | temp = xhci_readl(xhci, addr); | ||
387 | /* In spec software should not attempt to suspend | ||
388 | * a port unless the port reports that it is in the | ||
389 | * enabled (PED = ‘1’,PLS < ‘3’) state. | ||
390 | */ | ||
391 | if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) | ||
392 | || (temp & PORT_PLS_MASK) >= XDEV_U3) { | ||
393 | xhci_warn(xhci, "USB core suspending device " | ||
394 | "not in U0/U1/U2.\n"); | ||
395 | goto error; | ||
396 | } | ||
397 | |||
398 | slot_id = xhci_find_slot_id_by_port(xhci, wIndex + 1); | ||
399 | if (!slot_id) { | ||
400 | xhci_warn(xhci, "slot_id is zero\n"); | ||
401 | goto error; | ||
402 | } | ||
403 | /* unlock to execute stop endpoint commands */ | ||
404 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
405 | xhci_stop_device(xhci, slot_id, 1); | ||
406 | spin_lock_irqsave(&xhci->lock, flags); | ||
407 | |||
408 | temp = xhci_port_state_to_neutral(temp); | ||
409 | temp &= ~PORT_PLS_MASK; | ||
410 | temp |= PORT_LINK_STROBE | XDEV_U3; | ||
411 | xhci_writel(xhci, temp, addr); | ||
412 | |||
413 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
414 | msleep(10); /* wait device to enter */ | ||
415 | spin_lock_irqsave(&xhci->lock, flags); | ||
416 | |||
417 | temp = xhci_readl(xhci, addr); | ||
418 | xhci->suspended_ports[wIndex >> 5] |= | ||
419 | 1 << (wIndex & (31)); | ||
420 | break; | ||
241 | case USB_PORT_FEAT_POWER: | 421 | case USB_PORT_FEAT_POWER: |
242 | /* | 422 | /* |
243 | * Turn on ports, even if there isn't per-port switching. | 423 | * Turn on ports, even if there isn't per-port switching. |
@@ -271,6 +451,52 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
271 | temp = xhci_readl(xhci, addr); | 451 | temp = xhci_readl(xhci, addr); |
272 | temp = xhci_port_state_to_neutral(temp); | 452 | temp = xhci_port_state_to_neutral(temp); |
273 | switch (wValue) { | 453 | switch (wValue) { |
454 | case USB_PORT_FEAT_SUSPEND: | ||
455 | temp = xhci_readl(xhci, addr); | ||
456 | xhci_dbg(xhci, "clear USB_PORT_FEAT_SUSPEND\n"); | ||
457 | xhci_dbg(xhci, "PORTSC %04x\n", temp); | ||
458 | if (temp & PORT_RESET) | ||
459 | goto error; | ||
460 | if (temp & XDEV_U3) { | ||
461 | if ((temp & PORT_PE) == 0) | ||
462 | goto error; | ||
463 | if (DEV_SUPERSPEED(temp)) { | ||
464 | temp = xhci_port_state_to_neutral(temp); | ||
465 | temp &= ~PORT_PLS_MASK; | ||
466 | temp |= PORT_LINK_STROBE | XDEV_U0; | ||
467 | xhci_writel(xhci, temp, addr); | ||
468 | xhci_readl(xhci, addr); | ||
469 | } else { | ||
470 | temp = xhci_port_state_to_neutral(temp); | ||
471 | temp &= ~PORT_PLS_MASK; | ||
472 | temp |= PORT_LINK_STROBE | XDEV_RESUME; | ||
473 | xhci_writel(xhci, temp, addr); | ||
474 | |||
475 | spin_unlock_irqrestore(&xhci->lock, | ||
476 | flags); | ||
477 | msleep(20); | ||
478 | spin_lock_irqsave(&xhci->lock, flags); | ||
479 | |||
480 | temp = xhci_readl(xhci, addr); | ||
481 | temp = xhci_port_state_to_neutral(temp); | ||
482 | temp &= ~PORT_PLS_MASK; | ||
483 | temp |= PORT_LINK_STROBE | XDEV_U0; | ||
484 | xhci_writel(xhci, temp, addr); | ||
485 | } | ||
486 | xhci->port_c_suspend[wIndex >> 5] |= | ||
487 | 1 << (wIndex & 31); | ||
488 | } | ||
489 | |||
490 | slot_id = xhci_find_slot_id_by_port(xhci, wIndex + 1); | ||
491 | if (!slot_id) { | ||
492 | xhci_dbg(xhci, "slot_id is zero\n"); | ||
493 | goto error; | ||
494 | } | ||
495 | xhci_ring_device(xhci, slot_id); | ||
496 | break; | ||
497 | case USB_PORT_FEAT_C_SUSPEND: | ||
498 | xhci->port_c_suspend[wIndex >> 5] &= | ||
499 | ~(1 << (wIndex & 31)); | ||
274 | case USB_PORT_FEAT_C_RESET: | 500 | case USB_PORT_FEAT_C_RESET: |
275 | case USB_PORT_FEAT_C_CONNECTION: | 501 | case USB_PORT_FEAT_C_CONNECTION: |
276 | case USB_PORT_FEAT_C_OVER_CURRENT: | 502 | case USB_PORT_FEAT_C_OVER_CURRENT: |
@@ -306,6 +532,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) | |||
306 | { | 532 | { |
307 | unsigned long flags; | 533 | unsigned long flags; |
308 | u32 temp, status; | 534 | u32 temp, status; |
535 | u32 mask; | ||
309 | int i, retval; | 536 | int i, retval; |
310 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | 537 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
311 | int ports; | 538 | int ports; |
@@ -318,13 +545,18 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) | |||
318 | memset(buf, 0, retval); | 545 | memset(buf, 0, retval); |
319 | status = 0; | 546 | status = 0; |
320 | 547 | ||
548 | mask = PORT_CSC | PORT_PEC | PORT_OCC; | ||
549 | |||
321 | spin_lock_irqsave(&xhci->lock, flags); | 550 | spin_lock_irqsave(&xhci->lock, flags); |
322 | /* For each port, did anything change? If so, set that bit in buf. */ | 551 | /* For each port, did anything change? If so, set that bit in buf. */ |
323 | for (i = 0; i < ports; i++) { | 552 | for (i = 0; i < ports; i++) { |
324 | addr = &xhci->op_regs->port_status_base + | 553 | addr = &xhci->op_regs->port_status_base + |
325 | NUM_PORT_REGS*i; | 554 | NUM_PORT_REGS*i; |
326 | temp = xhci_readl(xhci, addr); | 555 | temp = xhci_readl(xhci, addr); |
327 | if (temp & (PORT_CSC | PORT_PEC | PORT_OCC)) { | 556 | if ((temp & mask) != 0 || |
557 | (xhci->port_c_suspend[i >> 5] & 1 << (i & 31)) || | ||
558 | (xhci->resume_done[i] && time_after_eq( | ||
559 | jiffies, xhci->resume_done[i]))) { | ||
328 | buf[(i + 1) / 8] |= 1 << (i + 1) % 8; | 560 | buf[(i + 1) / 8] |= 1 << (i + 1) % 8; |
329 | status = 1; | 561 | status = 1; |
330 | } | 562 | } |
@@ -332,3 +564,182 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) | |||
332 | spin_unlock_irqrestore(&xhci->lock, flags); | 564 | spin_unlock_irqrestore(&xhci->lock, flags); |
333 | return status ? retval : 0; | 565 | return status ? retval : 0; |
334 | } | 566 | } |
567 | |||
568 | #ifdef CONFIG_PM | ||
569 | |||
570 | int xhci_bus_suspend(struct usb_hcd *hcd) | ||
571 | { | ||
572 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | ||
573 | int port; | ||
574 | unsigned long flags; | ||
575 | |||
576 | xhci_dbg(xhci, "suspend root hub\n"); | ||
577 | |||
578 | spin_lock_irqsave(&xhci->lock, flags); | ||
579 | |||
580 | if (hcd->self.root_hub->do_remote_wakeup) { | ||
581 | port = HCS_MAX_PORTS(xhci->hcs_params1); | ||
582 | while (port--) { | ||
583 | if (xhci->resume_done[port] != 0) { | ||
584 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
585 | xhci_dbg(xhci, "suspend failed because " | ||
586 | "port %d is resuming\n", | ||
587 | port + 1); | ||
588 | return -EBUSY; | ||
589 | } | ||
590 | } | ||
591 | } | ||
592 | |||
593 | port = HCS_MAX_PORTS(xhci->hcs_params1); | ||
594 | xhci->bus_suspended = 0; | ||
595 | while (port--) { | ||
596 | /* suspend the port if the port is not suspended */ | ||
597 | u32 __iomem *addr; | ||
598 | u32 t1, t2; | ||
599 | int slot_id; | ||
600 | |||
601 | addr = &xhci->op_regs->port_status_base + | ||
602 | NUM_PORT_REGS * (port & 0xff); | ||
603 | t1 = xhci_readl(xhci, addr); | ||
604 | t2 = xhci_port_state_to_neutral(t1); | ||
605 | |||
606 | if ((t1 & PORT_PE) && !(t1 & PORT_PLS_MASK)) { | ||
607 | xhci_dbg(xhci, "port %d not suspended\n", port); | ||
608 | slot_id = xhci_find_slot_id_by_port(xhci, port + 1); | ||
609 | if (slot_id) { | ||
610 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
611 | xhci_stop_device(xhci, slot_id, 1); | ||
612 | spin_lock_irqsave(&xhci->lock, flags); | ||
613 | } | ||
614 | t2 &= ~PORT_PLS_MASK; | ||
615 | t2 |= PORT_LINK_STROBE | XDEV_U3; | ||
616 | set_bit(port, &xhci->bus_suspended); | ||
617 | } | ||
618 | if (hcd->self.root_hub->do_remote_wakeup) { | ||
619 | if (t1 & PORT_CONNECT) { | ||
620 | t2 |= PORT_WKOC_E | PORT_WKDISC_E; | ||
621 | t2 &= ~PORT_WKCONN_E; | ||
622 | } else { | ||
623 | t2 |= PORT_WKOC_E | PORT_WKCONN_E; | ||
624 | t2 &= ~PORT_WKDISC_E; | ||
625 | } | ||
626 | } else | ||
627 | t2 &= ~PORT_WAKE_BITS; | ||
628 | |||
629 | t1 = xhci_port_state_to_neutral(t1); | ||
630 | if (t1 != t2) | ||
631 | xhci_writel(xhci, t2, addr); | ||
632 | |||
633 | if (DEV_HIGHSPEED(t1)) { | ||
634 | /* enable remote wake up for USB 2.0 */ | ||
635 | u32 __iomem *addr; | ||
636 | u32 tmp; | ||
637 | |||
638 | addr = &xhci->op_regs->port_power_base + | ||
639 | NUM_PORT_REGS * (port & 0xff); | ||
640 | tmp = xhci_readl(xhci, addr); | ||
641 | tmp |= PORT_RWE; | ||
642 | xhci_writel(xhci, tmp, addr); | ||
643 | } | ||
644 | } | ||
645 | hcd->state = HC_STATE_SUSPENDED; | ||
646 | xhci->next_statechange = jiffies + msecs_to_jiffies(10); | ||
647 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
648 | return 0; | ||
649 | } | ||
650 | |||
651 | int xhci_bus_resume(struct usb_hcd *hcd) | ||
652 | { | ||
653 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | ||
654 | int port; | ||
655 | u32 temp; | ||
656 | unsigned long flags; | ||
657 | |||
658 | xhci_dbg(xhci, "resume root hub\n"); | ||
659 | |||
660 | if (time_before(jiffies, xhci->next_statechange)) | ||
661 | msleep(5); | ||
662 | |||
663 | spin_lock_irqsave(&xhci->lock, flags); | ||
664 | if (!HCD_HW_ACCESSIBLE(hcd)) { | ||
665 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
666 | return -ESHUTDOWN; | ||
667 | } | ||
668 | |||
669 | /* delay the irqs */ | ||
670 | temp = xhci_readl(xhci, &xhci->op_regs->command); | ||
671 | temp &= ~CMD_EIE; | ||
672 | xhci_writel(xhci, temp, &xhci->op_regs->command); | ||
673 | |||
674 | port = HCS_MAX_PORTS(xhci->hcs_params1); | ||
675 | while (port--) { | ||
676 | /* Check whether need resume ports. If needed | ||
677 | resume port and disable remote wakeup */ | ||
678 | u32 __iomem *addr; | ||
679 | u32 temp; | ||
680 | int slot_id; | ||
681 | |||
682 | addr = &xhci->op_regs->port_status_base + | ||
683 | NUM_PORT_REGS * (port & 0xff); | ||
684 | temp = xhci_readl(xhci, addr); | ||
685 | if (DEV_SUPERSPEED(temp)) | ||
686 | temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS); | ||
687 | else | ||
688 | temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); | ||
689 | if (test_bit(port, &xhci->bus_suspended) && | ||
690 | (temp & PORT_PLS_MASK)) { | ||
691 | if (DEV_SUPERSPEED(temp)) { | ||
692 | temp = xhci_port_state_to_neutral(temp); | ||
693 | temp &= ~PORT_PLS_MASK; | ||
694 | temp |= PORT_LINK_STROBE | XDEV_U0; | ||
695 | xhci_writel(xhci, temp, addr); | ||
696 | } else { | ||
697 | temp = xhci_port_state_to_neutral(temp); | ||
698 | temp &= ~PORT_PLS_MASK; | ||
699 | temp |= PORT_LINK_STROBE | XDEV_RESUME; | ||
700 | xhci_writel(xhci, temp, addr); | ||
701 | |||
702 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
703 | msleep(20); | ||
704 | spin_lock_irqsave(&xhci->lock, flags); | ||
705 | |||
706 | temp = xhci_readl(xhci, addr); | ||
707 | temp = xhci_port_state_to_neutral(temp); | ||
708 | temp &= ~PORT_PLS_MASK; | ||
709 | temp |= PORT_LINK_STROBE | XDEV_U0; | ||
710 | xhci_writel(xhci, temp, addr); | ||
711 | } | ||
712 | slot_id = xhci_find_slot_id_by_port(xhci, port + 1); | ||
713 | if (slot_id) | ||
714 | xhci_ring_device(xhci, slot_id); | ||
715 | } else | ||
716 | xhci_writel(xhci, temp, addr); | ||
717 | |||
718 | if (DEV_HIGHSPEED(temp)) { | ||
719 | /* disable remote wake up for USB 2.0 */ | ||
720 | u32 __iomem *addr; | ||
721 | u32 tmp; | ||
722 | |||
723 | addr = &xhci->op_regs->port_power_base + | ||
724 | NUM_PORT_REGS * (port & 0xff); | ||
725 | tmp = xhci_readl(xhci, addr); | ||
726 | tmp &= ~PORT_RWE; | ||
727 | xhci_writel(xhci, tmp, addr); | ||
728 | } | ||
729 | } | ||
730 | |||
731 | (void) xhci_readl(xhci, &xhci->op_regs->command); | ||
732 | |||
733 | xhci->next_statechange = jiffies + msecs_to_jiffies(5); | ||
734 | hcd->state = HC_STATE_RUNNING; | ||
735 | /* re-enable irqs */ | ||
736 | temp = xhci_readl(xhci, &xhci->op_regs->command); | ||
737 | temp |= CMD_EIE; | ||
738 | xhci_writel(xhci, temp, &xhci->op_regs->command); | ||
739 | temp = xhci_readl(xhci, &xhci->op_regs->command); | ||
740 | |||
741 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
742 | return 0; | ||
743 | } | ||
744 | |||
745 | #endif /* CONFIG_PM */ | ||