]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[xhci] Undo PCH-specific quirk fixes when removing device
authorMichael Brown <mcb30@ipxe.org>
Fri, 6 Mar 2015 17:15:29 +0000 (17:15 +0000)
committerMichael Brown <mcb30@ipxe.org>
Fri, 6 Mar 2015 17:15:29 +0000 (17:15 +0000)
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>
src/drivers/usb/xhci.c
src/drivers/usb/xhci.h

index 5d4cb15182c7236e6f8cc2fdd36ce2bef89561f4..5d067bd051d01330c9945c1cfe9fff73f08eb6e8 100644 (file)
@@ -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,10 +3046,27 @@ 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
  *
@@ -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 );
index d7bfff1690662ffe56775c78f2139302d9cdcabc..269f50b82f4bfa9b7f295a3637c7978d3b5b8aa1 100644 (file)
@@ -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 */