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