1 // SPDX-License-Identifier: GPL-2.0
3 * PCI-related functions used by the EFI stub on multiple
6 * Copyright 2019 Google, LLC
10 #include <linux/pci.h>
16 void efi_pci_disable_bridge_busmaster(void)
18 efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
19 efi_handle_t *pci_handle __free(efi_pool) = NULL;
20 unsigned long pci_handle_num;
25 status = efi_bs_call(locate_handle_buffer, EFI_LOCATE_BY_PROTOCOL,
26 &pci_proto, NULL, &pci_handle_num, &pci_handle);
27 if (status != EFI_SUCCESS) {
28 efi_err("Failed to locate PCI I/O handles\n");
32 for_each_efi_handle(handle, pci_handle, pci_handle_num) {
33 efi_pci_io_protocol_t *pci;
34 unsigned long segment_nr, bus_nr, device_nr, func_nr;
36 status = efi_bs_call(handle_protocol, handle, &pci_proto,
38 if (status != EFI_SUCCESS)
42 * Disregard devices living on bus 0 - these are not behind a
43 * bridge so no point in disconnecting them from their drivers.
45 status = efi_call_proto(pci, get_location, &segment_nr, &bus_nr,
46 &device_nr, &func_nr);
47 if (status != EFI_SUCCESS || bus_nr == 0)
51 * Don't disconnect VGA controllers so we don't risk losing
52 * access to the framebuffer. Drivers for true PCIe graphics
53 * controllers that are behind a PCIe root port do not use
54 * DMA to implement the GOP framebuffer anyway [although they
55 * may use it in their implementation of Gop->Blt()], and so
56 * disabling DMA in the PCI bridge should not interfere with
57 * normal operation of the device.
59 status = efi_call_proto(pci, pci.read, EfiPciIoWidthUint16,
60 PCI_CLASS_DEVICE, 1, &class);
61 if (status != EFI_SUCCESS || class == PCI_CLASS_DISPLAY_VGA)
64 /* Disconnect this handle from all its drivers */
65 efi_bs_call(disconnect_controller, handle, NULL, NULL);
68 for_each_efi_handle(handle, pci_handle, pci_handle_num) {
69 efi_pci_io_protocol_t *pci;
71 status = efi_bs_call(handle_protocol, handle, &pci_proto,
73 if (status != EFI_SUCCESS || !pci)
76 status = efi_call_proto(pci, pci.read, EfiPciIoWidthUint16,
77 PCI_CLASS_DEVICE, 1, &class);
79 if (status != EFI_SUCCESS || class != PCI_CLASS_BRIDGE_PCI)
82 /* Disable busmastering */
83 status = efi_call_proto(pci, pci.read, EfiPciIoWidthUint16,
84 PCI_COMMAND, 1, &command);
85 if (status != EFI_SUCCESS || !(command & PCI_COMMAND_MASTER))
88 command &= ~PCI_COMMAND_MASTER;
89 status = efi_call_proto(pci, pci.write, EfiPciIoWidthUint16,
90 PCI_COMMAND, 1, &command);
91 if (status != EFI_SUCCESS)
92 efi_err("Failed to disable PCI busmastering\n");