diff options
author | Michael Brown | 2015-03-06 18:15:29 +0100 |
---|---|---|
committer | Michael Brown | 2015-03-06 18:15:29 +0100 |
commit | e905cdcce386f9752ff8a655f9ed0e4961a9a902 (patch) | |
tree | 281e4d7142580a3b9991b7ad44d214092164b808 /src/drivers/usb | |
parent | [xhci] Enable USB3 ports on Intel PCH8/PCH9 controllers (diff) | |
download | ipxe-e905cdcce386f9752ff8a655f9ed0e4961a9a902.tar.gz ipxe-e905cdcce386f9752ff8a655f9ed0e4961a9a902.tar.xz ipxe-e905cdcce386f9752ff8a655f9ed0e4961a9a902.zip |
[xhci] Undo PCH-specific quirk fixes when removing device
Restore the original values of XUSB2PR and USB3PSSEN, in case we are
booting an OS with no support for xHCI.
Suggested-by: Dan Ellis <Dan.Ellis@displaylink.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/drivers/usb')
-rw-r--r-- | src/drivers/usb/xhci.c | 27 | ||||
-rw-r--r-- | src/drivers/usb/xhci.h | 41 |
2 files changed, 51 insertions, 17 deletions
diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c index 5d4cb151..5d067bd0 100644 --- a/src/drivers/usb/xhci.c +++ b/src/drivers/usb/xhci.c @@ -3019,7 +3019,8 @@ static struct usb_host_operations xhci_operations = { * @v xhci xHCI device * @v pci PCI device */ -static void xhci_pch ( struct xhci_device *xhci, struct pci_device *pci ) { +static void xhci_pch_fix ( struct xhci_device *xhci, struct pci_device *pci ) { + struct xhci_pch *pch = &xhci->pch; uint32_t xusb2pr; uint32_t xusb2prm; uint32_t usb3pssen; @@ -3034,6 +3035,7 @@ static void xhci_pch ( struct xhci_device *xhci, struct pci_device *pci ) { DBGC ( xhci, "XHCI %p enabling SuperSpeed on ports %08x\n", xhci, ( usb3prm & ~usb3pssen ) ); } + pch->usb3pssen = usb3pssen; usb3pssen |= usb3prm; pci_write_config_dword ( pci, XHCI_PCH_USB3PSSEN, usb3pssen ); @@ -3044,11 +3046,28 @@ static void xhci_pch ( struct xhci_device *xhci, struct pci_device *pci ) { DBGC ( xhci, "XHCI %p routing ports %08x from EHCI to xHCI\n", xhci, ( xusb2prm & ~xusb2pr ) ); } + pch->xusb2pr = xusb2pr; xusb2pr |= xusb2prm; pci_write_config_dword ( pci, XHCI_PCH_XUSB2PR, xusb2pr ); } /** + * Undo Intel PCH-specific quirk fixes + * + * @v xhci xHCI device + * @v pci PCI device + */ +static void xhci_pch_undo ( struct xhci_device *xhci, struct pci_device *pci ) { + struct xhci_pch *pch = &xhci->pch; + + /* Restore USB2 port routing to original state */ + pci_write_config_dword ( pci, XHCI_PCH_XUSB2PR, pch->xusb2pr ); + + /* Restore SuperSpeed capability to original state */ + pci_write_config_dword ( pci, XHCI_PCH_USB3PSSEN, pch->usb3pssen ); +} + +/** * Probe PCI device * * @v pci PCI device @@ -3091,7 +3110,7 @@ static int xhci_probe ( struct pci_device *pci ) { /* Fix Intel PCH-specific quirks, if applicable */ if ( pci->id->driver_data & XHCI_PCH ) - xhci_pch ( xhci, pci ); + xhci_pch_fix ( xhci, pci ); /* Reset device */ if ( ( rc = xhci_reset ( xhci ) ) != 0 ) @@ -3126,6 +3145,8 @@ static int xhci_probe ( struct pci_device *pci ) { err_alloc_bus: xhci_reset ( xhci ); err_reset: + if ( pci->id->driver_data & XHCI_PCH ) + xhci_pch_undo ( xhci, pci ); xhci_legacy_release ( xhci ); err_legacy_claim: iounmap ( xhci->regs ); @@ -3147,6 +3168,8 @@ static void xhci_remove ( struct pci_device *pci ) { unregister_usb_bus ( bus ); free_usb_bus ( bus ); xhci_reset ( xhci ); + if ( pci->id->driver_data & XHCI_PCH ) + xhci_pch_undo ( xhci, pci ); xhci_legacy_release ( xhci ); iounmap ( xhci->regs ); free ( xhci ); diff --git a/src/drivers/usb/xhci.h b/src/drivers/usb/xhci.h index d7bfff16..269f50b8 100644 --- a/src/drivers/usb/xhci.h +++ b/src/drivers/usb/xhci.h @@ -1004,6 +1004,29 @@ xhci_ring_consumed ( struct xhci_trb_ring *ring ) { */ #define XHCI_PORT_RESET_MAX_WAIT_MS 500 +/** Intel PCH quirk */ +struct xhci_pch { + /** USB2 port routing register original value */ + uint32_t xusb2pr; + /** USB3 port SuperSpeed enable register original value */ + uint32_t usb3pssen; +}; + +/** Intel PCH quirk flag */ +#define XHCI_PCH 0x0001 + +/** Intel PCH USB2 port routing register */ +#define XHCI_PCH_XUSB2PR 0xd0 + +/** Intel PCH USB2 port routing mask register */ +#define XHCI_PCH_XUSB2PRM 0xd4 + +/** Intel PCH SuperSpeed enable register */ +#define XHCI_PCH_USB3PSSEN 0xd8 + +/** Intel PCH USB3 port routing mask register */ +#define XHCI_PCH_USB3PRM 0xdc + /** An xHCI device */ struct xhci_device { /** Registers */ @@ -1061,6 +1084,9 @@ struct xhci_device { /** USB bus */ struct usb_bus *bus; + + /** Intel PCH quirk */ + struct xhci_pch pch; }; /** An xHCI device slot */ @@ -1103,19 +1129,4 @@ struct xhci_endpoint { struct xhci_trb_ring ring; }; -/** Intel PCH quirk */ -#define XHCI_PCH 0x0001 - -/** Intel PCH USB2 port routing register */ -#define XHCI_PCH_XUSB2PR 0xd0 - -/** Intel PCH USB2 port routing mask register */ -#define XHCI_PCH_XUSB2PRM 0xd4 - -/** Intel PCH USB3 port SuperSpeed enable register */ -#define XHCI_PCH_USB3PSSEN 0xd8 - -/** Intel PCH USB3 port routing mask register */ -#define XHCI_PCH_USB3PRM 0xdc - #endif /* _IPXE_XHCI_H */ |