Re: [PATCH v2 4/5] usb: xhci: change enumeration scheme to 'new scheme' by default

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

 



Hi Dan,

I'm attempting to put my queue together for usb-next, and this patch
doesn't apply, due to conflicts in the USB core.  Can you rebase this
patchset on top of my for-usb-next-queue branch, and resend the last two
patches?  The first three applied fine.

Thanks,
Sarah Sharp

On Tue, Oct 08, 2013 at 12:48:12AM +0000, Williams, Dan J wrote:
> Subject: usb: xhci: change enumeration scheme to 'new scheme' by default
> 
> From: Dan Williams <dan.j.williams@xxxxxxxxx>
> 
> Change the default enumeration scheme for xhci attached non-SuperSpeed
> devices from:
> 
>    Reset
>    SetAddress [xhci address-device BSR = 0]
>    GetDescriptor(8)
>    GetDescriptor(18)
> 
> ...to:
> 
>    Reset
>    [xhci address-device BSR = 1]
>    GetDescriptor(64)
>    Reset
>    SetAddress [xhci address-device BSR = 0]
>    GetDescriptor(18)
> 
> ...as some devices misbehave when encountering a SetAddress command
> prior to GetDescriptor.  There are known legacy devices that require
> this scheme, but testing has found at least one USB3 device that fails
> enumeration when presented with this ordering.  For now, follow the ehci
> case and enable 'new scheme' by default for non-SuperSpeed devices.
> 
> To support this enumeration scheme on xhci the AddressDevice operation
> needs to be performed twice.  The first instance of the command enables
> the HC's device and slot context info for the device, but omits sending
> the device a SetAddress command (BSR == block set address request).
> Then, after GetDescriptor completes, follow up with the full
> AddressDevice+SetAddress operation.
> 
> As mentioned before, this ordering of events with USB3 devices causes an
> extra state transition to be exposed to xhci.  Previously USB3 devices
> would transition directly from 'enabled' to 'addressed' and never need
> to underrun responses to 'get descriptor'. We do see the 64-byte
> descriptor fetch the correct data, but the following 18-byte descriptor
> read after the reset gets:
> 
> bLength            = 0
> bDescriptorType    = 0
> bcdUSB             = 0
> bDeviceClass       = 0
> bDeviceSubClass    = 0
> bDeviceProtocol    = 0
> bMaxPacketSize0    = 9
> 
> instead of:
> 
> bLength            = 12
> bDescriptorType    = 1
> bcdUSB             = 300
> bDeviceClass       = 0
> bDeviceSubClass    = 0
> bDeviceProtocol    = 0
> bMaxPacketSize0    = 9
> 
> which results in the discovery process looping until falling back to
> 'old scheme' enumeration.
> 
> Acked-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>
> Reported-by: David Moore <david.moore@xxxxxxxxx>
> Suggested-by: Sarah Sharp <sarah.a.sharp@xxxxxxxxxxxxxxx>
> Signed-off-by: Dan Williams <dan.j.williams@xxxxxxxxx>
> ---
> 
> Here is the patch again with the changelog clarifications.  Alan, I took
> your comments to mean acked-by, let me know it that's not the case.
> 
> --
> Dan
> 
> 
>  drivers/usb/core/hub.c       |   44 ++++++++++++++++++++++++++++++++++++++----
>  drivers/usb/host/xhci-pci.c  |    1 +
>  drivers/usb/host/xhci-plat.c |    1 +
>  drivers/usb/host/xhci-ring.c |    6 +++---
>  drivers/usb/host/xhci.c      |   19 ++++++++++++++----
>  drivers/usb/host/xhci.h      |   11 ++++++++++-
>  include/linux/usb/hcd.h      |    2 ++
>  7 files changed, 72 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
> index c2c5f5adb464..42069ac9c6b2 100644
> --- a/drivers/usb/core/hub.c
> +++ b/drivers/usb/core/hub.c
> @@ -2519,6 +2519,21 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
>  #define HUB_LONG_RESET_TIME	200
>  #define HUB_RESET_TIMEOUT	800
>  
> +/*
> + * "New scheme" enumeration causes an extra state transition to be
> + * exposed to an xhci host and causes USB3 devices to receive control
> + * commands in the default state.  This has been seen to cause
> + * enumeration failures, so disable this enumeration scheme for USB3
> + * devices.
> + */
> +static bool use_new_scheme(struct usb_device *udev, int retry)
> +{
> +	if (udev->speed == USB_SPEED_SUPER)
> +		return false;
> +
> +	return USE_NEW_SCHEME(retry);
> +}
> +
>  static int hub_port_reset(struct usb_hub *hub, int port1,
>  			struct usb_device *udev, unsigned int delay, bool warm);
>  
> @@ -3951,6 +3966,20 @@ static int hub_set_address(struct usb_device *udev, int devnum)
>  	return retval;
>  }
>  
> +static int hub_enable_device(struct usb_device *udev)
> +{
> +	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
> +
> +	if (!hcd->driver->enable_device)
> +		return 0;
> +	if (udev->state == USB_STATE_ADDRESS)
> +		return 0;
> +	if (udev->state != USB_STATE_DEFAULT)
> +		return -EINVAL;
> +
> +	return hcd->driver->enable_device(hcd, udev);
> +}
> +
>  /* Reset device, (re)assign address, get device descriptor.
>   * Device connection must be stable, no more debouncing needed.
>   * Returns device in USB_STATE_ADDRESS, except on error.
> @@ -4063,7 +4092,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
>  	 * this area, and this is how Linux has done it for ages.
>  	 * Change it cautiously.
>  	 *
> -	 * NOTE:  If USE_NEW_SCHEME() is true we will start by issuing
> +	 * NOTE:  If use_new_scheme() is true we will start by issuing
>  	 * a 64-byte GET_DESCRIPTOR request.  This is what Windows does,
>  	 * so it may help with some non-standards-compliant devices.
>  	 * Otherwise we start with SET_ADDRESS and then try to read the
> @@ -4071,10 +4100,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
>  	 * value.
>  	 */
>  	for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
> -		if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) {
> -			struct usb_device_descriptor *buf;
> +		struct usb_device_descriptor *buf;
> +		bool did_new_scheme = false;
> +
> +		if (use_new_scheme(udev, retry_counter)) {
>  			int r = 0;
>  
> +			did_new_scheme = true;
>  #define GET_DESCRIPTOR_BUFSIZE	64
>  			buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
>  			if (!buf) {
> @@ -4082,6 +4114,10 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
>  				continue;
>  			}
>  
> +			retval = hub_enable_device(udev);
> +			if (retval < 0)
> +				goto fail;
> +
>  			/* Retry on all errors; some devices are flakey.
>  			 * 255 is for WUSB devices, we actually need to use
>  			 * 512 (WUSB1.0[4.8.1]).
> @@ -4163,7 +4199,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
>  			 *  - read ep0 maxpacket even for high and low speed,
>  			 */
>  			msleep(10);
> -			if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3))
> +			if (did_new_scheme)
>  				break;
>    		}
>  
> diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
> index 236c3aabe940..96e51949c8b0 100644
> --- a/drivers/usb/host/xhci-pci.c
> +++ b/drivers/usb/host/xhci-pci.c
> @@ -306,6 +306,7 @@ static const struct hc_driver xhci_pci_hc_driver = {
>  	.check_bandwidth =	xhci_check_bandwidth,
>  	.reset_bandwidth =	xhci_reset_bandwidth,
>  	.address_device =	xhci_address_device,
> +	.enable_device =	xhci_enable_device,
>  	.update_hub_device =	xhci_update_hub_device,
>  	.reset_device =		xhci_discover_or_reset_device,
>  
> diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
> index d9c169f470d3..5413861ac0f5 100644
> --- a/drivers/usb/host/xhci-plat.c
> +++ b/drivers/usb/host/xhci-plat.c
> @@ -69,6 +69,7 @@ static const struct hc_driver xhci_plat_xhci_driver = {
>  	.check_bandwidth =	xhci_check_bandwidth,
>  	.reset_bandwidth =	xhci_reset_bandwidth,
>  	.address_device =	xhci_address_device,
> +	.enable_device =	xhci_enable_device,
>  	.update_hub_device =	xhci_update_hub_device,
>  	.reset_device =		xhci_discover_or_reset_device,
>  
> diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
> index 46d7fb8de990..515a21009d7e 100644
> --- a/drivers/usb/host/xhci-ring.c
> +++ b/drivers/usb/host/xhci-ring.c
> @@ -3962,12 +3962,12 @@ int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id)
>  
>  /* Queue an address device command TRB */
>  int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
> -		u32 slot_id)
> +			      u32 slot_id, enum xhci_setup_dev setup)
>  {
>  	return queue_command(xhci, lower_32_bits(in_ctx_ptr),
>  			upper_32_bits(in_ctx_ptr), 0,
> -			TRB_TYPE(TRB_ADDR_DEV) | SLOT_ID_FOR_TRB(slot_id),
> -			false);
> +			TRB_TYPE(TRB_ADDR_DEV) | SLOT_ID_FOR_TRB(slot_id)
> +			| (setup == SETUP_CONTEXT_ONLY ? TRB_BSR : 0), false);
>  }
>  
>  int xhci_queue_vendor_command(struct xhci_hcd *xhci,
> diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
> index d05ff362ddc7..b08369ed2f87 100644
> --- a/drivers/usb/host/xhci.c
> +++ b/drivers/usb/host/xhci.c
> @@ -3705,12 +3705,13 @@ disable_slot:
>  }
>  
>  /*
> - * Issue an Address Device command (which will issue a SetAddress request to
> - * the device).
> + * Issue an Address Device command and optionally send a corresponding
> + * SetAddress request to the device.
>   * We should be protected by the usb_address0_mutex in khubd's hub_port_init, so
>   * we should only issue and wait on one address command at the same time.
>   */
> -int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
> +static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
> +			     enum xhci_setup_dev setup)
>  {
>  	unsigned long flags;
>  	int timeleft;
> @@ -3769,7 +3770,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
>  	spin_lock_irqsave(&xhci->lock, flags);
>  	cmd_trb = xhci_find_next_enqueue(xhci->cmd_ring);
>  	ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma,
> -					udev->slot_id);
> +					udev->slot_id, setup);
>  	if (ret) {
>  		spin_unlock_irqrestore(&xhci->lock, flags);
>  		xhci_dbg_trace(xhci, trace_xhci_dbg_address,
> @@ -3864,6 +3865,16 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
>  	return 0;
>  }
>  
> +int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
> +{
> +	return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ADDRESS);
> +}
> +
> +int xhci_enable_device(struct usb_hcd *hcd, struct usb_device *udev)
> +{
> +	return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ONLY);
> +}
> +
>  /*
>   * Transfer the port index into real index in the HW port status
>   * registers. Caculate offset between the port's PORTSC register
> diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
> index 5f9dc1c1b538..e880776151ae 100644
> --- a/drivers/usb/host/xhci.h
> +++ b/drivers/usb/host/xhci.h
> @@ -1096,6 +1096,14 @@ struct xhci_event_cmd {
>  };
>  
>  /* flags bitmasks */
> +
> +/* Address device - disable SetAddress */
> +#define TRB_BSR		(1<<9)
> +enum xhci_setup_dev {
> +	SETUP_CONTEXT_ONLY,
> +	SETUP_CONTEXT_ADDRESS,
> +};
> +
>  /* bits 16:23 are the virtual function ID */
>  /* bits 24:31 are the slot ID */
>  #define TRB_TO_SLOT_ID(p)	(((p) & (0xff<<24)) >> 24)
> @@ -1787,6 +1795,7 @@ int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
>  		struct usb_host_endpoint **eps, unsigned int num_eps,
>  		gfp_t mem_flags);
>  int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev);
> +int xhci_enable_device(struct usb_hcd *hcd, struct usb_device *udev);
>  int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev);
>  int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
>  				struct usb_device *udev, int enable);
> @@ -1810,7 +1819,7 @@ int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code);
>  void xhci_ring_cmd_db(struct xhci_hcd *xhci);
>  int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id);
>  int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
> -		u32 slot_id);
> +		u32 slot_id, enum xhci_setup_dev);
>  int xhci_queue_vendor_command(struct xhci_hcd *xhci,
>  		u32 field1, u32 field2, u32 field3, u32 field4);
>  int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id,
> diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
> index fc64b6825f5e..21a8a4286063 100644
> --- a/include/linux/usb/hcd.h
> +++ b/include/linux/usb/hcd.h
> @@ -352,6 +352,8 @@ struct hc_driver {
>  	void	(*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
>  		/* Returns the hardware-chosen device address */
>  	int	(*address_device)(struct usb_hcd *, struct usb_device *udev);
> +		/* prepares the hardware to send commands to the device */
> +	int	(*enable_device)(struct usb_hcd *, struct usb_device *udev);
>  		/* Notifies the HCD after a hub descriptor is fetched.
>  		 * Will block.
>  		 */
> 
--
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