]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[ehci] Poll child companion controllers after disowning port
authorMichael Brown <mcb30@ipxe.org>
Fri, 8 May 2015 14:33:18 +0000 (15:33 +0100)
committerMichael Brown <mcb30@ipxe.org>
Sat, 9 May 2015 19:09:08 +0000 (20:09 +0100)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/drivers/usb/ehci.c
src/drivers/usb/ehci.h

index d64024da27060283620189d18bf1ae2b8527e269..e847c6b75a65d2b818cb597b9254a08201baf0bd 100644 (file)
@@ -292,6 +292,51 @@ static void ehci_legacy_release ( struct ehci_device *ehci,
        DBGC ( ehci, "EHCI %p released ownership to BIOS\n", 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;
 }
 
index 7ad1e64991e1a5fff8a81e6846640ba82bf8ae56..d8814ec709f6dbfcca49d2fe37191ab5fd06d405 100644 (file)
@@ -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.