summaryrefslogtreecommitdiffstats
path: root/src/drivers/usb
diff options
context:
space:
mode:
authorMichael Brown2015-05-08 16:33:18 +0200
committerMichael Brown2015-05-09 21:09:08 +0200
commitb3de9664c7b7d4878d3dcd5a3c62a8e0155d5e89 (patch)
tree73a28e46867e48c18f990e0fa295d6cd7f77716b /src/drivers/usb
parent[usb] Maintain single lists of halted endpoints and changed ports (diff)
downloadipxe-b3de9664c7b7d4878d3dcd5a3c62a8e0155d5e89.tar.gz
ipxe-b3de9664c7b7d4878d3dcd5a3c62a8e0155d5e89.tar.xz
ipxe-b3de9664c7b7d4878d3dcd5a3c62a8e0155d5e89.zip
[ehci] Poll child companion controllers after disowning port
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/drivers/usb')
-rw-r--r--src/drivers/usb/ehci.c53
-rw-r--r--src/drivers/usb/ehci.h6
2 files changed, 59 insertions, 0 deletions
diff --git a/src/drivers/usb/ehci.c b/src/drivers/usb/ehci.c
index d64024da..e847c6b7 100644
--- a/src/drivers/usb/ehci.c
+++ b/src/drivers/usb/ehci.c
@@ -294,6 +294,51 @@ static void ehci_legacy_release ( struct ehci_device *ehci,
/******************************************************************************
*
+ * Companion controllers
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Poll child companion controllers
+ *
+ * @v ehci EHCI device
+ */
+static void ehci_poll_companions ( struct ehci_device *ehci ) {
+ struct usb_bus *bus;
+ struct device_description *desc;
+
+ /* Poll any USB buses belonging to child companion controllers */
+ for_each_usb_bus ( bus ) {
+
+ /* Get underlying devices description */
+ desc = &bus->dev->desc;
+
+ /* Skip buses that are not PCI devices */
+ if ( desc->bus_type != BUS_TYPE_PCI )
+ continue;
+
+ /* Skip buses that are not part of the same PCI device */
+ if ( PCI_FIRST_FUNC ( desc->location ) !=
+ PCI_FIRST_FUNC ( ehci->bus->dev->desc.location ) )
+ continue;
+
+ /* Skip buses that are not UHCI or OHCI PCI devices */
+ if ( ( desc->class != PCI_CLASS ( PCI_CLASS_SERIAL,
+ PCI_CLASS_SERIAL_USB,
+ PCI_CLASS_SERIAL_USB_UHCI ))&&
+ ( desc->class != PCI_CLASS ( PCI_CLASS_SERIAL,
+ PCI_CLASS_SERIAL_USB,
+ PCI_CLASS_SERIAL_USB_OHCI ) ))
+ continue;
+
+ /* Poll child companion controller bus */
+ usb_poll ( bus );
+ }
+}
+
+/******************************************************************************
+ *
* Run / stop / reset
*
******************************************************************************
@@ -1460,9 +1505,17 @@ static int ehci_root_enable ( struct usb_hub *hub, struct usb_port *port ) {
return -ETIMEDOUT;
disown:
+ /* Disown port */
portsc &= ~EHCI_PORTSC_CHANGE;
portsc |= EHCI_PORTSC_OWNER;
writel ( portsc, ehci->op + EHCI_OP_PORTSC ( port->address ) );
+
+ /* Delay to allow child companion controllers to settle */
+ mdelay ( EHCI_DISOWN_DELAY_MS );
+
+ /* Poll child companion controllers */
+ ehci_poll_companions ( ehci );
+
return -ENODEV;
}
diff --git a/src/drivers/usb/ehci.h b/src/drivers/usb/ehci.h
index 7ad1e649..d8814ec7 100644
--- a/src/drivers/usb/ehci.h
+++ b/src/drivers/usb/ehci.h
@@ -424,6 +424,12 @@ ehci_ring_remaining ( struct ehci_ring *ring ) {
*/
#define EHCI_PORT_POWER_DELAY_MS 20
+/** Time to delay after releasing ownership of a port
+ *
+ * This is a policy decision.
+ */
+#define EHCI_DISOWN_DELAY_MS 100
+
/** Maximum time to wait for BIOS to release ownership
*
* This is a policy decision.