Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/firmware/efi/libstub/pci.c
26483 views
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
}
95
96