]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/PciHostBridgeLibScan/ScanForRootBridges.c
OvmfPkg/PciHostBridgeLibScan: clean up file names and file-top comments
[mirror_edk2.git] / OvmfPkg / Library / PciHostBridgeLibScan / ScanForRootBridges.c
1 /** @file
2 Scan the entire PCI bus for root bridges to support OVMF on Bhyve and Xen.
3
4 Copyright (C) 2021, Red Hat, Inc.
5 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include <IndustryStandard/Pci.h> // EFI_PCI_COMMAND_IO_SPACE
12 #include <Library/BaseLib.h> // DisableInterrupts()
13 #include <Library/BaseMemoryLib.h> // ZeroMem()
14 #include <Library/DebugLib.h> // ASSERT()
15 #include <Library/MemoryAllocationLib.h> // ReallocatePool()
16 #include <Library/PciHostBridgeLib.h> // PCI_ROOT_BRIDGE_APERTURE
17 #include <Library/PciHostBridgeUtilityLib.h> // PciHostBridgeUtilityInitRoot...
18 #include <Library/PciLib.h> // PciRead32()
19 #include <Protocol/PciRootBridgeIo.h> // EFI_PCI_ATTRIBUTE_ISA_IO
20
21 #include "PciHostBridge.h"
22
23 STATIC
24 VOID
25 PcatPciRootBridgeBarExisted (
26 IN UINTN Address,
27 OUT UINT32 *OriginalValue,
28 OUT UINT32 *Value
29 )
30 {
31 //
32 // Preserve the original value
33 //
34 *OriginalValue = PciRead32 (Address);
35
36 //
37 // Disable timer interrupt while the BAR is probed
38 //
39 DisableInterrupts ();
40
41 PciWrite32 (Address, 0xFFFFFFFF);
42 *Value = PciRead32 (Address);
43 PciWrite32 (Address, *OriginalValue);
44
45 //
46 // Enable interrupt
47 //
48 EnableInterrupts ();
49 }
50
51 #define PCI_COMMAND_DECODE ((UINT16)(EFI_PCI_COMMAND_IO_SPACE | \
52 EFI_PCI_COMMAND_MEMORY_SPACE))
53 STATIC
54 VOID
55 PcatPciRootBridgeDecodingDisable (
56 IN UINTN Address
57 )
58 {
59 UINT16 Value;
60
61 Value = PciRead16 (Address);
62 if (Value & PCI_COMMAND_DECODE) {
63 PciWrite16 (Address, Value & ~(UINT32)PCI_COMMAND_DECODE);
64 }
65 }
66
67 STATIC
68 VOID
69 PcatPciRootBridgeParseBars (
70 IN UINT16 Command,
71 IN UINTN Bus,
72 IN UINTN Device,
73 IN UINTN Function,
74 IN UINTN BarOffsetBase,
75 IN UINTN BarOffsetEnd,
76 IN PCI_ROOT_BRIDGE_APERTURE *Io,
77 IN PCI_ROOT_BRIDGE_APERTURE *Mem,
78 IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G
79
80 )
81 {
82 UINT32 OriginalValue;
83 UINT32 Value;
84 UINT32 OriginalUpperValue;
85 UINT32 UpperValue;
86 UINT64 Mask;
87 UINTN Offset;
88 UINT64 Base;
89 UINT64 Length;
90 UINT64 Limit;
91 PCI_ROOT_BRIDGE_APERTURE *MemAperture;
92
93 // Disable address decoding for every device before OVMF starts sizing it
94 PcatPciRootBridgeDecodingDisable (
95 PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET)
96 );
97
98 for (Offset = BarOffsetBase; Offset < BarOffsetEnd; Offset += sizeof (UINT32)) {
99 PcatPciRootBridgeBarExisted (
100 PCI_LIB_ADDRESS (Bus, Device, Function, Offset),
101 &OriginalValue, &Value
102 );
103 if (Value == 0) {
104 continue;
105 }
106 if ((Value & BIT0) == BIT0) {
107 //
108 // IO Bar
109 //
110 if (Command & EFI_PCI_COMMAND_IO_SPACE) {
111 Mask = 0xfffffffc;
112 Base = OriginalValue & Mask;
113 Length = ((~(Value & Mask)) & Mask) + 0x04;
114 if (!(Value & 0xFFFF0000)) {
115 Length &= 0x0000FFFF;
116 }
117 Limit = Base + Length - 1;
118
119 if (Base < Limit) {
120 if (Io->Base > Base) {
121 Io->Base = Base;
122 }
123 if (Io->Limit < Limit) {
124 Io->Limit = Limit;
125 }
126 }
127 }
128 } else {
129 //
130 // Mem Bar
131 //
132 if (Command & EFI_PCI_COMMAND_MEMORY_SPACE) {
133
134 Mask = 0xfffffff0;
135 Base = OriginalValue & Mask;
136 Length = Value & Mask;
137
138 if ((Value & (BIT1 | BIT2)) == 0) {
139 //
140 // 32bit
141 //
142 Length = ((~Length) + 1) & 0xffffffff;
143
144 MemAperture = Mem;
145 } else {
146 //
147 // 64bit
148 //
149 Offset += 4;
150 PcatPciRootBridgeBarExisted (
151 PCI_LIB_ADDRESS (Bus, Device, Function, Offset),
152 &OriginalUpperValue,
153 &UpperValue
154 );
155
156 Base = Base | LShiftU64 ((UINT64) OriginalUpperValue, 32);
157 Length = Length | LShiftU64 ((UINT64) UpperValue, 32);
158 Length = (~Length) + 1;
159
160 if (Base < BASE_4GB) {
161 MemAperture = Mem;
162 } else {
163 MemAperture = MemAbove4G;
164 }
165 }
166
167 Limit = Base + Length - 1;
168 if (Base < Limit) {
169 if (MemAperture->Base > Base) {
170 MemAperture->Base = Base;
171 }
172 if (MemAperture->Limit < Limit) {
173 MemAperture->Limit = Limit;
174 }
175 }
176 }
177 }
178 }
179 }
180
181 STATIC PCI_ROOT_BRIDGE_APERTURE mNonExistAperture = { MAX_UINT64, 0 };
182
183 PCI_ROOT_BRIDGE *
184 ScanForRootBridges (
185 UINTN *NumberOfRootBridges
186 )
187 {
188 UINTN PrimaryBus;
189 UINTN SubBus;
190 UINT8 Device;
191 UINT8 Function;
192 UINTN NumberOfDevices;
193 UINTN Address;
194 PCI_TYPE01 Pci;
195 UINT64 Attributes;
196 UINT64 Base;
197 UINT64 Limit;
198 UINT64 Value;
199 PCI_ROOT_BRIDGE_APERTURE Io, Mem, MemAbove4G, *MemAperture;
200 PCI_ROOT_BRIDGE *RootBridges;
201 UINTN BarOffsetEnd;
202
203
204 *NumberOfRootBridges = 0;
205 RootBridges = NULL;
206
207 //
208 // After scanning all the PCI devices on the PCI root bridge's primary bus,
209 // update the Primary Bus Number for the next PCI root bridge to be this PCI
210 // root bridge's subordinate bus number + 1.
211 //
212 for (PrimaryBus = 0; PrimaryBus <= PCI_MAX_BUS; PrimaryBus = SubBus + 1) {
213 SubBus = PrimaryBus;
214 Attributes = 0;
215
216 ZeroMem (&Io, sizeof (Io));
217 ZeroMem (&Mem, sizeof (Mem));
218 ZeroMem (&MemAbove4G, sizeof (MemAbove4G));
219 Io.Base = Mem.Base = MemAbove4G.Base = MAX_UINT64;
220 //
221 // Scan all the PCI devices on the primary bus of the PCI root bridge
222 //
223 for (Device = 0, NumberOfDevices = 0; Device <= PCI_MAX_DEVICE; Device++) {
224
225 for (Function = 0; Function <= PCI_MAX_FUNC; Function++) {
226
227 //
228 // Compute the PCI configuration address of the PCI device to probe
229 //
230 Address = PCI_LIB_ADDRESS (PrimaryBus, Device, Function, 0);
231
232 //
233 // Read the Vendor ID from the PCI Configuration Header
234 //
235 if (PciRead16 (Address) == MAX_UINT16) {
236 if (Function == 0) {
237 //
238 // If the PCI Configuration Read fails, or a PCI device does not
239 // exist, then skip this entire PCI device
240 //
241 break;
242 } else {
243 //
244 // If PCI function != 0, VendorId == 0xFFFF, we continue to search
245 // PCI function.
246 //
247 continue;
248 }
249 }
250
251 //
252 // Read the entire PCI Configuration Header
253 //
254 PciReadBuffer (Address, sizeof (Pci), &Pci);
255
256 //
257 // Increment the number of PCI device found on the primary bus of the
258 // PCI root bridge
259 //
260 NumberOfDevices++;
261
262 //
263 // Look for devices with the VGA Palette Snoop enabled in the COMMAND
264 // register of the PCI Config Header
265 //
266 if ((Pci.Hdr.Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {
267 Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
268 Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16;
269 }
270
271 BarOffsetEnd = 0;
272
273 //
274 // PCI-PCI Bridge
275 //
276 if (IS_PCI_BRIDGE (&Pci)) {
277 //
278 // Get the Bus range that the PPB is decoding
279 //
280 if (Pci.Bridge.SubordinateBus > SubBus) {
281 //
282 // If the subordinate bus number of the PCI-PCI bridge is greater
283 // than the PCI root bridge's current subordinate bus number,
284 // then update the PCI root bridge's subordinate bus number
285 //
286 SubBus = Pci.Bridge.SubordinateBus;
287 }
288
289 //
290 // Get the I/O range that the PPB is decoding
291 //
292 Value = Pci.Bridge.IoBase & 0x0f;
293 Base = ((UINT32) Pci.Bridge.IoBase & 0xf0) << 8;
294 Limit = (((UINT32) Pci.Bridge.IoLimit & 0xf0) << 8) | 0x0fff;
295 if (Value == BIT0) {
296 Base |= ((UINT32) Pci.Bridge.IoBaseUpper16 << 16);
297 Limit |= ((UINT32) Pci.Bridge.IoLimitUpper16 << 16);
298 }
299 if (Base < Limit) {
300 if (Io.Base > Base) {
301 Io.Base = Base;
302 }
303 if (Io.Limit < Limit) {
304 Io.Limit = Limit;
305 }
306 }
307
308 //
309 // Get the Memory range that the PPB is decoding
310 //
311 Base = ((UINT32) Pci.Bridge.MemoryBase & 0xfff0) << 16;
312 Limit = (((UINT32) Pci.Bridge.MemoryLimit & 0xfff0) << 16) | 0xfffff;
313 if (Base < Limit) {
314 if (Mem.Base > Base) {
315 Mem.Base = Base;
316 }
317 if (Mem.Limit < Limit) {
318 Mem.Limit = Limit;
319 }
320 }
321
322 //
323 // Get the Prefetchable Memory range that the PPB is decoding
324 // and merge it into Memory range
325 //
326 Value = Pci.Bridge.PrefetchableMemoryBase & 0x0f;
327 Base = ((UINT32) Pci.Bridge.PrefetchableMemoryBase & 0xfff0) << 16;
328 Limit = (((UINT32) Pci.Bridge.PrefetchableMemoryLimit & 0xfff0)
329 << 16) | 0xfffff;
330 MemAperture = &Mem;
331 if (Value == BIT0) {
332 Base |= LShiftU64 (Pci.Bridge.PrefetchableBaseUpper32, 32);
333 Limit |= LShiftU64 (Pci.Bridge.PrefetchableLimitUpper32, 32);
334 MemAperture = &MemAbove4G;
335 }
336 if (Base < Limit) {
337 if (MemAperture->Base > Base) {
338 MemAperture->Base = Base;
339 }
340 if (MemAperture->Limit < Limit) {
341 MemAperture->Limit = Limit;
342 }
343 }
344
345 //
346 // Look at the PPB Configuration for legacy decoding attributes
347 //
348 if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA)
349 == EFI_PCI_BRIDGE_CONTROL_ISA) {
350 Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO;
351 Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO_16;
352 Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO;
353 }
354 if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA)
355 == EFI_PCI_BRIDGE_CONTROL_VGA) {
356 Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
357 Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY;
358 Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO;
359 if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16)
360 != 0) {
361 Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16;
362 Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO_16;
363 }
364 }
365
366 BarOffsetEnd = OFFSET_OF (PCI_TYPE01, Bridge.Bar[2]);
367 } else {
368 //
369 // Parse the BARs of the PCI device to get what I/O Ranges, Memory
370 // Ranges, and Prefetchable Memory Ranges the device is decoding
371 //
372 if ((Pci.Hdr.HeaderType & HEADER_LAYOUT_CODE) == HEADER_TYPE_DEVICE) {
373 BarOffsetEnd = OFFSET_OF (PCI_TYPE00, Device.Bar[6]);
374 }
375 }
376
377 PcatPciRootBridgeParseBars (
378 Pci.Hdr.Command,
379 PrimaryBus,
380 Device,
381 Function,
382 OFFSET_OF (PCI_TYPE00, Device.Bar),
383 BarOffsetEnd,
384 &Io,
385 &Mem, &MemAbove4G
386 );
387
388 //
389 // See if the PCI device is an IDE controller
390 //
391 if (IS_CLASS2 (&Pci, PCI_CLASS_MASS_STORAGE,
392 PCI_CLASS_MASS_STORAGE_IDE)) {
393 if (Pci.Hdr.ClassCode[0] & 0x80) {
394 Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO;
395 Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO;
396 }
397 if (Pci.Hdr.ClassCode[0] & 0x01) {
398 Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO;
399 }
400 if (Pci.Hdr.ClassCode[0] & 0x04) {
401 Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO;
402 }
403 }
404
405 //
406 // See if the PCI device is a legacy VGA controller or
407 // a standard VGA controller
408 //
409 if (IS_CLASS2 (&Pci, PCI_CLASS_OLD, PCI_CLASS_OLD_VGA) ||
410 IS_CLASS2 (&Pci, PCI_CLASS_DISPLAY, PCI_CLASS_DISPLAY_VGA)
411 ) {
412 Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
413 Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16;
414 Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY;
415 Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO;
416 Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO_16;
417 }
418
419 //
420 // See if the PCI Device is a PCI - ISA or PCI - EISA
421 // or ISA_POSITIVE_DECODE Bridge device
422 //
423 if (Pci.Hdr.ClassCode[2] == PCI_CLASS_BRIDGE) {
424 if (Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA ||
425 Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_EISA ||
426 Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA_PDECODE) {
427 Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO;
428 Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO_16;
429 Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO;
430 }
431 }
432
433 //
434 // If this device is not a multi function device, then skip the rest
435 // of this PCI device
436 //
437 if (Function == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
438 break;
439 }
440 }
441 }
442
443 //
444 // If at least one PCI device was found on the primary bus of this PCI
445 // root bridge, then the PCI root bridge exists.
446 //
447 if (NumberOfDevices > 0) {
448 RootBridges = ReallocatePool (
449 (*NumberOfRootBridges) * sizeof (PCI_ROOT_BRIDGE),
450 (*NumberOfRootBridges + 1) * sizeof (PCI_ROOT_BRIDGE),
451 RootBridges
452 );
453 ASSERT (RootBridges != NULL);
454 PciHostBridgeUtilityInitRootBridge (
455 Attributes, Attributes, 0,
456 FALSE, TRUE /* NoExtendedConfigSpace */,
457 (UINT8) PrimaryBus, (UINT8) SubBus,
458 &Io, &Mem, &MemAbove4G, &mNonExistAperture, &mNonExistAperture,
459 &RootBridges[*NumberOfRootBridges]
460 );
461 RootBridges[*NumberOfRootBridges].ResourceAssigned = TRUE;
462 //
463 // Increment the index for the next PCI Root Bridge
464 //
465 (*NumberOfRootBridges)++;
466 }
467 }
468
469 return RootBridges;
470 }