mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH v2 0/7] Minor USB fixes and xHCI driver
@ 2014-07-26 15:24 Sebastian Hesselbarth
  2014-07-26 15:24 ` [PATCH v2 1/7] USB: Fix stale usb devices in usb_device_list Sebastian Hesselbarth
                   ` (7 more replies)
  0 siblings, 8 replies; 10+ messages in thread
From: Sebastian Hesselbarth @ 2014-07-26 15:24 UTC (permalink / raw)
  To: Sebastian Hesselbarth, Sascha Hauer; +Cc: Thomas Petazzoni, barebox

This is v2 of the xHCI platform and PCI driver patch set. Compared
to last version, this one successfully works with all kinds of USB
devices (LS,FS,HS,SS) attached to USB host controller. There still
is no SuperSpeed support and likely never will be, as devices work
well without it and speed isn't really important here. The HCD now
also correctly tracks device attach/removal of non-RH devices and
tears down the corresponding virtual devices, too.

The xHCI driver still has some FIXME statements inside, which are
mostly related with SS support. It also lacks some error warnings
when Slots or Endpoints moved to non-usable states. Also, don't
expect attach/detach to work smoothly like in your OS, give them
some time to settle before rescan the bus.

Anyway, I have again successfully tested attach/detach of LS,FS,HS,
SS devices on RH ports, Single-TT HS hub, and Multi-TT HS hub.
Compared to v1, this patch set now includes Patch 3/7 that improves
USB core error handling and device tear-down. The current error
handling caused hangs when something goes wrong, e.g. by unregistering
devices that have never been registered before.

There has been no changes to the patches besides Patch 3/7 which is
new and xHCI HCD and hub (now Patch 6/7) with the following changelog:

v1->v2:
- complete Endpoint Config
- update Endpoint Context for external hubs
- track non-RootHub device removal
- correct FS MaxPacketSize assumption
- drop fake USB 2.0/3.0 Root Hub separation
- cleanup housekeeping structs

Below is a sample output of 'usb -t' after retesting the driver. This
is without the SS device but also with Hub-Hub connections. From top
to bottom, the tree shows (1) Root Hub, (10) 7-port Multi-TT HS hub
with (14) LS USB Keyboard, (15) Single-TT HS Hub with (16) integrated
USB card reader (no card inserted), (17) FS 128M USB 1.1 thumb drive,
and (18) HS 2G USB 2.0 thumb drive.

barebox:/ usb -t
USB: scanning bus for devices...
Bus 001 Device 014: ID 0dc6:3401 SCISSORS Keyboard
Bus 001 Device 015: ID 058f:6254 USB2.0Hub
Bus 001 Device 016: ID 058f:6366 Mass Storage Device
Bus 001 Device 017: ID 05dc:0080 LEXR PLUG DRIVE
Using index 0 for the new disk
Bus 001 Device 018: ID 0951:1643 DataTraveler G3
Using index 1 for the new disk
7 USB Device(s) found
  1 ID 0000:0000
  |  barebox USB 3.0 Root Hub 
  |
  +-10 ID 1a40:0201
    |   USB 2.0 Hub [MTT] 
    |
    +-14 ID 0dc6:3401
    |      SCISSORS Keyboard 
    |  
    +-15 ID 058f:6254
    | |   USB2.0Hub 
    | |
    | +-16 ID 058f:6366
    |      Generic Mass Storage Device 058F0O1111B1
    |    
    +-17 ID 05dc:0080
    |    LEXR PLUG DRIVE LEXR PLUG DRIVE 0000001050509582980900000000000
    |  
    +-18 ID 0951:1643
         Kingston DataTraveler G3 001CC0EC348AFC6135AA2418

Sebastian Hesselbarth (7):
  USB: Fix stale usb devices in usb_device_list
  USB: Count detected USB devices independent of dev_index
  USB: improve error paths and tear-down
  USB: EHCI: use min3 from Linux
  include: import {lower,upper}_32_bits helpers
  USB: host: add xHCI HCD, Hub, and platform driver
  USB: host: add xHCI PCI driver

 drivers/usb/core/hub.c      |   19 +-
 drivers/usb/core/usb.c      |   50 +-
 drivers/usb/core/usb.h      |    1 +
 drivers/usb/host/Kconfig    |   18 +
 drivers/usb/host/Makefile   |    2 +
 drivers/usb/host/ehci-hcd.c |   12 +-
 drivers/usb/host/xhci-hcd.c | 1509 +++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/host/xhci-hub.c |  647 +++++++++++++++++++
 drivers/usb/host/xhci-pci.c |   45 ++
 drivers/usb/host/xhci.h     | 1279 ++++++++++++++++++++++++++++++++++++
 include/common.h            |   16 +
 include/linux/kernel.h      |   18 +
 include/usb/xhci.h          |   33 +
 13 files changed, 3612 insertions(+), 37 deletions(-)
 create mode 100644 drivers/usb/host/xhci-hcd.c
 create mode 100644 drivers/usb/host/xhci-hub.c
 create mode 100644 drivers/usb/host/xhci-pci.c
 create mode 100644 drivers/usb/host/xhci.h
 create mode 100644 include/usb/xhci.h

---
To: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
Cc: barebox@lists.infradead.org
-- 
2.0.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 1/7] USB: Fix stale usb devices in usb_device_list
  2014-07-26 15:24 [PATCH v2 0/7] Minor USB fixes and xHCI driver Sebastian Hesselbarth
@ 2014-07-26 15:24 ` Sebastian Hesselbarth
  2014-07-26 15:24 ` [PATCH v2 2/7] USB: Count detected USB devices independent of dev_index Sebastian Hesselbarth
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Sebastian Hesselbarth @ 2014-07-26 15:24 UTC (permalink / raw)
  To: Sebastian Hesselbarth, Sascha Hauer; +Cc: Thomas Petazzoni, barebox

New usb devices are added to a list of usb devices, but when removing
the corresponding usb_device it was not removed from that list. Fix it
by deleting it properly from the usb_device_list.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
To: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
Cc: barebox@lists.infradead.org
---
 drivers/usb/core/usb.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 351e783b6536..2cc338465539 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -472,6 +472,7 @@ void usb_remove_device(struct usb_device *usbdev)
 		dev_err(&usbdev->dev, "failed to unregister\n");
 
 	usbdev->parent->children[usbdev->portnr - 1] = NULL;
+	list_del(&usbdev->list);
 	free(usbdev);
 }
 
-- 
2.0.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 2/7] USB: Count detected USB devices independent of dev_index
  2014-07-26 15:24 [PATCH v2 0/7] Minor USB fixes and xHCI driver Sebastian Hesselbarth
  2014-07-26 15:24 ` [PATCH v2 1/7] USB: Fix stale usb devices in usb_device_list Sebastian Hesselbarth
@ 2014-07-26 15:24 ` Sebastian Hesselbarth
  2014-07-26 15:24 ` [PATCH v2 3/7] USB: improve error paths and tear-down Sebastian Hesselbarth
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Sebastian Hesselbarth @ 2014-07-26 15:24 UTC (permalink / raw)
  To: Sebastian Hesselbarth, Sascha Hauer; +Cc: Thomas Petazzoni, barebox

Adding a usb device increases dev_index every time a new device is
allocated. Removing a usb device does not decrease again, of course.
As we print the number of detected usb devices after each usb bus
scan based on dev_index, we cannot trust dev_index here. Keep track
of the correct number of (currently) detected usb devices by
introducing an independent dev_count that gets increased on detect
and decreased on remove.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
To: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
Cc: barebox@lists.infradead.org
---
 drivers/usb/core/usb.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 2cc338465539..d3bd19be706d 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -66,6 +66,7 @@
 
 #define USB_BUFSIZ	512
 
+static int dev_count;
 static int dev_index;
 static int asynch_allowed;
 
@@ -448,6 +449,7 @@ int usb_new_device(struct usb_device *dev)
 	dev_add_param_int_ro(&dev->dev, "idProduct",
 			le16_to_cpu(dev->descriptor->idProduct), "%04x");
 	list_add_tail(&dev->list, &usb_device_list);
+	dev_count++;
 
 	err = 0;
 
@@ -474,6 +476,7 @@ void usb_remove_device(struct usb_device *usbdev)
 	usbdev->parent->children[usbdev->portnr - 1] = NULL;
 	list_del(&usbdev->list);
 	free(usbdev);
+	dev_count--;
 }
 
 struct usb_device *usb_alloc_new_device(void)
@@ -527,7 +530,7 @@ void usb_rescan(void)
 			continue;
 	}
 
-	pr_info("%d USB Device(s) found\n", dev_index);
+	pr_info("%d USB Device(s) found\n", dev_count);
 }
 
 /*
-- 
2.0.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 3/7] USB: improve error paths and tear-down
  2014-07-26 15:24 [PATCH v2 0/7] Minor USB fixes and xHCI driver Sebastian Hesselbarth
  2014-07-26 15:24 ` [PATCH v2 1/7] USB: Fix stale usb devices in usb_device_list Sebastian Hesselbarth
  2014-07-26 15:24 ` [PATCH v2 2/7] USB: Count detected USB devices independent of dev_index Sebastian Hesselbarth
@ 2014-07-26 15:24 ` Sebastian Hesselbarth
  2014-07-26 15:24 ` [PATCH v2 4/7] USB: EHCI: use min3 from Linux Sebastian Hesselbarth
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Sebastian Hesselbarth @ 2014-07-26 15:24 UTC (permalink / raw)
  To: Sebastian Hesselbarth, Sascha Hauer; +Cc: Thomas Petazzoni, barebox

USB core isn't too strict about allocation/deallocation and
add/remove sequences of usb devices. Especially, error paths
and device tear-down are kind of broken and cause hangs on
failing usb device detect.

This patch improves the situation by introducing a
usb_free_device() that tears down allocated resources by
usb_alloc_new_device(). usb_remove_device() now only deals
with resources that have been added by usb_new_device().
Also, error handling is fixed or improved to ensure that no
devices are unregistered that have not been previously
registered.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
To: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
Cc: barebox@lists.infradead.org
---
 drivers/usb/core/hub.c | 19 ++++++++++++-------
 drivers/usb/core/usb.c | 48 ++++++++++++++++++++++++++++--------------------
 drivers/usb/core/usb.h |  1 +
 3 files changed, 41 insertions(+), 27 deletions(-)

diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index c1f743cbed12..d42b47cbe0b8 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -186,19 +186,21 @@ static void usb_hub_port_connect_change(struct usb_device *dev, int port)
 	usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_CONNECTION);
 
 	/* Disconnect any existing devices under this port */
-	if (((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
-	     (!(portstatus & USB_PORT_STAT_ENABLE))) || (dev->children[port])) {
-		dev_dbg(&dev->dev, "usb_disconnect(&hub->children[port]);\n");
+	if (dev->children[port] && !(portstatus & USB_PORT_STAT_CONNECTION)) {
+		dev_dbg(&dev->dev, "disconnect detected on port %d\n", port + 1);
 		usb_remove_device(dev->children[port]);
-		/* Return now if nothing is connected */
-		if (!(portstatus & USB_PORT_STAT_CONNECTION))
-			return;
+		return;
 	}
+
+	/* Remove disabled but connected devices */
+	if (dev->children[port] && !(portstatus & USB_PORT_STAT_ENABLE))
+		usb_remove_device(dev->children[port]);
+
 	wait_ms(200);
 
 	/* Reset the port */
 	if (hub_port_reset(dev, port, &portstatus) < 0) {
-		printf("cannot reset port %i!?\n", port + 1);
+		dev_warn(&dev->dev, "cannot reset port %i!?\n", port + 1);
 		return;
 	}
 
@@ -225,7 +227,10 @@ static void usb_hub_port_connect_change(struct usb_device *dev, int port)
 		/* Woops, disable the port */
 		dev_dbg(&dev->dev, "hub: disabling port %d\n", port + 1);
 		usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_ENABLE);
+		usb_free_device(usb);
+		return;
 	}
+
 	device_detect(&usb->dev);
 }
 
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index d3bd19be706d..3f3d59577ca4 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -431,7 +431,7 @@ int usb_new_device(struct usb_device *dev)
 	err = register_device(&dev->dev);
 	if (err) {
 		printf("Failed to register device: %s\n", strerror(-err));
-		return err;
+		goto err_out;
 	}
 
 	dev_add_param_int_ro(&dev->dev, "iManufacturer",
@@ -458,42 +458,45 @@ err_out:
 	return err;
 }
 
+void usb_free_device(struct usb_device *usbdev)
+{
+	dma_free(usbdev->descriptor);
+	dma_free(usbdev->setup_packet);
+	free(usbdev);
+}
+
 void usb_remove_device(struct usb_device *usbdev)
 {
-	int i, ret;
+	int i;
 
-	for (i = 0; i < usbdev->maxchild; i++) {
-		if (usbdev->children[i])
-			usb_remove_device(usbdev->children[i]);
-	}
+	if (!usbdev)
+		return;
 
-	dev_info(&usbdev->dev, "removing\n");
+	for (i = 0; i < usbdev->maxchild; i++)
+		usb_remove_device(usbdev->children[i]);
+	if (usbdev->parent && usbdev->portnr)
+		usbdev->parent->children[usbdev->portnr - 1] = NULL;
+	list_del(&usbdev->list);
+	dev_count--;
 
-	ret = unregister_device(&usbdev->dev);
-	if (ret)
+	if (unregister_device(&usbdev->dev))
 		dev_err(&usbdev->dev, "failed to unregister\n");
+	else
+		dev_info(&usbdev->dev, "removed\n");
 
-	usbdev->parent->children[usbdev->portnr - 1] = NULL;
-	list_del(&usbdev->list);
-	free(usbdev);
-	dev_count--;
+	usb_free_device(usbdev);
 }
 
 struct usb_device *usb_alloc_new_device(void)
 {
 	struct usb_device *usbdev = xzalloc(sizeof (*usbdev));
 
-	if (!usbdev)
-		return NULL;
-
-	usbdev->devnum = dev_index + 1;
+	usbdev->devnum = ++dev_index;
 	usbdev->maxchild = 0;
 	usbdev->dev.bus = &usb_bus_type;
 	usbdev->setup_packet = dma_alloc(sizeof(*usbdev->setup_packet));
 	usbdev->descriptor = dma_alloc(sizeof(*usbdev->descriptor));
 
-	dev_index++;
-
 	return usbdev;
 }
 
@@ -509,7 +512,12 @@ int usb_host_detect(struct usb_host *host)
 		host->root_dev = usb_alloc_new_device();
 		host->root_dev->dev.parent = host->hw_dev;
 		host->root_dev->host = host;
-		usb_new_device(host->root_dev);
+
+		ret = usb_new_device(host->root_dev);
+		if (ret) {
+			usb_free_device(host->root_dev);
+			return ret;
+		}
 	}
 
 	device_detect(&host->root_dev->dev);
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index a0c05506dde8..a5bb255121b2 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -2,6 +2,7 @@
 #define __CORE_USB_H
 
 struct usb_device *usb_alloc_new_device(void);
+void usb_free_device(struct usb_device *dev);
 int usb_new_device(struct usb_device *dev);
 void usb_remove_device(struct usb_device *dev);
 
-- 
2.0.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 4/7] USB: EHCI: use min3 from Linux
  2014-07-26 15:24 [PATCH v2 0/7] Minor USB fixes and xHCI driver Sebastian Hesselbarth
                   ` (2 preceding siblings ...)
  2014-07-26 15:24 ` [PATCH v2 3/7] USB: improve error paths and tear-down Sebastian Hesselbarth
@ 2014-07-26 15:24 ` Sebastian Hesselbarth
  2014-07-26 15:24 ` [PATCH v2 5/7] include: import {lower,upper}_32_bits helpers Sebastian Hesselbarth
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Sebastian Hesselbarth @ 2014-07-26 15:24 UTC (permalink / raw)
  To: Sebastian Hesselbarth, Sascha Hauer; +Cc: Thomas Petazzoni, barebox

EHCI HCD has a private version of min3() determining the smallest
number out of 3. We already have min()/max() imported from Linux,
also get min3()/max3() and use it instead of EHCI's private one.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
To: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
Cc: barebox@lists.infradead.org
---
 drivers/usb/host/ehci-hcd.c | 12 +-----------
 include/linux/kernel.h      | 18 ++++++++++++++++++
 2 files changed, 19 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index a76e06bd565f..c0ea8d013a21 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -436,16 +436,6 @@ fail:
 	return -1;
 }
 
-static inline int min3(int a, int b, int c)
-{
-
-	if (b < a)
-		a = b;
-	if (c < a)
-		a = c;
-	return a;
-}
-
 #ifdef CONFIG_MACH_EFIKA_MX_SMARTBOOK
 #include <usb/ulpi.h>
 /*
@@ -717,7 +707,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 	}
 
 	wait_ms(1);
-	len = min3(srclen, le16_to_cpu(req->length), length);
+	len = min3(srclen, (int)le16_to_cpu(req->length), length);
 	if (srcptr != NULL && len > 0)
 		memcpy(buffer, srcptr, len);
 	else
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index d512adcea113..98f12e1b934f 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -34,6 +34,24 @@
 	(void) (&_max1 == &_max2);		\
 	_max1 > _max2 ? _max1 : _max2; })
 
+#define min3(x, y, z) ({			\
+	typeof(x) _min1 = (x);			\
+	typeof(y) _min2 = (y);			\
+	typeof(z) _min3 = (z);			\
+	(void) (&_min1 == &_min2);		\
+	(void) (&_min1 == &_min3);		\
+	_min1 < _min2 ? (_min1 < _min3 ? _min1 : _min3) :	\
+		(_min2 < _min3 ? _min2 : _min3); })
+
+#define max3(x, y, z) ({			\
+	typeof(x) _max1 = (x);			\
+	typeof(y) _max2 = (y);			\
+	typeof(z) _max3 = (z);			\
+	(void) (&_max1 == &_max2);		\
+	(void) (&_max1 == &_max3);		\
+	_max1 > _max2 ? (_max1 > _max3 ? _max1 : _max3) :	\
+		(_max2 > _max3 ? _max2 : _max3); })
+
 /**
  * clamp - return a value clamped to a given range with strict typechecking
  * @val: current value
-- 
2.0.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 5/7] include: import {lower,upper}_32_bits helpers
  2014-07-26 15:24 [PATCH v2 0/7] Minor USB fixes and xHCI driver Sebastian Hesselbarth
                   ` (3 preceding siblings ...)
  2014-07-26 15:24 ` [PATCH v2 4/7] USB: EHCI: use min3 from Linux Sebastian Hesselbarth
@ 2014-07-26 15:24 ` Sebastian Hesselbarth
  2014-07-26 15:24 ` [PATCH v2 6/7] USB: host: add xHCI HCD, Hub, and platform driver Sebastian Hesselbarth
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Sebastian Hesselbarth @ 2014-07-26 15:24 UTC (permalink / raw)
  To: Sebastian Hesselbarth, Sascha Hauer; +Cc: Thomas Petazzoni, barebox

This imports {lower,upper}_32_bits defines to allow to get upper
and lower 32b part of a 64b number.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
To: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
Cc: barebox@lists.infradead.org
---
 include/common.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/include/common.h b/include/common.h
index ca817aac4f06..de635718d2fe 100644
--- a/include/common.h
+++ b/include/common.h
@@ -282,6 +282,22 @@ void barebox_set_hostname(const char *);
 }							\
 )
 
+/**
+ * upper_32_bits - return bits 32-63 of a number
+ * @n: the number we're accessing
+ *
+ * A basic shift-right of a 64- or 32-bit quantity.  Use this to suppress
+ * the "right shift count >= width of type" warning when that quantity is
+ * 32-bits.
+ */
+#define upper_32_bits(n)	((u32)(((n) >> 16) >> 16))
+
+/**
+ * lower_32_bits - return bits 0-31 of a number
+ * @n: the number we're accessing
+ */
+#define lower_32_bits(n)	((u32)(n))
+
 #define abs(x) ({                               \
 		long __x = (x);                 \
 		(__x < 0) ? -__x : __x;         \
-- 
2.0.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 6/7] USB: host: add xHCI HCD, Hub, and platform driver
  2014-07-26 15:24 [PATCH v2 0/7] Minor USB fixes and xHCI driver Sebastian Hesselbarth
                   ` (4 preceding siblings ...)
  2014-07-26 15:24 ` [PATCH v2 5/7] include: import {lower,upper}_32_bits helpers Sebastian Hesselbarth
@ 2014-07-26 15:24 ` Sebastian Hesselbarth
  2014-07-26 15:24 ` [PATCH v2 7/7] USB: host: add xHCI PCI driver Sebastian Hesselbarth
  2014-07-28  5:41 ` [PATCH v2 0/7] Minor USB fixes and xHCI driver Sascha Hauer
  7 siblings, 0 replies; 10+ messages in thread
From: Sebastian Hesselbarth @ 2014-07-26 15:24 UTC (permalink / raw)
  To: Sebastian Hesselbarth, Sascha Hauer; +Cc: Thomas Petazzoni, barebox

This adds support for xHCI USB 3.0 host controllers found on various
SoCs and PCI devices. Currently, the driver only supports the virtual
USB 2.0 ports of the host controller, so if you plan to use USB 3.0
devices, put a USB 2.0 cable in between.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
To: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
Cc: barebox@lists.infradead.org
---
 drivers/usb/host/Kconfig    |   11 +
 drivers/usb/host/Makefile   |    1 +
 drivers/usb/host/xhci-hcd.c | 1509 +++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/host/xhci-hub.c |  647 +++++++++++++++++++
 drivers/usb/host/xhci.h     | 1279 ++++++++++++++++++++++++++++++++++++
 include/usb/xhci.h          |   33 +
 6 files changed, 3480 insertions(+)
 create mode 100644 drivers/usb/host/xhci-hcd.c
 create mode 100644 drivers/usb/host/xhci-hub.c
 create mode 100644 drivers/usb/host/xhci.h
 create mode 100644 include/usb/xhci.h

diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 5a3ce40705e8..8c64a3b99c11 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -22,3 +22,14 @@ config USB_OHCI_AT91
 	bool "AT91 OHCI driver"
 
 endif
+
+config USB_XHCI
+	bool "xHCI driver"
+	help
+	  The eXtensible Host Controller Interface (xHCI) is standard for
+	  USB 3.0 "SuperSpeed" host controller hardware. xHCI specification
+	  defines support for all USB device speeds from USB 3.0 down to
+	  USB 1.1 without the need for companion controllers.
+
+	  This driver currently only supports virtual USB 2.0 ports, if you
+	  plan to use USB 3.0 devices, use a USB 2.0 cable in between.
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 156fc7fed92b..a5c009ebd6a8 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -3,3 +3,4 @@ obj-$(CONFIG_USB_EHCI_OMAP)	+= ehci-omap.o
 obj-$(CONFIG_USB_EHCI_ATMEL)	+= ehci-atmel.o
 obj-$(CONFIG_USB_OHCI)		+= ohci-hcd.o
 obj-$(CONFIG_USB_OHCI_AT91)	+= ohci-at91.o
+obj-$(CONFIG_USB_XHCI)		+= xhci-hcd.o xhci-hub.o
diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
new file mode 100644
index 000000000000..925341975078
--- /dev/null
+++ b/drivers/usb/host/xhci-hcd.c
@@ -0,0 +1,1509 @@
+/*
+ * xHCI HCD driver
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * Some code borrowed from the Linux xHCI driver
+ *   Author: Sarah Sharp
+ *   Copyright (C) 2008 Intel Corp.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+//#define DEBUG
+#include <asm/mmu.h>
+#include <clock.h>
+#include <common.h>
+#include <init.h>
+#include <io.h>
+#include <linux/err.h>
+#include <usb/usb.h>
+#include <usb/xhci.h>
+
+#include "xhci.h"
+
+/*
+ * xHCI ring handling
+ */
+
+static int xhci_ring_is_last_trb(struct xhci_ring *ring, union xhci_trb *trb)
+{
+        if (ring->type == TYPE_EVENT)
+                return trb == &ring->trbs[NUM_EVENT_TRBS];
+        else
+                return TRB_TYPE_LINK(le32_to_cpu(trb->link.control));
+}
+
+static int xhci_ring_increment(struct xhci_ring *ring, bool enqueue)
+{
+	union xhci_trb **queue = (enqueue) ? &ring->enqueue : &ring->dequeue;
+
+	(*queue)++;
+
+        if (!xhci_ring_is_last_trb(ring, *queue))
+		return 0;
+
+	if (ring->type == TYPE_EVENT) {
+		*queue = &ring->trbs[0];
+		ring->cycle_state ^= 1;
+	} else {
+		u32 ctrl = le32_to_cpu((*queue)->link.control);
+		void *p = (void *)(dma_addr_t)
+			le64_to_cpu((*queue)->link.segment_ptr);
+
+		ctrl = (ctrl & ~TRB_CYCLE) | ring->cycle_state;
+		(*queue)->link.control = cpu_to_le32(ctrl);
+
+		if (enqueue)
+			ring->enqueue = p;
+		else
+			ring->dequeue = p;
+
+		if (ctrl & LINK_TOGGLE)
+			ring->cycle_state ^= 1;
+	}
+
+	return 0;
+}
+
+static int xhci_ring_issue_trb(struct xhci_ring *ring, union xhci_trb *trb)
+{
+	union xhci_trb *enq = ring->enqueue;
+	int i;
+
+	/* Pass TRB to hardware */
+	trb->generic.field[3] &= ~TRB_CYCLE;
+	trb->generic.field[3] |= ring->cycle_state;
+	for (i = 0; i < 4; i++)
+		enq->generic.field[i] = cpu_to_le32(trb->generic.field[i]);
+
+	xhci_ring_increment(ring, 1);
+
+	return 0;
+}
+
+static void xhci_ring_init(struct xhci_ring *ring, int num_trbs,
+			   enum xhci_ring_type type)
+{
+	ring->type = type;
+	ring->cycle_state = 1;
+	ring->num_trbs = num_trbs;
+	ring->enqueue = ring->dequeue = &ring->trbs[0];
+
+	/* Event ring is not linked */
+	if (type == TYPE_EVENT)
+		return;
+
+	ring->trbs[num_trbs-1].link.segment_ptr =
+		cpu_to_le64((dma_addr_t)&ring->trbs[0]);
+	ring->trbs[num_trbs-1].link.control =
+		cpu_to_le32(TRB_TYPE(TRB_LINK) | LINK_TOGGLE);
+}
+
+static struct xhci_ring *xhci_get_endpoint_ring(struct xhci_hcd *xhci)
+{
+	struct xhci_ring *ring;
+
+	if (list_empty(&xhci->rings_list)) {
+		dev_err(xhci->dev, "no more endpoint rings available\n");
+		return NULL;
+	}
+
+	ring = list_last_entry(&xhci->rings_list, struct xhci_ring, list);
+	list_del_init(&ring->list);
+
+	return ring;
+}
+
+static void xhci_put_endpoint_ring(struct xhci_hcd *xhci, struct xhci_ring *ring)
+{
+	if (!ring)
+		return;
+
+	memset(ring->trbs, 0, ring->num_trbs * sizeof(union xhci_trb));
+	list_add_tail(&ring->list, &xhci->rings_list);
+}
+
+/*
+ * xhci_get_endpoint_index - Used for passing endpoint bitmasks between the
+ * core and HCDs.  Find the index for an endpoint given its descriptor.
+ * Use the return value to right shift 1 for the bitmask.
+ *
+ * Index  = (epnum * 2) + direction - 1,
+ * where direction = 0 for OUT, 1 for IN.
+ * For control endpoints, the IN index is used (OUT index is unused), so
+ * index = (epnum * 2) + direction - 1 = (epnum * 2) + 1 - 1 = (epnum * 2)
+ */
+static unsigned int xhci_get_endpoint_index(u8 epaddress, u8 epattributes)
+{
+	u8 epnum = epaddress & USB_ENDPOINT_NUMBER_MASK;
+	u8 xfer = epattributes & USB_ENDPOINT_XFERTYPE_MASK;
+        unsigned int index;
+
+        if (xfer == USB_ENDPOINT_XFER_CONTROL)
+                index = (unsigned int)(epnum * 2);
+        else
+                index = (unsigned int)(epnum * 2) +
+                        ((epaddress & USB_DIR_IN) ? 1 : 0) - 1;
+
+        return index;
+}
+
+static u8 xhci_get_endpoint_type(u8 epaddress, u8 epattributes)
+{
+	int in = epaddress & USB_ENDPOINT_DIR_MASK;
+	u8 xfer = epattributes & USB_ENDPOINT_XFERTYPE_MASK;
+	u8 type;
+
+	switch (xfer) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		type = CTRL_EP;
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		type = (in) ? ISOC_IN_EP : ISOC_OUT_EP;
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		type = (in) ? BULK_IN_EP : BULK_OUT_EP;
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		type = (in) ? INT_IN_EP : INT_OUT_EP;
+		break;
+	}
+
+	return type;
+}
+
+/*
+ * Convert interval expressed as 2^(bInterval - 1) == interval into
+ * straight exponent value 2^n == interval.
+ *
+ */
+static u32 xhci_parse_exponent_interval(struct usb_device *udev,
+					struct usb_endpoint_descriptor *ep)
+{
+	u32 interval;
+
+	interval = clamp_val(ep->bInterval, 1, 16) - 1;
+	/*
+	 * Full speed isoc endpoints specify interval in frames,
+	 * not microframes. We are using microframes everywhere,
+	 * so adjust accordingly.
+	 */
+	if (udev->speed == USB_SPEED_FULL)
+		interval += 3;	/* 1 frame = 2^3 uframes */
+
+	return interval;
+}
+
+/*
+ * Convert bInterval expressed in microframes (in 1-255 range) to exponent of
+ * microframes, rounded down to nearest power of 2.
+ */
+static u32 xhci_microframes_to_exponent(struct usb_device *udev,
+			struct usb_endpoint_descriptor *ep, u32 desc_interval,
+			u32 min_exponent, u32 max_exponent)
+{
+	u32 interval;
+
+	interval = fls(desc_interval) - 1;
+	return clamp_val(interval, min_exponent, max_exponent);
+}
+
+static inline u32 xhci_parse_microframe_interval(struct usb_device *udev,
+					  struct usb_endpoint_descriptor *ep)
+{
+	if (ep->bInterval == 0)
+		return 0;
+	return xhci_microframes_to_exponent(udev, ep, ep->bInterval, 0, 15);
+}
+
+
+static inline u32 xhci_parse_frame_interval(struct usb_device *udev,
+				     struct usb_endpoint_descriptor *ep)
+{
+	return xhci_microframes_to_exponent(udev, ep, ep->bInterval * 8, 3, 10);
+}
+
+static u32 xhci_get_endpoint_interval(struct usb_device *udev,
+				      struct usb_endpoint_descriptor *ep)
+{
+	u8 type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+	u32 interval = 0;
+
+	switch (udev->speed) {
+	case USB_SPEED_HIGH:
+		/* Max NAK rate */
+		if (type == USB_ENDPOINT_XFER_CONTROL ||
+		    type == USB_ENDPOINT_XFER_BULK) {
+			interval = xhci_parse_microframe_interval(udev, ep);
+			break;
+		}
+		/* Fall through - SS and HS isoc/int have same decoding */
+	case USB_SPEED_SUPER:
+		if (type == USB_ENDPOINT_XFER_ISOC ||
+		    type == USB_ENDPOINT_XFER_INT)
+			interval = xhci_parse_exponent_interval(udev, ep);
+		break;
+	case USB_SPEED_FULL:
+		if (type == USB_ENDPOINT_XFER_ISOC) {
+			interval = xhci_parse_exponent_interval(udev, ep);
+			break;
+		}
+		/*
+		 * Fall through for interrupt endpoint interval decoding
+		 * since it uses the same rules as low speed interrupt
+		 * endpoints.
+		 */
+	case USB_SPEED_LOW:
+		if (type == USB_ENDPOINT_XFER_ISOC ||
+		    type == USB_ENDPOINT_XFER_INT)
+			interval = xhci_parse_frame_interval(udev, ep);
+		break;
+	}
+
+	return interval;
+}
+
+/* The "Mult" field in the endpoint context is only set for SuperSpeed isoc eps.
+ * High speed endpoint descriptors can define "the number of additional
+ * transaction opportunities per microframe", but that goes in the Max Burst
+ * endpoint context field.
+ */
+static u32 xhci_get_endpoint_mult(struct usb_device *udev,
+				  struct usb_endpoint_descriptor *ep)
+{
+	u8 type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+	if (udev->speed != USB_SPEED_SUPER || type != USB_ENDPOINT_XFER_ISOC)
+		return 0;
+	/* FIXME: return ss_ep_comp_descriptor.bmAttributes */
+	return 0;
+}
+
+/* Return the maximum endpoint service interval time (ESIT) payload.
+ * Basically, this is the maxpacket size, multiplied by the burst size
+ * and mult size.
+ */
+static u32 xhci_get_max_esit_payload(struct usb_device *udev,
+				     struct usb_endpoint_descriptor *ep)
+{
+	u8 type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+	int max_burst;
+	int max_packet;
+	u16 mps;
+
+	/* Only applies for interrupt or isochronous endpoints */
+	if (type != USB_ENDPOINT_XFER_INT && type != USB_ENDPOINT_XFER_ISOC)
+		return 0;
+
+	/* FIXME: return ss_ep_comp_descriptor.wBytesPerInterval */
+	if (udev->speed == USB_SPEED_SUPER)
+		return 0;
+
+	mps = le16_to_cpu(ep->wMaxPacketSize);
+	max_packet = GET_MAX_PACKET(mps);
+	max_burst = (mps & 0x1800) >> 11;
+	/* A 0 in max burst means 1 transfer per ESIT */
+	return max_packet * (max_burst + 1);
+}
+
+int xhci_handshake(void __iomem *p, u32 mask, u32 done, int usec)
+{
+	u32 result;
+	u64 start;
+
+	start = get_time_ns();
+
+	while (1) {
+		result = readl(p) & mask;
+		if (result == done)
+			return 0;
+		if (is_timeout(start, usec * USECOND))
+			return -ETIMEDOUT;
+	}
+}
+
+int xhci_issue_command(struct xhci_hcd *xhci, union xhci_trb *trb)
+{
+	int ret;
+
+	ret = xhci_ring_issue_trb(&xhci->cmd_ring, trb);
+	if (ret)
+		return ret;
+
+	/* Ring the bell */
+	writel(DB_VALUE_HOST, &xhci->dba->doorbell[0]);
+	readl(&xhci->dba->doorbell[0]);
+
+	return 0;
+}
+
+static void xhci_set_event_dequeue(struct xhci_hcd *xhci)
+{
+        u64 reg64;
+
+        reg64 = xhci_read_64(&xhci->ir_set->erst_dequeue);
+        reg64 &= ERST_PTR_MASK;
+        /*
+	 * Don't clear the EHB bit (which is RW1C) because
+         * there might be more events to service.
+         */
+        reg64 &= ~ERST_EHB;
+	reg64 |= (dma_addr_t)xhci->event_ring.dequeue &
+		~(dma_addr_t)ERST_PTR_MASK;
+
+	/* Update HC event ring dequeue pointer */
+	xhci_write_64(reg64, &xhci->ir_set->erst_dequeue);
+}
+
+int xhci_wait_for_event(struct xhci_hcd *xhci, u8 type, union xhci_trb *trb)
+{
+	while (true) {
+		union xhci_trb *deq = xhci->event_ring.dequeue;
+		u8 event_type;
+		int i, ret;
+
+		ret = xhci_handshake(&deq->event_cmd.flags,
+				     cpu_to_le32(TRB_CYCLE),
+				     cpu_to_le32(xhci->event_ring.cycle_state),
+				     XHCI_CMD_DEFAULT_TIMEOUT / USECOND);
+		if (ret) {
+			dev_err(xhci->dev, "Timeout while waiting for event\n");
+			return ret;
+		}
+
+		for (i = 0; i < 4; i++)
+			trb->generic.field[i] =
+				le32_to_cpu(deq->generic.field[i]);
+
+		xhci_set_event_dequeue(xhci);
+		xhci_ring_increment(&xhci->event_ring, 0);
+
+		event_type = TRB_FIELD_TO_TYPE(trb->event_cmd.flags);
+
+		switch (event_type) {
+		case TRB_PORT_STATUS:
+			dev_dbg(xhci->dev, "Event PortStatusChange %u\n",
+				GET_PORT_ID(trb->generic.field[0]));
+			break;
+		case TRB_TRANSFER:
+			dev_dbg(xhci->dev, "Event Transfer %u\n",
+				GET_COMP_CODE(trb->event_cmd.status));
+			ret = -GET_COMP_CODE(trb->event_cmd.status);
+			if (ret == -COMP_SUCCESS)
+				ret = 0;
+			break;
+		case TRB_COMPLETION:
+			dev_dbg(xhci->dev, "Event CommandCompletion %u\n",
+				GET_COMP_CODE(trb->event_cmd.status));
+			ret = -GET_COMP_CODE(trb->event_cmd.status);
+			if (ret == -COMP_SUCCESS)
+				ret = 0;
+			break;
+		default:
+			dev_err(xhci->dev, "unhandled event %u (%02x) [%08x %08x %08x %08x]\n",
+				event_type, event_type,
+				trb->generic.field[0], trb->generic.field[1],
+				trb->generic.field[2], trb->generic.field[3]);
+		}
+
+		if (event_type == type)
+			return ret;
+	}
+	return -ENOSYS;
+}
+
+static struct xhci_virtual_device *xhci_find_virtdev(struct xhci_hcd *xhci,
+						     struct usb_device *udev)
+{
+	struct xhci_virtual_device *vdev;
+
+	list_for_each_entry(vdev, &xhci->vdev_list, list)
+		if (vdev->udev == udev)
+			return vdev;
+
+	return NULL;
+}
+
+static struct xhci_virtual_device *xhci_alloc_virtdev(struct xhci_hcd *xhci,
+						      struct usb_device *udev)
+{
+	struct xhci_virtual_device *vdev;
+	size_t sz_ctx, sz_ictx, sz_dctx;
+	void *p;
+
+	vdev = xzalloc(sizeof(*vdev));
+	vdev->udev = udev;
+	list_add_tail(&vdev->list, &xhci->vdev_list);
+
+	sz_ctx = HCC_64BYTE_CONTEXT(xhci->hcc_params) ? 2048 : 1024;
+	/* Device Context: 64B aligned */
+	sz_dctx = ALIGN(sz_ctx, 64);
+	/* Input Control Context: 64B aligned */
+	sz_ictx = ALIGN(sz_ctx + HCC_CTX_SIZE(xhci->hcc_params), 64);
+
+	vdev->dma_size = sz_ictx + sz_dctx;
+	p = vdev->dma = dma_alloc_coherent(vdev->dma_size);
+	memset(vdev->dma, 0, vdev->dma_size);
+
+	vdev->out_ctx = p; p += sz_dctx;
+	vdev->in_ctx = p; p += sz_ictx;
+
+	return vdev;
+}
+
+static void xhci_free_virtdev(struct xhci_virtual_device *vdev)
+{
+	struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
+	int i;
+
+	for (i = 0; i < USB_MAXENDPOINTS; i++)
+		if (vdev->ep[i])
+			xhci_put_endpoint_ring(xhci, vdev->ep[i]);
+
+	list_del(&vdev->list);
+	dma_free_coherent(vdev->dma, vdev->dma_size);
+	free(vdev);
+}
+
+static int xhci_virtdev_issue_transfer(struct xhci_virtual_device *vdev,
+				 u8 ep, union xhci_trb *trb, bool ringbell)
+{
+	struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
+	struct xhci_ring *ring = vdev->ep[ep];
+	int ret;
+
+	ret = xhci_ring_issue_trb(ring, trb);
+	if (ret || !ringbell)
+		return ret;
+
+	/* Ring the bell */
+	writel(DB_VALUE(ep, 0), &xhci->dba->doorbell[vdev->slot_id]);
+	readl(&xhci->dba->doorbell[vdev->slot_id]);
+
+	return 0;
+}
+
+static void xhci_virtdev_zero_in_ctx(struct xhci_virtual_device *vdev)
+{
+	int i;
+
+        /* When a device's add flag and drop flag are zero, any subsequent
+         * configure endpoint command will leave that endpoint's state
+         * untouched.  Make sure we don't leave any old state in the input
+         * endpoint contexts.
+         */
+        vdev->in_ctx->icc.drop_flags = 0;
+        vdev->in_ctx->icc.add_flags = 0;
+        vdev->in_ctx->slot.dev_info &= cpu_to_le32(~LAST_CTX_MASK);
+        /* Endpoint 0 is always valid */
+        vdev->in_ctx->slot.dev_info |= cpu_to_le32(LAST_CTX(1));
+	for (i = 1; i < 31; i++) {
+		vdev->in_ctx->ep[i].ep_info = 0;
+		vdev->in_ctx->ep[i].ep_info2 = 0;
+		vdev->in_ctx->ep[i].deq = 0;
+		vdev->in_ctx->ep[i].tx_info = 0;
+	}
+}
+
+static int xhci_virtdev_disable_slot(struct xhci_virtual_device *vdev)
+{
+	struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
+	union xhci_trb trb;
+	int ret;
+
+	/* Issue Disable Slot Command */
+	memset(&trb, 0, sizeof(union xhci_trb));
+	trb.event_cmd.flags = TRB_TYPE(TRB_DISABLE_SLOT) |
+		SLOT_ID_FOR_TRB(vdev->slot_id);
+	xhci_print_trb(xhci, &trb, "Request  DisableSlot");
+	xhci_issue_command(xhci, &trb);
+	ret = xhci_wait_for_event(xhci, TRB_COMPLETION, &trb);
+	xhci_print_trb(xhci, &trb, "Response DisableSlot");
+
+        /* Clear Device Context Base Address Array */
+	xhci->dcbaa[vdev->slot_id] = 0;
+
+	return ret;
+}
+
+static int xhci_virtdev_enable_slot(struct xhci_virtual_device *vdev)
+{
+	struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
+	union xhci_trb trb;
+	int slot_id;
+	int ret;
+
+	/* Issue Enable Slot Command */
+	memset(&trb, 0, sizeof(union xhci_trb));
+	trb.event_cmd.flags = TRB_TYPE(TRB_ENABLE_SLOT);
+	xhci_print_trb(xhci, &trb, "Request  EnableSlot");
+	xhci_issue_command(xhci, &trb);
+	ret = xhci_wait_for_event(xhci, TRB_COMPLETION, &trb);
+	xhci_print_trb(xhci, &trb, "Response EnableSlot");
+	if (ret)
+		return ret;
+
+	slot_id = TRB_TO_SLOT_ID(trb.event_cmd.flags);
+	if (slot_id == 0) {
+		dev_err(xhci->dev, "EnableSlot returned reserved slot ID 0\n");
+		return -EINVAL;
+	}
+
+	vdev->slot_id = slot_id;
+
+	return 0;
+}
+
+int xhci_virtdev_reset(struct xhci_virtual_device *vdev)
+{
+	struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
+	union xhci_trb trb;
+	int ret;
+
+	/* If device is not setup, there is no point in resetting it */
+	if (GET_SLOT_STATE(le32_to_cpu(vdev->out_ctx->slot.dev_state)) ==
+	    SLOT_STATE_DISABLED)
+                return 0;
+
+	memset(&trb, 0, sizeof(union xhci_trb));
+	trb.event_cmd.flags = TRB_TYPE(TRB_RESET_DEV) |
+		SLOT_ID_FOR_TRB(vdev->slot_id);
+	xhci_print_trb(xhci, &trb, "Request  Reset");
+	xhci_issue_command(xhci, &trb);
+	ret = xhci_wait_for_event(xhci, TRB_COMPLETION, &trb);
+	xhci_print_trb(xhci, &trb, "Response Reset");
+
+        /*
+	 * The Reset Device command can't fail, according to the 0.95/0.96 spec,
+         * unless we tried to reset a slot ID that wasn't enabled,
+         * or the device wasn't in the addressed or configured state.
+         */
+        switch (GET_COMP_CODE(trb.event_cmd.status)) {
+        case COMP_CMD_ABORT:
+        case COMP_CMD_STOP:
+                dev_warn(xhci->dev, "Timeout waiting for reset device command\n");
+                ret = -ETIMEDOUT;
+		break;
+        case COMP_EBADSLT: /* 0.95 completion code for bad slot ID */
+        case COMP_CTX_STATE: /* 0.96 completion code for same thing */
+                /* Don't treat this as an error.  May change my mind later. */
+                ret = 0;
+        case COMP_SUCCESS:
+                break;
+        default:
+                ret = -EINVAL;
+        }
+
+	return ret;
+}
+
+/*
+ * Once a hub descriptor is fetched for a device, we need to update the xHC's
+ * internal data structures for the device.
+ */
+static int xhci_virtdev_update_hub_device(struct xhci_virtual_device *vdev,
+					  void *buffer, int length)
+{
+	struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
+	struct usb_hub_descriptor *desc = buffer;
+	union xhci_trb trb;
+	u32 dev_info, dev_info2, tt_info;
+	u8 maxchild;
+	u16 hubchar;
+	int ret;
+
+	/* Need at least first byte of wHubCharacteristics */
+	if (length < 4)
+		return 0;
+	/* Skip already configured hub device */
+	if (vdev->out_ctx->slot.dev_info & DEV_HUB)
+		return 0;
+
+	maxchild = desc->bNbrPorts;
+	hubchar = le16_to_cpu(desc->wHubCharacteristics);
+
+	/* update slot context */
+	memcpy(&vdev->in_ctx->slot, &vdev->out_ctx->slot,
+	       sizeof(struct xhci_slot_ctx));
+	vdev->in_ctx->icc.add_flags |= cpu_to_le32(SLOT_FLAG);
+	vdev->in_ctx->icc.drop_flags = 0;
+	vdev->in_ctx->slot.dev_state = 0;
+	dev_info = le32_to_cpu(vdev->in_ctx->slot.dev_info);
+	dev_info2 = le32_to_cpu(vdev->in_ctx->slot.dev_info2);
+	tt_info = le32_to_cpu(vdev->in_ctx->slot.tt_info);
+
+	dev_info |= DEV_HUB;
+	/* HS Multi-TT in bDeviceProtocol */
+	if (vdev->udev->speed == USB_SPEED_HIGH &&
+	    vdev->udev->descriptor->bDeviceProtocol == USB_HUB_PR_HS_MULTI_TT)
+		dev_info |= DEV_MTT;
+	if (xhci->hci_version > 0x95) {
+		dev_info2 |= XHCI_MAX_PORTS(maxchild);
+		/* Set TT think time - convert from ns to FS bit times.
+		 * 0 = 8 FS bit times, 1 = 16 FS bit times,
+		 * 2 = 24 FS bit times, 3 = 32 FS bit times.
+		 *
+		 * xHCI 1.0: this field shall be 0 if the device is not a
+		 * High-speed hub.
+		 */
+		if (xhci->hci_version < 0x100 ||
+		    vdev->udev->speed == USB_SPEED_HIGH) {
+			u32 think_time = (hubchar & HUB_CHAR_TTTT) >> 5;
+                        tt_info |= TT_THINK_TIME(think_time);
+		}
+        }
+	vdev->in_ctx->slot.dev_info = cpu_to_le32(dev_info);
+	vdev->in_ctx->slot.dev_info2 = cpu_to_le32(dev_info2);
+	vdev->in_ctx->slot.tt_info = cpu_to_le32(tt_info);
+
+        /* Issue Configure Endpoint or Evaluate Context Command */
+	memset(&trb, 0, sizeof(union xhci_trb));
+	xhci_write_64((dma_addr_t)vdev->in_ctx, &trb.event_cmd.cmd_trb);
+	trb.event_cmd.flags = SLOT_ID_FOR_TRB(vdev->slot_id);
+	if (xhci->hci_version > 0x95)
+		trb.event_cmd.flags |= TRB_TYPE(TRB_CONFIG_EP);
+	else
+		trb.event_cmd.flags |= TRB_TYPE(TRB_EVAL_CONTEXT);
+	xhci_print_trb(xhci, &trb, "Request  ConfigureEndpoint");
+	xhci_issue_command(xhci, &trb);
+	ret = xhci_wait_for_event(xhci, TRB_COMPLETION, &trb);
+	xhci_print_trb(xhci, &trb, "Response ConfigureEndpoint");
+	xhci_virtdev_zero_in_ctx(vdev);
+
+	return ret;
+}
+
+static int xhci_virtdev_update_hub_status(struct xhci_virtual_device *vhub,
+					  int port)
+{
+	struct xhci_hcd *xhci = to_xhci_hcd(vhub->udev->host);
+	struct usb_device *udev = vhub->udev->children[port - 1];
+	struct xhci_virtual_device *vdev;
+
+	if (!udev)
+		return 0;
+
+	/* Check if we have a virtual device for it */
+	vdev = xhci_find_virtdev(xhci, udev);
+	if (vdev)
+		xhci_virtdev_detach(vdev);
+
+	return 0;
+}
+
+static int xhci_virtdev_configure(struct xhci_virtual_device *vdev, int config)
+{
+	struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
+	struct usb_device *udev = vdev->udev;
+	union xhci_trb trb;
+	u32 add_flags = 0, last_ctx;
+	int i, j;
+	int ret;
+
+	for (i = 0; i < udev->config.no_of_if; i++) {
+		struct usb_interface *intf = &udev->config.interface[i];
+
+		for (j = 0; j < intf->no_of_ep; j++) {
+			struct usb_endpoint_descriptor *ep = &intf->ep_desc[j];
+			u8 type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+			u8 eptype = xhci_get_endpoint_type(ep->bEndpointAddress,
+							   ep->bmAttributes);
+			u8 epi = xhci_get_endpoint_index(ep->bEndpointAddress,
+							 ep->bmAttributes);
+			struct xhci_ep_ctx *ctx = &vdev->in_ctx->ep[epi];
+			u32 mps, interval, mult, esit, max_packet, max_burst;
+			u32 ep_info, ep_info2, tx_info;
+
+			vdev->ep[epi] = xhci_get_endpoint_ring(xhci);
+			if (!vdev->ep[epi])
+				return -ENOMEM;
+			/* FIXME: set correct ring type */
+			xhci_ring_init(vdev->ep[epi], NUM_TRANSFER_TRBS,
+				       TYPE_BULK);
+			add_flags |= BIT(epi+1);
+
+			mps = le16_to_cpu(ep->wMaxPacketSize);
+			interval = xhci_get_endpoint_interval(vdev->udev, ep);
+			mult = xhci_get_endpoint_mult(vdev->udev, ep);
+			esit = xhci_get_max_esit_payload(vdev->udev, ep);
+			max_packet = GET_MAX_PACKET(mps);
+			max_burst = 0;
+
+			ep_info = EP_INTERVAL(interval) | EP_MULT(mult);
+			ep_info2 = EP_TYPE(eptype);
+			if (type == USB_ENDPOINT_XFER_ISOC)
+				ep_info2 |= ERROR_COUNT(0);
+			else
+				ep_info2 |= ERROR_COUNT(3);
+
+			switch (udev->speed) {
+			case USB_SPEED_SUPER:
+				/* FIXME: max_burst = ss_ep_comp.bMaxBurst */
+				max_burst = 0;
+				break;
+			case USB_SPEED_HIGH:
+				/* Some devices get this wrong */
+				if (type == USB_ENDPOINT_XFER_BULK)
+					max_packet = 512;
+				if (type == USB_ENDPOINT_XFER_ISOC ||
+				    type == USB_ENDPOINT_XFER_INT)
+					max_burst = (mps & 0x1800) >> 11;
+				break;
+			case USB_SPEED_FULL:
+			case USB_SPEED_LOW:
+				break;
+			}
+			ep_info2 |= MAX_PACKET(max_packet) | MAX_BURST(max_burst);
+
+			tx_info = MAX_ESIT_PAYLOAD_FOR_EP(esit);
+			switch (type) {
+			case USB_ENDPOINT_XFER_CONTROL:
+				tx_info |= AVG_TRB_LENGTH_FOR_EP(8);
+				break;
+			case USB_ENDPOINT_XFER_ISOC:
+			case USB_ENDPOINT_XFER_BULK:
+				tx_info |= AVG_TRB_LENGTH_FOR_EP(3 * 1024);
+				break;
+			case USB_ENDPOINT_XFER_INT:
+				tx_info |= AVG_TRB_LENGTH_FOR_EP(1 * 1024);
+				break;
+			}
+
+			ctx->ep_info = cpu_to_le32(ep_info);
+			ctx->ep_info2 = cpu_to_le32(ep_info2);
+			ctx->tx_info = cpu_to_le32(tx_info);
+			ctx->deq =
+				cpu_to_le64((dma_addr_t)vdev->ep[epi]->enqueue |
+					    vdev->ep[epi]->cycle_state);
+		}
+	}
+
+	last_ctx = fls(add_flags) - 1;
+
+        /* See section 4.6.6 - A0 = 1; A1 = D0 = D1 = 0 */
+	vdev->in_ctx->icc.add_flags = cpu_to_le32(add_flags);
+        vdev->in_ctx->icc.add_flags |= cpu_to_le32(SLOT_FLAG);
+        vdev->in_ctx->icc.add_flags &= cpu_to_le32(~EP0_FLAG);
+        vdev->in_ctx->icc.drop_flags &= cpu_to_le32(~(SLOT_FLAG | EP0_FLAG));
+
+	/* Don't issue the command if there's no endpoints to update. */
+        if (vdev->in_ctx->icc.add_flags == cpu_to_le32(SLOT_FLAG) &&
+            vdev->in_ctx->icc.drop_flags == 0)
+		return 0;
+
+	vdev->in_ctx->slot.dev_info &= cpu_to_le32(~LAST_CTX_MASK);
+	vdev->in_ctx->slot.dev_info |= cpu_to_le32(LAST_CTX(last_ctx));
+
+        /* Issue Configure Endpoint Command */
+	memset(&trb, 0, sizeof(union xhci_trb));
+	xhci_write_64((dma_addr_t)vdev->in_ctx, &trb.event_cmd.cmd_trb);
+	trb.event_cmd.flags = TRB_TYPE(TRB_CONFIG_EP) |
+		SLOT_ID_FOR_TRB(vdev->slot_id);
+	xhci_print_trb(xhci, &trb, "Request  ConfigureEndpoint");
+	xhci_issue_command(xhci, &trb);
+	ret = xhci_wait_for_event(xhci, TRB_COMPLETION, &trb);
+	xhci_print_trb(xhci, &trb, "Response ConfigureEndpoint");
+	xhci_virtdev_zero_in_ctx(vdev);
+
+	return ret;
+}
+
+static int xhci_virtdev_deconfigure(struct xhci_virtual_device *vdev)
+{
+	struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
+	union xhci_trb trb;
+	int ret;
+
+        /* Issue Deconfigure Endpoint Command */
+	memset(&trb, 0, sizeof(union xhci_trb));
+	xhci_write_64((dma_addr_t)vdev->in_ctx, &trb.event_cmd.cmd_trb);
+	trb.event_cmd.flags = TRB_TYPE(TRB_CONFIG_EP) | TRB_DC |
+		SLOT_ID_FOR_TRB(vdev->slot_id);
+	xhci_print_trb(xhci, &trb, "Request  DeconfigureEndpoint");
+	xhci_issue_command(xhci, &trb);
+	ret = xhci_wait_for_event(xhci, TRB_COMPLETION, &trb);
+	xhci_print_trb(xhci, &trb, "Response DeconfigureEndpoint");
+	xhci_virtdev_zero_in_ctx(vdev);
+
+	return ret;
+}
+
+static int xhci_virtdev_init(struct xhci_virtual_device *vdev)
+{
+	struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
+	struct usb_device *top_dev;
+	int max_packets;
+	u32 route = 0, dev_info, dev_info2, tt_info, ep_info2, tx_info;
+	bool on_hs_hub = false;
+	int hs_slot_id = 0;
+
+	/*
+	 * Find the root hub port this device is under, also determine SlotID
+	 * of possible external HS hub a LS/FS device could be connected to.
+	 */
+	for (top_dev = vdev->udev; top_dev->parent && top_dev->parent->parent;
+	     top_dev = top_dev->parent) {
+		if (top_dev->parent->descriptor->bDeviceClass == USB_CLASS_HUB)
+			route = (route << 4) | (top_dev->portnr & 0xf);
+		if (top_dev->parent->descriptor->bDeviceClass == USB_CLASS_HUB &&
+		    top_dev->parent->speed != USB_SPEED_LOW &&
+		    top_dev->parent->speed != USB_SPEED_FULL) {
+			on_hs_hub |= true;
+			if (!hs_slot_id) {
+				struct xhci_virtual_device *vhub =
+					xhci_find_virtdev(xhci, top_dev->parent);
+				hs_slot_id = vhub->slot_id;
+			}
+		}
+	}
+
+	/* 4.3.3 3) Initalize Input Slot Context */
+	dev_info = LAST_CTX(1);
+	switch (vdev->udev->speed) {
+	case USB_SPEED_SUPER:
+		dev_info |= SLOT_SPEED_SS;
+		max_packets = 512;
+		break;
+	case USB_SPEED_HIGH:
+		dev_info |= SLOT_SPEED_HS;
+		max_packets = 64;
+		break;
+	case USB_SPEED_FULL:
+		dev_info |= SLOT_SPEED_FS;
+		max_packets = 64;
+		break;
+	case USB_SPEED_LOW:
+		dev_info |= SLOT_SPEED_LS;
+		max_packets = 8;
+		break;
+	default:
+		max_packets = 0;
+		break;
+	}
+	dev_info |= route;
+	dev_info2 = ROOT_HUB_PORT(top_dev->portnr);
+	tt_info = 0;
+
+	/* Is this a LS/FS device under an external HS hub? */
+	if (on_hs_hub && (vdev->udev->speed == USB_SPEED_FULL ||
+			  vdev->udev->speed == USB_SPEED_LOW)) {
+		dev_info |= DEV_MTT;
+		tt_info |= (top_dev->portnr << 8) | hs_slot_id;
+	}
+
+	vdev->in_ctx->slot.dev_info = cpu_to_le32(dev_info);
+	vdev->in_ctx->slot.dev_info2 = cpu_to_le32(dev_info2);
+	vdev->in_ctx->slot.tt_info = cpu_to_le32(tt_info);
+
+	/* 4.3.3 4) Initalize Transfer Ring */
+	vdev->ep[0] = xhci_get_endpoint_ring(xhci);
+	if (!vdev->ep[0])
+		return -ENOMEM;
+	xhci_ring_init(vdev->ep[0], NUM_TRANSFER_TRBS, TYPE_CTRL);
+
+	/* 4.3.3 5) Initialize Input Control Endpoint 0 Context */
+	ep_info2 = EP_TYPE(CTRL_EP) | MAX_BURST(0) | ERROR_COUNT(3);
+	ep_info2 |= MAX_PACKET(max_packets);
+	tx_info = AVG_TRB_LENGTH_FOR_EP(8);
+	vdev->in_ctx->ep[0].ep_info2 = cpu_to_le32(ep_info2);
+	vdev->in_ctx->ep[0].tx_info = cpu_to_le32(tx_info);
+	vdev->in_ctx->ep[0].deq = cpu_to_le64((dma_addr_t)vdev->ep[0]->enqueue |
+					      vdev->ep[0]->cycle_state);
+
+        /* 4.3.3 6+7) Initalize and Set Device Context Base Address Array */
+	xhci->dcbaa[vdev->slot_id] = cpu_to_le64((dma_addr_t)vdev->out_ctx);
+
+	return 0;
+}
+
+static int xhci_virtdev_setup(struct xhci_virtual_device *vdev,
+			      enum xhci_setup_dev setup)
+{
+	struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
+	union xhci_trb trb;
+	int ret;
+
+	/*
+	 * If this is the first Set Address since device
+	 * plug-in then initialize Slot Context
+	 */
+	if (!vdev->in_ctx->slot.dev_info)
+		xhci_virtdev_init(vdev);
+	else {
+		/* Otherwise, update Control Ring Dequeue pointer */
+		vdev->in_ctx->ep[0].deq =
+			cpu_to_le64((dma_addr_t)vdev->ep[0]->enqueue |
+				    vdev->ep[0]->cycle_state);
+		/*
+		 * FS devices have MaxPacketSize0 of 8 or 64, we start
+		 * with 64. If assumtion was wrong, fix it up here.
+		 */
+		if (vdev->udev->speed == USB_SPEED_FULL &&
+		    vdev->udev->maxpacketsize == PACKET_SIZE_8) {
+			u32 info = le32_to_cpu(vdev->in_ctx->ep[0].ep_info2);
+			info &= ~MAX_PACKET_MASK;
+			info |= MAX_PACKET(8);
+			vdev->in_ctx->ep[0].ep_info2 = cpu_to_le32(info);
+		}
+	}
+
+	vdev->in_ctx->icc.add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG);
+	vdev->in_ctx->icc.drop_flags = 0;
+
+        /* Issue Address Device Command */
+	memset(&trb, 0, sizeof(union xhci_trb));
+	xhci_write_64((dma_addr_t)vdev->in_ctx, &trb.event_cmd.cmd_trb);
+	trb.event_cmd.flags = TRB_TYPE(TRB_ADDR_DEV) |
+		SLOT_ID_FOR_TRB(vdev->slot_id);
+	if (setup == SETUP_CONTEXT_ONLY)
+		trb.event_cmd.flags |= TRB_BSR;
+	xhci_print_trb(xhci, &trb, "Request  AddressDevice");
+	xhci_issue_command(xhci, &trb);
+	ret = xhci_wait_for_event(xhci, TRB_COMPLETION, &trb);
+	xhci_print_trb(xhci, &trb, "Response AddressDevice");
+	xhci_virtdev_zero_in_ctx(vdev);
+
+	return ret;
+}
+
+static int xhci_virtdev_set_address(struct xhci_virtual_device *vdev)
+{
+        return xhci_virtdev_setup(vdev, SETUP_CONTEXT_ADDRESS);
+}
+
+static int xhci_virtdev_enable(struct xhci_virtual_device *vdev)
+{
+        return xhci_virtdev_setup(vdev, SETUP_CONTEXT_ONLY);
+}
+
+static int xhci_virtdev_attach(struct xhci_hcd *xhci, struct usb_device *udev)
+{
+	struct xhci_virtual_device *vdev;
+	int ret;
+
+	vdev = xhci_alloc_virtdev(xhci, udev);
+	if (IS_ERR(vdev))
+		return PTR_ERR(vdev);
+
+	ret = xhci_virtdev_enable_slot(vdev);
+	if (ret)
+		return ret;
+
+	return xhci_virtdev_enable(vdev);
+}
+
+int xhci_virtdev_detach(struct xhci_virtual_device *vdev)
+{
+	xhci_virtdev_deconfigure(vdev);
+	xhci_virtdev_disable_slot(vdev);
+	xhci_free_virtdev(vdev);
+
+	return 0;
+}
+
+static int xhci_submit_normal(struct usb_device *udev, unsigned long pipe,
+			      void *buffer, int length)
+{
+	struct usb_host *host = udev->host;
+	struct xhci_hcd *xhci = to_xhci_hcd(host);
+	struct xhci_virtual_device *vdev;
+	union xhci_trb trb;
+	u8 epaddr = (usb_pipein(pipe) ? USB_DIR_IN : USB_DIR_OUT) |
+		usb_pipeendpoint(pipe);
+	u8 epi = xhci_get_endpoint_index(epaddr, usb_pipetype(pipe));
+	int ret;
+
+	vdev = xhci_find_virtdev(xhci, udev);
+	if (!vdev)
+		return -ENODEV;
+
+	dev_dbg(xhci->dev, "%s udev %p vdev %p slot %u state %u epi %u in_ctx %p out_ctx %p\n",
+		__func__, udev, vdev, vdev->slot_id,
+		GET_SLOT_STATE(le32_to_cpu(vdev->out_ctx->slot.dev_state)), epi,
+		vdev->in_ctx, vdev->out_ctx);
+
+	/* Normal TRB */
+	memset(&trb, 0, sizeof(union xhci_trb));
+	trb.event_cmd.cmd_trb = cpu_to_le64((dma_addr_t)buffer);
+	/* FIXME: TD remainder */
+	trb.event_cmd.status = TRB_LEN(length) | TRB_INTR_TARGET(0);
+	trb.event_cmd.flags = TRB_TYPE(TRB_NORMAL) | TRB_IOC;
+	if (usb_pipein(pipe))
+		trb.event_cmd.flags |= TRB_ISP;
+	xhci_print_trb(xhci, &trb, "Request  Normal");
+	xhci_virtdev_issue_transfer(vdev, epi, &trb, true);
+	ret = xhci_wait_for_event(xhci, TRB_TRANSFER, &trb);
+	xhci_print_trb(xhci, &trb, "Response Normal");
+
+	switch (ret) {
+	case -COMP_SHORT_TX:
+		udev->status = 0;
+		udev->act_len = length - EVENT_TRB_LEN(trb.event_cmd.status);
+		return 0;
+	case 0:
+		udev->status = 0;
+		udev->act_len = 0;
+		return 0;
+	case -ETIMEDOUT:
+		udev->status = USB_ST_CRC_ERR;
+		return -1;
+	default:
+		return -1;
+	}
+}
+
+static int xhci_submit_control(struct usb_device *udev, unsigned long pipe,
+			       void *buffer, int length, struct devrequest *req)
+{
+	struct usb_host *host = udev->host;
+	struct xhci_hcd *xhci = to_xhci_hcd(host);
+	struct xhci_virtual_device *vdev;
+	union xhci_trb trb;
+	u16 typeReq = (req->requesttype << 8) | req->request;
+	int ret;
+
+	dev_dbg(xhci->dev, "%s req %u (%#x), type %u (%#x), value %u (%#x), index %u (%#x), length %u (%#x)\n",
+		__func__, req->request, req->request,
+		req->requesttype, req->requesttype,
+		le16_to_cpu(req->value), le16_to_cpu(req->value),
+		le16_to_cpu(req->index), le16_to_cpu(req->index),
+		le16_to_cpu(req->length), le16_to_cpu(req->length));
+
+	vdev = xhci_find_virtdev(xhci, udev);
+	if (!vdev) {
+		ret = xhci_virtdev_attach(xhci, udev);
+		if (ret)
+			return ret;
+		vdev = xhci_find_virtdev(xhci, udev);
+	}
+	if (!vdev)
+		return -ENODEV;
+
+	dev_dbg(xhci->dev, "%s udev %p vdev %p slot %u state %u epi %u in_ctx %p out_ctx %p\n",
+		__func__, udev, vdev, vdev->slot_id,
+		GET_SLOT_STATE(le32_to_cpu(vdev->out_ctx->slot.dev_state)), 0,
+		vdev->in_ctx, vdev->out_ctx);
+
+	if (req->request == USB_REQ_SET_ADDRESS)
+		return xhci_virtdev_set_address(vdev);
+	if (req->request == USB_REQ_SET_CONFIGURATION) {
+		ret = xhci_virtdev_configure(vdev, le16_to_cpu(req->value));
+		if (ret)
+			return ret;
+	}
+
+	/* Setup TRB */
+	memset(&trb, 0, sizeof(union xhci_trb));
+	trb.generic.field[0] = le16_to_cpu(req->value) << 16 |
+		req->request << 8 | req->requesttype;
+	trb.generic.field[1] = le16_to_cpu(req->length) << 16 |
+		le16_to_cpu(req->index);
+	trb.event_cmd.status = TRB_LEN(8) | TRB_INTR_TARGET(0);
+	trb.event_cmd.flags = TRB_TYPE(TRB_SETUP) | TRB_IDT;
+	if (xhci->hci_version == 0x100 && length > 0) {
+		if (req->requesttype & USB_DIR_IN)
+			trb.event_cmd.flags |= TRB_TX_TYPE(TRB_DATA_IN);
+		else
+			trb.event_cmd.flags |= TRB_TX_TYPE(TRB_DATA_OUT);
+	}
+	xhci_print_trb(xhci, &trb, "Request  Setup ");
+	xhci_virtdev_issue_transfer(vdev, 0, &trb, false);
+
+	/* Data TRB */
+	if (length > 0) {
+		memset(&trb, 0, sizeof(union xhci_trb));
+		trb.event_cmd.cmd_trb = cpu_to_le64((dma_addr_t)buffer);
+		/* FIXME: TD remainder */
+		trb.event_cmd.status = TRB_LEN(length) | TRB_INTR_TARGET(0);
+		trb.event_cmd.flags = TRB_TYPE(TRB_DATA) | TRB_IOC;
+		if (req->requesttype & USB_DIR_IN)
+			trb.event_cmd.flags |= TRB_ISP | TRB_DIR_IN;
+		xhci_print_trb(xhci, &trb, "Request  Data  ");
+		xhci_virtdev_issue_transfer(vdev, 0, &trb, false);
+	}
+
+	/* Status TRB */
+	memset(&trb, 0, sizeof(union xhci_trb));
+	trb.event_cmd.status = TRB_INTR_TARGET(0);
+	if (length > 0 && req->requesttype & USB_DIR_IN)
+		trb.event_cmd.flags = 0;
+	else
+		trb.event_cmd.flags = TRB_DIR_IN;
+	trb.event_cmd.flags |= TRB_TYPE(TRB_STATUS) | TRB_IOC;
+	xhci_print_trb(xhci, &trb, "Request  Status");
+	xhci_virtdev_issue_transfer(vdev, 0, &trb, true);
+
+	if (length > 0 && req->requesttype & USB_DIR_IN) {
+		ret = xhci_wait_for_event(xhci, TRB_TRANSFER, &trb);
+		xhci_print_trb(xhci, &trb, "Response Data  ");
+		if (ret == -COMP_SHORT_TX)
+			length -= EVENT_TRB_LEN(trb.event_cmd.status);
+		else if (ret < 0)
+			return ret;
+	}
+
+	ret = xhci_wait_for_event(xhci, TRB_TRANSFER, &trb);
+	xhci_print_trb(xhci, &trb, "Response Status");
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * usb core doesn't notify us about device events on
+	 * external Hubs, track it ourselves.
+	 */
+	if (typeReq == GetHubDescriptor)
+		xhci_virtdev_update_hub_device(vdev, buffer, length);
+	if (typeReq == ClearPortFeature &&
+	    cpu_to_le16(req->value) == USB_PORT_FEAT_C_CONNECTION)
+		xhci_virtdev_update_hub_status(vdev, le16_to_cpu(req->index));
+
+	return length;
+}
+
+/*
+ * xHCI host controller driver
+ */
+
+static void xhci_dma_alloc(struct xhci_hcd *xhci)
+{
+	size_t sz_sp, sz_spa, sz_dca, sz_cmd, sz_evt, sz_erst, sz_ep;
+	u64 reg64;
+	void *p;
+	int i, num_ep;
+
+	/* Scratchpad buffers: PAGE_SIZE aligned */
+	sz_sp = ALIGN(xhci->num_sp * xhci->page_size, xhci->page_size);
+	/* Device Context Array: 64B aligned */
+	sz_dca = ALIGN(xhci->max_slots * sizeof(u64), 64);
+	/* Command Ring: 64B aligned */
+	sz_cmd = ALIGN(NUM_COMMAND_TRBS * sizeof(union xhci_trb), 64);
+	/* Event Ring: 64B aligned */
+	sz_evt = NUM_EVENT_SEGM *
+		ALIGN(NUM_EVENT_TRBS * sizeof(union xhci_trb), 64);
+	/* Event Ring Segment Table: 64B aligned */
+	sz_erst = ALIGN(NUM_EVENT_SEGM * sizeof(struct xhci_erst_entry), 64);
+	/* Scratchpad Buffer Array: 64B aligned */
+	sz_spa = ALIGN(xhci->num_sp * sizeof(u64), 64);
+
+	xhci->dma_size = sz_sp + sz_spa + sz_dca + sz_cmd + sz_evt + sz_erst;
+
+	/*
+	 * Endpoint Transfer Ring: 16B aligned
+	 *
+	 * We allocate up to MAX_EP_RINGS from the rest of the PAGE
+	 * for virtual devices to pick-up (and return) for endpoint trbs.
+	 */
+	sz_ep = ALIGN(NUM_TRANSFER_TRBS * sizeof(union xhci_trb), 16);
+
+	num_ep = PAGE_ALIGN(xhci->dma_size) -
+		MIN_EP_RINGS * sz_ep - xhci->dma_size;
+	num_ep /= sz_ep;
+	num_ep = max(MAX_EP_RINGS, MIN_EP_RINGS + num_ep);
+	xhci->dma_size += num_ep * sz_ep;
+
+	p = xhci->dma = dma_alloc_coherent(xhci->dma_size);
+	memset(xhci->dma, 0, xhci->dma_size);
+
+	xhci->sp = p; p += sz_sp;
+	xhci->dcbaa = p; p += sz_dca;
+	xhci->cmd_ring.trbs = p; p += sz_cmd;
+	xhci->event_ring.trbs = p; p += sz_evt;
+	xhci->event_erst = p; p += sz_erst;
+	xhci->sp_array = p; p += sz_spa;
+
+	xhci->rings = xzalloc(num_ep * sizeof(*xhci->rings));
+	for (i = 0; i < num_ep; i++) {
+		xhci->rings[i].trbs = p;
+		p += sz_ep;
+		xhci_put_endpoint_ring(xhci, &xhci->rings[i]);
+	}
+
+	/* Setup Scratchpad Buffer Array and Base Address in Device Context */
+	reg64 = cpu_to_le64((dma_addr_t)xhci->sp);
+	for (i = 0; i < xhci->num_sp; i++, reg64 += xhci->page_size)
+		xhci->sp_array[i] = cpu_to_le64(reg64);
+	if (xhci->num_sp)
+		xhci->dcbaa[0] = cpu_to_le64((dma_addr_t)xhci->sp_array);
+
+	/* Setup Event Ring Segment Table and Event Ring */
+	reg64 = (dma_addr_t)&xhci->event_ring.trbs[0];
+	xhci->event_erst[0].seg_addr = cpu_to_le64(reg64);
+	xhci->event_erst[0].seg_size = cpu_to_le32(NUM_EVENT_TRBS);
+	xhci_ring_init(&xhci->event_ring, NUM_EVENT_TRBS, TYPE_EVENT);
+
+	/* Setup Command Ring */
+	xhci_ring_init(&xhci->cmd_ring, NUM_COMMAND_TRBS, TYPE_COMMAND);
+}
+
+static int xhci_halt(struct xhci_hcd *xhci)
+{
+	u32 reg = readl(&xhci->op_regs->status);
+	u32 mask = ~XHCI_IRQS;
+
+	if (!(reg & STS_HALT))
+		mask &= ~CMD_RUN;
+
+	/* disable any IRQs and begin halting process */
+	reg = readl(&xhci->op_regs->command);
+	reg &= mask;
+	writel(reg, &xhci->op_regs->command);
+
+	return xhci_handshake(&xhci->op_regs->status,
+			      STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC);
+}
+
+static int xhci_reset(struct xhci_hcd *xhci)
+{
+	u32 reg;
+	int ret;
+
+	reg = readl(&xhci->op_regs->command);
+	reg |= CMD_RESET;
+	writel(reg, &xhci->op_regs->command);
+
+	ret = xhci_handshake(&xhci->op_regs->command,
+			     CMD_RESET, 0, 10 * SECOND / USECOND);
+	if (ret) {
+		dev_err(xhci->dev, "failed to reset\n");
+		return ret;
+	}
+
+        return 0;
+}
+
+static int xhci_start(struct xhci_hcd *xhci)
+{
+	u32 reg;
+	int ret, i;
+
+	reg = readl(&xhci->op_regs->command);
+	reg |= CMD_RUN;
+	writel(reg, &xhci->op_regs->command);
+
+	ret = xhci_handshake(&xhci->op_regs->status,
+			     STS_HALT, 0, XHCI_MAX_HALT_USEC);
+        if (ret) {
+                dev_err(xhci->dev, "failed to start\n");
+		return ret;
+	}
+
+	/* Ensure ports are powered-off */
+	for (i = 0; i < xhci->num_usb_ports; i++)
+		xhci_hub_port_power(xhci, i, false);
+
+        return 0;
+}
+
+static int xhci_init(struct usb_host *host)
+{
+	struct xhci_hcd *xhci = to_xhci_hcd(host);
+	u32 reg;
+	u64 reg64;
+	int i, tmp, ret;
+
+	ret = xhci_halt(xhci);
+	if (ret)
+		return ret;
+
+	ret = xhci_reset(xhci);
+	if (ret)
+		return ret;
+
+	tmp = readl(&xhci->op_regs->page_size);
+	for (i = 0; i < 16; i++) {
+		if ((0x1 & tmp) != 0)
+			break;
+		tmp >>= 1;
+	}
+	if (i < 16)
+		tmp = (1 << (i+12));
+	else
+		dev_warn(xhci->dev, "unsupported page size %d\n", tmp);
+	/* Use 4K pages, since that's common and the minimum the HC supports */
+	xhci->page_shift = 12;
+	xhci->page_size = 1 << xhci->page_shift;
+
+	xhci->rootdev = 0;
+	xhci->num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2);
+	xhci->max_slots = HCS_MAX_SLOTS(xhci->hcs_params1);
+	xhci_dma_alloc(xhci);
+
+	ret = xhci_hub_setup_ports(xhci);
+	if (ret)
+		return ret;
+
+	/*
+	 * Program the Max Device Slots Enabled (MaxSlotsEn) field in the
+	 * CONFIG register (5.4.7) with the max number of slots HC can handle.
+	 */
+	reg = readl(&xhci->op_regs->config_reg);
+	reg |= (xhci->max_slots & HCS_SLOTS_MASK);
+	writel(reg, &xhci->op_regs->config_reg);
+
+	/*
+	 * Program the Device Context Base Address Array Pointer (DCBAAP)
+	 * register (5.4.6) with a 64-bit address pointing to where the
+	 * Device Context Base Address Array is located.
+	 */
+	xhci_write_64((dma_addr_t)xhci->dcbaa, &xhci->op_regs->dcbaa_ptr);
+
+	/*
+	 * Define the Command Ring Dequeue Pointer by programming the
+	 * Command Ring Control Register (5.4.5) with a 64-bit address
+	 * pointing to the starting address of the first TRB of the Command
+	 * Ring.
+	 */
+	reg64 = xhci_read_64(&xhci->op_regs->cmd_ring);
+	reg64 = (reg64 & (u64)CMD_RING_RSVD_BITS) |
+		((dma_addr_t)&xhci->cmd_ring.trbs[0] &
+		 ~(dma_addr_t)CMD_RING_RSVD_BITS) |
+		xhci->cmd_ring.cycle_state;
+	xhci_write_64(reg64, &xhci->op_regs->cmd_ring);
+
+	reg = readl(&xhci->cap_regs->db_off) & DBOFF_MASK;
+	xhci->dba = (void __iomem *)xhci->cap_regs + reg;
+	xhci->ir_set = &xhci->run_regs->ir_set[0];
+
+	reg64 = (dma_addr_t)&xhci->event_ring.trbs[0] &
+		~(dma_addr_t)CMD_RING_RSVD_BITS;
+	xhci->event_erst[i].seg_addr = cpu_to_le64(reg64);
+	xhci->event_erst[i].seg_size = cpu_to_le32(NUM_EVENT_TRBS);
+	reg = readl(&xhci->ir_set->erst_size) & ~ERST_SIZE_MASK;
+	writel(reg | NUM_EVENT_SEGM, &xhci->ir_set->erst_size);
+	xhci_set_event_dequeue(xhci);
+
+	reg64 = xhci_read_64(&xhci->ir_set->erst_base);
+	reg64 &= ERST_PTR_MASK;
+	reg64 |= (dma_addr_t)xhci->event_erst &
+		~(dma_addr_t)CMD_RING_RSVD_BITS;
+	xhci_write_64(reg64, &xhci->ir_set->erst_base);
+
+	/*
+	 * Write the USBCMD (5.4.1) to turn the host controller ON via
+	 * setting the Run/Stop (R/S) bit to ‘1’. This operation allows the
+	 * xHC to begin accepting doorbell references.
+	 */
+
+	return xhci_start(xhci);
+
+	/*
+	 * At this point, the host controller is up and running and the Root
+	 * Hub ports (5.4.8) will begin reporting device connects, etc.,
+	 * and system software may begin enumerating devices.
+	 * System software may follow the procedures described in section 4.3,
+	 * to enumerate attached devices.
+	 *
+	 * USB2 (LS/FS/HS) devices require the port reset process to advance
+	 * the port to the Enabled state. Once USB2 ports are Enabled, the port
+	 * is active with SOFs occurring on the port, but the Pipe Schedules
+	 * have not yet been enabled.
+	 *
+	 * SS ports automatically advance to the Enabled state if a successful
+	 * device attach is detected.
+	 */
+}
+
+static int xhci_submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
+				void *buffer, int length, int timeout)
+{
+	return xhci_submit_normal(dev, pipe, buffer, length);
+}
+
+static int xhci_submit_control_msg(struct usb_device *dev, unsigned long pipe,
+	   void *buffer, int length, struct devrequest *setup, int timeout)
+{
+	struct xhci_hcd *xhci = to_xhci_hcd(dev->host);
+
+	/* Catch Root Hub requests */
+	if (usb_pipedevice(pipe) == xhci->rootdev) {
+		if (xhci->rootdev == 0)
+			dev->speed = USB_SPEED_HIGH;
+		return xhci_hub_control(dev, pipe, buffer, length, setup);
+	}
+
+	return xhci_submit_control(dev, pipe, buffer, length, setup);
+}
+
+static int xhci_submit_int_msg(struct usb_device *dev, unsigned long pipe,
+			       void *buffer, int length, int interval)
+{
+	struct xhci_hcd *xhci = to_xhci_hcd(dev->host);
+
+	dev_err(xhci->dev, "Interrupt messages not supported\n");
+
+	return -ENOTSUPP;
+}
+
+static int xhci_detect(struct device_d *dev)
+{
+	struct xhci_hcd *xhci = dev->priv;
+
+	return usb_host_detect(&xhci->host);
+}
+
+int xhci_register(struct device_d *dev, struct xhci_data *data)
+{
+	struct usb_host	*host;
+	struct xhci_hcd *xhci;
+
+	xhci = xzalloc(sizeof(*xhci));
+	host = &xhci->host;
+	INIT_LIST_HEAD(&xhci->vdev_list);
+	xhci->dev = dev;
+	xhci->cap_regs = data->regs;
+	xhci->op_regs = (void __iomem *)xhci->cap_regs +
+		HC_LENGTH(readl(&xhci->cap_regs->hc_capbase));
+	xhci->run_regs = (void __iomem *)xhci->cap_regs +
+		(readl(&xhci->cap_regs->run_regs_off) & RTSOFF_MASK);
+	/* Cache read-only capability registers */
+	xhci->hcs_params1 = readl(&xhci->cap_regs->hcs_params1);
+	xhci->hcs_params2 = readl(&xhci->cap_regs->hcs_params2);
+	xhci->hcs_params3 = readl(&xhci->cap_regs->hcs_params3);
+	xhci->hcc_capbase = readl(&xhci->cap_regs->hc_capbase);
+	xhci->hci_version = HC_VERSION(xhci->hcc_capbase);
+	xhci->hcc_params = readl(&xhci->cap_regs->hcc_params);
+
+	host->hw_dev = dev;
+	host->init = xhci_init;
+	host->submit_int_msg = xhci_submit_int_msg;
+	host->submit_control_msg = xhci_submit_control_msg;
+	host->submit_bulk_msg = xhci_submit_bulk_msg;
+
+	dev->priv = xhci;
+	dev->detect = xhci_detect;
+
+	usb_register_host(host);
+
+	dev_info(dev, "USB xHCI %x.%02x\n",
+		 xhci->hci_version >> 8, xhci->hci_version & 0xff);
+
+	return 0;
+}
+
+/*
+ * xHCI platform driver
+ */
+
+static int xhci_probe(struct device_d *dev)
+{
+	struct xhci_data data = {};
+
+	data.regs = dev_request_mem_region(dev, 0);
+
+	return xhci_register(dev, &data);
+}
+
+static void xhci_remove(struct device_d *dev)
+{
+	struct xhci_hcd *xhci = dev->priv;
+	xhci_halt(xhci);
+}
+
+static struct driver_d xhci_driver = {
+	.name  = "xHCI",
+	.probe = xhci_probe,
+	.remove = xhci_remove,
+};
+device_platform_driver(xhci_driver);
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
new file mode 100644
index 000000000000..bf952570f8aa
--- /dev/null
+++ b/drivers/usb/host/xhci-hub.c
@@ -0,0 +1,647 @@
+/*
+ * xHCI USB 3.0 Root Hub
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This currently does not support any SuperSpeed capabilities.
+ *
+ * Some code borrowed from the Linux xHCI driver
+ *   Author: Sarah Sharp
+ *   Copyright (C) 2008 Intel Corp.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+//#define DEBUG
+#include <asm/mmu.h>
+#include <clock.h>
+#include <common.h>
+#include <io.h>
+#include <linux/err.h>
+#include <usb/usb.h>
+#include <usb/xhci.h>
+
+#include "xhci.h"
+
+static const struct usb_root_hub_info usb_rh_info = {
+	.hub = {
+		.bLength		= USB_DT_HUB_NONVAR_SIZE +
+					  ((USB_MAXCHILDREN + 1 + 7) / 8),
+		.bDescriptorType	= USB_DT_HUB,
+		.bNbrPorts		= 0,	/* runtime modified */
+		.wHubCharacteristics	= 0,
+		.bPwrOn2PwrGood		= 10,
+		.bHubContrCurrent	= 0,
+		.u.hs.DeviceRemovable	= {},
+		.u.hs.PortPwrCtrlMask	= {}
+	},
+	.device = {
+		.bLength		= USB_DT_DEVICE_SIZE,
+		.bDescriptorType	= USB_DT_DEVICE,
+		.bcdUSB			= __constant_cpu_to_le16(0x0002), /* v2.0 */
+		.bDeviceClass		= USB_CLASS_HUB,
+		.bDeviceSubClass	= 0,
+		.bDeviceProtocol	= USB_HUB_PR_HS_MULTI_TT,
+		.bMaxPacketSize0	= 64,
+		.idVendor		= 0x0000,
+		.idProduct		= 0x0000,
+		.bcdDevice		= __constant_cpu_to_le16(0x0001),
+		.iManufacturer		= 1,
+		.iProduct		= 2,
+		.iSerialNumber		= 0,
+		.bNumConfigurations	= 1
+	},
+	.config = {
+		.bLength		= USB_DT_CONFIG_SIZE,
+		.bDescriptorType	= USB_DT_CONFIG,
+		.wTotalLength		= __constant_cpu_to_le16(USB_DT_CONFIG_SIZE +
+					 USB_DT_INTERFACE_SIZE + USB_DT_ENDPOINT_SIZE),
+		.bNumInterfaces		= 1,
+		.bConfigurationValue	= 1,
+		.iConfiguration		= 0,
+		.bmAttributes		= USB_CONFIG_ATT_SELFPOWER,
+		.bMaxPower		= 0
+	},
+	.interface = {
+		.bLength		= USB_DT_INTERFACE_SIZE,
+		.bDescriptorType	= USB_DT_INTERFACE,
+		.bInterfaceNumber	= 0,
+		.bAlternateSetting	= 0,
+		.bNumEndpoints		= 1,
+		.bInterfaceClass	= USB_CLASS_HUB,
+		.bInterfaceSubClass	= 0,
+		.bInterfaceProtocol	= 0,
+		.iInterface		= 0
+	},
+	.endpoint = {
+		.bLength		= USB_DT_ENDPOINT_SIZE,
+		.bDescriptorType	= USB_DT_ENDPOINT,
+		.bEndpointAddress	= 0x81,	/* UE_DIR_IN | EHCI_INTR_ENDPT */
+		.bmAttributes		= USB_ENDPOINT_XFER_INT,
+		.wMaxPacketSize		= __constant_cpu_to_le16((USB_MAXCHILDREN + 1 + 7) / 8),
+		.bInterval		= 255
+	}
+};
+
+static void xhci_setup_common_hub_descriptor(struct xhci_hcd *xhci,
+				     struct usb_hub_descriptor *desc, int ports)
+{
+	u16 val;
+
+	/* xhci section 5.4.9 says 20ms max */
+	desc->bPwrOn2PwrGood = 10;
+	desc->bHubContrCurrent = 0;
+	desc->bNbrPorts = xhci->num_usb_ports;
+
+	val = 0;
+	/* Bits 1:0 - support per-port power switching, or power always on */
+	if (HCC_PPC(xhci->hcc_params))
+		val |= HUB_CHAR_INDV_PORT_LPSM;
+	else
+		val |= HUB_CHAR_NO_LPSM;
+	/* Bit  2 - root hubs are not part of a compound device */
+	/* Bits 4:3 - individual port over current protection */
+	val |= HUB_CHAR_INDV_PORT_OCPM;
+	/* Bits 6:5 - no TTs in root ports */
+	/* Bit  7 - no port indicators */
+	desc->wHubCharacteristics = cpu_to_le16(val);
+}
+
+static void xhci_setup_usb2_hub_descriptor(struct xhci_hcd *xhci)
+{
+	struct usb_hub_descriptor *desc = &xhci->usb_info.hub;
+	__u8 port_removable[(USB_MAXCHILDREN + 1 + 7) / 8];
+	int ports;
+	u32 portsc;
+	u16 val;
+	int i;
+
+	ports = xhci->num_usb_ports;
+	xhci_setup_common_hub_descriptor(xhci, desc, ports);
+	desc->bDescriptorType = USB_DT_HUB;
+	val = 1 + (ports / 8);
+	desc->bLength = USB_DT_HUB_NONVAR_SIZE + 2 * val;
+
+	/* The Device Removable bits are reported on a byte granularity.
+	 * If the port doesn't exist within that byte, the bit is set to 0.
+	 */
+	memset(port_removable, 0, sizeof(port_removable));
+	for (i = 0; i < ports; i++) {
+		portsc = readl(xhci->usb_ports[i]);
+		/* If a device is removable, PORTSC reports a 0, same as in the
+		 * hub descriptor DeviceRemovable bits.
+		 */
+		if (portsc & PORT_DEV_REMOVE)
+			/* This math is hairy because bit 0 of DeviceRemovable
+			 * is reserved, and bit 1 is for port 1, etc.
+			 */
+			port_removable[(i + 1) / 8] |= 1 << ((i + 1) % 8);
+	}
+
+	/* ch11.h defines a hub descriptor that has room for USB_MAXCHILDREN
+	 * ports on it.  The USB 2.0 specification says that there are two
+	 * variable length fields at the end of the hub descriptor:
+	 * DeviceRemovable and PortPwrCtrlMask.  But since we can have less than
+	 * USB_MAXCHILDREN ports, we may need to use the DeviceRemovable array
+	 * to set PortPwrCtrlMask bits.  PortPwrCtrlMask must always be set to
+	 * 0xFF, so we initialize the both arrays (DeviceRemovable and
+	 * PortPwrCtrlMask) to 0xFF.  Then we set the DeviceRemovable for each
+	 * set of ports that actually exist.
+	 */
+	memset(desc->u.hs.DeviceRemovable, 0xff,
+	       sizeof(desc->u.hs.DeviceRemovable));
+	memset(desc->u.hs.PortPwrCtrlMask, 0xff,
+	       sizeof(desc->u.hs.PortPwrCtrlMask));
+
+	for (i = 0; i < (ports + 1 + 7) / 8; i++)
+		memset(&desc->u.hs.DeviceRemovable[i], port_removable[i],
+		       sizeof(__u8));
+}
+
+/* FIXME: usb core does not know about USB_SPEED_SUPER at all */
+static __maybe_unused void xhci_setup_usb3_hub_descriptor(struct xhci_hcd *xhci)
+{
+	struct usb_hub_descriptor *desc = &xhci->usb_info.hub;
+	int ports;
+	u16 port_removable;
+	u32 portsc;
+	int i;
+
+	ports = xhci->num_usb_ports;
+	xhci_setup_common_hub_descriptor(xhci, desc, ports);
+	desc->bDescriptorType = USB_DT_SS_HUB;
+	desc->bLength = USB_DT_SS_HUB_SIZE;
+	/*
+	 * header decode latency should be zero for roothubs,
+	 * see section 4.23.5.2.
+	 */
+	desc->u.ss.bHubHdrDecLat = 0;
+	desc->u.ss.wHubDelay = 0;
+	port_removable = 0;
+	/* bit 0 is reserved, bit 1 is for port 1, etc. */
+	for (i = 0; i < ports; i++) {
+		portsc = readl(xhci->usb_ports[i]);
+		if (portsc & PORT_DEV_REMOVE)
+			port_removable |= 1 << (i + 1);
+	}
+	desc->u.ss.DeviceRemovable = cpu_to_le16(port_removable);
+}
+
+static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
+		     __le32 __iomem *addr, u8 major_revision, int max_caps)
+{
+	u32 reg, port_offset, port_count;
+	int i;
+
+	if (major_revision > 0x03) {
+		dev_warn(xhci->dev, "Ignoring unknown port speed, Ext Cap %p, rev %02x\n",
+			 addr, major_revision);
+		return;
+	}
+
+	/* Port offset and count in the third dword, see section 7.2 */
+	reg = readl(addr + 2);
+	port_offset = XHCI_EXT_PORT_OFF(reg);
+	port_count = XHCI_EXT_PORT_COUNT(reg);
+
+	/* Port count includes the current port offset */
+	if (port_offset == 0 || (port_offset + port_count - 1) > num_ports)
+		/* WTF? "Valid values are ‘1’ to MaxPorts" */
+		return;
+
+	/* cache usb2 port capabilities */
+	if (major_revision < 0x03 && xhci->num_ext_caps < max_caps)
+		xhci->ext_caps[xhci->num_ext_caps++] = reg;
+
+	port_offset--;
+	for (i = port_offset; i < (port_offset + port_count); i++) {
+		/* Duplicate entry.  Ignore the port if the revisions differ. */
+		if (xhci->port_array[i] != 0) {
+			dev_warn(xhci->dev, "Duplicate port entry, Ext Cap %p, port %u\n",
+				 addr, i);
+			dev_warn(xhci->dev, "Port was marked as USB %u, duplicated as USB %u\n",
+				 xhci->port_array[i], major_revision);
+			/*
+			 * Only adjust the roothub port counts if we haven't
+			 * found a similar duplicate.
+			 */
+			if (xhci->port_array[i] != major_revision &&
+			    xhci->port_array[i] != DUPLICATE_ENTRY) {
+				xhci->num_usb_ports--;
+				xhci->port_array[i] = DUPLICATE_ENTRY;
+			}
+			continue;
+		}
+		xhci->port_array[i] = major_revision;
+		xhci->num_usb_ports++;
+	}
+}
+
+int xhci_hub_setup_ports(struct xhci_hcd *xhci)
+{
+	u32 offset, tmp_offset;
+	__le32 __iomem *addr, *tmp_addr;
+	unsigned int num_ports;
+	int i, cap_count = 0;
+
+	offset = HCC_EXT_CAPS(xhci->hcc_params);
+	if (offset == 0) {
+		dev_err(xhci->dev, "No Extended Capability Registers\n");
+		return -ENODEV;
+	}
+
+	addr = &xhci->cap_regs->hc_capbase + offset;
+
+	/* count extended protocol capability entries for later caching */
+	tmp_addr = addr;
+	tmp_offset = offset;
+	do {
+		u32 cap_id = readl(tmp_addr);
+
+		if (XHCI_EXT_CAPS_ID(cap_id) == XHCI_EXT_CAPS_PROTOCOL)
+			cap_count++;
+
+		tmp_offset = XHCI_EXT_CAPS_NEXT(cap_id);
+		tmp_addr += tmp_offset;
+	} while (tmp_offset);
+
+	num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
+	xhci->port_array = xzalloc(num_ports * sizeof(*xhci->port_array));
+	xhci->ext_caps = xzalloc(cap_count * sizeof(*xhci->ext_caps));
+
+	while (1) {
+		u32 cap_id = readl(addr);
+
+		if (XHCI_EXT_CAPS_ID(cap_id) == XHCI_EXT_CAPS_PROTOCOL)
+			xhci_add_in_port(xhci, num_ports, addr,
+					 (u8)XHCI_EXT_PORT_MAJOR(cap_id),
+					 cap_count);
+		offset = XHCI_EXT_CAPS_NEXT(cap_id);
+		if (!offset || xhci->num_usb_ports == num_ports)
+                        break;
+		addr += offset;
+	}
+
+	if (xhci->num_usb_ports == 0) {
+		dev_err(xhci->dev, "No ports on the roothubs?\n");
+		return -ENODEV;
+	}
+
+	xhci->usb_ports = xzalloc(num_ports * sizeof(*xhci->usb_ports));
+	for (i = 0; i < num_ports; i++)
+		xhci->usb_ports[i] = &xhci->op_regs->port_status_base +
+			NUM_PORT_REGS * i;
+	memcpy(&xhci->usb_info, &usb_rh_info, sizeof(usb_rh_info));
+	xhci_setup_usb2_hub_descriptor(xhci);
+
+	return 0;
+}
+
+/*
+ * These bits are Read Only (RO) and should be saved and written to the
+ * registers: 0, 3, 10:13, 30
+ * connect status, over-current status, port speed, and device removable.
+ * connect status and port speed are also sticky - meaning they're in
+ * the AUX well and they aren't changed by a hot, warm, or cold reset.
+ */
+#define XHCI_PORT_RO	(PORT_CONNECT | PORT_OC | DEV_SPEED_MASK | \
+			 PORT_DEV_REMOVE)
+/*
+ * These bits are RW; writing a 0 clears the bit, writing a 1 sets the bit:
+ * bits 5:8, 9, 14:15, 25:27
+ * link state, port power, port indicator state, "wake on" enable state
+ */
+#define XHCI_PORT_RWS	(PORT_PLS_MASK | PORT_POWER | PORT_LED_MASK | \
+			 PORT_WKCONN_E | PORT_WKDISC_E | PORT_WKOC_E)
+/*
+ * These bits are RW; writing a 1 sets the bit, writing a 0 has no effect:
+ * bit 4 (port reset)
+ */
+#define XHCI_PORT_RW1S	(PORT_RESET)
+/*
+ * These bits are RW; writing a 1 clears the bit, writing a 0 has no effect:
+ * bits 1, 17, 18, 19, 20, 21, 22, 23
+ * port enable/disable, and
+ * change bits: connect, PED, warm port reset changed (reserved 0 for USB 2.0),
+ * over-current, reset, link state, and L1 change
+ */
+#define XHCI_PORT_RW1CS	(PORT_PE | PORT_CSC | PORT_PEC | PORT_WRC | \
+			 PORT_OCC | PORT_RC | PORT_PLC | PORT_CEC)
+/*
+ * Bit 16 is RW, and writing a '1' to it causes the link state control to be
+ * latched in
+ */
+#define XHCI_PORT_RW	(PORT_LINK_STROBE)
+/*
+ * These bits are Reserved Zero (RsvdZ) and zero should be written to them:
+ * bits 2, 24, 28:31
+ */
+#define XHCI_PORT_RZ	(BIT(2) | BIT(24) | (0xf<<28))
+
+/*
+ * Given a port state, this function returns a value that would result in the
+ * port being in the same state, if the value was written to the port status
+ * control register.
+ * Save Read Only (RO) bits and save read/write bits where
+ * writing a 0 clears the bit and writing a 1 sets the bit (RWS).
+ * For all other types (RW1S, RW1CS, RW, and RZ), writing a '0' has no effect.
+ */
+static u32 inline xhci_port_state_to_neutral(u32 state)
+{
+	/* Save read-only status and port state */
+        return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS);
+}
+
+static int xhci_hub_finish_port_detach(struct xhci_hcd *xhci, int port)
+{
+	struct xhci_virtual_device *vdev, *temp;
+	union xhci_trb trb;
+	int ret;
+
+	ret = xhci_wait_for_event(xhci, TRB_PORT_STATUS, &trb);
+	if (ret)
+		return ret;
+
+	/* Tear-down any attached virtual devices */
+	list_for_each_entry_safe(vdev, temp, &xhci->vdev_list, list)
+		if (vdev->udev && vdev->udev->portnr == port)
+			xhci_virtdev_detach(vdev);
+
+	return 0;
+}
+
+static int xhci_hub_finish_port_reset(struct xhci_hcd *xhci, int port)
+{
+	struct xhci_virtual_device *vdev;
+	union xhci_trb trb;
+	int ret;
+
+	ret = xhci_wait_for_event(xhci, TRB_PORT_STATUS, &trb);
+	if (ret)
+		return ret;
+
+	/* Reset any attached virtual devices */
+	list_for_each_entry(vdev, &xhci->vdev_list, list)
+		if (vdev->udev && vdev->udev->portnr == port)
+			xhci_virtdev_reset(vdev);
+
+	return 0;
+}
+
+void xhci_hub_port_power(struct xhci_hcd *xhci, int port,
+			 bool enable)
+{
+	u32 reg = readl(xhci->usb_ports[port]);
+
+	reg = xhci_port_state_to_neutral(reg);
+	if (enable)
+		reg |= PORT_POWER;
+	else
+		reg &= ~PORT_POWER;
+	writel(reg, xhci->usb_ports[port]);
+}
+
+static __maybe_unused int xhci_hub_port_warm_reset(struct xhci_hcd *xhci, int port)
+{
+	void __iomem *portsc = xhci->usb_ports[port];
+	u32 reg;
+
+	reg = xhci_port_state_to_neutral(readl(portsc));
+	writel(reg | PORT_WR, portsc);
+	return xhci_handshake(portsc, PORT_RESET, 0, 10 * SECOND/USECOND);
+}
+
+int xhci_hub_control(struct usb_device *dev, unsigned long pipe,
+		     void *buffer, int length, struct devrequest *req)
+{
+	struct usb_host *host = dev->host;
+	struct xhci_hcd *xhci = to_xhci_hcd(host);
+	struct usb_root_hub_info *info;
+	__le32 __iomem **port_array;
+	int max_ports;
+	void *srcptr = NULL;
+	u8 tmpbuf[4];
+	u16 typeReq;
+	int len, port, srclen = 0;
+	u32 reg;
+
+	dev_dbg(xhci->dev, "%s req %u (%#x), type %u (%#x), value %u (%#x), index %u (%#x), length %u (%#x)\n",
+		__func__, req->request, req->request,
+		req->requesttype, req->requesttype,
+		le16_to_cpu(req->value), le16_to_cpu(req->value),
+		le16_to_cpu(req->index), le16_to_cpu(req->index),
+		le16_to_cpu(req->length), le16_to_cpu(req->length));
+
+	info = &xhci->usb_info;
+	port_array = xhci->usb_ports;
+	max_ports = xhci->num_usb_ports;
+
+	typeReq = (req->requesttype << 8) | req->request;
+	switch (typeReq) {
+	case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+		dev_dbg(xhci->dev, "GetDeviceDescriptor %u\n",
+			le16_to_cpu(req->value) >> 8);
+
+		switch (le16_to_cpu(req->value) >> 8) {
+		case USB_DT_DEVICE:
+			srcptr = &info->device;
+			srclen = info->device.bLength;
+			break;
+		case USB_DT_CONFIG:
+			srcptr = &info->config;
+			srclen = le16_to_cpu(info->config.wTotalLength);
+			break;
+		case USB_DT_STRING:
+			switch (le16_to_cpu(req->value) & 0xff) {
+			case 0:	/* Language */
+				srcptr = "\4\3\1\0";
+				srclen = 4;
+				break;
+			case 1:	/* Vendor: "barebox" */
+				srcptr = "\20\3b\0a\0r\0e\0b\0o\0x\0";
+				srclen = 16;
+				break;
+			case 2:	/* Product: "USB 3.0 Root Hub" */
+				srcptr = "\42\3U\0S\0B\0 \0\63\0.\0\60\0 \0R\0o\0o\0t\0 \0H\0u\0b";
+				srclen = 34;
+				break;
+			default:
+				dev_warn(xhci->dev, "unknown string descriptor %x\n",
+					 le16_to_cpu(req->value) >> 8);
+				goto unknown;
+			}
+			break;
+		}
+		break;
+	case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+		dev_dbg(xhci->dev, "SetDeviceConfiguration\n");
+		/* Nothing to do */
+		break;
+	case DeviceOutRequest | USB_REQ_SET_ADDRESS:
+		dev_dbg(xhci->dev, "SetDeviceAddress %u\n",
+			le16_to_cpu(req->value));
+
+		xhci->rootdev = le16_to_cpu(req->value);
+		break;
+	case GetHubDescriptor:
+		dev_dbg(xhci->dev, "GetHubDescriptor %u\n",
+			le16_to_cpu(req->value) >> 8);
+
+		switch (le16_to_cpu(req->value) >> 8) {
+		case USB_DT_HUB:
+			srcptr = &info->hub;
+			srclen = info->hub.bLength;
+			break;
+		default:
+			dev_warn(xhci->dev, "unknown descriptor %x\n",
+				 le16_to_cpu(req->value) >> 8);
+			goto unknown;
+		}
+		break;
+	case GetHubStatus:
+		dev_dbg(xhci->dev, "GetHubStatus\n");
+
+		/* No power source, over-current reported per port */
+		tmpbuf[0] = 0x00;
+		tmpbuf[1] = 0x00;
+		srcptr = tmpbuf;
+		srclen = 2;
+		break;
+	case GetPortStatus:
+		dev_dbg(xhci->dev, "GetPortStatus %u\n",
+			le16_to_cpu(req->index));
+
+		memset(tmpbuf, 0, 4);
+
+		port = le16_to_cpu(req->index);
+		if (!port || port > max_ports)
+			goto unknown;
+		port--;
+
+		/* read PORTSC register */
+		reg = readl(port_array[port]);
+
+		if (reg & PORT_CONNECT) {
+			tmpbuf[0] |= USB_PORT_STAT_CONNECTION;
+			if (DEV_LOWSPEED(reg))
+				tmpbuf[1] |= USB_PORT_STAT_LOW_SPEED >> 8;
+			else if (DEV_HIGHSPEED(reg))
+				tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
+		}
+		if (reg & PORT_PE)
+			tmpbuf[0] |= USB_PORT_STAT_ENABLE;
+		if (reg & PORT_OC)
+			tmpbuf[0] |= USB_PORT_STAT_OVERCURRENT;
+		if (reg & PORT_RESET)
+			tmpbuf[0] |= USB_PORT_STAT_RESET;
+		/* USB 2.0 only */
+		if ((reg & PORT_PLS_MASK) == XDEV_U3 && reg & PORT_POWER)
+                        tmpbuf[0] |= USB_PORT_STAT_SUSPEND;
+		/* USB 2.0 only */
+		if (reg & PORT_POWER)
+			tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
+		if (reg & PORT_CSC)
+			tmpbuf[2] |= USB_PORT_STAT_C_CONNECTION;
+		if (reg & PORT_PEC)
+			tmpbuf[2] |= USB_PORT_STAT_C_ENABLE;
+		if (reg & PORT_OCC)
+			tmpbuf[2] |= USB_PORT_STAT_C_OVERCURRENT;
+		if (reg & PORT_RC)
+			tmpbuf[2] |= USB_PORT_STAT_C_RESET;
+		srcptr = tmpbuf;
+		srclen = 4;
+		break;
+	case ClearPortFeature:
+		dev_dbg(xhci->dev, "ClearPortFeature %u %u\n",
+			le16_to_cpu(req->index), le16_to_cpu(req->value));
+
+		port = le16_to_cpu(req->index);
+		if (!port || port > max_ports)
+			goto unknown;
+		port--;
+
+		reg = xhci_port_state_to_neutral(readl(port_array[port]));
+
+		switch (le16_to_cpu(req->value)) {
+		case USB_PORT_FEAT_ENABLE:
+                        reg &= ~PORT_PE;
+			break;
+		case USB_PORT_FEAT_POWER:
+                        reg &= ~PORT_POWER;
+			break;
+                case USB_PORT_FEAT_C_CONNECTION:
+			reg |= PORT_CSC;
+			break;
+                case USB_PORT_FEAT_C_ENABLE:
+			reg |= PORT_PEC;
+			break;
+                case USB_PORT_FEAT_C_OVER_CURRENT:
+			reg |= PORT_OCC;
+			break;
+                case USB_PORT_FEAT_C_RESET:
+			reg |= PORT_RC;
+			break;
+		default:
+			dev_warn(xhci->dev, "unknown feature %u\n",
+				 le16_to_cpu(req->value));
+			goto unknown;
+		}
+		writel(reg, port_array[port]);
+		readl(port_array[port]);
+
+		if ((reg & PORT_CONNECT) == 0 &&
+		    le16_to_cpu(req->value) == USB_PORT_FEAT_C_CONNECTION)
+			xhci_hub_finish_port_detach(xhci, port + 1);
+
+		break;
+	case SetPortFeature:
+		dev_dbg(xhci->dev, "SetPortFeature %u %u\n",
+			le16_to_cpu(req->index), le16_to_cpu(req->value));
+
+		port = le16_to_cpu(req->index);
+		if (!port || port > max_ports)
+			goto unknown;
+		port--;
+
+		reg = xhci_port_state_to_neutral(readl(port_array[port]));
+
+		switch (le16_to_cpu(req->value)) {
+		case USB_PORT_FEAT_POWER:
+			reg |= PORT_POWER;
+			break;
+		case USB_PORT_FEAT_RESET:
+			reg |= PORT_RESET;
+			break;
+		default:
+			dev_warn(xhci->dev, "unknown feature %u\n",
+				 le16_to_cpu(req->value));
+			goto unknown;
+		}
+		writel(reg, port_array[port]);
+		readl(port_array[port]);
+
+		if (le16_to_cpu(req->value) == USB_PORT_FEAT_RESET)
+			xhci_hub_finish_port_reset(xhci, port + 1);
+
+		break;
+	default:
+		dev_warn(xhci->dev, "unknown root hub request %u (%#x) type %u (%#x)\n",
+			 req->request, req->request,
+			 req->requesttype, req->requesttype);
+		goto unknown;
+	}
+
+	len = min3(srclen, (int)le16_to_cpu(req->length), length);
+	if (srcptr && len)
+		memcpy(buffer, srcptr, len);
+	dev->act_len = len;
+	dev->status = 0;
+
+	return 0;
+
+unknown:
+	dev->act_len = 0;
+	dev->status = USB_ST_STALLED;
+	return -ENOTSUPP;
+}
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
new file mode 100644
index 000000000000..078f88118320
--- /dev/null
+++ b/drivers/usb/host/xhci.h
@@ -0,0 +1,1279 @@
+/*
+ * xHCI USB 3.0 Specification
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * Some code borrowed from the Linux xHCI driver
+ *   Author: Sarah Sharp
+ *   Copyright (C) 2008 Intel Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __XHCI_H
+#define __XHCI_H
+
+#define NUM_COMMAND_TRBS	8
+#define NUM_TRANSFER_TRBS	8
+#define NUM_EVENT_SEGM		1	/* only one supported */
+#define NUM_EVENT_TRBS		16	/* minimum 16 TRBS */
+#define MIN_EP_RINGS		3	/* Control + Bulk In/Out */
+#define MAX_EP_RINGS		(MIN_EP_RINGS * USB_MAXCHILDREN)
+
+/* Up to 16 ms to halt an HC */
+#define XHCI_MAX_HALT_USEC	(16 * 1000)
+
+/* Command and Status registers offset from the Operational Registers address */
+#define XHCI_CMD_OFFSET		0x00
+#define XHCI_STS_OFFSET		0x04
+/* HCCPARAMS offset from PCI base address */
+#define XHCI_HCC_PARAMS_OFFSET	0x10
+/* xHCI PCI Configuration Registers */
+#define XHCI_SBRN_OFFSET	0x60
+
+/* Max number of USB devices for any host controller - limit in section 6.1 */
+#define MAX_HC_SLOTS		256
+/* Section 5.3.3 - MaxPorts */
+#define MAX_HC_PORTS		127
+
+/*
+ * xHCI register interface.
+ * This corresponds to the eXtensible Host Controller Interface (xHCI)
+ * Revision 0.95 specification
+ */
+
+/**
+ * struct xhci_cap_regs - xHCI Host Controller Capability Registers.
+ * @hc_capbase:		length of the capabilities register and HC version number
+ * @hcs_params1:	HCSPARAMS1 - Structural Parameters 1
+ * @hcs_params2:	HCSPARAMS2 - Structural Parameters 2
+ * @hcs_params3:	HCSPARAMS3 - Structural Parameters 3
+ * @hcc_params:		HCCPARAMS - Capability Parameters
+ * @db_off:		DBOFF - Doorbell array offset
+ * @run_regs_off:	RTSOFF - Runtime register space offset
+ */
+struct xhci_cap_regs {
+	__le32	hc_capbase;
+	__le32	hcs_params1;
+	__le32	hcs_params2;
+	__le32	hcs_params3;
+	__le32	hcc_params;
+	__le32	db_off;
+	__le32	run_regs_off;
+	/* Reserved up to (CAPLENGTH - 0x1C) */
+};
+
+/* hc_capbase bitmasks */
+/* bits 7:0 - how long is the Capabilities register */
+#define HC_LENGTH(p)		((p) & 0x00ff)
+/* bits 31:16   */
+#define HC_VERSION(p)		(((p) >> 16) & 0xffff)
+
+/* HCSPARAMS1 - hcs_params1 - bitmasks */
+/* bits 0:7, Max Device Slots */
+#define HCS_MAX_SLOTS(p)	(((p) >> 0) & 0xff)
+#define HCS_SLOTS_MASK		0xff
+/* bits 8:18, Max Interrupters */
+#define HCS_MAX_INTRS(p)	(((p) >> 8) & 0x7ff)
+/* bits 24:31, Max Ports - max value is 0x7F = 127 ports */
+#define HCS_MAX_PORTS(p)	(((p) >> 24) & 0x7f)
+
+/* HCSPARAMS2 - hcs_params2 - bitmasks */
+/* bits 0:3, frames or uframes that SW needs to queue transactions
+ * ahead of the HW to meet periodic deadlines */
+#define HCS_IST(p)		(((p) >> 0) & 0xf)
+/* bits 4:7, max number of Event Ring segments */
+#define HCS_ERST_MAX(p)		(((p) >> 4) & 0xf)
+/* bit 26 Scratchpad restore - for save/restore HW state - not used yet */
+/* bits 27:31 number of Scratchpad buffers SW must allocate for the HW */
+#define HCS_MAX_SCRATCHPAD(p)	(((p) >> 27) & 0x1f)
+
+/* HCSPARAMS3 - hcs_params3 - bitmasks */
+/* bits 0:7, Max U1 to U0 latency for the roothub ports */
+#define HCS_U1_LATENCY(p)	(((p) >> 0) & 0xff)
+/* bits 16:31, Max U2 to U0 latency for the roothub ports */
+#define HCS_U2_LATENCY(p)	(((p) >> 16) & 0xffff)
+
+/* HCCPARAMS - hcc_params - bitmasks */
+/* true: HC can use 64-bit address pointers */
+#define HCC_64BIT_ADDR(p)	((p) & BIT(0))
+/* true: HC can do bandwidth negotiation */
+#define HCC_BANDWIDTH_NEG(p)	((p) & BIT(1))
+/* true: HC uses 64-byte Device Context structures
+ * FIXME 64-byte context structures aren't supported yet.
+ */
+#define HCC_64BYTE_CONTEXT(p)	((p) & BIT(2))
+#define HCC_CTX_SIZE(p)		(HCC_64BYTE_CONTEXT(p) ? 64 : 32)
+/* true: HC has port power switches */
+#define HCC_PPC(p)		((p) & BIT(3))
+/* true: HC has port indicators */
+#define HCC_INDICATOR(p)	((p) & BIT(4))
+/* true: HC has Light HC Reset Capability */
+#define HCC_LIGHT_RESET(p)	((p) & BIT(5))
+/* true: HC supports latency tolerance messaging */
+#define HCC_LTC(p)		((p) & BIT(6))
+/* true: no secondary Stream ID Support */
+#define HCC_NSS(p)		((p) & BIT(7))
+/* Max size for Primary Stream Arrays - 2^(n+1), where n is bits 12:15 */
+#define HCC_MAX_PSA(p)		(1 << ((((p) >> 12) & 0xf) + 1))
+/* Extended Capabilities pointer from PCI base - section 5.3.6 */
+#define HCC_EXT_CAPS(p)		(((p) >> 16) & 0xffff)
+
+/* db_off bitmask - bits 0:1 reserved */
+#define DBOFF_MASK		(~0x3)
+
+/* run_regs_off bitmask - bits 0:4 reserved */
+#define RTSOFF_MASK		(~0x1f)
+
+/* Number of registers per port */
+#define NUM_PORT_REGS	4
+
+#define PORTSC		0
+#define PORTPMSC	1
+#define PORTLI		2
+#define PORTHLPMC	3
+
+/**
+ * struct xhci_op_regs - xHCI Host Controller Operational Registers.
+ * @command:            USBCMD - xHC command register
+ * @status:             USBSTS - xHC status register
+ * @page_size:          This indicates the page size that the host controller
+ *                      supports.  If bit n is set, the HC supports a page size
+ *                      of 2^(n+12), up to a 128MB page size.
+ *                      4K is the minimum page size.
+ * @cmd_ring:           CRP - 64-bit Command Ring Pointer
+ * @dcbaa_ptr:          DCBAAP - 64-bit Device Context Base Address Array Pointer
+ * @config_reg:         CONFIG - Configure Register
+ * @port_status_base:   PORTSCn - base address for Port Status and Control
+ *                      Each port has a Port Status and Control register,
+ *                      followed by a Port Power Management Status and Control
+ *                      register, a Port Link Info register, and a reserved
+ *                      register.
+ * @port_power_base:    PORTPMSCn - base address for
+ *                      Port Power Management Status and Control
+ * @port_link_base:     PORTLIn - base address for Port Link Info (current
+ *                      Link PM state and control) for USB 2.1 and USB 3.0
+ *                      devices.
+ */
+struct xhci_op_regs {
+	__le32	command;
+	__le32	status;
+	__le32	page_size;
+	__le32	reserved1;
+	__le32	reserved2;
+	__le32	dev_notification;
+	__le64	cmd_ring;
+	/* rsvd: offset 0x20-2F */
+	__le32	reserved3[4];
+	__le64	dcbaa_ptr;
+	__le32	config_reg;
+	/* rsvd: offset 0x3C-3FF */
+	__le32	reserved4[241];
+	/* port 1 registers, which serve as a base address for other ports */
+	__le32	port_status_base;
+	__le32	port_power_base;
+	__le32	port_link_base;
+	__le32	reserved5;
+	/* registers for ports 2-255 */
+	__le32	reserved6[NUM_PORT_REGS*254];
+};
+
+/* USBCMD - USB command - command bitmasks */
+/* start/stop HC execution - do not write unless HC is halted*/
+#define CMD_RUN		BIT(0)
+/* Reset HC - resets internal HC state machine and all registers (except
+ * PCI config regs).  HC does NOT drive a USB reset on the downstream ports.
+ * The xHCI driver must reinitialize the xHC after setting this bit.
+ */
+#define CMD_RESET	BIT(1)
+/* Event Interrupt Enable - a '1' allows interrupts from the host controller */
+#define CMD_EIE		BIT(2)
+/* Host System Error Interrupt Enable - get out-of-band signal for HC errors */
+#define CMD_HSEIE	BIT(3)
+/* bits 4:6 are reserved (and should be preserved on writes). */
+/* light reset (port status stays unchanged) - reset completed when this is 0 */
+#define CMD_LRESET	BIT(7)
+/* host controller save/restore state. */
+#define CMD_CSS		BIT(8)
+#define CMD_CRS		BIT(9)
+/* Enable Wrap Event - '1' means xHC generates an event when MFINDEX wraps. */
+#define CMD_EWE		BIT(10)
+/* MFINDEX power management - '1' means xHC can stop MFINDEX counter if all root
+ * hubs are in U3 (selective suspend), disconnect, disabled, or powered-off.
+ * '0' means the xHC can power it off if all ports are in the disconnect,
+ * disabled, or powered-off state.
+ */
+#define CMD_PM_INDEX	BIT(11)
+/* bits 12:31 are reserved (and should be preserved on writes). */
+#define XHCI_IRQS	(CMD_EIE | CMD_HSEIE | CMD_EWE)
+
+/* IMAN - Interrupt Management Register */
+#define IMAN_IE		BIT(1)
+#define IMAN_IP		BIT(0)
+
+/* USBSTS - USB status - status bitmasks */
+/* HC not running - set to 1 when run/stop bit is cleared. */
+#define STS_HALT	BIT(0)
+/* serious error, e.g. PCI parity error.  The HC will clear the run/stop bit. */
+#define STS_FATAL	BIT(2)
+/* event interrupt - clear this prior to clearing any IP flags in IR set*/
+#define STS_EINT	BIT(3)
+/* port change detect */
+#define STS_PORT	BIT(4)
+/* bits 5:7 reserved and zeroed */
+/* save state status - '1' means xHC is saving state */
+#define STS_SAVE	BIT(8)
+/* restore state status - '1' means xHC is restoring state */
+#define STS_RESTORE	BIT(9)
+/* true: save or restore error */
+#define STS_SRE		BIT(10)
+/* true: Controller Not Ready to accept doorbell or op reg writes after reset */
+#define STS_CNR		BIT(11)
+/* true: internal Host Controller Error - SW needs to reset and reinitialize */
+#define STS_HCE		BIT(12)
+/* bits 13:31 reserved and should be preserved */
+
+/*
+ * DNCTRL - Device Notification Control Register - dev_notification bitmasks
+ * Generate a device notification event when the HC sees a transaction with a
+ * notification type that matches a bit set in this bit field.
+ */
+#define DEV_NOTE_MASK		(0xffff)
+#define ENABLE_DEV_NOTE(x)	BIT(x)
+/* Most of the device notification types should only be used for debug.
+ * SW does need to pay attention to function wake notifications.
+ */
+#define DEV_NOTE_FWAKE		ENABLE_DEV_NOTE(1)
+
+/* CRCR - Command Ring Control Register - cmd_ring bitmasks */
+/* bit 0 is the command ring cycle state */
+/* stop ring operation after completion of the currently executing command */
+#define CMD_RING_PAUSE		BIT(1)
+/* stop ring immediately - abort the currently executing command */
+#define CMD_RING_ABORT		BIT(2)
+/* true: command ring is running */
+#define CMD_RING_RUNNING	BIT(3)
+/* bits 4:5 reserved and should be preserved */
+/* Command Ring pointer - bit mask for the lower 32 bits. */
+#define CMD_RING_RSVD_BITS	(0x3f)
+
+/* CONFIG - Configure Register - config_reg bitmasks */
+/* bits 0:7 - maximum number of device slots enabled (NumSlotsEn) */
+#define MAX_DEVS(p)		((p) & 0xff)
+/* bits 8:31 - reserved and should be preserved */
+
+/* PORTSC - Port Status and Control Register - port_status_base bitmasks */
+/* true: device connected */
+#define PORT_CONNECT		BIT(0)
+/* true: port enabled */
+#define PORT_PE			BIT(1)
+/* bit 2 reserved and zeroed */
+/* true: port has an over-current condition */
+#define PORT_OC			BIT(3)
+/* true: port reset signaling asserted */
+#define PORT_RESET		BIT(4)
+/* Port Link State - bits 5:8
+ * A read gives the current link PM state of the port,
+ * a write with Link State Write Strobe set sets the link state.
+ */
+#define PORT_PLS_MASK		(0xf << 5)
+#define XDEV_U0			(0x0 << 5)
+#define XDEV_U2			(0x2 << 5)
+#define XDEV_U3			(0x3 << 5)
+#define XDEV_RESUME		(0xf << 5)
+/* true: port has power (see HCC_PPC) */
+#define PORT_POWER		BIT(9)
+/* bits 10:13 indicate device speed:
+ * 0 - undefined speed - port hasn't be initialized by a reset yet
+ * 1 - full speed
+ * 2 - low speed
+ * 3 - high speed
+ * 4 - super speed
+ * 5-15 reserved
+ */
+#define DEV_SPEED_MASK		(0xf << 10)
+#define XDEV_FS			(0x1 << 10)
+#define XDEV_LS			(0x2 << 10)
+#define XDEV_HS			(0x3 << 10)
+#define XDEV_SS			(0x4 << 10)
+#define DEV_UNDEFSPEED(p)	(((p) & DEV_SPEED_MASK) == (0x0<<10))
+#define DEV_FULLSPEED(p)	(((p) & DEV_SPEED_MASK) == XDEV_FS)
+#define DEV_LOWSPEED(p)		(((p) & DEV_SPEED_MASK) == XDEV_LS)
+#define DEV_HIGHSPEED(p)	(((p) & DEV_SPEED_MASK) == XDEV_HS)
+#define DEV_SUPERSPEED(p)	(((p) & DEV_SPEED_MASK) == XDEV_SS)
+/* Bits 20:23 in the Slot Context are the speed for the device */
+#define SLOT_SPEED_FS		(XDEV_FS << 10)
+#define SLOT_SPEED_LS		(XDEV_LS << 10)
+#define SLOT_SPEED_HS		(XDEV_HS << 10)
+#define SLOT_SPEED_SS		(XDEV_SS << 10)
+/* Port Indicator Control */
+#define PORT_LED_OFF		(0 << 14)
+#define PORT_LED_AMBER		(1 << 14)
+#define PORT_LED_GREEN		(2 << 14)
+#define PORT_LED_MASK		(3 << 14)
+/* Port Link State Write Strobe - set this when changing link state */
+#define PORT_LINK_STROBE	BIT(16)
+/* true: connect status change */
+#define PORT_CSC		BIT(17)
+/* true: port enable change */
+#define PORT_PEC		BIT(18)
+/* true: warm reset for a USB 3.0 device is done.  A "hot" reset puts the port
+ * into an enabled state, and the device into the default state.  A "warm" reset
+ * also resets the link, forcing the device through the link training sequence.
+ * SW can also look at the Port Reset register to see when warm reset is done.
+ */
+#define PORT_WRC		BIT(19)
+/* true: over-current change */
+#define PORT_OCC		BIT(20)
+/* true: reset change - 1 to 0 transition of PORT_RESET */
+#define PORT_RC			BIT(21)
+/* port link status change - set on some port link state transitions:
+ *  Transition                          Reason
+ *  ------------------------------------------------------------------------------
+ *  - U3 to Resume                      Wakeup signaling from a device
+ *  - Resume to Recovery to U0          USB 3.0 device resume
+ *  - Resume to U0                      USB 2.0 device resume
+ *  - U3 to Recovery to U0              Software resume of USB 3.0 device complete
+ *  - U3 to U0                          Software resume of USB 2.0 device complete
+ *  - U2 to U0                          L1 resume of USB 2.1 device complete
+ *  - U0 to U0 (???)                    L1 entry rejection by USB 2.1 device
+ *  - U0 to disabled                    L1 entry error with USB 2.1 device
+ *  - Any state to inactive             Error on USB 3.0 port
+ */
+#define PORT_PLC		BIT(22)
+/* port configure error change - port failed to configure its link partner */
+#define PORT_CEC		BIT(23)
+/* Cold Attach Status - xHC can set this bit to report device attached during
+ * Sx state. Warm port reset should be perfomed to clear this bit and move port
+ * to connected state.
+ */
+#define PORT_CAS		BIT(24)
+/* wake on connect (enable) */
+#define PORT_WKCONN_E		BIT(25)
+/* wake on disconnect (enable) */
+#define PORT_WKDISC_E		BIT(26)
+/* wake on over-current (enable) */
+#define PORT_WKOC_E		BIT(27)
+/* bits 28:29 reserved */
+/* true: device is removable - for USB 3.0 roothub emulation */
+#define PORT_DEV_REMOVE		BIT(30)
+/* Initiate a warm port reset - complete when PORT_WRC is '1' */
+#define PORT_WR			BIT(31)
+
+/* We mark duplicate entries with -1 */
+#define DUPLICATE_ENTRY		((u8)(-1))
+
+/* Port Power Management Status and Control - port_power_base bitmasks */
+/* Inactivity timer value for transitions into U1, in microseconds.
+ * Timeout can be up to 127us.  0xFF means an infinite timeout.
+ */
+#define PORT_U1_TIMEOUT(p)	((p) & 0xff)
+#define PORT_U1_TIMEOUT_MASK	0xff
+/* Inactivity timer value for transitions into U2 */
+#define PORT_U2_TIMEOUT(p)	(((p) & 0xff) << 8)
+#define PORT_U2_TIMEOUT_MASK	(0xff << 8)
+/* Bits 24:31 for port testing */
+
+/* USB2 Protocol PORTSPMSC */
+#define PORT_L1S_MASK		0x7
+#define PORT_L1S_SUCCESS	0x1
+#define PORT_RWE		BIT(3)
+#define PORT_HIRD(p)		(((p) & 0xf) << 4)
+#define PORT_HIRD_MASK		(0xf << 4)
+#define PORT_L1DS_MASK		(0xff << 8)
+#define PORT_L1DS(p)		(((p) & 0xff) << 8)
+#define PORT_HLE		BIT(16)
+
+/* USB2 Protocol PORTHLPMC */
+#define PORT_HIRDM(p)		((p) & 3)
+#define PORT_L1_TIMEOUT(p)	(((p) & 0xff) << 2)
+#define PORT_BESLD(p)		(((p) & 0xf) << 10)
+
+/* use 512 microseconds as USB2 LPM L1 default timeout. */
+#define XHCI_L1_TIMEOUT		512
+
+/* Set default HIRD/BESL value to 4 (350/400us) for USB2 L1 LPM resume latency.
+ * Safe to use with mixed HIRD and BESL systems (host and device) and is used
+ * by other operating systems.
+ *
+ * XHCI 1.0 errata 8/14/12 Table 13 notes:
+ * "Software should choose xHC BESL/BESLD field values that do not violate a
+ * device's resume latency requirements,
+ * e.g. not program values > '4' if BLC = '1' and a HIRD device is attached,
+ * or not program values < '4' if BLC = '0' and a BESL device is attached.
+ */
+#define XHCI_DEFAULT_BESL	4
+
+/**
+ * struct xhci_intr_reg - Interrupt Register Set
+ * @irq_pending:	IMAN - Interrupt Management Register.  Used to enable
+ * 			interrupts and check for pending interrupts.
+ * @irq_control:	IMOD - Interrupt Moderation Register.
+ * 			Used to throttle interrupts.
+ * @erst_size:		Number of segments in the Event Ring Segment Table (ERST).
+ * @erst_base:		ERST base address.
+ * @erst_dequeue:	Event ring dequeue pointer.
+ *
+ * Each interrupter (defined by a MSI-X vector) has an event ring and an Event
+ * Ring Segment Table (ERST) associated with it.  The event ring is comprised of
+ * multiple segments of the same size.  The HC places events on the ring and
+ * "updates the Cycle bit in the TRBs to indicate to software the current
+ * position of the Enqueue Pointer." The HCD (Linux) processes those events and
+ * updates the dequeue pointer.
+ */
+struct xhci_intr_reg {
+	__le32	irq_pending;
+	__le32	irq_control;
+	__le32	erst_size;
+	__le32	rsvd;
+	__le64	erst_base;
+	__le64	erst_dequeue;
+};
+
+/* irq_pending bitmasks */
+#define ER_IRQ_PENDING(p)	((p) & 0x1)
+/* bits 2:31 need to be preserved */
+/* THIS IS BUGGY - FIXME - IP IS WRITE 1 TO CLEAR */
+#define ER_IRQ_CLEAR(p)		((p) & 0xfffffffe)
+#define ER_IRQ_ENABLE(p)	((ER_IRQ_CLEAR(p)) | 0x2)
+#define ER_IRQ_DISABLE(p)	((ER_IRQ_CLEAR(p)) & ~(0x2))
+
+/* irq_control bitmasks */
+/* Minimum interval between interrupts (in 250ns intervals).  The interval
+ * between interrupts will be longer if there are no events on the event ring.
+ * Default is 4000 (1 ms).
+ */
+#define ER_IRQ_INTERVAL_MASK	0xffff
+/* Counter used to count down the time to the next interrupt - HW use only */
+#define ER_IRQ_COUNTER_MASK	(0xffff << 16)
+
+/* erst_size bitmasks */
+/* Preserve bits 16:31 of erst_size */
+#define ERST_SIZE_MASK		(0xffff << 16)
+
+/* erst_dequeue bitmasks */
+/* Dequeue ERST Segment Index (DESI) - Segment number (or alias)
+ * where the current dequeue pointer lies.  This is an optional HW hint.
+ */
+#define ERST_DESI_MASK		0x7
+/* Event Handler Busy (EHB) - is the event ring scheduled to be serviced by
+ * a work queue (or delayed service routine)?
+ */
+#define ERST_EHB		BIT(3)
+#define ERST_PTR_MASK		0xf
+
+/**
+ * struct xhci_run_regs
+ * @microframe_index: MFINDEX - current microframe number
+ *
+ * Section 5.5 Host Controller Runtime Registers:
+ * "Software should read and write these registers using only Dword (32 bit)
+ * or larger accesses"
+ */
+struct xhci_run_regs {
+	__le32			microframe_index;
+	__le32			rsvd[7];
+	struct xhci_intr_reg	ir_set[128];
+};
+
+/**
+ * struct doorbell_array
+ *
+ * Bits  0 -  7: Endpoint target
+ * Bits  8 - 15: RsvdZ
+ * Bits 16 - 31: Stream ID
+ *
+ * Section 5.6
+ */
+struct xhci_doorbell_array {
+	__le32	doorbell[256];
+};
+
+#define DB_VALUE(ep, stream)	((((ep) + 1) & 0xff) | ((stream) << 16))
+#define DB_VALUE_HOST		0x00000000
+
+/**
+ * struct xhci_slot_ctx
+ * @dev_info:	Route string, device speed, hub info, and last valid endpoint
+ * @dev_info2:	Max exit latency for device number, root hub port number
+ * @tt_info:	tt_info is used to construct split transaction tokens
+ * @dev_state:	slot state and device address
+ *
+ * Slot Context - section 6.2.1.1.  This assumes the HC uses 32-byte context
+ * structures.  If the HC uses 64-byte contexts, there is an additional 32 bytes
+ * reserved at the end of the slot context for HC internal use.
+ */
+struct xhci_slot_ctx {
+	__le32	dev_info;
+	__le32	dev_info2;
+	__le32	tt_info;
+	__le32	dev_state;
+	/* offset 0x10 to 0x1f reserved for HC internal use */
+	__le32	reserved[4];
+};
+
+/* dev_info bitmasks */
+/* Route String - 0:19 */
+#define ROUTE_STRING_MASK	0xfffff
+/* Device speed - values defined by PORTSC Device Speed field - 20:23 */
+#define DEV_SPEED		(0xf << 20)
+/* bit 24 reserved */
+/* Is this LS/FS device connected through a HS hub? - bit 25 */
+#define DEV_MTT			BIT(25)
+/* Set if the device is a hub - bit 26 */
+#define DEV_HUB			BIT(26)
+/* Index of the last valid endpoint context in this device context - 27:31 */
+#define LAST_CTX_MASK		(0x1f << 27)
+#define LAST_CTX(p)		((p) << 27)
+#define LAST_CTX_TO_EP_NUM(p)	(((p) >> 27) - 1)
+#define SLOT_FLAG		BIT(0)
+#define EP0_FLAG		BIT(1)
+
+/* dev_info2 bitmasks */
+/* Max Exit Latency (ms) - worst case time to wake up all links in dev path */
+#define MAX_EXIT		0xffff
+/* Root hub port number that is needed to access the USB device */
+#define ROOT_HUB_PORT(p)	(((p) & 0xff) << 16)
+#define DEVINFO_TO_ROOT_HUB_PORT(p)	(((p) >> 16) & 0xff)
+/* Maximum number of ports under a hub device */
+#define XHCI_MAX_PORTS(p)	(((p) & 0xff) << 24)
+
+/* tt_info bitmasks */
+/*
+ * TT Hub Slot ID - for low or full speed devices attached to a high-speed hub
+ * The Slot ID of the hub that isolates the high speed signaling from
+ * this low or full-speed device.  '0' if attached to root hub port.
+ */
+#define TT_SLOT			0xff
+/*
+ * The number of the downstream facing port of the high-speed hub
+ * '0' if the device is not low or full speed.
+ */
+#define TT_PORT			(0xff << 8)
+#define TT_THINK_TIME(p)	(((p) & 0x3) << 16)
+
+/* dev_state bitmasks */
+/* USB device address - assigned by the HC */
+#define DEV_ADDR_MASK		0xff
+/* bits 8:26 reserved */
+/* Slot state */
+#define SLOT_STATE		(0x1f << 27)
+#define GET_SLOT_STATE(p)	(((p) & (0x1f << 27)) >> 27)
+
+#define SLOT_STATE_DISABLED	0x0
+#define SLOT_STATE_ENABLED	SLOT_STATE_DISABLED
+#define SLOT_STATE_DEFAULT	0x1
+#define SLOT_STATE_ADDRESSED	0x2
+#define SLOT_STATE_CONFIGURED   0x3
+
+/**
+ * struct xhci_ep_ctx
+ * @ep_info:	endpoint state, streams, mult, and interval information.
+ * @ep_info2:	information on endpoint type, max packet size, max burst size,
+ * 		error count, and whether the HC will force an event for all
+ * 		transactions.
+ * @deq:	64-bit ring dequeue pointer address.  If the endpoint only
+ * 		defines one stream, this points to the endpoint transfer ring.
+ * 		Otherwise, it points to a stream context array, which has a
+ * 		ring pointer for each flow.
+ * @tx_info:	Average TRB lengths for the endpoint ring and
+ * 		max payload within an Endpoint Service Interval Time (ESIT).
+ *
+ * Endpoint Context - section 6.2.1.2.  This assumes the HC uses 32-byte context
+ * structures.  If the HC uses 64-byte contexts, there is an additional 32 bytes
+ * reserved at the end of the endpoint context for HC internal use.
+ */
+struct xhci_ep_ctx {
+	__le32	ep_info;
+	__le32	ep_info2;
+	__le64	deq;
+	__le32	tx_info;
+	/* offset 0x14 - 0x1f reserved for HC internal use */
+	__le32	reserved[3];
+};
+
+/* ep_info bitmasks */
+/*
+ * Endpoint State - bits 0:2
+ * 0 - disabled
+ * 1 - running
+ * 2 - halted due to halt condition - ok to manipulate endpoint ring
+ * 3 - stopped
+ * 4 - TRB error
+ * 5-7 - reserved
+ */
+#define EP_STATE_MASK		0xf
+#define EP_STATE_DISABLED	0x0
+#define EP_STATE_RUNNING	0x1
+#define EP_STATE_HALTED		0x2
+#define EP_STATE_STOPPED	0x3
+#define EP_STATE_ERROR		0x4
+/* Mult - Max number of burtst within an interval, in EP companion desc. */
+#define EP_MULT(p)		(((p) & 0x3) << 8)
+#define CTX_TO_EP_MULT(p)	(((p) >> 8) & 0x3)
+/* bits 10:14 are Max Primary Streams */
+/* bit 15 is Linear Stream Array */
+/* Interval - period between requests to an endpoint - 125u increments. */
+#define EP_INTERVAL(p)		(((p) & 0xff) << 16)
+#define EP_INTERVAL_TO_UFRAMES(p)	(1 << (((p) >> 16) & 0xff))
+#define CTX_TO_EP_INTERVAL(p)	(((p) >> 16) & 0xff)
+#define EP_MAXPSTREAMS_MASK	(0x1f << 10)
+#define EP_MAXPSTREAMS(p)	(((p) << 10) & EP_MAXPSTREAMS_MASK)
+/* Endpoint is set up with a Linear Stream Array (vs. Secondary Stream Array) */
+#define EP_HAS_LSA		BIT(15)
+
+/* ep_info2 bitmasks */
+/*
+ * Force Event - generate transfer events for all TRBs for this endpoint
+ * This will tell the HC to ignore the IOC and ISP flags (for debugging only).
+ */
+#define FORCE_EVENT		BIT(0)
+#define ERROR_COUNT(p)		(((p) & 0x3) << 1)
+#define CTX_TO_EP_TYPE(p)	(((p) >> 3) & 0x7)
+#define EP_TYPE(p)		((p) << 3)
+#define ISOC_OUT_EP		0x1
+#define BULK_OUT_EP		0x2
+#define INT_OUT_EP		0x3
+#define CTRL_EP			0x4
+#define ISOC_IN_EP		0x5
+#define BULK_IN_EP		0x6
+#define INT_IN_EP		0x7
+/* bit 6 reserved */
+/* bit 7 is Host Initiate Disable - for disabling stream selection */
+#define MAX_BURST(p)		(((p) & 0xff) << 8)
+#define CTX_TO_MAX_BURST(p)	(((p) >> 8) & 0xff)
+#define MAX_PACKET(p)		(((p) & 0xffff) << 16)
+#define MAX_PACKET_MASK		(0xffff << 16)
+#define MAX_PACKET_DECODED(p)	(((p) >> 16) & 0xffff)
+
+/* Get max packet size from ep desc. Bit 10..0 specify the max packet size.
+ * USB2.0 spec 9.6.6.
+ */
+#define GET_MAX_PACKET(p)	((p) & 0x7ff)
+
+/* tx_info bitmasks */
+#define AVG_TRB_LENGTH_FOR_EP(p)	((p) & 0xffff)
+#define MAX_ESIT_PAYLOAD_FOR_EP(p)	(((p) & 0xffff) << 16)
+#define CTX_TO_MAX_ESIT_PAYLOAD(p)	(((p) >> 16) & 0xffff)
+
+/* deq bitmasks */
+#define EP_CTX_CYCLE_MASK	BIT(0)
+#define SCTX_DEQ_MASK		(~0xfL)
+
+/**
+ * struct xhci_input_control_context
+ * Input control context; see section 6.2.5.
+ *
+ * @drop_context:	set the bit of the endpoint context you want to disable
+ * @add_context:	set the bit of the endpoint context you want to enable
+ */
+struct xhci_input_control_ctx {
+	__le32	drop_flags;
+	__le32	add_flags;
+	__le32	rsvd2[6];
+};
+
+#define EP_IS_ADDED(ctrl_ctx, i)	\
+	(le32_to_cpu(ctrl_ctx->add_flags) & (1 << (i + 1)))
+#define EP_IS_DROPPED(ctrl_ctx, i)	\
+	(le32_to_cpu(ctrl_ctx->drop_flags) & (1 << (i + 1)))
+
+/* drop context bitmasks */
+#define DROP_EP(x)	BIT(x)
+/* add context bitmasks */
+#define ADD_EP(x)	BIT(x)
+
+struct xhci_stream_ctx {
+	/* 64-bit stream ring address, cycle state, and stream type */
+	__le64	stream_ring;
+	/* offset 0x14 - 0x1f reserved for HC internal use */
+	__le32	reserved[2];
+};
+
+/* Stream Context Types (section 6.4.1) - bits 3:1 of stream ctx deq ptr */
+#define SCT_FOR_CTX(p)		(((p) & 0x7) << 1)
+/* Secondary stream array type, dequeue pointer is to a transfer ring */
+#define SCT_SEC_TR		0x0
+/* Primary stream array type, dequeue pointer is to a transfer ring */
+#define SCT_PRI_TR		0x1
+/* Dequeue pointer is for a secondary stream array (SSA) with 8 entries */
+#define SCT_SSA_8		0x2
+#define SCT_SSA_16		0x3
+#define SCT_SSA_32		0x4
+#define SCT_SSA_64		0x5
+#define SCT_SSA_128		0x6
+#define SCT_SSA_256		0x7
+
+#define SMALL_STREAM_ARRAY_SIZE		256
+#define MEDIUM_STREAM_ARRAY_SIZE	1024
+
+/* "Block" sizes in bytes the hardware uses for different device speeds.
+ * The logic in this part of the hardware limits the number of bits the hardware
+ * can use, so must represent bandwidth in a less precise manner to mimic what
+ * the scheduler hardware computes.
+ */
+#define FS_BLOCK		1
+#define HS_BLOCK		4
+#define SS_BLOCK		16
+#define DMI_BLOCK		32
+
+/* Each device speed has a protocol overhead (CRC, bit stuffing, etc) associated
+ * with each byte transferred.  SuperSpeed devices have an initial overhead to
+ * set up bursts.  These are in blocks, see above.  LS overhead has already been
+ * translated into FS blocks.
+ */
+#define DMI_OVERHEAD		8
+#define DMI_OVERHEAD_BURST	4
+#define SS_OVERHEAD		8
+#define SS_OVERHEAD_BURST	32
+#define HS_OVERHEAD		26
+#define FS_OVERHEAD		20
+#define LS_OVERHEAD		128
+
+/* The TTs need to claim roughly twice as much bandwidth (94 bytes per
+ * microframe ~= 24Mbps) of the HS bus as the devices can actually use because
+ * of overhead associated with split transfers crossing microframe boundaries.
+ * 31 blocks is pure protocol overhead.
+ */
+#define TT_HS_OVERHEAD		(31 + 94)
+#define TT_DMI_OVERHEAD		(25 + 12)
+
+/* Bandwidth limits in blocks */
+#define FS_BW_LIMIT		1285
+#define TT_BW_LIMIT		1320
+#define HS_BW_LIMIT		1607
+#define SS_BW_LIMIT_IN		3906
+#define DMI_BW_LIMIT_IN		3906
+#define SS_BW_LIMIT_OUT		3906
+#define DMI_BW_LIMIT_OUT	3906
+
+/* Percentage of bus bandwidth reserved for non-periodic transfers */
+#define FS_BW_RESERVED		10
+#define HS_BW_RESERVED		20
+#define SS_BW_RESERVED		10
+
+enum xhci_overhead_type {
+	LS_OVERHEAD_TYPE = 0,
+	FS_OVERHEAD_TYPE,
+	HS_OVERHEAD_TYPE,
+};
+
+struct xhci_transfer_event {
+	/* 64-bit buffer address, or immediate data */
+	__le64	buffer;
+	__le32	transfer_len;
+	/* This field is interpreted differently based on the type of TRB */
+	__le32	flags;
+};
+
+/* Transfer event TRB length bit mask */
+/* bits 0:23 */
+#define EVENT_TRB_LEN(p)	((p) & 0xffffff)
+
+/** Transfer Event bit fields **/
+#define TRB_TO_EP_ID(p)		(((p) >> 16) & 0x1f)
+
+/* Completion Code - only applicable for some types of TRBs */
+#define COMP_CODE_MASK		(0xff << 24)
+#define GET_COMP_CODE(p)	(((p) & COMP_CODE_MASK) >> 24)
+#define COMP_SUCCESS		1
+/* Data Buffer Error */
+#define COMP_DB_ERR		2
+/* Babble Detected Error */
+#define COMP_BABBLE		3
+/* USB Transaction Error */
+#define COMP_TX_ERR		4
+/* TRB Error - some TRB field is invalid */
+#define COMP_TRB_ERR		5
+/* Stall Error - USB device is stalled */
+#define COMP_STALL		6
+/* Resource Error - HC doesn't have memory for that device configuration */
+#define COMP_ENOMEM		7
+/* Bandwidth Error - not enough room in schedule for this dev config */
+#define COMP_BW_ERR		8
+/* No Slots Available Error - HC ran out of device slots */
+#define COMP_ENOSLOTS		9
+/* Invalid Stream Type Error */
+#define COMP_STREAM_ERR		10
+/* Slot Not Enabled Error - doorbell rung for disabled device slot */
+#define COMP_EBADSLT		11
+/* Endpoint Not Enabled Error */
+#define COMP_EBADEP		12
+/* Short Packet */
+#define COMP_SHORT_TX		13
+/* Ring Underrun - doorbell rung for an empty isoc OUT ep ring */
+#define COMP_UNDERRUN		14
+/* Ring Overrun - isoc IN ep ring is empty when ep is scheduled to RX */
+#define COMP_OVERRUN		15
+/* Virtual Function Event Ring Full Error */
+#define COMP_VF_FULL		16
+/* Parameter Error - Context parameter is invalid */
+#define COMP_EINVAL		17
+/* Bandwidth Overrun Error - isoc ep exceeded its allocated bandwidth */
+#define COMP_BW_OVER		18
+/* Context State Error - illegal context state transition requested */
+#define COMP_CTX_STATE		19
+/* No Ping Response Error - HC didn't get PING_RESPONSE in time to TX */
+#define COMP_PING_ERR		20
+/* Event Ring is full */
+#define COMP_ER_FULL		21
+/* Incompatible Device Error */
+#define COMP_DEV_ERR		22
+/* Missed Service Error - HC couldn't service an isoc ep within interval */
+#define COMP_MISSED_INT		23
+/* Successfully stopped command ring */
+#define COMP_CMD_STOP		24
+/* Successfully aborted current command and stopped command ring */
+#define COMP_CMD_ABORT		25
+/* Stopped - transfer was terminated by a stop endpoint command */
+#define COMP_STOP		26
+/* Same as COMP_EP_STOPPED, but the transferred length in the event is invalid */
+#define COMP_STOP_INVAL		27
+/* Control Abort Error - Debug Capability - control pipe aborted */
+#define COMP_DBG_ABORT		28
+/* Max Exit Latency Too Large Error */
+#define COMP_MEL_ERR		29
+/* TRB type 30 reserved */
+/* Isoc Buffer Overrun - an isoc IN ep sent more data than could fit in TD */
+#define COMP_BUFF_OVER		31
+/* Event Lost Error - xHC has an "internal event overrun condition" */
+#define COMP_ISSUES		32
+/* Undefined Error - reported when other error codes don't apply */
+#define COMP_UNKNOWN		33
+/* Invalid Stream ID Error */
+#define COMP_STRID_ERR		34
+/* Secondary Bandwidth Error - may be returned by a Configure Endpoint cmd */
+#define COMP_2ND_BW_ERR		35
+/* Split Transaction Error */
+#define COMP_SPLIT_ERR		36
+
+struct xhci_link_trb {
+	/* 64-bit segment pointer*/
+	__le64	segment_ptr;
+	__le32	intr_target;
+	__le32	control;
+};
+
+/* control bitfields */
+#define LINK_TOGGLE		BIT(1)
+
+/* Command completion event TRB */
+struct xhci_event_cmd {
+	/* Pointer to command TRB, or the value passed by the event data trb */
+	__le64	cmd_trb;
+	__le32	status;
+	__le32	flags;
+};
+
+/* flags bitmasks */
+
+/* Address device - disable SetAddress */
+#define TRB_BSR			BIT(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)
+#define SLOT_ID_FOR_TRB(p)	(((p) & 0xff) << 24)
+
+/* Configure Endpoint Command TRB - deconfigure */
+#define TRB_DC			BIT(9)
+
+/* Stop Endpoint TRB - ep_index to endpoint ID for this TRB */
+#define TRB_TO_EP_INDEX(p)	((((p) & (0x1f << 16)) >> 16) - 1)
+#define EP_ID_FOR_TRB(p)	((((p) + 1) & 0x1f) << 16)
+
+#define SUSPEND_PORT_FOR_TRB(p)	(((p) & 1) << 23)
+#define TRB_TO_SUSPEND_PORT(p)	(((p) & (1 << 23)) >> 23)
+#define LAST_EP_INDEX		30
+
+/* Set TR Dequeue Pointer command TRB fields, 6.4.3.9 */
+#define TRB_TO_STREAM_ID(p)	((((p) & (0xffff << 16)) >> 16))
+#define STREAM_ID_FOR_TRB(p)	((((p)) & 0xffff) << 16)
+#define SCT_FOR_TRB(p)		(((p) << 1) & 0x7)
+
+/* Port Status Change Event TRB fields */
+/* Port ID - bits 31:24 */
+#define GET_PORT_ID(p)		(((p) & (0xff << 24)) >> 24)
+
+/* Normal TRB fields */
+/* transfer_len bitmasks - bits 0:16 */
+#define TRB_LEN(p)		((p) & 0x1ffff)
+/* Interrupter Target - which MSI-X vector to target the completion event at */
+#define TRB_INTR_TARGET(p)	(((p) & 0x3ff) << 22)
+#define GET_INTR_TARGET(p)	(((p) >> 22) & 0x3ff)
+#define TRB_TBC(p)		(((p) & 0x3) << 7)
+#define TRB_TLBPC(p)		(((p) & 0xf) << 16)
+
+/* Cycle bit - indicates TRB ownership by HC or HCD */
+#define TRB_CYCLE		BIT(0)
+/*
+ * Force next event data TRB to be evaluated before task switch.
+ * Used to pass OS data back after a TD completes.
+ */
+#define TRB_ENT			BIT(1)
+/* Interrupt on short packet */
+#define TRB_ISP			BIT(2)
+/* Set PCIe no snoop attribute */
+#define TRB_NO_SNOOP		BIT(3)
+/* Chain multiple TRBs into a TD */
+#define TRB_CHAIN		BIT(4)
+/* Interrupt on completion */
+#define TRB_IOC			BIT(5)
+/* The buffer pointer contains immediate data */
+#define TRB_IDT			BIT(6)
+
+/* Block Event Interrupt */
+#define TRB_BEI			BIT(9)
+
+/* Control transfer TRB specific fields */
+#define TRB_DIR_IN		BIT(16)
+#define TRB_TX_TYPE(p)		((p) << 16)
+#define TRB_DATA_OUT		2
+#define TRB_DATA_IN		3
+
+/* Isochronous TRB specific fields */
+#define TRB_SIA			BIT(31)
+
+struct xhci_generic_trb {
+	__le32	field[4];
+};
+
+union xhci_trb {
+	struct xhci_link_trb		link;
+	struct xhci_transfer_event	trans_event;
+	struct xhci_event_cmd		event_cmd;
+	struct xhci_generic_trb		generic;
+};
+
+/* TRB bit mask */
+#define TRB_TYPE_BITMASK	(0xfc00)
+#define TRB_TYPE(p)		((p) << 10)
+#define TRB_FIELD_TO_TYPE(p)	(((p) & TRB_TYPE_BITMASK) >> 10)
+/* TRB type IDs */
+/* bulk, interrupt, isoc scatter/gather, and control data stage */
+#define TRB_NORMAL		1
+/* setup stage for control transfers */
+#define TRB_SETUP		2
+/* data stage for control transfers */
+#define TRB_DATA		3
+/* status stage for control transfers */
+#define TRB_STATUS		4
+/* isoc transfers */
+#define TRB_ISOC		5
+/* TRB for linking ring segments */
+#define TRB_LINK		6
+#define TRB_EVENT_DATA		7
+/* Transfer Ring No-op (not for the command ring) */
+#define TRB_TR_NOOP		8
+/* Command TRBs */
+/* Enable Slot Command */
+#define TRB_ENABLE_SLOT		9
+/* Disable Slot Command */
+#define TRB_DISABLE_SLOT	10
+/* Address Device Command */
+#define TRB_ADDR_DEV		11
+/* Configure Endpoint Command */
+#define TRB_CONFIG_EP		12
+/* Evaluate Context Command */
+#define TRB_EVAL_CONTEXT	13
+/* Reset Endpoint Command */
+#define TRB_RESET_EP		14
+/* Stop Transfer Ring Command */
+#define TRB_STOP_RING		15
+/* Set Transfer Ring Dequeue Pointer Command */
+#define TRB_SET_DEQ		16
+/* Reset Device Command */
+#define TRB_RESET_DEV		17
+/* Force Event Command (opt) */
+#define TRB_FORCE_EVENT		18
+/* Negotiate Bandwidth Command (opt) */
+#define TRB_NEG_BANDWIDTH	19
+/* Set Latency Tolerance Value Command (opt) */
+#define TRB_SET_LT		20
+/* Get port bandwidth Command */
+#define TRB_GET_BW		21
+/* Force Header Command - generate a transaction or link management packet */
+#define TRB_FORCE_HEADER	22
+/* No-op Command - not for transfer rings */
+#define TRB_CMD_NOOP		23
+/* TRB IDs 24-31 reserved */
+/* Event TRBS */
+/* Transfer Event */
+#define TRB_TRANSFER		32
+/* Command Completion Event */
+#define TRB_COMPLETION		33
+/* Port Status Change Event */
+#define TRB_PORT_STATUS		34
+/* Bandwidth Request Event (opt) */
+#define TRB_BANDWIDTH_EVENT	35
+/* Doorbell Event (opt) */
+#define TRB_DOORBELL		36
+/* Host Controller Event */
+#define TRB_HC_EVENT		37
+/* Device Notification Event - device sent function wake notification */
+#define TRB_DEV_NOTE		38
+/* MFINDEX Wrap Event - microframe counter wrapped */
+#define TRB_MFINDEX_WRAP	39
+/* TRB IDs 40-47 reserved, 48-63 is vendor-defined */
+
+/* Nec vendor-specific command completion event. */
+#define TRB_NEC_CMD_COMP	48
+/* Get NEC firmware revision. */
+#define TRB_NEC_GET_FW		49
+
+#define TRB_TYPE_LINK(x)	(((x) & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK))
+/* Above, but for __le32 types -- can avoid work by swapping constants: */
+#define TRB_TYPE_LINK_LE32(x)	\
+	(((x) & cpu_to_le32(TRB_TYPE_BITMASK)) == cpu_to_le32(TRB_TYPE(TRB_LINK)))
+#define TRB_TYPE_NOOP_LE32(x)	\
+	(((x) & cpu_to_le32(TRB_TYPE_BITMASK)) == cpu_to_le32(TRB_TYPE(TRB_TR_NOOP)))
+
+#define NEC_FW_MINOR(p)		(((p) >> 0) & 0xff)
+#define NEC_FW_MAJOR(p)		(((p) >> 8) & 0xff)
+
+/*
+ * TRBS_PER_SEGMENT must be a multiple of 4,
+ * since the command ring is 64-byte aligned.
+ * It must also be greater than 16.
+ */
+#define TRBS_PER_SEGMENT	64
+/* Allow two commands + a link TRB, along with any reserved command TRBs */
+#define MAX_RSVD_CMD_TRBS	(TRBS_PER_SEGMENT - 3)
+#define TRB_SEGMENT_SIZE	(TRBS_PER_SEGMENT * 16)
+#define TRB_SEGMENT_SHIFT	(ilog2(TRB_SEGMENT_SIZE))
+/* TRB buffer pointers can't cross 64KB boundaries */
+#define TRB_MAX_BUFF_SHIFT	16
+#define TRB_MAX_BUFF_SIZE	(1 << TRB_MAX_BUFF_SHIFT)
+
+/* xHCI command default timeout value */
+#define XHCI_CMD_DEFAULT_TIMEOUT	(5 * SECOND)
+
+struct xhci_erst_entry {
+	/* 64-bit event ring segment address */
+	__le64	seg_addr;
+	__le32	seg_size;
+	/* Set to zero */
+	__le32	rsvd;
+};
+
+/*
+ * Each segment table entry is 4*32bits long.  1K seems like an ok size:
+ * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table,
+ * meaning 64 ring segments.
+ * Initial allocated size of the ERST, in number of entries */
+#define ERST_NUM_SEGS			1
+/* Initial allocated size of the ERST, in number of entries */
+#define ERST_SIZE			64
+/* Initial number of event segment rings allocated */
+#define ERST_ENTRIES			1
+/* Poll every 60 seconds */
+#define POLL_TIMEOUT			60
+/* Stop endpoint command timeout (secs) for URB cancellation watchdog timer */
+#define XHCI_STOP_EP_CMD_TIMEOUT	5
+/* XXX: Make these module parameters */
+
+/*
+ * It can take up to 20 ms to transition from RExit to U0 on the
+ * Intel Lynx Point LP xHCI host.
+ */
+#define XHCI_MAX_REXIT_TIMEOUT	(20 * MSECONDS)
+
+#define XHCI_MAX_EXT_CAPS	50
+
+#define XHCI_EXT_PORT_MAJOR(x)	(((x) >> 24) & 0xff)
+#define XHCI_EXT_PORT_OFF(x)	((x) & 0xff)
+#define XHCI_EXT_PORT_COUNT(x)	(((x) >> 8) & 0xff)
+
+/* Extended capability register fields */
+#define XHCI_EXT_CAPS_ID(p)	(((p)>>0)&0xff)
+#define XHCI_EXT_CAPS_NEXT(p)	(((p)>>8)&0xff)
+#define XHCI_EXT_CAPS_VAL(p)	((p)>>16)
+/* Extended capability IDs - ID 0 reserved */
+#define XHCI_EXT_CAPS_LEGACY	1
+#define XHCI_EXT_CAPS_PROTOCOL	2
+#define XHCI_EXT_CAPS_PM	3
+#define XHCI_EXT_CAPS_VIRT	4
+#define XHCI_EXT_CAPS_ROUTE	5
+/* IDs 6-9 reserved */
+#define XHCI_EXT_CAPS_DEBUG	10
+/* USB Legacy Support Capability - section 7.1.1 */
+#define XHCI_HC_BIOS_OWNED	BIT(16)
+#define XHCI_HC_OS_OWNED	BIT(24)
+
+/* USB Legacy Support Capability - section 7.1.1 */
+/* Add this offset, plus the value of xECP in HCCPARAMS to the base address */
+#define XHCI_LEGACY_SUPPORT_OFFSET	0x00
+
+/* USB Legacy Support Control and Status Register  - section 7.1.2 */
+/* Add this offset, plus the value of xECP in HCCPARAMS to the base address */
+#define XHCI_LEGACY_CONTROL_OFFSET	0x04
+/* bits 1:3, 5:12, and 17:19 need to be preserved; bits 21:28 should be zero */
+#define XHCI_LEGACY_DISABLE_SMI		((0x7 << 1) + (0xff << 5) + (0x7 << 17))
+#define XHCI_LEGACY_SMI_EVENTS		(0x7 << 29)
+
+/* USB 2.0 xHCI 0.96 L1C capability - section 7.2.2.1.3.2 */
+#define XHCI_L1C		BIT(16)
+
+/* USB 2.0 xHCI 1.0 hardware LMP capability - section 7.2.2.1.3.2 */
+#define XHCI_HLC		BIT(19)
+#define XHCI_BLC		BIT(20)
+
+/*
+ * Registers should always be accessed with double word or quad word accesses.
+ *
+ * Some xHCI implementations may support 64-bit address pointers.  Registers
+ * with 64-bit address pointers should be written to with dword accesses by
+ * writing the low dword first (ptr[0]), then the high dword (ptr[1]) second.
+ * xHCI implementations that do not support 64-bit address pointers will ignore
+ * the high dword, and write order is irrelevant.
+ */
+static inline u64 xhci_read_64(__le64 __iomem *regs)
+{
+	__u32 __iomem *ptr = (__u32 __iomem *)regs;
+	u64 val_lo = readl(ptr);
+	u64 val_hi = readl(ptr + 1);
+	return val_lo + (val_hi << 32);
+}
+static inline void xhci_write_64(const u64 val, __le64 __iomem *regs)
+{
+	__u32 __iomem *ptr = (__u32 __iomem *)regs;
+	u32 val_lo = lower_32_bits(val);
+	u32 val_hi = upper_32_bits(val);
+
+	writel(val_lo, ptr);
+	writel(val_hi, ptr + 1);
+}
+
+/*
+ * Barebox xHCI housekeeping structs
+ */
+
+enum xhci_ring_type {
+        TYPE_CTRL = 0,
+        TYPE_ISOC,
+        TYPE_BULK,
+        TYPE_INTR,
+        TYPE_STREAM,
+        TYPE_COMMAND,
+        TYPE_EVENT,
+};
+
+struct xhci_ring {
+	struct list_head list;
+	union xhci_trb *trbs;
+	union xhci_trb *enqueue;
+	union xhci_trb *dequeue;
+	enum xhci_ring_type type;
+	int num_trbs;
+	int cycle_state;
+};
+
+struct xhci_device_context {
+	struct xhci_slot_ctx slot;
+	struct xhci_ep_ctx ep[31];
+};
+
+struct xhci_input_context {
+	struct xhci_input_control_ctx icc;
+	struct xhci_slot_ctx slot;
+	struct xhci_ep_ctx ep[31];
+};
+
+struct xhci_virtual_device {
+	struct list_head list;
+	struct usb_device *udev;
+	void *dma;
+	size_t dma_size;
+	int slot_id;
+	struct xhci_ring *ep[USB_MAXENDPOINTS];
+	struct xhci_input_context *in_ctx;
+	struct xhci_device_context *out_ctx;
+};
+
+struct usb_root_hub_info {
+	struct usb_hub_descriptor hub;
+	struct usb_device_descriptor device;
+	struct usb_config_descriptor config;
+	struct usb_interface_descriptor interface;
+	struct usb_endpoint_descriptor endpoint;
+} __attribute__ ((packed));
+
+struct xhci_hcd {
+	struct usb_host host;
+	struct device_d *dev;
+	struct xhci_cap_regs __iomem *cap_regs;
+	struct xhci_op_regs __iomem *op_regs;
+	struct xhci_run_regs __iomem *run_regs;
+	struct xhci_doorbell_array __iomem *dba;
+	struct xhci_intr_reg __iomem *ir_set;
+	/* Cached register copies of read-only HC data */
+	u32 hcs_params1;
+	u32 hcs_params2;
+	u32 hcs_params3;
+	u32 hcc_capbase;
+	u32 hcc_params;
+	u16 hci_version;
+	int max_slots;
+	int num_sp;
+	int page_size;
+	int page_shift;
+	void *dma;
+	size_t dma_size;
+	__le64 *dcbaa;
+	void *sp;
+	__le64 *sp_array;
+	struct xhci_ring cmd_ring;
+	struct xhci_ring event_ring;
+	struct xhci_ring *rings;
+	struct list_head rings_list;
+	struct xhci_erst_entry *event_erst;
+	u8 *port_array;
+	int rootdev;
+	struct list_head vdev_list;
+	u32 *ext_caps;
+	unsigned int num_ext_caps;
+	__le32 __iomem **usb_ports;
+	unsigned int num_usb_ports;
+	struct usb_root_hub_info usb_info;
+};
+
+#define to_xhci_hcd(_h)	\
+	container_of(_h, struct xhci_hcd, host)
+
+int xhci_handshake(void __iomem *p, u32 mask, u32 done, int usec);
+
+int xhci_issue_command(struct xhci_hcd *xhci, union xhci_trb *trb);
+int xhci_wait_for_event(struct xhci_hcd *xhci, u8 type, union xhci_trb *trb);
+
+int xhci_virtdev_reset(struct xhci_virtual_device *vdev);
+int xhci_virtdev_detach(struct xhci_virtual_device *vdev);
+
+int xhci_hub_setup_ports(struct xhci_hcd *xhci);
+void xhci_hub_port_power(struct xhci_hcd *xhci, int port, bool enable);
+int xhci_hub_control(struct usb_device *dev, unsigned long pipe,
+		     void *buffer, int length, struct devrequest *req);
+
+static inline void xhci_print_trb(struct xhci_hcd *xhci,
+				  union xhci_trb *trb, const char *desc)
+{
+	dev_dbg(xhci->dev, "%s [%08x %08x %08x %08x]\n", desc,
+		trb->generic.field[0], trb->generic.field[1],
+		trb->generic.field[2], trb->generic.field[3]);
+}
+
+#endif
diff --git a/include/usb/xhci.h b/include/usb/xhci.h
new file mode 100644
index 000000000000..1a3138b13288
--- /dev/null
+++ b/include/usb/xhci.h
@@ -0,0 +1,33 @@
+/*
+ * xHCI host controller driver
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * Some code borrowed from the Linux xHCI driver
+ *   Author: Sarah Sharp
+ *   Copyright (C) 2008 Intel Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __XHCI_HCD_H
+#define __XHCI_HCD_H
+
+struct xhci_data {
+	void __iomem *regs;
+};
+
+int xhci_register(struct device_d *dev, struct xhci_data *data);
+
+#endif
-- 
2.0.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 7/7] USB: host: add xHCI PCI driver
  2014-07-26 15:24 [PATCH v2 0/7] Minor USB fixes and xHCI driver Sebastian Hesselbarth
                   ` (5 preceding siblings ...)
  2014-07-26 15:24 ` [PATCH v2 6/7] USB: host: add xHCI HCD, Hub, and platform driver Sebastian Hesselbarth
@ 2014-07-26 15:24 ` Sebastian Hesselbarth
  2014-07-28  5:41 ` [PATCH v2 0/7] Minor USB fixes and xHCI driver Sascha Hauer
  7 siblings, 0 replies; 10+ messages in thread
From: Sebastian Hesselbarth @ 2014-07-26 15:24 UTC (permalink / raw)
  To: Sebastian Hesselbarth, Sascha Hauer; +Cc: Thomas Petazzoni, barebox

This adds a driver for PCI-attached xHCI controllers.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
To: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
Cc: barebox@lists.infradead.org
---
 drivers/usb/host/Kconfig    |  7 +++++++
 drivers/usb/host/Makefile   |  1 +
 drivers/usb/host/xhci-pci.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 53 insertions(+)
 create mode 100644 drivers/usb/host/xhci-pci.c

diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 8c64a3b99c11..c5dc2ea532c4 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -33,3 +33,10 @@ config USB_XHCI
 
 	  This driver currently only supports virtual USB 2.0 ports, if you
 	  plan to use USB 3.0 devices, use a USB 2.0 cable in between.
+
+config USB_XHCI_PCI
+	depends on PCI
+	select USB_XHCI
+	bool "PCI xHCI driver"
+	help
+	  Enables support for PCI attached xHCI controllers.
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index a5c009ebd6a8..0478d342720d 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_USB_EHCI_ATMEL)	+= ehci-atmel.o
 obj-$(CONFIG_USB_OHCI)		+= ohci-hcd.o
 obj-$(CONFIG_USB_OHCI_AT91)	+= ohci-at91.o
 obj-$(CONFIG_USB_XHCI)		+= xhci-hcd.o xhci-hub.o
+obj-$(CONFIG_USB_XHCI_PCI)	+= xhci-pci.o
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
new file mode 100644
index 000000000000..a140b1dd07d3
--- /dev/null
+++ b/drivers/usb/host/xhci-pci.c
@@ -0,0 +1,45 @@
+/*
+ * PCI driver for xHCI controllers
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <io.h>
+#include <linux/pci.h>
+#include <usb/xhci.h>
+
+static int xhci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct xhci_data data = {};
+
+	pci_enable_device(pdev);
+	pci_set_master(pdev);
+
+	data.regs = pci_iomap(pdev, 0);
+
+	return xhci_register(&pdev->dev, &data);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(xhci_pci_tbl) = {
+	/* handle any USB 3.0 xHCI controller */
+	{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_XHCI, ~0), },
+	{ },
+};
+
+static struct pci_driver xhci_pci_driver = {
+	.name = "xHCI PCI",
+	.id_table = xhci_pci_tbl,
+	.probe = xhci_pci_probe,
+};
+
+static int xhci_pci_init(void)
+{
+	return pci_register_driver(&xhci_pci_driver);
+}
+device_initcall(xhci_pci_init);
-- 
2.0.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 0/7] Minor USB fixes and xHCI driver
  2014-07-26 15:24 [PATCH v2 0/7] Minor USB fixes and xHCI driver Sebastian Hesselbarth
                   ` (6 preceding siblings ...)
  2014-07-26 15:24 ` [PATCH v2 7/7] USB: host: add xHCI PCI driver Sebastian Hesselbarth
@ 2014-07-28  5:41 ` Sascha Hauer
  2014-07-28  6:09   ` Sebastian Hesselbarth
  7 siblings, 1 reply; 10+ messages in thread
From: Sascha Hauer @ 2014-07-28  5:41 UTC (permalink / raw)
  To: Sebastian Hesselbarth; +Cc: Thomas Petazzoni, barebox

On Sat, Jul 26, 2014 at 05:24:38PM +0200, Sebastian Hesselbarth wrote:
> 
> Sebastian Hesselbarth (7):
>   USB: Fix stale usb devices in usb_device_list
>   USB: Count detected USB devices independent of dev_index
>   USB: improve error paths and tear-down
>   USB: EHCI: use min3 from Linux
>   include: import {lower,upper}_32_bits helpers
>   USB: host: add xHCI HCD, Hub, and platform driver
>   USB: host: add xHCI PCI driver

Applied, thanks.

You probably need the PCIe driver aswell to make use of this series,
but it shouldn't be needed to compile this series, right?

Sascha


> 
>  drivers/usb/core/hub.c      |   19 +-
>  drivers/usb/core/usb.c      |   50 +-
>  drivers/usb/core/usb.h      |    1 +
>  drivers/usb/host/Kconfig    |   18 +
>  drivers/usb/host/Makefile   |    2 +
>  drivers/usb/host/ehci-hcd.c |   12 +-
>  drivers/usb/host/xhci-hcd.c | 1509 +++++++++++++++++++++++++++++++++++++++++++
>  drivers/usb/host/xhci-hub.c |  647 +++++++++++++++++++
>  drivers/usb/host/xhci-pci.c |   45 ++
>  drivers/usb/host/xhci.h     | 1279 ++++++++++++++++++++++++++++++++++++
>  include/common.h            |   16 +
>  include/linux/kernel.h      |   18 +
>  include/usb/xhci.h          |   33 +
>  13 files changed, 3612 insertions(+), 37 deletions(-)
>  create mode 100644 drivers/usb/host/xhci-hcd.c
>  create mode 100644 drivers/usb/host/xhci-hub.c
>  create mode 100644 drivers/usb/host/xhci-pci.c
>  create mode 100644 drivers/usb/host/xhci.h
>  create mode 100644 include/usb/xhci.h
> 
> ---
> To: Sascha Hauer <s.hauer@pengutronix.de>
> Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> Cc: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
> Cc: barebox@lists.infradead.org
> -- 
> 2.0.0
> 
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 0/7] Minor USB fixes and xHCI driver
  2014-07-28  5:41 ` [PATCH v2 0/7] Minor USB fixes and xHCI driver Sascha Hauer
@ 2014-07-28  6:09   ` Sebastian Hesselbarth
  0 siblings, 0 replies; 10+ messages in thread
From: Sebastian Hesselbarth @ 2014-07-28  6:09 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: Thomas Petazzoni, barebox

On 07/28/2014 07:41 AM, Sascha Hauer wrote:
> On Sat, Jul 26, 2014 at 05:24:38PM +0200, Sebastian Hesselbarth wrote:
>>
>> Sebastian Hesselbarth (7):
>>   USB: Fix stale usb devices in usb_device_list
>>   USB: Count detected USB devices independent of dev_index
>>   USB: improve error paths and tear-down
>>   USB: EHCI: use min3 from Linux
>>   include: import {lower,upper}_32_bits helpers
>>   USB: host: add xHCI HCD, Hub, and platform driver
>>   USB: host: add xHCI PCI driver
> 
> Applied, thanks.
> 
> You probably need the PCIe driver aswell to make use of this series,
> but it shouldn't be needed to compile this series, right?

Yep, no compile time dependency here.

Thanks!

Sebastian


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2014-07-28  6:09 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-26 15:24 [PATCH v2 0/7] Minor USB fixes and xHCI driver Sebastian Hesselbarth
2014-07-26 15:24 ` [PATCH v2 1/7] USB: Fix stale usb devices in usb_device_list Sebastian Hesselbarth
2014-07-26 15:24 ` [PATCH v2 2/7] USB: Count detected USB devices independent of dev_index Sebastian Hesselbarth
2014-07-26 15:24 ` [PATCH v2 3/7] USB: improve error paths and tear-down Sebastian Hesselbarth
2014-07-26 15:24 ` [PATCH v2 4/7] USB: EHCI: use min3 from Linux Sebastian Hesselbarth
2014-07-26 15:24 ` [PATCH v2 5/7] include: import {lower,upper}_32_bits helpers Sebastian Hesselbarth
2014-07-26 15:24 ` [PATCH v2 6/7] USB: host: add xHCI HCD, Hub, and platform driver Sebastian Hesselbarth
2014-07-26 15:24 ` [PATCH v2 7/7] USB: host: add xHCI PCI driver Sebastian Hesselbarth
2014-07-28  5:41 ` [PATCH v2 0/7] Minor USB fixes and xHCI driver Sascha Hauer
2014-07-28  6:09   ` Sebastian Hesselbarth

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox