}
/* Updates Link Status for super Speed port */
-static void xhci_hub_report_usb3_link_state(struct xhci_hcd *xhci,
- u32 *status, u32 portsc)
+static void xhci_hub_report_usb3_link_state(struct xhci_hcd *xhci, u32 *status, u32 portsc)
{
u32 pls = portsc & PORT_PLS_MASK;
- /* When the CAS bit is set then warm reset
- * should be performed on port
+ /*
+ * CAS indicates that a warm reset is required, it may be set in any
+ * link state and is only present on roothubs.
*/
if (portsc & PORT_CAS) {
- /* The CAS bit can be set while the port is
- * in any link state.
- * Only roothubs have CAS bit, so we
- * pretend to be in compliance mode
- * unless we're already in compliance
- * or the inactive state.
+ /*
+ * If not already in Compliance or Inactive state,
+ * report Compliance Mode so the hub logic triggers a warm reset.
*/
- if (pls != XDEV_COMP_MODE &&
- pls != XDEV_INACTIVE) {
+ if (pls != XDEV_COMP_MODE && pls != XDEV_INACTIVE)
pls = USB_SS_PORT_LS_COMP_MOD;
- }
- /* Return also connection bit -
- * hub state machine resets port
- * when this bit is set.
- */
- pls |= USB_PORT_STAT_CONNECTION;
- } else {
+
+ /* Signal a connection change to force a reset */
+ *status |= USB_PORT_STAT_CONNECTION;
+ } else if (pls == XDEV_RESUME) {
/*
- * Resume state is an xHCI internal state. Do not report it to
- * usb core, instead, pretend to be U3, thus usb core knows
- * it's not ready for transfer.
+ * Resume is an internal xHCI-only state and must not be exposed
+ * to usbcore. Report it as U3 so transfers are blocked.
*/
- if (pls == XDEV_RESUME) {
- *status |= USB_SS_PORT_LS_U3;
- return;
- }
-
+ pls = USB_SS_PORT_LS_U3;
+ } else if (pls == XDEV_COMP_MODE) {
/*
- * If CAS bit isn't set but the Port is already at
- * Compliance Mode, fake a connection so the USB core
- * notices the Compliance state and resets the port.
- * This resolves an issue generated by the SN65LVPE502CP
- * in which sometimes the port enters compliance mode
- * caused by a delay on the host-device negotiation.
+ * Some hardware may enter Compliance Mode without CAS.
+ * Fake a connection event so usbcore notices and resets the port.
*/
- if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
- (pls == XDEV_COMP_MODE))
- pls |= USB_PORT_STAT_CONNECTION;
+ if (xhci->quirks & XHCI_COMP_MODE_QUIRK)
+ *status |= USB_PORT_STAT_CONNECTION;
}
/* update status field */