summaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/xhci.h
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2013-12-05 17:07:27 -0800
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2013-12-10 13:54:37 -0800
commit48fc7dbd52c0559647291f33a10ccdc6cdbe4c72 (patch)
tree4a2403420a69b2d40e38a53302771ec3d3eb6b66 /drivers/usb/host/xhci.h
parent40fcd88b8d49fd911518190c985112097d3a8a17 (diff)
downloadlinux-48fc7dbd52c0559647291f33a10ccdc6cdbe4c72.tar.bz2
usb: xhci: change enumeration scheme to 'new scheme' by default
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@rowland.harvard.edu> Reported-by: David Moore <david.moore@gmail.com> Suggested-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Reported-by: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Diffstat (limited to 'drivers/usb/host/xhci.h')
-rw-r--r--drivers/usb/host/xhci.h11
1 files changed, 10 insertions, 1 deletions
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 7807f621a713..24344aab2107 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1108,6 +1108,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)
@@ -1760,6 +1768,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);
@@ -1783,7 +1792,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,