]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.c
OvmfPkg: Apply uncrustify changes
[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
7ac1f28d 15#include <Library/BaseMemoryLib.h>\r
7a6172f8 16#include <Library/DebugLib.h>\r
7ac1f28d
JC
17#include <Library/DevicePathLib.h>\r
18#include <Library/MemoryAllocationLib.h>\r
7a6172f8 19#include <Library/PciHostBridgeUtilityLib.h>\r
4edba296
JC
20#include <Library/PciLib.h>\r
21#include <Library/QemuFwCfgLib.h>\r
7a6172f8 22\r
7ac1f28d
JC
23#pragma pack(1)\r
24typedef struct {\r
ac0a286f
MK
25 ACPI_HID_DEVICE_PATH AcpiDevicePath;\r
26 EFI_DEVICE_PATH_PROTOCOL EndDevicePath;\r
7ac1f28d
JC
27} OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH;\r
28#pragma pack ()\r
29\r
7a6172f8 30GLOBAL_REMOVE_IF_UNREFERENCED\r
ac0a286f 31CHAR16 *mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr[] = {\r
7a6172f8
JC
32 L"Mem", L"I/O", L"Bus"\r
33};\r
34\r
7ac1f28d
JC
35STATIC\r
36CONST\r
ac0a286f 37OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH mRootBridgeDevicePathTemplate = {\r
7ac1f28d
JC
38 {\r
39 {\r
40 ACPI_DEVICE_PATH,\r
41 ACPI_DP,\r
42 {\r
ac0a286f
MK
43 (UINT8)(sizeof (ACPI_HID_DEVICE_PATH)),\r
44 (UINT8)((sizeof (ACPI_HID_DEVICE_PATH)) >> 8)\r
7ac1f28d
JC
45 }\r
46 },\r
ac0a286f
MK
47 EISA_PNP_ID (0x0A03), // HID\r
48 0 // UID\r
7ac1f28d
JC
49 },\r
50\r
51 {\r
52 END_DEVICE_PATH_TYPE,\r
53 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
54 {\r
55 END_DEVICE_PATH_LENGTH,\r
56 0\r
57 }\r
58 }\r
59};\r
60\r
7ac1f28d
JC
61/**\r
62 Utility function to initialize a PCI_ROOT_BRIDGE structure.\r
63\r
e1b259da 64 @param[in] Supports Supported attributes.\r
7ac1f28d 65\r
e1b259da 66 @param[in] Attributes Initial attributes.\r
7ac1f28d 67\r
e1b259da 68 @param[in] AllocAttributes Allocation attributes.\r
7ac1f28d 69\r
e1b259da 70 @param[in] DmaAbove4G DMA above 4GB memory.\r
7ac1f28d 71\r
e1b259da 72 @param[in] NoExtendedConfigSpace No Extended Config Space.\r
7ac1f28d 73\r
e1b259da 74 @param[in] RootBusNumber The bus number to store in RootBus.\r
7ac1f28d 75\r
e1b259da
JC
76 @param[in] MaxSubBusNumber The inclusive maximum bus number that can\r
77 be assigned to any subordinate bus found\r
78 behind any PCI bridge hanging off this\r
79 root bus.\r
7ac1f28d 80\r
e1b259da
JC
81 The caller is repsonsible for ensuring\r
82 that RootBusNumber <= MaxSubBusNumber. If\r
83 RootBusNumber equals MaxSubBusNumber, then\r
84 the root bus has no room for subordinate\r
85 buses.\r
7ac1f28d 86\r
e1b259da 87 @param[in] Io IO aperture.\r
7ac1f28d 88\r
e1b259da 89 @param[in] Mem MMIO aperture.\r
7ac1f28d 90\r
e1b259da 91 @param[in] MemAbove4G MMIO aperture above 4G.\r
7ac1f28d 92\r
e1b259da 93 @param[in] PMem Prefetchable MMIO aperture.\r
7ac1f28d 94\r
e1b259da 95 @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.\r
7ac1f28d 96\r
e1b259da
JC
97 @param[out] RootBus The PCI_ROOT_BRIDGE structure (allocated\r
98 by the caller) that should be filled in by\r
99 this function.\r
100\r
101 @retval EFI_SUCCESS Initialization successful. A device path\r
102 consisting of an ACPI device path node,\r
103 with UID = RootBusNumber, has been\r
104 allocated and linked into RootBus.\r
105\r
106 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.\r
7ac1f28d
JC
107**/\r
108EFI_STATUS\r
109EFIAPI\r
110PciHostBridgeUtilityInitRootBridge (\r
ac0a286f
MK
111 IN UINT64 Supports,\r
112 IN UINT64 Attributes,\r
113 IN UINT64 AllocAttributes,\r
114 IN BOOLEAN DmaAbove4G,\r
115 IN BOOLEAN NoExtendedConfigSpace,\r
116 IN UINT8 RootBusNumber,\r
117 IN UINT8 MaxSubBusNumber,\r
118 IN PCI_ROOT_BRIDGE_APERTURE *Io,\r
119 IN PCI_ROOT_BRIDGE_APERTURE *Mem,\r
120 IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G,\r
121 IN PCI_ROOT_BRIDGE_APERTURE *PMem,\r
122 IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G,\r
123 OUT PCI_ROOT_BRIDGE *RootBus\r
7ac1f28d
JC
124 )\r
125{\r
ac0a286f 126 OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH *DevicePath;\r
7ac1f28d
JC
127\r
128 //\r
129 // Be safe if other fields are added to PCI_ROOT_BRIDGE later.\r
130 //\r
131 ZeroMem (RootBus, sizeof *RootBus);\r
132\r
133 RootBus->Segment = 0;\r
134\r
135 RootBus->Supports = Supports;\r
136 RootBus->Attributes = Attributes;\r
137\r
e1b259da 138 RootBus->DmaAbove4G = DmaAbove4G;\r
7ac1f28d
JC
139\r
140 RootBus->AllocationAttributes = AllocAttributes;\r
ac0a286f
MK
141 RootBus->Bus.Base = RootBusNumber;\r
142 RootBus->Bus.Limit = MaxSubBusNumber;\r
7ac1f28d
JC
143 CopyMem (&RootBus->Io, Io, sizeof (*Io));\r
144 CopyMem (&RootBus->Mem, Mem, sizeof (*Mem));\r
145 CopyMem (&RootBus->MemAbove4G, MemAbove4G, sizeof (*MemAbove4G));\r
146 CopyMem (&RootBus->PMem, PMem, sizeof (*PMem));\r
147 CopyMem (&RootBus->PMemAbove4G, PMemAbove4G, sizeof (*PMemAbove4G));\r
148\r
e1b259da 149 RootBus->NoExtendedConfigSpace = NoExtendedConfigSpace;\r
7ac1f28d 150\r
ac0a286f
MK
151 DevicePath = AllocateCopyPool (\r
152 sizeof mRootBridgeDevicePathTemplate,\r
153 &mRootBridgeDevicePathTemplate\r
154 );\r
7ac1f28d
JC
155 if (DevicePath == NULL) {\r
156 DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES));\r
157 return EFI_OUT_OF_RESOURCES;\r
158 }\r
ac0a286f 159\r
7ac1f28d 160 DevicePath->AcpiDevicePath.UID = RootBusNumber;\r
ac0a286f 161 RootBus->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;\r
7ac1f28d 162\r
ac0a286f
MK
163 DEBUG ((\r
164 DEBUG_INFO,\r
7ac1f28d 165 "%a: populated root bus %d, with room for %d subordinate bus(es)\n",\r
ac0a286f
MK
166 __FUNCTION__,\r
167 RootBusNumber,\r
168 MaxSubBusNumber - RootBusNumber\r
169 ));\r
7ac1f28d
JC
170 return EFI_SUCCESS;\r
171}\r
172\r
7ac1f28d
JC
173/**\r
174 Utility function to uninitialize a PCI_ROOT_BRIDGE structure set up with\r
175 PciHostBridgeUtilityInitRootBridge().\r
176\r
177 @param[in] RootBus The PCI_ROOT_BRIDGE structure, allocated by the caller and\r
178 initialized with PciHostBridgeUtilityInitRootBridge(),\r
179 that should be uninitialized. This function doesn't free\r
180 RootBus.\r
181**/\r
182VOID\r
183EFIAPI\r
184PciHostBridgeUtilityUninitRootBridge (\r
ac0a286f 185 IN PCI_ROOT_BRIDGE *RootBus\r
7ac1f28d
JC
186 )\r
187{\r
188 FreePool (RootBus->DevicePath);\r
189}\r
190\r
4edba296
JC
191/**\r
192 Utility function to return all the root bridge instances in an array.\r
193\r
14d4b6be 194 @param[out] Count The number of root bridge instances.\r
4edba296 195\r
14d4b6be 196 @param[in] Attributes Initial attributes.\r
4edba296 197\r
14d4b6be 198 @param[in] AllocAttributes Allocation attributes.\r
4edba296 199\r
14d4b6be 200 @param[in] DmaAbove4G DMA above 4GB memory.\r
4edba296 201\r
14d4b6be 202 @param[in] NoExtendedConfigSpace No Extended Config Space.\r
4edba296 203\r
f4a257a3
JC
204 @param[in] BusMin Minimum Bus number, inclusive.\r
205\r
206 @param[in] BusMax Maximum Bus number, inclusive.\r
207\r
14d4b6be 208 @param[in] Io IO aperture.\r
4edba296 209\r
14d4b6be 210 @param[in] Mem MMIO aperture.\r
4edba296 211\r
14d4b6be 212 @param[in] MemAbove4G MMIO aperture above 4G.\r
4edba296 213\r
14d4b6be
JC
214 @param[in] PMem Prefetchable MMIO aperture.\r
215\r
216 @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.\r
217\r
218 @return All the root bridge instances in an array.\r
4edba296
JC
219**/\r
220PCI_ROOT_BRIDGE *\r
221EFIAPI\r
222PciHostBridgeUtilityGetRootBridges (\r
ac0a286f
MK
223 OUT UINTN *Count,\r
224 IN UINT64 Attributes,\r
225 IN UINT64 AllocationAttributes,\r
226 IN BOOLEAN DmaAbove4G,\r
227 IN BOOLEAN NoExtendedConfigSpace,\r
228 IN UINTN BusMin,\r
229 IN UINTN BusMax,\r
230 IN PCI_ROOT_BRIDGE_APERTURE *Io,\r
231 IN PCI_ROOT_BRIDGE_APERTURE *Mem,\r
232 IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G,\r
233 IN PCI_ROOT_BRIDGE_APERTURE *PMem,\r
234 IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G\r
4edba296
JC
235 )\r
236{\r
ac0a286f
MK
237 EFI_STATUS Status;\r
238 FIRMWARE_CONFIG_ITEM FwCfgItem;\r
239 UINTN FwCfgSize;\r
240 UINT64 ExtraRootBridges;\r
241 PCI_ROOT_BRIDGE *Bridges;\r
242 UINTN Initialized;\r
243 UINTN LastRootBridgeNumber;\r
244 UINTN RootBridgeNumber;\r
4edba296
JC
245\r
246 *Count = 0;\r
247\r
ac0a286f
MK
248 if ((BusMin > BusMax) || (BusMax > PCI_MAX_BUS)) {\r
249 DEBUG ((\r
250 DEBUG_ERROR,\r
251 "%a: invalid bus range with BusMin %Lu and BusMax "\r
252 "%Lu\n",\r
253 __FUNCTION__,\r
254 (UINT64)BusMin,\r
255 (UINT64)BusMax\r
256 ));\r
f4a257a3
JC
257 return NULL;\r
258 }\r
259\r
4edba296
JC
260 //\r
261 // QEMU provides the number of extra root buses, shortening the exhaustive\r
262 // search below. If there is no hint, the feature is missing.\r
263 //\r
264 Status = QemuFwCfgFindFile ("etc/extra-pci-roots", &FwCfgItem, &FwCfgSize);\r
ac0a286f 265 if (EFI_ERROR (Status) || (FwCfgSize != sizeof ExtraRootBridges)) {\r
4edba296
JC
266 ExtraRootBridges = 0;\r
267 } else {\r
268 QemuFwCfgSelectItem (FwCfgItem);\r
269 QemuFwCfgReadBytes (FwCfgSize, &ExtraRootBridges);\r
270\r
f4a257a3
JC
271 //\r
272 // Validate the number of extra root bridges. As BusMax is inclusive, the\r
273 // max bus count is (BusMax - BusMin + 1). From that, the "main" root bus\r
274 // is always a given, so the max count for the "extra" root bridges is one\r
275 // less, i.e. (BusMax - BusMin). If the QEMU hint exceeds that, we have\r
276 // invalid behavior.\r
277 //\r
278 if (ExtraRootBridges > BusMax - BusMin) {\r
ac0a286f
MK
279 DEBUG ((\r
280 DEBUG_ERROR,\r
281 "%a: invalid count of extra root buses (%Lu) "\r
282 "reported by QEMU\n",\r
283 __FUNCTION__,\r
284 ExtraRootBridges\r
285 ));\r
4edba296
JC
286 return NULL;\r
287 }\r
ac0a286f
MK
288\r
289 DEBUG ((\r
290 DEBUG_INFO,\r
291 "%a: %Lu extra root buses reported by QEMU\n",\r
292 __FUNCTION__,\r
293 ExtraRootBridges\r
294 ));\r
4edba296
JC
295 }\r
296\r
297 //\r
298 // Allocate the "main" root bridge, and any extra root bridges.\r
299 //\r
300 Bridges = AllocatePool ((1 + (UINTN)ExtraRootBridges) * sizeof *Bridges);\r
301 if (Bridges == NULL) {\r
302 DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES));\r
303 return NULL;\r
304 }\r
ac0a286f 305\r
4edba296
JC
306 Initialized = 0;\r
307\r
308 //\r
309 // The "main" root bus is always there.\r
310 //\r
f4a257a3 311 LastRootBridgeNumber = BusMin;\r
4edba296
JC
312\r
313 //\r
314 // Scan all other root buses. If function 0 of any device on a bus returns a\r
315 // VendorId register value different from all-bits-one, then that bus is\r
316 // alive.\r
317 //\r
f4a257a3
JC
318 for (RootBridgeNumber = BusMin + 1;\r
319 RootBridgeNumber <= BusMax && Initialized < ExtraRootBridges;\r
ac0a286f
MK
320 ++RootBridgeNumber)\r
321 {\r
322 UINTN Device;\r
4edba296
JC
323\r
324 for (Device = 0; Device <= PCI_MAX_DEVICE; ++Device) {\r
ac0a286f
MK
325 if (PciRead16 (\r
326 PCI_LIB_ADDRESS (\r
327 RootBridgeNumber,\r
328 Device,\r
329 0,\r
330 PCI_VENDOR_ID_OFFSET\r
331 )\r
332 ) != MAX_UINT16)\r
333 {\r
4edba296
JC
334 break;\r
335 }\r
336 }\r
ac0a286f 337\r
4edba296
JC
338 if (Device <= PCI_MAX_DEVICE) {\r
339 //\r
340 // Found the next root bus. We can now install the *previous* one,\r
341 // because now we know how big a bus number range *that* one has, for any\r
342 // subordinate buses that might exist behind PCI bridges hanging off it.\r
343 //\r
344 Status = PciHostBridgeUtilityInitRootBridge (\r
ac0a286f
MK
345 Attributes,\r
346 Attributes,\r
347 AllocationAttributes,\r
348 DmaAbove4G,\r
349 NoExtendedConfigSpace,\r
350 (UINT8)LastRootBridgeNumber,\r
351 (UINT8)(RootBridgeNumber - 1),\r
352 Io,\r
353 Mem,\r
354 MemAbove4G,\r
355 PMem,\r
356 PMemAbove4G,\r
357 &Bridges[Initialized]\r
358 );\r
4edba296
JC
359 if (EFI_ERROR (Status)) {\r
360 goto FreeBridges;\r
361 }\r
ac0a286f 362\r
4edba296
JC
363 ++Initialized;\r
364 LastRootBridgeNumber = RootBridgeNumber;\r
365 }\r
366 }\r
367\r
368 //\r
369 // Install the last root bus (which might be the only, ie. main, root bus, if\r
370 // we've found no extra root buses).\r
371 //\r
372 Status = PciHostBridgeUtilityInitRootBridge (\r
ac0a286f
MK
373 Attributes,\r
374 Attributes,\r
375 AllocationAttributes,\r
376 DmaAbove4G,\r
377 NoExtendedConfigSpace,\r
378 (UINT8)LastRootBridgeNumber,\r
379 (UINT8)BusMax,\r
380 Io,\r
381 Mem,\r
382 MemAbove4G,\r
383 PMem,\r
384 PMemAbove4G,\r
385 &Bridges[Initialized]\r
386 );\r
4edba296
JC
387 if (EFI_ERROR (Status)) {\r
388 goto FreeBridges;\r
389 }\r
ac0a286f 390\r
4edba296
JC
391 ++Initialized;\r
392\r
393 *Count = Initialized;\r
394 return Bridges;\r
395\r
396FreeBridges:\r
397 while (Initialized > 0) {\r
398 --Initialized;\r
399 PciHostBridgeUtilityUninitRootBridge (&Bridges[Initialized]);\r
400 }\r
401\r
402 FreePool (Bridges);\r
403 return NULL;\r
404}\r
405\r
4edba296
JC
406/**\r
407 Utility function to free root bridge instances array from\r
408 PciHostBridgeUtilityGetRootBridges().\r
409\r
410 @param[in] Bridges The root bridge instances array.\r
411 @param[in] Count The count of the array.\r
412**/\r
413VOID\r
414EFIAPI\r
415PciHostBridgeUtilityFreeRootBridges (\r
ac0a286f
MK
416 IN PCI_ROOT_BRIDGE *Bridges,\r
417 IN UINTN Count\r
4edba296
JC
418 )\r
419{\r
ac0a286f 420 if ((Bridges == NULL) && (Count == 0)) {\r
4edba296
JC
421 return;\r
422 }\r
ac0a286f 423\r
4edba296
JC
424 ASSERT (Bridges != NULL && Count > 0);\r
425\r
426 do {\r
427 --Count;\r
428 PciHostBridgeUtilityUninitRootBridge (&Bridges[Count]);\r
429 } while (Count > 0);\r
430\r
431 FreePool (Bridges);\r
432}\r
433\r
7a6172f8
JC
434/**\r
435 Utility function to inform the platform that the resource conflict happens.\r
436\r
437 @param[in] Configuration Pointer to PCI I/O and PCI memory resource\r
438 descriptors. The Configuration contains the\r
439 resources for all the root bridges. The resource\r
440 for each root bridge is terminated with END\r
441 descriptor and an additional END is appended\r
442 indicating the end of the entire resources. The\r
443 resource descriptor field values follow the\r
444 description in\r
445 EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL\r
446 .SubmitResources().\r
447**/\r
448VOID\r
449EFIAPI\r
450PciHostBridgeUtilityResourceConflict (\r
451 IN VOID *Configuration\r
452 )\r
453{\r
ac0a286f
MK
454 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
455 UINTN RootBridgeIndex;\r
456\r
7a6172f8
JC
457 DEBUG ((DEBUG_ERROR, "PciHostBridge: Resource conflict happens!\n"));\r
458\r
459 RootBridgeIndex = 0;\r
ac0a286f 460 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Configuration;\r
7a6172f8
JC
461 while (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) {\r
462 DEBUG ((DEBUG_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++));\r
ac0a286f
MK
463 for ( ; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {\r
464 ASSERT (\r
465 Descriptor->ResType <\r
466 ARRAY_SIZE (mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr)\r
467 );\r
468 DEBUG ((\r
469 DEBUG_ERROR,\r
470 " %s: Length/Alignment = 0x%lx / 0x%lx\n",\r
471 mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr[Descriptor->ResType],\r
472 Descriptor->AddrLen,\r
473 Descriptor->AddrRangeMax\r
474 ));\r
7a6172f8 475 if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {\r
ac0a286f
MK
476 DEBUG ((\r
477 DEBUG_ERROR,\r
478 " Granularity/SpecificFlag = %ld / %02x%s\n",\r
479 Descriptor->AddrSpaceGranularity,\r
480 Descriptor->SpecificFlag,\r
481 ((Descriptor->SpecificFlag &\r
482 EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE\r
483 ) != 0) ? L" (Prefetchable)" : L""\r
484 ));\r
7a6172f8
JC
485 }\r
486 }\r
ac0a286f 487\r
7a6172f8
JC
488 //\r
489 // Skip the END descriptor for root bridge\r
490 //\r
491 ASSERT (Descriptor->Desc == ACPI_END_TAG_DESCRIPTOR);\r
492 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(\r
ac0a286f
MK
493 (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor + 1\r
494 );\r
7a6172f8
JC
495 }\r
496}\r