diff options
Diffstat (limited to 'drivers/usb/host/xhci-hub.c')
| -rw-r--r-- | drivers/usb/host/xhci-hub.c | 44 | 
1 files changed, 38 insertions, 6 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 2732ef660c5..7b01094d799 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -462,6 +462,42 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,  	}  } +/* Updates Link Status for super Speed port */ +static void xhci_hub_report_link_state(u32 *status, u32 status_reg) +{ +	u32 pls = status_reg & PORT_PLS_MASK; + +	/* resume state is a xHCI internal state. +	 * Do not report it to usb core. +	 */ +	if (pls == XDEV_RESUME) +		return; + +	/* When the CAS bit is set then warm reset +	 * should be performed on port +	 */ +	if (status_reg & 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 (pls != USB_SS_PORT_LS_COMP_MOD && +		    pls != USB_SS_PORT_LS_SS_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; +	} +	/* update status field */ +	*status |= pls; +} +  int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  		u16 wIndex, char *buf, u16 wLength)  { @@ -606,13 +642,9 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  			else  				status |= USB_PORT_STAT_POWER;  		} -		/* Port Link State */ +		/* Update Port Link State for super speed ports*/  		if (hcd->speed == HCD_USB3) { -			/* resume state is a xHCI internal state. -			 * Do not report it to usb core. -			 */ -			if ((temp & PORT_PLS_MASK) != XDEV_RESUME) -				status |= (temp & PORT_PLS_MASK); +			xhci_hub_report_link_state(&status, temp);  		}  		if (bus_state->port_c_suspend & (1 << wIndex))  			status |= 1 << USB_PORT_FEAT_C_SUSPEND;  |