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