aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/xhci-hub.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/xhci-hub.c')
-rw-r--r--drivers/usb/host/xhci-hub.c41
1 files changed, 30 insertions, 11 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 0be788cc2fd..ce9f974dac0 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -392,6 +392,20 @@ static int xhci_get_ports(struct usb_hcd *hcd, __le32 __iomem ***port_array)
392 return max_ports; 392 return max_ports;
393} 393}
394 394
395/* Test and clear port RWC bit */
396void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
397 int port_id, u32 port_bit)
398{
399 u32 temp;
400
401 temp = xhci_readl(xhci, port_array[port_id]);
402 if (temp & port_bit) {
403 temp = xhci_port_state_to_neutral(temp);
404 temp |= port_bit;
405 xhci_writel(xhci, temp, port_array[port_id]);
406 }
407}
408
395int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, 409int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
396 u16 wIndex, char *buf, u16 wLength) 410 u16 wIndex, char *buf, u16 wLength)
397{ 411{
@@ -463,11 +477,12 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
463 && (temp & PORT_POWER)) 477 && (temp & PORT_POWER))
464 status |= USB_PORT_STAT_SUSPEND; 478 status |= USB_PORT_STAT_SUSPEND;
465 } 479 }
466 if ((temp & PORT_PLS_MASK) == XDEV_RESUME) { 480 if ((temp & PORT_PLS_MASK) == XDEV_RESUME &&
481 !DEV_SUPERSPEED(temp)) {
467 if ((temp & PORT_RESET) || !(temp & PORT_PE)) 482 if ((temp & PORT_RESET) || !(temp & PORT_PE))
468 goto error; 483 goto error;
469 if (!DEV_SUPERSPEED(temp) && time_after_eq(jiffies, 484 if (time_after_eq(jiffies,
470 bus_state->resume_done[wIndex])) { 485 bus_state->resume_done[wIndex])) {
471 xhci_dbg(xhci, "Resume USB2 port %d\n", 486 xhci_dbg(xhci, "Resume USB2 port %d\n",
472 wIndex + 1); 487 wIndex + 1);
473 bus_state->resume_done[wIndex] = 0; 488 bus_state->resume_done[wIndex] = 0;
@@ -487,6 +502,14 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
487 xhci_ring_device(xhci, slot_id); 502 xhci_ring_device(xhci, slot_id);
488 bus_state->port_c_suspend |= 1 << wIndex; 503 bus_state->port_c_suspend |= 1 << wIndex;
489 bus_state->suspended_ports &= ~(1 << wIndex); 504 bus_state->suspended_ports &= ~(1 << wIndex);
505 } else {
506 /*
507 * The resume has been signaling for less than
508 * 20ms. Report the port status as SUSPEND,
509 * let the usbcore check port status again
510 * and clear resume signaling later.
511 */
512 status |= USB_PORT_STAT_SUSPEND;
490 } 513 }
491 } 514 }
492 if ((temp & PORT_PLS_MASK) == XDEV_U0 515 if ((temp & PORT_PLS_MASK) == XDEV_U0
@@ -664,7 +687,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
664 xhci_dbg(xhci, "PORTSC %04x\n", temp); 687 xhci_dbg(xhci, "PORTSC %04x\n", temp);
665 if (temp & PORT_RESET) 688 if (temp & PORT_RESET)
666 goto error; 689 goto error;
667 if (temp & XDEV_U3) { 690 if ((temp & PORT_PLS_MASK) == XDEV_U3) {
668 if ((temp & PORT_PE) == 0) 691 if ((temp & PORT_PE) == 0)
669 goto error; 692 goto error;
670 693
@@ -752,7 +775,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
752 memset(buf, 0, retval); 775 memset(buf, 0, retval);
753 status = 0; 776 status = 0;
754 777
755 mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC; 778 mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC;
756 779
757 spin_lock_irqsave(&xhci->lock, flags); 780 spin_lock_irqsave(&xhci->lock, flags);
758 /* For each port, did anything change? If so, set that bit in buf. */ 781 /* For each port, did anything change? If so, set that bit in buf. */
@@ -929,12 +952,8 @@ int xhci_bus_resume(struct usb_hcd *hcd)
929 spin_lock_irqsave(&xhci->lock, flags); 952 spin_lock_irqsave(&xhci->lock, flags);
930 953
931 /* Clear PLC */ 954 /* Clear PLC */
932 temp = xhci_readl(xhci, port_array[port_index]); 955 xhci_test_and_clear_bit(xhci, port_array, port_index,
933 if (temp & PORT_PLC) { 956 PORT_PLC);
934 temp = xhci_port_state_to_neutral(temp);
935 temp |= PORT_PLC;
936 xhci_writel(xhci, temp, port_array[port_index]);
937 }
938 957
939 slot_id = xhci_find_slot_id_by_port(hcd, 958 slot_id = xhci_find_slot_id_by_port(hcd,
940 xhci, port_index + 1); 959 xhci, port_index + 1);