^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * PCI-related functions used by the EFI stub on multiple
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * architectures.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright 2019 Google, LLC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/efi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <asm/efi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "efistub.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) void efi_pci_disable_bridge_busmaster(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) unsigned long pci_handle_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) efi_handle_t *pci_handle = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) efi_handle_t handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) efi_status_t status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) u16 class, command;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) status = efi_bs_call(locate_handle, EFI_LOCATE_BY_PROTOCOL, &pci_proto,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) NULL, &pci_handle_size, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) if (status != EFI_BUFFER_TOO_SMALL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) if (status != EFI_SUCCESS && status != EFI_NOT_FOUND)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) efi_err("Failed to locate PCI I/O handles'\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, pci_handle_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) (void **)&pci_handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) if (status != EFI_SUCCESS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) efi_err("Failed to allocate memory for 'pci_handle'\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) status = efi_bs_call(locate_handle, EFI_LOCATE_BY_PROTOCOL, &pci_proto,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) NULL, &pci_handle_size, pci_handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) if (status != EFI_SUCCESS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) efi_err("Failed to locate PCI I/O handles'\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) goto free_handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) for_each_efi_handle(handle, pci_handle, pci_handle_size, i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) efi_pci_io_protocol_t *pci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) unsigned long segment_nr, bus_nr, device_nr, func_nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) status = efi_bs_call(handle_protocol, handle, &pci_proto,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) (void **)&pci);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (status != EFI_SUCCESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * Disregard devices living on bus 0 - these are not behind a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * bridge so no point in disconnecting them from their drivers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) status = efi_call_proto(pci, get_location, &segment_nr, &bus_nr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) &device_nr, &func_nr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (status != EFI_SUCCESS || bus_nr == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * Don't disconnect VGA controllers so we don't risk losing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * access to the framebuffer. Drivers for true PCIe graphics
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * controllers that are behind a PCIe root port do not use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * DMA to implement the GOP framebuffer anyway [although they
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * may use it in their implementation of Gop->Blt()], and so
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * disabling DMA in the PCI bridge should not interfere with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * normal operation of the device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) status = efi_call_proto(pci, pci.read, EfiPciIoWidthUint16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) PCI_CLASS_DEVICE, 1, &class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (status != EFI_SUCCESS || class == PCI_CLASS_DISPLAY_VGA)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /* Disconnect this handle from all its drivers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) efi_bs_call(disconnect_controller, handle, NULL, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) for_each_efi_handle(handle, pci_handle, pci_handle_size, i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) efi_pci_io_protocol_t *pci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) status = efi_bs_call(handle_protocol, handle, &pci_proto,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) (void **)&pci);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (status != EFI_SUCCESS || !pci)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) status = efi_call_proto(pci, pci.read, EfiPciIoWidthUint16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) PCI_CLASS_DEVICE, 1, &class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (status != EFI_SUCCESS || class != PCI_CLASS_BRIDGE_PCI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) /* Disable busmastering */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) status = efi_call_proto(pci, pci.read, EfiPciIoWidthUint16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) PCI_COMMAND, 1, &command);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (status != EFI_SUCCESS || !(command & PCI_COMMAND_MASTER))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) command &= ~PCI_COMMAND_MASTER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) status = efi_call_proto(pci, pci.write, EfiPciIoWidthUint16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) PCI_COMMAND, 1, &command);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (status != EFI_SUCCESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) efi_err("Failed to disable PCI busmastering\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) free_handle:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) efi_bs_call(free_pool, pci_handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }