Re: [PATCH 4/6 v3] xHCI: report USB3.0 portstatus comply with USB3.0 specification

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This new version looks fine, thanks Andiry.  I'll apply these to the
for-linux-next branch and get them sent to Greg by end-of-week after I
test them.

Sarah Sharp

On Wed, Apr 27, 2011 at 06:07:43PM +0800, Andiry Xu wrote:
> USB3.0 specification has different wPortStatus and wPortChange definitions
> from USB2.0 specification. Since USB3 root hub and USB2 root hub are split
> now and USB3 hub only has USB3 protocol ports, we should modify the
> portstatus and portchange report of USB3 ports to comply with USB3.0
> specification.
> 
> Signed-off-by: Andiry Xu <andiry.xu@xxxxxxx>
> ---
>  drivers/usb/core/hub.c      |   52 ++++++++++++++++++++++++++++++------------
>  drivers/usb/host/xhci-hub.c |   41 ++++++++++++++++++++++++----------
>  2 files changed, 66 insertions(+), 27 deletions(-)
> 
> diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
> index 93720bd..dcd78c1 100644
> --- a/drivers/usb/core/hub.c
> +++ b/drivers/usb/core/hub.c
> @@ -379,15 +379,6 @@ static int hub_port_status(struct usb_hub *hub, int port1,
>  		*status = le16_to_cpu(hub->status->port.wPortStatus);
>  		*change = le16_to_cpu(hub->status->port.wPortChange);
>  
> -		if ((hub->hdev->parent != NULL) &&
> -				hub_is_superspeed(hub->hdev)) {
> -			/* Translate the USB 3 port status */
> -			u16 tmp = *status & USB_SS_PORT_STAT_MASK;
> -			if (*status & USB_SS_PORT_STAT_POWER)
> -				tmp |= USB_PORT_STAT_POWER;
> -			*status = tmp;
> -		}
> -
>  		ret = 0;
>  	}
>  	mutex_unlock(&hub->status_mutex);
> @@ -2160,11 +2151,40 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
>  	return status;
>  }
>  
> +/* Check if a port is power on */
> +static int port_is_power_on(struct usb_hub *hub, unsigned portstatus)
> +{
> +	int ret = 0;
> +
> +	if (hub_is_superspeed(hub->hdev)) {
> +		if (portstatus & USB_SS_PORT_STAT_POWER)
> +			ret = 1;
> +	} else {
> +		if (portstatus & USB_PORT_STAT_POWER)
> +			ret = 1;
> +	}
> +
> +	return ret;
> +}
> +
>  #ifdef	CONFIG_PM
>  
> -#define MASK_BITS	(USB_PORT_STAT_POWER | USB_PORT_STAT_CONNECTION | \
> -				USB_PORT_STAT_SUSPEND)
> -#define WANT_BITS	(USB_PORT_STAT_POWER | USB_PORT_STAT_CONNECTION)
> +/* Check if a port is suspended(USB2.0 port) or in U3 state(USB3.0 port) */
> +static int port_is_suspended(struct usb_hub *hub, unsigned portstatus)
> +{
> +	int ret = 0;
> +
> +	if (hub_is_superspeed(hub->hdev)) {
> +		if ((portstatus & USB_PORT_STAT_LINK_STATE)
> +				== USB_SS_PORT_LS_U3)
> +			ret = 1;
> +	} else {
> +		if (portstatus & USB_PORT_STAT_SUSPEND)
> +			ret = 1;
> +	}
> +
> +	return ret;
> +}
>  
>  /* Determine whether the device on a port is ready for a normal resume,
>   * is ready for a reset-resume, or should be disconnected.
> @@ -2174,7 +2194,9 @@ static int check_port_resume_type(struct usb_device *udev,
>  		int status, unsigned portchange, unsigned portstatus)
>  {
>  	/* Is the device still present? */
> -	if (status || (portstatus & MASK_BITS) != WANT_BITS) {
> +	if (status || port_is_suspended(hub, portstatus) ||
> +			!port_is_power_on(hub, portstatus) ||
> +			!(portstatus & USB_PORT_STAT_CONNECTION)) {
>  		if (status >= 0)
>  			status = -ENODEV;
>  	}
> @@ -2439,7 +2461,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
>  
>  	/* Skip the initial Clear-Suspend step for a remote wakeup */
>  	status = hub_port_status(hub, port1, &portstatus, &portchange);
> -	if (status == 0 && !(portstatus & USB_PORT_STAT_SUSPEND))
> +	if (status == 0 && !port_is_suspended(hub, portstatus))
>  		goto SuspendCleared;
>  
>  	// dev_dbg(hub->intfdev, "resume port %d\n", port1);
> @@ -3147,7 +3169,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
>  
>  		/* maybe switch power back on (e.g. root hub was reset) */
>  		if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2
> -				&& !(portstatus & USB_PORT_STAT_POWER))
> +				&& !port_is_power_on(hub, portstatus))
>  			set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
>  
>  		if (portstatus & USB_PORT_STAT_ENABLE)
> diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
> index c93fc66..4b76b83 100644
> --- a/drivers/usb/host/xhci-hub.c
> +++ b/drivers/usb/host/xhci-hub.c
> @@ -431,9 +431,6 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
>  		}
>  		xhci_dbg(xhci, "get port status, actual port %d status  = 0x%x\n", wIndex, temp);
>  
> -		/* FIXME - should we return a port status value like the USB
> -		 * 3.0 external hubs do?
> -		 */
>  		/* wPortChange bits */
>  		if (temp & PORT_CSC)
>  			status |= USB_PORT_STAT_C_CONNECTION << 16;
> @@ -441,13 +438,21 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
>  			status |= USB_PORT_STAT_C_ENABLE << 16;
>  		if ((temp & PORT_OCC))
>  			status |= USB_PORT_STAT_C_OVERCURRENT << 16;
> -		/*
> -		 * FIXME ignoring reset and USB 2.1/3.0 specific
> -		 * changes
> -		 */
> -		if ((temp & PORT_PLS_MASK) == XDEV_U3
> -			&& (temp & PORT_POWER))
> -			status |= 1 << USB_PORT_FEAT_SUSPEND;
> +		if ((temp & PORT_RC))
> +			status |= USB_PORT_STAT_C_RESET << 16;
> +		/* USB3.0 only */
> +		if (hcd->speed == HCD_USB3) {
> +			if ((temp & PORT_PLC))
> +				status |= USB_PORT_STAT_C_LINK_STATE << 16;
> +			if ((temp & PORT_WRC))
> +				status |= USB_PORT_STAT_C_BH_RESET << 16;
> +		}
> +
> +		if (hcd->speed != HCD_USB3) {
> +			if ((temp & PORT_PLS_MASK) == XDEV_U3
> +					&& (temp & PORT_POWER))
> +				status |= USB_PORT_STAT_SUSPEND;
> +		}
>  		if ((temp & PORT_PLS_MASK) == XDEV_RESUME) {
>  			if ((temp & PORT_RESET) || !(temp & PORT_PE))
>  				goto error;
> @@ -490,8 +495,20 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
>  			status |= USB_PORT_STAT_OVERCURRENT;
>  		if (temp & PORT_RESET)
>  			status |= USB_PORT_STAT_RESET;
> -		if (temp & PORT_POWER)
> -			status |= USB_PORT_STAT_POWER;
> +		if (temp & PORT_POWER) {
> +			if (hcd->speed == HCD_USB3)
> +				status |= USB_SS_PORT_STAT_POWER;
> +			else
> +				status |= USB_PORT_STAT_POWER;
> +		}
> +		/* Port Link State */
> +		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);
> +		}
>  		if (bus_state->port_c_suspend & (1 << wIndex))
>  			status |= 1 << USB_PORT_FEAT_C_SUSPEND;
>  		xhci_dbg(xhci, "Get port status returned 0x%x\n", status);
> -- 
> 1.7.1
> 
> 
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux