]> git.proxmox.com Git - mirror_edk2.git/blob - CorebootPayloadPkg/Library/PciHostBridgeLib/PciHostBridgeSupport.c
CorebootPayloadPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / CorebootPayloadPkg / Library / PciHostBridgeLib / PciHostBridgeSupport.c
1 /** @file
2 Scan the entire PCI bus for root bridges to support coreboot UEFI payload.
3
4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include <PiDxe.h>
11 #include <IndustryStandard/Pci.h>
12 #include <Protocol/PciHostBridgeResourceAllocation.h>
13 #include <Protocol/PciRootBridgeIo.h>
14 #include <Library/BaseMemoryLib.h>
15 #include <Library/DebugLib.h>
16 #include <Library/MemoryAllocationLib.h>
17 #include <Library/PciHostBridgeLib.h>
18 #include <Library/PciLib.h>
19 #include "PciHostBridge.h"
20
21 /**
22 Adjust the collected PCI resource.
23
24 @param[in] Io IO aperture.
25
26 @param[in] Mem MMIO aperture.
27
28 @param[in] MemAbove4G MMIO aperture above 4G.
29
30 @param[in] PMem Prefetchable MMIO aperture.
31
32 @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.
33 **/
34 VOID
35 AdjustRootBridgeResource (
36 IN PCI_ROOT_BRIDGE_APERTURE *Io,
37 IN PCI_ROOT_BRIDGE_APERTURE *Mem,
38 IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G,
39 IN PCI_ROOT_BRIDGE_APERTURE *PMem,
40 IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G
41 )
42 {
43 UINT64 Mask;
44
45 //
46 // For now try to downgrade everything into MEM32 since
47 // - coreboot does not assign resource above 4GB
48 // - coreboot might allocate interleaved MEM32 and PMEM32 resource
49 // in some cases
50 //
51 if (PMem->Base < Mem->Base) {
52 Mem->Base = PMem->Base;
53 }
54
55 if (PMem->Limit > Mem->Limit) {
56 Mem->Limit = PMem->Limit;
57 }
58
59 PMem->Base = MAX_UINT64;
60 PMem->Limit = 0;
61
62 if (MemAbove4G->Base < 0x100000000ULL) {
63 if (MemAbove4G->Base < Mem->Base) {
64 Mem->Base = MemAbove4G->Base;
65 }
66 if (MemAbove4G->Limit > Mem->Limit) {
67 Mem->Limit = MemAbove4G->Limit;
68 }
69 MemAbove4G->Base = MAX_UINT64;
70 MemAbove4G->Limit = 0;
71 }
72
73 if (PMemAbove4G->Base < 0x100000000ULL) {
74 if (PMemAbove4G->Base < Mem->Base) {
75 Mem->Base = PMemAbove4G->Base;
76 }
77 if (PMemAbove4G->Limit > Mem->Limit) {
78 Mem->Limit = PMemAbove4G->Limit;
79 }
80 PMemAbove4G->Base = MAX_UINT64;
81 PMemAbove4G->Limit = 0;
82 }
83
84 //
85 // Align IO resource at 4K boundary
86 //
87 Mask = 0xFFFULL;
88 Io->Limit = ((Io->Limit + Mask) & ~Mask) - 1;
89 if (Io->Base != MAX_UINT64) {
90 Io->Base &= ~Mask;
91 }
92
93 //
94 // Align MEM resource at 1MB boundary
95 //
96 Mask = 0xFFFFFULL;
97 Mem->Limit = ((Mem->Limit + Mask) & ~Mask) - 1;
98 if (Mem->Base != MAX_UINT64) {
99 Mem->Base &= ~Mask;
100 }
101 }
102
103 /**
104 Probe a bar is existed or not.
105
106 @param[in] Address PCI address for the BAR.
107 @param[out] OriginalValue The original bar value returned.
108 @param[out] Value The probed bar value returned.
109 **/
110 STATIC
111 VOID
112 PcatPciRootBridgeBarExisted (
113 IN UINT64 Address,
114 OUT UINT32 *OriginalValue,
115 OUT UINT32 *Value
116 )
117 {
118 UINTN PciAddress;
119
120 PciAddress = (UINTN)Address;
121
122 //
123 // Preserve the original value
124 //
125 *OriginalValue = PciRead32 (PciAddress);
126
127 //
128 // Disable timer interrupt while the BAR is probed
129 //
130 DisableInterrupts ();
131
132 PciWrite32 (PciAddress, 0xFFFFFFFF);
133 *Value = PciRead32 (PciAddress);
134 PciWrite32 (PciAddress, *OriginalValue);
135
136 //
137 // Enable interrupt
138 //
139 EnableInterrupts ();
140 }
141
142 /**
143 Parse PCI bar and collect the assigned PCI resource information.
144
145 @param[in] Command Supported attributes.
146
147 @param[in] Bus PCI bus number.
148
149 @param[in] Device PCI device number.
150
151 @param[in] Function PCI function number.
152
153 @param[in] BarOffsetBase PCI bar start offset.
154
155 @param[in] BarOffsetEnd PCI bar end offset.
156
157 @param[in] Io IO aperture.
158
159 @param[in] Mem MMIO aperture.
160
161 @param[in] MemAbove4G MMIO aperture above 4G.
162
163 @param[in] PMem Prefetchable MMIO aperture.
164
165 @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.
166 **/
167 STATIC
168 VOID
169 PcatPciRootBridgeParseBars (
170 IN UINT16 Command,
171 IN UINTN Bus,
172 IN UINTN Device,
173 IN UINTN Function,
174 IN UINTN BarOffsetBase,
175 IN UINTN BarOffsetEnd,
176 IN PCI_ROOT_BRIDGE_APERTURE *Io,
177 IN PCI_ROOT_BRIDGE_APERTURE *Mem,
178 IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G,
179 IN PCI_ROOT_BRIDGE_APERTURE *PMem,
180 IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G
181
182 )
183 {
184 UINT32 OriginalValue;
185 UINT32 Value;
186 UINT32 OriginalUpperValue;
187 UINT32 UpperValue;
188 UINT64 Mask;
189 UINTN Offset;
190 UINTN LowBit;
191 UINT64 Base;
192 UINT64 Length;
193 UINT64 Limit;
194 PCI_ROOT_BRIDGE_APERTURE *MemAperture;
195
196 for (Offset = BarOffsetBase; Offset < BarOffsetEnd; Offset += sizeof (UINT32)) {
197 PcatPciRootBridgeBarExisted (
198 PCI_LIB_ADDRESS (Bus, Device, Function, Offset),
199 &OriginalValue, &Value
200 );
201 if (Value == 0) {
202 continue;
203 }
204 if ((Value & BIT0) == BIT0) {
205 //
206 // IO Bar
207 //
208 if (Command & EFI_PCI_COMMAND_IO_SPACE) {
209 Mask = 0xfffffffc;
210 Base = OriginalValue & Mask;
211 Length = ((~(Value & Mask)) & Mask) + 0x04;
212 if (!(Value & 0xFFFF0000)) {
213 Length &= 0x0000FFFF;
214 }
215 Limit = Base + Length - 1;
216
217 if ((Base > 0) && (Base < Limit)) {
218 if (Io->Base > Base) {
219 Io->Base = Base;
220 }
221 if (Io->Limit < Limit) {
222 Io->Limit = Limit;
223 }
224 }
225 }
226 } else {
227 //
228 // Mem Bar
229 //
230 if (Command & EFI_PCI_COMMAND_MEMORY_SPACE) {
231
232 Mask = 0xfffffff0;
233 Base = OriginalValue & Mask;
234 Length = Value & Mask;
235
236 if ((Value & (BIT1 | BIT2)) == 0) {
237 //
238 // 32bit
239 //
240 Length = ((~Length) + 1) & 0xffffffff;
241
242 if ((Value & BIT3) == BIT3) {
243 MemAperture = PMem;
244 } else {
245 MemAperture = Mem;
246 }
247 } else {
248 //
249 // 64bit
250 //
251 Offset += 4;
252 PcatPciRootBridgeBarExisted (
253 PCI_LIB_ADDRESS (Bus, Device, Function, Offset),
254 &OriginalUpperValue,
255 &UpperValue
256 );
257
258 Base = Base | LShiftU64 ((UINT64) OriginalUpperValue, 32);
259 Length = Length | LShiftU64 ((UINT64) UpperValue, 32);
260 if (Length != 0) {
261 LowBit = LowBitSet64 (Length);
262 Length = LShiftU64 (1ULL, LowBit);
263 }
264
265 if ((Value & BIT3) == BIT3) {
266 MemAperture = PMemAbove4G;
267 } else {
268 MemAperture = MemAbove4G;
269 }
270 }
271
272 Limit = Base + Length - 1;
273 if ((Base > 0) && (Base < Limit)) {
274 if (MemAperture->Base > Base) {
275 MemAperture->Base = Base;
276 }
277 if (MemAperture->Limit < Limit) {
278 MemAperture->Limit = Limit;
279 }
280 }
281 }
282 }
283 }
284 }
285
286 /**
287 Scan for all root bridges in platform.
288
289 @param[out] NumberOfRootBridges Number of root bridges detected
290
291 @retval Pointer to the allocated PCI_ROOT_BRIDGE structure array.
292 **/
293 PCI_ROOT_BRIDGE *
294 ScanForRootBridges (
295 OUT UINTN *NumberOfRootBridges
296 )
297 {
298 UINTN PrimaryBus;
299 UINTN SubBus;
300 UINT8 Device;
301 UINT8 Function;
302 UINTN NumberOfDevices;
303 UINTN Address;
304 PCI_TYPE01 Pci;
305 UINT64 Attributes;
306 UINT64 Base;
307 UINT64 Limit;
308 UINT64 Value;
309 PCI_ROOT_BRIDGE_APERTURE Io, Mem, MemAbove4G, PMem, PMemAbove4G, *MemAperture;
310 PCI_ROOT_BRIDGE *RootBridges;
311 UINTN BarOffsetEnd;
312
313
314 *NumberOfRootBridges = 0;
315 RootBridges = NULL;
316
317 //
318 // After scanning all the PCI devices on the PCI root bridge's primary bus,
319 // update the Primary Bus Number for the next PCI root bridge to be this PCI
320 // root bridge's subordinate bus number + 1.
321 //
322 for (PrimaryBus = 0; PrimaryBus <= PCI_MAX_BUS; PrimaryBus = SubBus + 1) {
323 SubBus = PrimaryBus;
324 Attributes = 0;
325
326 ZeroMem (&Io, sizeof (Io));
327 ZeroMem (&Mem, sizeof (Mem));
328 ZeroMem (&MemAbove4G, sizeof (MemAbove4G));
329 ZeroMem (&PMem, sizeof (PMem));
330 ZeroMem (&PMemAbove4G, sizeof (PMemAbove4G));
331 Io.Base = Mem.Base = MemAbove4G.Base = PMem.Base = PMemAbove4G.Base = MAX_UINT64;
332 //
333 // Scan all the PCI devices on the primary bus of the PCI root bridge
334 //
335 for (Device = 0, NumberOfDevices = 0; Device <= PCI_MAX_DEVICE; Device++) {
336
337 for (Function = 0; Function <= PCI_MAX_FUNC; Function++) {
338
339 //
340 // Compute the PCI configuration address of the PCI device to probe
341 //
342 Address = PCI_LIB_ADDRESS (PrimaryBus, Device, Function, 0);
343
344 //
345 // Read the Vendor ID from the PCI Configuration Header
346 //
347 if (PciRead16 (Address) == MAX_UINT16) {
348 if (Function == 0) {
349 //
350 // If the PCI Configuration Read fails, or a PCI device does not
351 // exist, then skip this entire PCI device
352 //
353 break;
354 } else {
355 //
356 // If PCI function != 0, VendorId == 0xFFFF, we continue to search
357 // PCI function.
358 //
359 continue;
360 }
361 }
362
363 //
364 // Read the entire PCI Configuration Header
365 //
366 PciReadBuffer (Address, sizeof (Pci), &Pci);
367
368 //
369 // Increment the number of PCI device found on the primary bus of the
370 // PCI root bridge
371 //
372 NumberOfDevices++;
373
374 //
375 // Look for devices with the VGA Palette Snoop enabled in the COMMAND
376 // register of the PCI Config Header
377 //
378 if ((Pci.Hdr.Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {
379 Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
380 Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16;
381 }
382
383 BarOffsetEnd = 0;
384
385 //
386 // PCI-PCI Bridge
387 //
388 if (IS_PCI_BRIDGE (&Pci)) {
389 //
390 // Get the Bus range that the PPB is decoding
391 //
392 if (Pci.Bridge.SubordinateBus > SubBus) {
393 //
394 // If the subordinate bus number of the PCI-PCI bridge is greater
395 // than the PCI root bridge's current subordinate bus number,
396 // then update the PCI root bridge's subordinate bus number
397 //
398 SubBus = Pci.Bridge.SubordinateBus;
399 }
400
401 //
402 // Get the I/O range that the PPB is decoding
403 //
404 Value = Pci.Bridge.IoBase & 0x0f;
405 Base = ((UINT32) Pci.Bridge.IoBase & 0xf0) << 8;
406 Limit = (((UINT32) Pci.Bridge.IoLimit & 0xf0) << 8) | 0x0fff;
407 if (Value == BIT0) {
408 Base |= ((UINT32) Pci.Bridge.IoBaseUpper16 << 16);
409 Limit |= ((UINT32) Pci.Bridge.IoLimitUpper16 << 16);
410 }
411 if ((Base > 0) && (Base < Limit)) {
412 if (Io.Base > Base) {
413 Io.Base = Base;
414 }
415 if (Io.Limit < Limit) {
416 Io.Limit = Limit;
417 }
418 }
419
420 //
421 // Get the Memory range that the PPB is decoding
422 //
423 Base = ((UINT32) Pci.Bridge.MemoryBase & 0xfff0) << 16;
424 Limit = (((UINT32) Pci.Bridge.MemoryLimit & 0xfff0) << 16) | 0xfffff;
425 if ((Base > 0) && (Base < Limit)) {
426 if (Mem.Base > Base) {
427 Mem.Base = Base;
428 }
429 if (Mem.Limit < Limit) {
430 Mem.Limit = Limit;
431 }
432 }
433
434 //
435 // Get the Prefetchable Memory range that the PPB is decoding
436 //
437 Value = Pci.Bridge.PrefetchableMemoryBase & 0x0f;
438 Base = ((UINT32) Pci.Bridge.PrefetchableMemoryBase & 0xfff0) << 16;
439 Limit = (((UINT32) Pci.Bridge.PrefetchableMemoryLimit & 0xfff0)
440 << 16) | 0xfffff;
441 MemAperture = &PMem;
442 if (Value == BIT0) {
443 Base |= LShiftU64 (Pci.Bridge.PrefetchableBaseUpper32, 32);
444 Limit |= LShiftU64 (Pci.Bridge.PrefetchableLimitUpper32, 32);
445 MemAperture = &PMemAbove4G;
446 }
447 if ((Base > 0) && (Base < Limit)) {
448 if (MemAperture->Base > Base) {
449 MemAperture->Base = Base;
450 }
451 if (MemAperture->Limit < Limit) {
452 MemAperture->Limit = Limit;
453 }
454 }
455
456 //
457 // Look at the PPB Configuration for legacy decoding attributes
458 //
459 if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA)
460 == EFI_PCI_BRIDGE_CONTROL_ISA) {
461 Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO;
462 Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO_16;
463 Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO;
464 }
465 if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA)
466 == EFI_PCI_BRIDGE_CONTROL_VGA) {
467 Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
468 Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY;
469 Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO;
470 if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16)
471 != 0) {
472 Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16;
473 Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO_16;
474 }
475 }
476
477 BarOffsetEnd = OFFSET_OF (PCI_TYPE01, Bridge.Bar[2]);
478 } else {
479 //
480 // Parse the BARs of the PCI device to get what I/O Ranges, Memory
481 // Ranges, and Prefetchable Memory Ranges the device is decoding
482 //
483 if ((Pci.Hdr.HeaderType & HEADER_LAYOUT_CODE) == HEADER_TYPE_DEVICE) {
484 BarOffsetEnd = OFFSET_OF (PCI_TYPE00, Device.Bar[6]);
485 }
486 }
487
488 PcatPciRootBridgeParseBars (
489 Pci.Hdr.Command,
490 PrimaryBus,
491 Device,
492 Function,
493 OFFSET_OF (PCI_TYPE00, Device.Bar),
494 BarOffsetEnd,
495 &Io,
496 &Mem, &MemAbove4G,
497 &PMem, &PMemAbove4G
498 );
499
500 //
501 // See if the PCI device is an IDE controller
502 //
503 if (IS_CLASS2 (&Pci, PCI_CLASS_MASS_STORAGE,
504 PCI_CLASS_MASS_STORAGE_IDE)) {
505 if (Pci.Hdr.ClassCode[0] & 0x80) {
506 Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO;
507 Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO;
508 }
509 if (Pci.Hdr.ClassCode[0] & 0x01) {
510 Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO;
511 }
512 if (Pci.Hdr.ClassCode[0] & 0x04) {
513 Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO;
514 }
515 }
516
517 //
518 // See if the PCI device is a legacy VGA controller or
519 // a standard VGA controller
520 //
521 if (IS_CLASS2 (&Pci, PCI_CLASS_OLD, PCI_CLASS_OLD_VGA) ||
522 IS_CLASS2 (&Pci, PCI_CLASS_DISPLAY, PCI_CLASS_DISPLAY_VGA)
523 ) {
524 Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
525 Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16;
526 Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY;
527 Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO;
528 Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO_16;
529 }
530
531 //
532 // See if the PCI Device is a PCI - ISA or PCI - EISA
533 // or ISA_POSITIVE_DECODE Bridge device
534 //
535 if (Pci.Hdr.ClassCode[2] == PCI_CLASS_BRIDGE) {
536 if (Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA ||
537 Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_EISA ||
538 Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA_PDECODE) {
539 Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO;
540 Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO_16;
541 Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO;
542 }
543 }
544
545 //
546 // If this device is not a multi function device, then skip the rest
547 // of this PCI device
548 //
549 if (Function == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
550 break;
551 }
552 }
553 }
554
555 //
556 // If at least one PCI device was found on the primary bus of this PCI
557 // root bridge, then the PCI root bridge exists.
558 //
559 if (NumberOfDevices > 0) {
560 RootBridges = ReallocatePool (
561 (*NumberOfRootBridges) * sizeof (PCI_ROOT_BRIDGE),
562 (*NumberOfRootBridges + 1) * sizeof (PCI_ROOT_BRIDGE),
563 RootBridges
564 );
565 ASSERT (RootBridges != NULL);
566
567 AdjustRootBridgeResource (&Io, &Mem, &MemAbove4G, &PMem, &PMemAbove4G);
568
569 InitRootBridge (
570 Attributes, Attributes, 0,
571 (UINT8) PrimaryBus, (UINT8) SubBus,
572 &Io, &Mem, &MemAbove4G, &PMem, &PMemAbove4G,
573 &RootBridges[*NumberOfRootBridges]
574 );
575 RootBridges[*NumberOfRootBridges].ResourceAssigned = TRUE;
576 //
577 // Increment the index for the next PCI Root Bridge
578 //
579 (*NumberOfRootBridges)++;
580 }
581 }
582
583 return RootBridges;
584 }