|
@@ -1355,6 +1355,35 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Workaround for missing Cold Attach Status (CAS) if device re-plugged in S3.
|
|
|
+ * warm reset a USB3 device stuck in polling or compliance mode after resume.
|
|
|
+ * See Intel 100/c230 series PCH specification update Doc #332692-006 Errata #8
|
|
|
+ */
|
|
|
+static bool xhci_port_missing_cas_quirk(int port_index,
|
|
|
+ __le32 __iomem **port_array)
|
|
|
+{
|
|
|
+ u32 portsc;
|
|
|
+
|
|
|
+ portsc = readl(port_array[port_index]);
|
|
|
+
|
|
|
+ /* if any of these are set we are not stuck */
|
|
|
+ if (portsc & (PORT_CONNECT | PORT_CAS))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ if (((portsc & PORT_PLS_MASK) != XDEV_POLLING) &&
|
|
|
+ ((portsc & PORT_PLS_MASK) != XDEV_COMP_MODE))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /* clear wakeup/change bits, and do a warm port reset */
|
|
|
+ portsc &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
|
|
|
+ portsc |= PORT_WR;
|
|
|
+ writel(portsc, port_array[port_index]);
|
|
|
+ /* flush write */
|
|
|
+ readl(port_array[port_index]);
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
int xhci_bus_resume(struct usb_hcd *hcd)
|
|
|
{
|
|
|
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
|
@@ -1392,6 +1421,14 @@ int xhci_bus_resume(struct usb_hcd *hcd)
|
|
|
u32 temp;
|
|
|
|
|
|
temp = readl(port_array[port_index]);
|
|
|
+
|
|
|
+ /* warm reset CAS limited ports stuck in polling/compliance */
|
|
|
+ if ((xhci->quirks & XHCI_MISSING_CAS) &&
|
|
|
+ (hcd->speed >= HCD_USB3) &&
|
|
|
+ xhci_port_missing_cas_quirk(port_index, port_array)) {
|
|
|
+ xhci_dbg(xhci, "reset stuck port %d\n", port_index);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
if (DEV_SUPERSPEED_ANY(temp))
|
|
|
temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
|
|
|
else
|