diff options
author | Michael Brown | 2015-05-08 16:33:18 +0200 |
---|---|---|
committer | Michael Brown | 2015-05-09 21:09:08 +0200 |
commit | b3de9664c7b7d4878d3dcd5a3c62a8e0155d5e89 (patch) | |
tree | 73a28e46867e48c18f990e0fa295d6cd7f77716b /src/drivers/usb | |
parent | [usb] Maintain single lists of halted endpoints and changed ports (diff) | |
download | ipxe-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.c | 53 | ||||
-rw-r--r-- | src/drivers/usb/ehci.h | 6 |
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. |