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