diff options
author | Michael Brown <mcb30@ipxe.org> | 2021-11-12 15:57:51 +0000 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2021-11-12 15:57:51 +0000 |
commit | eff6a07aa2d681b21609a9c58c555a5d62db865a (patch) | |
tree | 502765d9cc5f64412e3322976f223e9e1a93cd84 | |
parent | 1844aacc837bf81cb1959fa65f2e52dcc70a0cae (diff) | |
download | ipxe-thunderbolt_workaround.tar.gz |
[xhci] Avoid DMA during shutdown if firmware has disabled bus masteringthunderbolt_workaround
On some systems (observed with the Thunderbolt ports on a ThinkPad X1
Extreme Gen3 and a ThinkPad P53), the system firmware will disable bus
mastering on the xHCI controller and all PCI bridges at the point that
ExitBootServices() is called if the IOMMU is enabled. This leaves the
xHCI controller unable to shut down cleanly since all commands will
fail with a timeout.
Commit 85eb961 ("[xhci] Allow for permanent failure of the command
mechanism") allows us to detect that this has happened and respond
cleanly. However, some unidentified hardware component (either the
xHCI controller or one of the PCI bridges) seems to manage to enqueue
the attempted DMA operation and eventually complete it after the
operating system kernel has reenabled bus mastering. This results in
a DMA operation to an area of memory that the hardware is no longer
permitted to access. On Windows with the Driver Verifier enabled,
this will result in a STOP 0xE6 (DRIVER_VERIFIER_DMA_VIOLATION).
Work around this problem by detecting when bus mastering has been
disabled, and immediately failing the device to avoid initiating any
further DMA attempts.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r-- | src/drivers/usb/xhci.c | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c index 3d98b1e10..3247ee69c 100644 --- a/src/drivers/usb/xhci.c +++ b/src/drivers/usb/xhci.c @@ -3459,14 +3459,36 @@ static int xhci_probe ( struct pci_device *pci ) { static void xhci_remove ( struct pci_device *pci ) { struct xhci_device *xhci = pci_get_drvdata ( pci ); struct usb_bus *bus = xhci->bus; + uint16_t command; + /* Some systems are observed to disable bus mastering on + * Thunderbolt controllers before we get a chance to shut + * down. Detect this and avoid attempting any DMA operations, + * which are guaranteed to fail and may end up spuriously + * completing after the operating system kernel starts up. + */ + pci_read_config_word ( pci, PCI_COMMAND, &command ); + if ( ! ( command & PCI_COMMAND_MASTER ) ) { + DBGC ( xhci, "XHCI %s DMA was disabled\n", xhci->name ); + xhci_fail ( xhci ); + } + + /* Unregister and free USB bus */ unregister_usb_bus ( bus ); free_usb_bus ( bus ); + + /* Reset device and undo any PCH-specific fixes */ xhci_reset ( xhci ); if ( xhci->quirks & XHCI_PCH ) xhci_pch_undo ( xhci, pci ); + + /* Release ownership back to BIOS */ xhci_legacy_release ( xhci ); + + /* Unmap registers */ iounmap ( xhci->regs ); + + /* Free device */ free ( xhci ); } |