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, 39 insertions, 2 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 730b9fd26685..0ef16900efed 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -1166,7 +1166,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
1166 xhci_set_link_state(xhci, port_array, wIndex, 1166 xhci_set_link_state(xhci, port_array, wIndex,
1167 XDEV_RESUME); 1167 XDEV_RESUME);
1168 spin_unlock_irqrestore(&xhci->lock, flags); 1168 spin_unlock_irqrestore(&xhci->lock, flags);
1169 msleep(20); 1169 msleep(USB_RESUME_TIMEOUT);
1170 spin_lock_irqsave(&xhci->lock, flags); 1170 spin_lock_irqsave(&xhci->lock, flags);
1171 xhci_set_link_state(xhci, port_array, wIndex, 1171 xhci_set_link_state(xhci, port_array, wIndex,
1172 XDEV_U0); 1172 XDEV_U0);
@@ -1355,6 +1355,35 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
1355 return 0; 1355 return 0;
1356} 1356}
1357 1357
1358/*
1359 * Workaround for missing Cold Attach Status (CAS) if device re-plugged in S3.
1360 * warm reset a USB3 device stuck in polling or compliance mode after resume.
1361 * See Intel 100/c230 series PCH specification update Doc #332692-006 Errata #8
1362 */
1363static bool xhci_port_missing_cas_quirk(int port_index,
1364 __le32 __iomem **port_array)
1365{
1366 u32 portsc;
1367
1368 portsc = readl(port_array[port_index]);
1369
1370 /* if any of these are set we are not stuck */
1371 if (portsc & (PORT_CONNECT | PORT_CAS))
1372 return false;
1373
1374 if (((portsc & PORT_PLS_MASK) != XDEV_POLLING) &&
1375 ((portsc & PORT_PLS_MASK) != XDEV_COMP_MODE))
1376 return false;
1377
1378 /* clear wakeup/change bits, and do a warm port reset */
1379 portsc &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
1380 portsc |= PORT_WR;
1381 writel(portsc, port_array[port_index]);
1382 /* flush write */
1383 readl(port_array[port_index]);
1384 return true;
1385}
1386
1358int xhci_bus_resume(struct usb_hcd *hcd) 1387int xhci_bus_resume(struct usb_hcd *hcd)
1359{ 1388{
1360 struct xhci_hcd *xhci = hcd_to_xhci(hcd); 1389 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
@@ -1392,6 +1421,14 @@ int xhci_bus_resume(struct usb_hcd *hcd)
1392 u32 temp; 1421 u32 temp;
1393 1422
1394 temp = readl(port_array[port_index]); 1423 temp = readl(port_array[port_index]);
1424
1425 /* warm reset CAS limited ports stuck in polling/compliance */
1426 if ((xhci->quirks & XHCI_MISSING_CAS) &&
1427 (hcd->speed >= HCD_USB3) &&
1428 xhci_port_missing_cas_quirk(port_index, port_array)) {
1429 xhci_dbg(xhci, "reset stuck port %d\n", port_index);
1430 continue;
1431 }
1395 if (DEV_SUPERSPEED_ANY(temp)) 1432 if (DEV_SUPERSPEED_ANY(temp))
1396 temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS); 1433 temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
1397 else 1434 else
@@ -1410,7 +1447,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
1410 1447
1411 if (need_usb2_u3_exit) { 1448 if (need_usb2_u3_exit) {
1412 spin_unlock_irqrestore(&xhci->lock, flags); 1449 spin_unlock_irqrestore(&xhci->lock, flags);
1413 msleep(20); 1450 msleep(USB_RESUME_TIMEOUT);
1414 spin_lock_irqsave(&xhci->lock, flags); 1451 spin_lock_irqsave(&xhci->lock, flags);
1415 } 1452 }
1416 1453