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