File Index
Files and directories
Sign in
FILE

pci.c

File preview with syntax highlighting.

linux-6.19.14/drivers/firmware/efi/libstub/pci.c 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
16void 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}
~/ Read-only file preview.