Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * PCI-related functions used by the EFI stub on multiple
0004  * architectures.
0005  *
0006  * Copyright 2019 Google, LLC
0007  */
0008 
0009 #include <linux/efi.h>
0010 #include <linux/pci.h>
0011 
0012 #include <asm/efi.h>
0013 
0014 #include "efistub.h"
0015 
0016 void efi_pci_disable_bridge_busmaster(void)
0017 {
0018     efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
0019     unsigned long pci_handle_size = 0;
0020     efi_handle_t *pci_handle = NULL;
0021     efi_handle_t handle;
0022     efi_status_t status;
0023     u16 class, command;
0024     int i;
0025 
0026     status = efi_bs_call(locate_handle, EFI_LOCATE_BY_PROTOCOL, &pci_proto,
0027                  NULL, &pci_handle_size, NULL);
0028 
0029     if (status != EFI_BUFFER_TOO_SMALL) {
0030         if (status != EFI_SUCCESS && status != EFI_NOT_FOUND)
0031             efi_err("Failed to locate PCI I/O handles'\n");
0032         return;
0033     }
0034 
0035     status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, pci_handle_size,
0036                  (void **)&pci_handle);
0037     if (status != EFI_SUCCESS) {
0038         efi_err("Failed to allocate memory for 'pci_handle'\n");
0039         return;
0040     }
0041 
0042     status = efi_bs_call(locate_handle, EFI_LOCATE_BY_PROTOCOL, &pci_proto,
0043                  NULL, &pci_handle_size, pci_handle);
0044     if (status != EFI_SUCCESS) {
0045         efi_err("Failed to locate PCI I/O handles'\n");
0046         goto free_handle;
0047     }
0048 
0049     for_each_efi_handle(handle, pci_handle, pci_handle_size, i) {
0050         efi_pci_io_protocol_t *pci;
0051         unsigned long segment_nr, bus_nr, device_nr, func_nr;
0052 
0053         status = efi_bs_call(handle_protocol, handle, &pci_proto,
0054                      (void **)&pci);
0055         if (status != EFI_SUCCESS)
0056             continue;
0057 
0058         /*
0059          * Disregard devices living on bus 0 - these are not behind a
0060          * bridge so no point in disconnecting them from their drivers.
0061          */
0062         status = efi_call_proto(pci, get_location, &segment_nr, &bus_nr,
0063                     &device_nr, &func_nr);
0064         if (status != EFI_SUCCESS || bus_nr == 0)
0065             continue;
0066 
0067         /*
0068          * Don't disconnect VGA controllers so we don't risk losing
0069          * access to the framebuffer. Drivers for true PCIe graphics
0070          * controllers that are behind a PCIe root port do not use
0071          * DMA to implement the GOP framebuffer anyway [although they
0072          * may use it in their implementation of Gop->Blt()], and so
0073          * disabling DMA in the PCI bridge should not interfere with
0074          * normal operation of the device.
0075          */
0076         status = efi_call_proto(pci, pci.read, EfiPciIoWidthUint16,
0077                     PCI_CLASS_DEVICE, 1, &class);
0078         if (status != EFI_SUCCESS || class == PCI_CLASS_DISPLAY_VGA)
0079             continue;
0080 
0081         /* Disconnect this handle from all its drivers */
0082         efi_bs_call(disconnect_controller, handle, NULL, NULL);
0083     }
0084 
0085     for_each_efi_handle(handle, pci_handle, pci_handle_size, i) {
0086         efi_pci_io_protocol_t *pci;
0087 
0088         status = efi_bs_call(handle_protocol, handle, &pci_proto,
0089                      (void **)&pci);
0090         if (status != EFI_SUCCESS || !pci)
0091             continue;
0092 
0093         status = efi_call_proto(pci, pci.read, EfiPciIoWidthUint16,
0094                     PCI_CLASS_DEVICE, 1, &class);
0095 
0096         if (status != EFI_SUCCESS || class != PCI_CLASS_BRIDGE_PCI)
0097             continue;
0098 
0099         /* Disable busmastering */
0100         status = efi_call_proto(pci, pci.read, EfiPciIoWidthUint16,
0101                     PCI_COMMAND, 1, &command);
0102         if (status != EFI_SUCCESS || !(command & PCI_COMMAND_MASTER))
0103             continue;
0104 
0105         command &= ~PCI_COMMAND_MASTER;
0106         status = efi_call_proto(pci, pci.write, EfiPciIoWidthUint16,
0107                     PCI_COMMAND, 1, &command);
0108         if (status != EFI_SUCCESS)
0109             efi_err("Failed to disable PCI busmastering\n");
0110     }
0111 
0112 free_handle:
0113     efi_bs_call(free_pool, pci_handle);
0114 }