summaryrefslogtreecommitdiffstats
path: root/src/drivers/usb
diff options
context:
space:
mode:
authorMichael Brown2015-03-06 18:15:29 +0100
committerMichael Brown2015-03-06 18:15:29 +0100
commite905cdcce386f9752ff8a655f9ed0e4961a9a902 (patch)
tree281e4d7142580a3b9991b7ad44d214092164b808 /src/drivers/usb
parent[xhci] Enable USB3 ports on Intel PCH8/PCH9 controllers (diff)
downloadipxe-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.c27
-rw-r--r--src/drivers/usb/xhci.h41
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 */