]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.c
OvmfPkg/PciHostBridgeUtilityLib: Initialize RootBridges apertures with spec
[mirror_edk2.git] / OvmfPkg / Library / PciHostBridgeUtilityLib / PciHostBridgeUtilityLib.c
CommitLineData
7a6172f8
JC
1/** @file\r
2 Provide common utility functions to PciHostBridgeLib instances in\r
3 ArmVirtPkg and OvmfPkg.\r
4\r
5 Copyright (C) 2016, Red Hat, Inc.\r
6 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
7 Copyright (c) 2020, Huawei Corporation. All rights reserved.<BR>\r
8\r
9 SPDX-License-Identifier: BSD-2-Clause-Patent\r
10\r
11**/\r
12\r
13#include <IndustryStandard/Acpi10.h>\r
4edba296 14#include <IndustryStandard/Pci.h>\r
3f5b1b91 15#include <Library/BaseLib.h>\r
7ac1f28d 16#include <Library/BaseMemoryLib.h>\r
7a6172f8 17#include <Library/DebugLib.h>\r
7ac1f28d 18#include <Library/DevicePathLib.h>\r
3f5b1b91 19#include <Library/HardwareInfoLib.h>\r
7ac1f28d 20#include <Library/MemoryAllocationLib.h>\r
7a6172f8 21#include <Library/PciHostBridgeUtilityLib.h>\r
4edba296
JC
22#include <Library/PciLib.h>\r
23#include <Library/QemuFwCfgLib.h>\r
3f5b1b91 24#include <Protocol/PciHostBridgeResourceAllocation.h>\r
7a6172f8 25\r
7ac1f28d
JC
26#pragma pack(1)\r
27typedef struct {\r
ac0a286f
MK
28 ACPI_HID_DEVICE_PATH AcpiDevicePath;\r
29 EFI_DEVICE_PATH_PROTOCOL EndDevicePath;\r
7ac1f28d
JC
30} OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH;\r
31#pragma pack ()\r
32\r
7a6172f8 33GLOBAL_REMOVE_IF_UNREFERENCED\r
ac0a286f 34CHAR16 *mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr[] = {\r
7a6172f8
JC
35 L"Mem", L"I/O", L"Bus"\r
36};\r
37\r
7ac1f28d
JC
38STATIC\r
39CONST\r
ac0a286f 40OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH mRootBridgeDevicePathTemplate = {\r
7ac1f28d
JC
41 {\r
42 {\r
43 ACPI_DEVICE_PATH,\r
44 ACPI_DP,\r
45 {\r
ac0a286f
MK
46 (UINT8)(sizeof (ACPI_HID_DEVICE_PATH)),\r
47 (UINT8)((sizeof (ACPI_HID_DEVICE_PATH)) >> 8)\r
7ac1f28d
JC
48 }\r
49 },\r
ac0a286f
MK
50 EISA_PNP_ID (0x0A03), // HID\r
51 0 // UID\r
7ac1f28d
JC
52 },\r
53\r
54 {\r
55 END_DEVICE_PATH_TYPE,\r
56 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
57 {\r
58 END_DEVICE_PATH_LENGTH,\r
59 0\r
60 }\r
61 }\r
62};\r
63\r
7ac1f28d
JC
64/**\r
65 Utility function to initialize a PCI_ROOT_BRIDGE structure.\r
66\r
e1b259da 67 @param[in] Supports Supported attributes.\r
7ac1f28d 68\r
e1b259da 69 @param[in] Attributes Initial attributes.\r
7ac1f28d 70\r
e1b259da 71 @param[in] AllocAttributes Allocation attributes.\r
7ac1f28d 72\r
e1b259da 73 @param[in] DmaAbove4G DMA above 4GB memory.\r
7ac1f28d 74\r
e1b259da 75 @param[in] NoExtendedConfigSpace No Extended Config Space.\r
7ac1f28d 76\r
e1b259da 77 @param[in] RootBusNumber The bus number to store in RootBus.\r
7ac1f28d 78\r
e1b259da
JC
79 @param[in] MaxSubBusNumber The inclusive maximum bus number that can\r
80 be assigned to any subordinate bus found\r
81 behind any PCI bridge hanging off this\r
82 root bus.\r
7ac1f28d 83\r
e1b259da
JC
84 The caller is repsonsible for ensuring\r
85 that RootBusNumber <= MaxSubBusNumber. If\r
86 RootBusNumber equals MaxSubBusNumber, then\r
87 the root bus has no room for subordinate\r
88 buses.\r
7ac1f28d 89\r
e1b259da 90 @param[in] Io IO aperture.\r
7ac1f28d 91\r
e1b259da 92 @param[in] Mem MMIO aperture.\r
7ac1f28d 93\r
e1b259da 94 @param[in] MemAbove4G MMIO aperture above 4G.\r
7ac1f28d 95\r
e1b259da 96 @param[in] PMem Prefetchable MMIO aperture.\r
7ac1f28d 97\r
e1b259da 98 @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.\r
7ac1f28d 99\r
e1b259da
JC
100 @param[out] RootBus The PCI_ROOT_BRIDGE structure (allocated\r
101 by the caller) that should be filled in by\r
102 this function.\r
103\r
104 @retval EFI_SUCCESS Initialization successful. A device path\r
105 consisting of an ACPI device path node,\r
106 with UID = RootBusNumber, has been\r
107 allocated and linked into RootBus.\r
108\r
109 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.\r
7ac1f28d
JC
110**/\r
111EFI_STATUS\r
112EFIAPI\r
113PciHostBridgeUtilityInitRootBridge (\r
ac0a286f
MK
114 IN UINT64 Supports,\r
115 IN UINT64 Attributes,\r
116 IN UINT64 AllocAttributes,\r
117 IN BOOLEAN DmaAbove4G,\r
118 IN BOOLEAN NoExtendedConfigSpace,\r
119 IN UINT8 RootBusNumber,\r
120 IN UINT8 MaxSubBusNumber,\r
121 IN PCI_ROOT_BRIDGE_APERTURE *Io,\r
122 IN PCI_ROOT_BRIDGE_APERTURE *Mem,\r
123 IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G,\r
124 IN PCI_ROOT_BRIDGE_APERTURE *PMem,\r
125 IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G,\r
126 OUT PCI_ROOT_BRIDGE *RootBus\r
7ac1f28d
JC
127 )\r
128{\r
ac0a286f 129 OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH *DevicePath;\r
7ac1f28d
JC
130\r
131 //\r
132 // Be safe if other fields are added to PCI_ROOT_BRIDGE later.\r
133 //\r
134 ZeroMem (RootBus, sizeof *RootBus);\r
135\r
136 RootBus->Segment = 0;\r
137\r
138 RootBus->Supports = Supports;\r
139 RootBus->Attributes = Attributes;\r
140\r
e1b259da 141 RootBus->DmaAbove4G = DmaAbove4G;\r
7ac1f28d
JC
142\r
143 RootBus->AllocationAttributes = AllocAttributes;\r
ac0a286f
MK
144 RootBus->Bus.Base = RootBusNumber;\r
145 RootBus->Bus.Limit = MaxSubBusNumber;\r
7ac1f28d
JC
146 CopyMem (&RootBus->Io, Io, sizeof (*Io));\r
147 CopyMem (&RootBus->Mem, Mem, sizeof (*Mem));\r
148 CopyMem (&RootBus->MemAbove4G, MemAbove4G, sizeof (*MemAbove4G));\r
149 CopyMem (&RootBus->PMem, PMem, sizeof (*PMem));\r
150 CopyMem (&RootBus->PMemAbove4G, PMemAbove4G, sizeof (*PMemAbove4G));\r
151\r
e1b259da 152 RootBus->NoExtendedConfigSpace = NoExtendedConfigSpace;\r
7ac1f28d 153\r
ac0a286f
MK
154 DevicePath = AllocateCopyPool (\r
155 sizeof mRootBridgeDevicePathTemplate,\r
156 &mRootBridgeDevicePathTemplate\r
157 );\r
7ac1f28d
JC
158 if (DevicePath == NULL) {\r
159 DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES));\r
160 return EFI_OUT_OF_RESOURCES;\r
161 }\r
ac0a286f 162\r
7ac1f28d 163 DevicePath->AcpiDevicePath.UID = RootBusNumber;\r
ac0a286f 164 RootBus->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;\r
7ac1f28d 165\r
ac0a286f
MK
166 DEBUG ((\r
167 DEBUG_INFO,\r
7ac1f28d 168 "%a: populated root bus %d, with room for %d subordinate bus(es)\n",\r
ac0a286f
MK
169 __FUNCTION__,\r
170 RootBusNumber,\r
171 MaxSubBusNumber - RootBusNumber\r
172 ));\r
7ac1f28d
JC
173 return EFI_SUCCESS;\r
174}\r
175\r
7ac1f28d
JC
176/**\r
177 Utility function to uninitialize a PCI_ROOT_BRIDGE structure set up with\r
178 PciHostBridgeUtilityInitRootBridge().\r
179\r
180 @param[in] RootBus The PCI_ROOT_BRIDGE structure, allocated by the caller and\r
181 initialized with PciHostBridgeUtilityInitRootBridge(),\r
182 that should be uninitialized. This function doesn't free\r
183 RootBus.\r
184**/\r
185VOID\r
186EFIAPI\r
187PciHostBridgeUtilityUninitRootBridge (\r
ac0a286f 188 IN PCI_ROOT_BRIDGE *RootBus\r
7ac1f28d
JC
189 )\r
190{\r
191 FreePool (RootBus->DevicePath);\r
192}\r
193\r
4edba296 194/**\r
3f5b1b91
NOL
195 Utility function to scan PCI root bridges and create instances for those\r
196 that are found not empty. Populate their resources from the default\r
197 provided parameters and return all the root bridge instances in an array.\r
4edba296 198\r
14d4b6be 199 @param[out] Count The number of root bridge instances.\r
4edba296 200\r
14d4b6be 201 @param[in] Attributes Initial attributes.\r
4edba296 202\r
14d4b6be 203 @param[in] AllocAttributes Allocation attributes.\r
4edba296 204\r
14d4b6be 205 @param[in] DmaAbove4G DMA above 4GB memory.\r
4edba296 206\r
14d4b6be 207 @param[in] NoExtendedConfigSpace No Extended Config Space.\r
4edba296 208\r
f4a257a3
JC
209 @param[in] BusMin Minimum Bus number, inclusive.\r
210\r
211 @param[in] BusMax Maximum Bus number, inclusive.\r
212\r
14d4b6be 213 @param[in] Io IO aperture.\r
4edba296 214\r
14d4b6be 215 @param[in] Mem MMIO aperture.\r
4edba296 216\r
14d4b6be 217 @param[in] MemAbove4G MMIO aperture above 4G.\r
4edba296 218\r
14d4b6be
JC
219 @param[in] PMem Prefetchable MMIO aperture.\r
220\r
221 @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.\r
222\r
223 @return All the root bridge instances in an array.\r
4edba296 224**/\r
3f5b1b91 225STATIC\r
4edba296 226PCI_ROOT_BRIDGE *\r
3f5b1b91 227PciHostBridgeUtilityGetRootBridgesBusScan (\r
ac0a286f
MK
228 OUT UINTN *Count,\r
229 IN UINT64 Attributes,\r
230 IN UINT64 AllocationAttributes,\r
231 IN BOOLEAN DmaAbove4G,\r
232 IN BOOLEAN NoExtendedConfigSpace,\r
233 IN UINTN BusMin,\r
234 IN UINTN BusMax,\r
235 IN PCI_ROOT_BRIDGE_APERTURE *Io,\r
236 IN PCI_ROOT_BRIDGE_APERTURE *Mem,\r
237 IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G,\r
238 IN PCI_ROOT_BRIDGE_APERTURE *PMem,\r
239 IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G\r
4edba296
JC
240 )\r
241{\r
ac0a286f
MK
242 EFI_STATUS Status;\r
243 FIRMWARE_CONFIG_ITEM FwCfgItem;\r
244 UINTN FwCfgSize;\r
245 UINT64 ExtraRootBridges;\r
246 PCI_ROOT_BRIDGE *Bridges;\r
247 UINTN Initialized;\r
248 UINTN LastRootBridgeNumber;\r
249 UINTN RootBridgeNumber;\r
4edba296 250\r
ac0a286f
MK
251 if ((BusMin > BusMax) || (BusMax > PCI_MAX_BUS)) {\r
252 DEBUG ((\r
253 DEBUG_ERROR,\r
254 "%a: invalid bus range with BusMin %Lu and BusMax "\r
255 "%Lu\n",\r
256 __FUNCTION__,\r
257 (UINT64)BusMin,\r
258 (UINT64)BusMax\r
259 ));\r
f4a257a3
JC
260 return NULL;\r
261 }\r
262\r
4edba296
JC
263 //\r
264 // QEMU provides the number of extra root buses, shortening the exhaustive\r
265 // search below. If there is no hint, the feature is missing.\r
266 //\r
267 Status = QemuFwCfgFindFile ("etc/extra-pci-roots", &FwCfgItem, &FwCfgSize);\r
ac0a286f 268 if (EFI_ERROR (Status) || (FwCfgSize != sizeof ExtraRootBridges)) {\r
4edba296
JC
269 ExtraRootBridges = 0;\r
270 } else {\r
271 QemuFwCfgSelectItem (FwCfgItem);\r
272 QemuFwCfgReadBytes (FwCfgSize, &ExtraRootBridges);\r
273\r
f4a257a3
JC
274 //\r
275 // Validate the number of extra root bridges. As BusMax is inclusive, the\r
276 // max bus count is (BusMax - BusMin + 1). From that, the "main" root bus\r
277 // is always a given, so the max count for the "extra" root bridges is one\r
278 // less, i.e. (BusMax - BusMin). If the QEMU hint exceeds that, we have\r
279 // invalid behavior.\r
280 //\r
281 if (ExtraRootBridges > BusMax - BusMin) {\r
ac0a286f
MK
282 DEBUG ((\r
283 DEBUG_ERROR,\r
284 "%a: invalid count of extra root buses (%Lu) "\r
285 "reported by QEMU\n",\r
286 __FUNCTION__,\r
287 ExtraRootBridges\r
288 ));\r
4edba296
JC
289 return NULL;\r
290 }\r
ac0a286f
MK
291\r
292 DEBUG ((\r
293 DEBUG_INFO,\r
294 "%a: %Lu extra root buses reported by QEMU\n",\r
295 __FUNCTION__,\r
296 ExtraRootBridges\r
297 ));\r
4edba296
JC
298 }\r
299\r
300 //\r
301 // Allocate the "main" root bridge, and any extra root bridges.\r
302 //\r
303 Bridges = AllocatePool ((1 + (UINTN)ExtraRootBridges) * sizeof *Bridges);\r
304 if (Bridges == NULL) {\r
305 DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES));\r
306 return NULL;\r
307 }\r
ac0a286f 308\r
4edba296
JC
309 Initialized = 0;\r
310\r
311 //\r
312 // The "main" root bus is always there.\r
313 //\r
f4a257a3 314 LastRootBridgeNumber = BusMin;\r
4edba296
JC
315\r
316 //\r
317 // Scan all other root buses. If function 0 of any device on a bus returns a\r
318 // VendorId register value different from all-bits-one, then that bus is\r
319 // alive.\r
320 //\r
f4a257a3
JC
321 for (RootBridgeNumber = BusMin + 1;\r
322 RootBridgeNumber <= BusMax && Initialized < ExtraRootBridges;\r
ac0a286f
MK
323 ++RootBridgeNumber)\r
324 {\r
325 UINTN Device;\r
4edba296
JC
326\r
327 for (Device = 0; Device <= PCI_MAX_DEVICE; ++Device) {\r
ac0a286f
MK
328 if (PciRead16 (\r
329 PCI_LIB_ADDRESS (\r
330 RootBridgeNumber,\r
331 Device,\r
332 0,\r
333 PCI_VENDOR_ID_OFFSET\r
334 )\r
335 ) != MAX_UINT16)\r
336 {\r
4edba296
JC
337 break;\r
338 }\r
339 }\r
ac0a286f 340\r
4edba296
JC
341 if (Device <= PCI_MAX_DEVICE) {\r
342 //\r
343 // Found the next root bus. We can now install the *previous* one,\r
344 // because now we know how big a bus number range *that* one has, for any\r
345 // subordinate buses that might exist behind PCI bridges hanging off it.\r
346 //\r
347 Status = PciHostBridgeUtilityInitRootBridge (\r
ac0a286f
MK
348 Attributes,\r
349 Attributes,\r
350 AllocationAttributes,\r
351 DmaAbove4G,\r
352 NoExtendedConfigSpace,\r
353 (UINT8)LastRootBridgeNumber,\r
354 (UINT8)(RootBridgeNumber - 1),\r
355 Io,\r
356 Mem,\r
357 MemAbove4G,\r
358 PMem,\r
359 PMemAbove4G,\r
360 &Bridges[Initialized]\r
361 );\r
4edba296
JC
362 if (EFI_ERROR (Status)) {\r
363 goto FreeBridges;\r
364 }\r
ac0a286f 365\r
4edba296
JC
366 ++Initialized;\r
367 LastRootBridgeNumber = RootBridgeNumber;\r
368 }\r
369 }\r
370\r
371 //\r
372 // Install the last root bus (which might be the only, ie. main, root bus, if\r
373 // we've found no extra root buses).\r
374 //\r
375 Status = PciHostBridgeUtilityInitRootBridge (\r
ac0a286f
MK
376 Attributes,\r
377 Attributes,\r
378 AllocationAttributes,\r
379 DmaAbove4G,\r
380 NoExtendedConfigSpace,\r
381 (UINT8)LastRootBridgeNumber,\r
382 (UINT8)BusMax,\r
383 Io,\r
384 Mem,\r
385 MemAbove4G,\r
386 PMem,\r
387 PMemAbove4G,\r
388 &Bridges[Initialized]\r
389 );\r
4edba296
JC
390 if (EFI_ERROR (Status)) {\r
391 goto FreeBridges;\r
392 }\r
ac0a286f 393\r
4edba296
JC
394 ++Initialized;\r
395\r
396 *Count = Initialized;\r
397 return Bridges;\r
398\r
399FreeBridges:\r
400 while (Initialized > 0) {\r
401 --Initialized;\r
402 PciHostBridgeUtilityUninitRootBridge (&Bridges[Initialized]);\r
403 }\r
404\r
405 FreePool (Bridges);\r
406 return NULL;\r
407}\r
408\r
3f5b1b91
NOL
409/**\r
410 Utility function to read root bridges information from host-provided fw-cfg\r
411 file and return them in an array.\r
412\r
413 @param[out] Count The number of root bridge instances.\r
414\r
415 @return All the root bridge instances in an array parsed from\r
416 host-provided fw-cfg file (hardware-info).\r
417**/\r
418STATIC\r
419PCI_ROOT_BRIDGE *\r
420PciHostBridgeUtilityGetRootBridgesHostProvided (\r
421 OUT UINTN *Count\r
422 )\r
423{\r
424 EFI_STATUS Status;\r
425 FIRMWARE_CONFIG_ITEM FwCfgItem;\r
426 UINTN FwCfgSize;\r
427 PCI_ROOT_BRIDGE *Bridges;\r
428 UINTN Initialized;\r
429 UINTN LastRootBridgeNumber;\r
430 UINTN RootBridgeNumber;\r
431 UINTN PciHostBridgeCount;\r
432 UINT8 *HardwareInfoBlob;\r
433 LIST_ENTRY HwInfoList;\r
434 LIST_ENTRY *HwLink;\r
435 HARDWARE_INFO *HwInfo;\r
436 UINT64 Attributes;\r
437 UINT64 AllocationAttributes;\r
438 BOOLEAN DmaAbove4G;\r
439 BOOLEAN NoExtendedConfigSpace;\r
440 BOOLEAN CombineMemPMem;\r
441 PCI_ROOT_BRIDGE_APERTURE Io;\r
442 PCI_ROOT_BRIDGE_APERTURE Mem;\r
443 PCI_ROOT_BRIDGE_APERTURE MemAbove4G;\r
444 PCI_ROOT_BRIDGE_APERTURE PMem;\r
445 PCI_ROOT_BRIDGE_APERTURE PMemAbove4G;\r
446\r
447 //\r
448 // Initialize the Hardware Info list head to start with an empty but valid\r
449 // list head.\r
450 //\r
451 InitializeListHead (&HwInfoList);\r
452 HardwareInfoBlob = NULL;\r
453 Initialized = 0;\r
454 Bridges = NULL;\r
455 PciHostBridgeCount = 0;\r
456\r
457 //\r
458 // Hypervisor can provide the specifications (resources) for one or more\r
459 // PCI host bridges. Such information comes through fw-cfg as part of\r
460 // the hardware-info file.\r
461 //\r
462 Status = QemuFwCfgFindFile ("etc/hardware-info", &FwCfgItem, &FwCfgSize);\r
463\r
464 if (EFI_ERROR (Status)) {\r
465 return NULL;\r
466 }\r
467\r
468 HardwareInfoBlob = AllocatePool (FwCfgSize);\r
469\r
470 if (HardwareInfoBlob == NULL) {\r
471 DEBUG ((\r
472 DEBUG_ERROR,\r
473 "%a: Failed to allocate memory for hardware resources info\n",\r
474 __FUNCTION__\r
475 ));\r
476 return NULL;\r
477 }\r
478\r
479 QemuFwCfgSelectItem (FwCfgItem);\r
480 QemuFwCfgReadBytes (FwCfgSize, HardwareInfoBlob);\r
481\r
482 //\r
483 // Create the list of hardware info devices filtering for PCI host\r
484 // bridges\r
485 //\r
486 Status = CreateHardwareInfoList (\r
487 HardwareInfoBlob,\r
488 FwCfgSize,\r
489 HardwareInfoTypeHostBridge,\r
490 &HwInfoList\r
491 );\r
492\r
493 if (EFI_ERROR (Status)) {\r
494 DEBUG ((\r
495 DEBUG_ERROR,\r
496 "%a: Failed to create hardware info list to retrieve host "\r
497 "bridges information from fw-cfg\n",\r
498 __FUNCTION__\r
499 ));\r
500\r
501 goto FreeBridges;\r
502 }\r
503\r
504 PciHostBridgeCount = GetHardwareInfoCountByType (\r
505 &HwInfoList,\r
506 HardwareInfoTypeHostBridge,\r
507 sizeof (HOST_BRIDGE_INFO)\r
508 );\r
509\r
510 if (PciHostBridgeCount == 0) {\r
511 goto FreeBridges;\r
512 }\r
513\r
514 DEBUG ((\r
515 DEBUG_INFO,\r
516 "%a: Host provided description for %Lu root bridges\n",\r
517 __FUNCTION__,\r
518 PciHostBridgeCount\r
519 ));\r
520\r
521 //\r
522 // Allocate the root bridges\r
523 //\r
524 Bridges = AllocatePool (((UINTN)PciHostBridgeCount) * sizeof *Bridges);\r
525 if (Bridges == NULL) {\r
526 DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES));\r
527 goto FreeBridges;\r
528 }\r
529\r
530 //\r
531 // If Host Bridges' specification was obtained from fw-cfg, the list\r
532 // contains information to populate all root bridges in the system\r
533 // including resources and attributes.\r
534 //\r
535 HwLink = GetFirstHardwareInfoByType (\r
536 &HwInfoList,\r
537 HardwareInfoTypeHostBridge,\r
538 sizeof (HOST_BRIDGE_INFO)\r
539 );\r
540\r
541 while (!EndOfHardwareInfoList (&HwInfoList, HwLink)) {\r
542 HwInfo = HARDWARE_INFO_FROM_LINK (HwLink);\r
543\r
544 Status = HardwareInfoPciHostBridgeGet (\r
545 HwInfo->Data.PciHostBridge,\r
546 (UINTN)HwInfo->Header.Size,\r
547 &RootBridgeNumber,\r
548 &LastRootBridgeNumber,\r
549 &Attributes,\r
550 &DmaAbove4G,\r
551 &NoExtendedConfigSpace,\r
552 &CombineMemPMem,\r
553 &Io,\r
554 &Mem,\r
555 &MemAbove4G,\r
556 &PMem,\r
557 &PMemAbove4G,\r
558 NULL\r
559 );\r
560\r
561 if (EFI_ERROR (Status)) {\r
562 goto FreeBridges;\r
563 }\r
564\r
565 if ((RootBridgeNumber > LastRootBridgeNumber) || (LastRootBridgeNumber > PCI_MAX_BUS)) {\r
566 DEBUG ((\r
567 DEBUG_ERROR,\r
568 "%a: invalid bus range with BusMin %Lu and BusMax "\r
569 "%Lu\n",\r
570 __FUNCTION__,\r
571 (UINT64)RootBridgeNumber,\r
572 (UINT64)LastRootBridgeNumber\r
573 ));\r
574 goto FreeBridges;\r
575 }\r
576\r
577 AllocationAttributes = 0;\r
578 if (CombineMemPMem) {\r
579 AllocationAttributes |= EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM;\r
580 }\r
581\r
582 if ((MemAbove4G.Limit > MemAbove4G.Base) ||\r
583 (PMemAbove4G.Limit > PMemAbove4G.Base))\r
584 {\r
585 AllocationAttributes |= EFI_PCI_HOST_BRIDGE_MEM64_DECODE;\r
586 }\r
587\r
588 Status = PciHostBridgeUtilityInitRootBridge (\r
589 Attributes,\r
590 Attributes,\r
591 AllocationAttributes,\r
592 DmaAbove4G,\r
593 NoExtendedConfigSpace,\r
594 (UINT8)RootBridgeNumber,\r
595 (UINT8)LastRootBridgeNumber,\r
596 &Io,\r
597 &Mem,\r
598 &MemAbove4G,\r
599 &PMem,\r
600 &PMemAbove4G,\r
601 &Bridges[Initialized]\r
602 );\r
603\r
604 if (EFI_ERROR (Status)) {\r
605 goto FreeBridges;\r
606 }\r
607\r
608 ++Initialized;\r
609\r
610 HwLink = GetNextHardwareInfoByType (\r
611 &HwInfoList,\r
612 HwLink,\r
613 HardwareInfoTypeHostBridge,\r
614 sizeof (HOST_BRIDGE_INFO)\r
615 );\r
616 }\r
617\r
618 *Count = Initialized;\r
619\r
620 //\r
621 // If resources were allocated for host bridges info, release them\r
622 //\r
623 if (HardwareInfoBlob) {\r
624 FreePool (HardwareInfoBlob);\r
625 }\r
626\r
627 FreeHardwareInfoList (&HwInfoList);\r
628 return Bridges;\r
629\r
630FreeBridges:\r
631 while (Initialized > 0) {\r
632 --Initialized;\r
633 PciHostBridgeUtilityUninitRootBridge (&Bridges[Initialized]);\r
634 }\r
635\r
636 if (Bridges) {\r
637 FreePool (Bridges);\r
638 }\r
639\r
640 if (HardwareInfoBlob) {\r
641 FreePool (HardwareInfoBlob);\r
642 }\r
643\r
644 FreeHardwareInfoList (&HwInfoList);\r
645 return NULL;\r
646}\r
647\r
648/**\r
649 Utility function to return all the root bridge instances in an array.\r
650\r
651 @param[out] Count The number of root bridge instances.\r
652\r
653 @param[in] Attributes Initial attributes.\r
654\r
655 @param[in] AllocAttributes Allocation attributes.\r
656\r
657 @param[in] DmaAbove4G DMA above 4GB memory.\r
658\r
659 @param[in] NoExtendedConfigSpace No Extended Config Space.\r
660\r
661 @param[in] BusMin Minimum Bus number, inclusive.\r
662\r
663 @param[in] BusMax Maximum Bus number, inclusive.\r
664\r
665 @param[in] Io IO aperture.\r
666\r
667 @param[in] Mem MMIO aperture.\r
668\r
669 @param[in] MemAbove4G MMIO aperture above 4G.\r
670\r
671 @param[in] PMem Prefetchable MMIO aperture.\r
672\r
673 @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.\r
674\r
675 @return All the root bridge instances in an array.\r
676**/\r
677PCI_ROOT_BRIDGE *\r
678EFIAPI\r
679PciHostBridgeUtilityGetRootBridges (\r
680 OUT UINTN *Count,\r
681 IN UINT64 Attributes,\r
682 IN UINT64 AllocationAttributes,\r
683 IN BOOLEAN DmaAbove4G,\r
684 IN BOOLEAN NoExtendedConfigSpace,\r
685 IN UINTN BusMin,\r
686 IN UINTN BusMax,\r
687 IN PCI_ROOT_BRIDGE_APERTURE *Io,\r
688 IN PCI_ROOT_BRIDGE_APERTURE *Mem,\r
689 IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G,\r
690 IN PCI_ROOT_BRIDGE_APERTURE *PMem,\r
691 IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G\r
692 )\r
693{\r
694 PCI_ROOT_BRIDGE *Bridges;\r
695\r
696 *Count = 0;\r
697\r
698 //\r
699 // First attempt to get the host provided descriptions of the Root Bridges\r
700 // if available.\r
701 //\r
702 Bridges = PciHostBridgeUtilityGetRootBridgesHostProvided (Count);\r
703\r
704 //\r
705 // If host did not provide Root Bridge information, scan the buses and\r
706 // auto populate them with default resources.\r
707 //\r
708 if (Bridges == NULL) {\r
709 Bridges = PciHostBridgeUtilityGetRootBridgesBusScan (\r
710 Count,\r
711 Attributes,\r
712 AllocationAttributes,\r
713 DmaAbove4G,\r
714 NoExtendedConfigSpace,\r
715 BusMin,\r
716 BusMax,\r
717 Io,\r
718 Mem,\r
719 MemAbove4G,\r
720 PMem,\r
721 PMemAbove4G\r
722 );\r
723 }\r
724\r
725 return Bridges;\r
726}\r
727\r
4edba296
JC
728/**\r
729 Utility function to free root bridge instances array from\r
730 PciHostBridgeUtilityGetRootBridges().\r
731\r
732 @param[in] Bridges The root bridge instances array.\r
733 @param[in] Count The count of the array.\r
734**/\r
735VOID\r
736EFIAPI\r
737PciHostBridgeUtilityFreeRootBridges (\r
ac0a286f
MK
738 IN PCI_ROOT_BRIDGE *Bridges,\r
739 IN UINTN Count\r
4edba296
JC
740 )\r
741{\r
ac0a286f 742 if ((Bridges == NULL) && (Count == 0)) {\r
4edba296
JC
743 return;\r
744 }\r
ac0a286f 745\r
4edba296
JC
746 ASSERT (Bridges != NULL && Count > 0);\r
747\r
748 do {\r
749 --Count;\r
750 PciHostBridgeUtilityUninitRootBridge (&Bridges[Count]);\r
751 } while (Count > 0);\r
752\r
753 FreePool (Bridges);\r
754}\r
755\r
7a6172f8
JC
756/**\r
757 Utility function to inform the platform that the resource conflict happens.\r
758\r
759 @param[in] Configuration Pointer to PCI I/O and PCI memory resource\r
760 descriptors. The Configuration contains the\r
761 resources for all the root bridges. The resource\r
762 for each root bridge is terminated with END\r
763 descriptor and an additional END is appended\r
764 indicating the end of the entire resources. The\r
765 resource descriptor field values follow the\r
766 description in\r
767 EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL\r
768 .SubmitResources().\r
769**/\r
770VOID\r
771EFIAPI\r
772PciHostBridgeUtilityResourceConflict (\r
773 IN VOID *Configuration\r
774 )\r
775{\r
ac0a286f
MK
776 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
777 UINTN RootBridgeIndex;\r
778\r
7a6172f8
JC
779 DEBUG ((DEBUG_ERROR, "PciHostBridge: Resource conflict happens!\n"));\r
780\r
781 RootBridgeIndex = 0;\r
ac0a286f 782 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Configuration;\r
7a6172f8
JC
783 while (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) {\r
784 DEBUG ((DEBUG_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++));\r
ac0a286f
MK
785 for ( ; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {\r
786 ASSERT (\r
787 Descriptor->ResType <\r
788 ARRAY_SIZE (mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr)\r
789 );\r
790 DEBUG ((\r
791 DEBUG_ERROR,\r
792 " %s: Length/Alignment = 0x%lx / 0x%lx\n",\r
793 mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr[Descriptor->ResType],\r
794 Descriptor->AddrLen,\r
795 Descriptor->AddrRangeMax\r
796 ));\r
7a6172f8 797 if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {\r
ac0a286f
MK
798 DEBUG ((\r
799 DEBUG_ERROR,\r
800 " Granularity/SpecificFlag = %ld / %02x%s\n",\r
801 Descriptor->AddrSpaceGranularity,\r
802 Descriptor->SpecificFlag,\r
803 ((Descriptor->SpecificFlag &\r
804 EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE\r
805 ) != 0) ? L" (Prefetchable)" : L""\r
806 ));\r
7a6172f8
JC
807 }\r
808 }\r
ac0a286f 809\r
7a6172f8
JC
810 //\r
811 // Skip the END descriptor for root bridge\r
812 //\r
813 ASSERT (Descriptor->Desc == ACPI_END_TAG_DESCRIPTOR);\r
814 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(\r
ac0a286f
MK
815 (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor + 1\r
816 );\r
7a6172f8
JC
817 }\r
818}\r