Commit 3d13e2b6 authored by Felipe Balbi's avatar Felipe Balbi Committed by Ben Hutchings

usb: host: xhci: fix compliance mode workaround

commit 96908589 upstream.

Commit 71c731a2 (usb: host: xhci: Fix Compliance Mode
on SN65LVP3502CP Hardware) implemented a workaround
for a known issue with Texas Instruments' USB 3.0
redriver IC but it left a condition where any xHCI
host would be taken out of reset if port was placed
in compliance mode and there was no device connected
to the port.

That condition would trigger a fake connection to a
non-existent device so that usbcore would trigger a
warm reset of the port, thus taking the link out of
reset.

This has the side-effect of preventing any xHCI host
connected to a Linux machine from starting and running
the USB 3.0 Electrical Compliance Suite because the
port will mysteriously taken out of compliance mode
and, thus, xHCI won't step through the necessary
compliance patterns for link validation.

This patch fixes the issue by just adding a missing
check for XHCI_COMP_MODE_QUIRK inside
xhci_hub_report_usb3_link_state() when PORT_CAS isn't
set.

This patch should be backported to all kernels containing
commit 71c731a2.

Fixes: 71c731a2 (usb: host: xhci: Fix Compliance Mode on SN65LVP3502CP Hardware)
Cc: Alexis R. Cortes <alexis.cortes@ti.com>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
Acked-by: default avatarMathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
[bwh: Backported to 3.2:
 - s/xhci_hub_report_usb3_link_state/xhci_hub_report_link_state/
 - s/raw_port_status/temp/
 - Adjust indentation]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent dfc9c24e
...@@ -440,7 +440,8 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, ...@@ -440,7 +440,8 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
} }
/* Updates Link Status for super Speed port */ /* Updates Link Status for super Speed port */
static void xhci_hub_report_link_state(u32 *status, u32 status_reg) static void xhci_hub_report_link_state(struct xhci_hcd *xhci,
u32 *status, u32 status_reg)
{ {
u32 pls = status_reg & PORT_PLS_MASK; u32 pls = status_reg & PORT_PLS_MASK;
...@@ -479,7 +480,8 @@ static void xhci_hub_report_link_state(u32 *status, u32 status_reg) ...@@ -479,7 +480,8 @@ static void xhci_hub_report_link_state(u32 *status, u32 status_reg)
* in which sometimes the port enters compliance mode * in which sometimes the port enters compliance mode
* caused by a delay on the host-device negotiation. * caused by a delay on the host-device negotiation.
*/ */
if (pls == USB_SS_PORT_LS_COMP_MOD) if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
(pls == USB_SS_PORT_LS_COMP_MOD))
pls |= USB_PORT_STAT_CONNECTION; pls |= USB_PORT_STAT_CONNECTION;
} }
...@@ -655,7 +657,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -655,7 +657,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
} }
/* Update Port Link State for super speed ports*/ /* Update Port Link State for super speed ports*/
if (hcd->speed == HCD_USB3) { if (hcd->speed == HCD_USB3) {
xhci_hub_report_link_state(&status, temp); xhci_hub_report_link_state(xhci, &status, temp);
/* /*
* Verify if all USB3 Ports Have entered U0 already. * Verify if all USB3 Ports Have entered U0 already.
* Delete Compliance Mode Timer if so. * Delete Compliance Mode Timer if so.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment