aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2021-11-12 15:57:51 +0000
committerMichael Brown <mcb30@ipxe.org>2021-11-12 15:57:51 +0000
commiteff6a07aa2d681b21609a9c58c555a5d62db865a (patch)
tree502765d9cc5f64412e3322976f223e9e1a93cd84
parent1844aacc837bf81cb1959fa65f2e52dcc70a0cae (diff)
downloadipxe-thunderbolt_workaround.zip
ipxe-thunderbolt_workaround.tar.gz
ipxe-thunderbolt_workaround.tar.bz2
[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.c22
1 files changed, 22 insertions, 0 deletions
diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c
index 3d98b1e..3247ee6 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 );
}