]> Git Repo - linux.git/blob - drivers/firmware/efi/libstub/pci.c
Linux 6.14-rc3
[linux.git] / drivers / firmware / efi / libstub / pci.c
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
16 void efi_pci_disable_bridge_busmaster(void)
17 {
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;
21         efi_handle_t handle;
22         efi_status_t status;
23         u16 class, command;
24
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");
29                 return;
30         }
31
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;
35
36                 status = efi_bs_call(handle_protocol, handle, &pci_proto,
37                                      (void **)&pci);
38                 if (status != EFI_SUCCESS)
39                         continue;
40
41                 /*
42                  * Disregard devices living on bus 0 - these are not behind a
43                  * bridge so no point in disconnecting them from their drivers.
44                  */
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)
48                         continue;
49
50                 /*
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.
58                  */
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)
62                         continue;
63
64                 /* Disconnect this handle from all its drivers */
65                 efi_bs_call(disconnect_controller, handle, NULL, NULL);
66         }
67
68         for_each_efi_handle(handle, pci_handle, pci_handle_num) {
69                 efi_pci_io_protocol_t *pci;
70
71                 status = efi_bs_call(handle_protocol, handle, &pci_proto,
72                                      (void **)&pci);
73                 if (status != EFI_SUCCESS || !pci)
74                         continue;
75
76                 status = efi_call_proto(pci, pci.read, EfiPciIoWidthUint16,
77                                         PCI_CLASS_DEVICE, 1, &class);
78
79                 if (status != EFI_SUCCESS || class != PCI_CLASS_BRIDGE_PCI)
80                         continue;
81
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))
86                         continue;
87
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");
93         }
94 }
This page took 0.034902 seconds and 4 git commands to generate.