]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.c
OvmfPkg/PciHostBridgeUtilityLib: Extend parameter list of GetRootBridges
[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] Io IO aperture.
204
205 @param[in] Mem MMIO aperture.
206
207 @param[in] MemAbove4G MMIO aperture above 4G.
208
209 @param[in] PMem Prefetchable MMIO aperture.
210
211 @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.
212
213 @return All the root bridge instances in an array.
214 **/
215 PCI_ROOT_BRIDGE *
216 EFIAPI
217 PciHostBridgeUtilityGetRootBridges (
218 OUT UINTN *Count,
219 IN UINT64 Attributes,
220 IN UINT64 AllocationAttributes,
221 IN BOOLEAN DmaAbove4G,
222 IN BOOLEAN NoExtendedConfigSpace,
223 IN PCI_ROOT_BRIDGE_APERTURE *Io,
224 IN PCI_ROOT_BRIDGE_APERTURE *Mem,
225 IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G,
226 IN PCI_ROOT_BRIDGE_APERTURE *PMem,
227 IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G
228 )
229 {
230 EFI_STATUS Status;
231 FIRMWARE_CONFIG_ITEM FwCfgItem;
232 UINTN FwCfgSize;
233 UINT64 ExtraRootBridges;
234 PCI_ROOT_BRIDGE *Bridges;
235 UINTN Initialized;
236 UINTN LastRootBridgeNumber;
237 UINTN RootBridgeNumber;
238
239 *Count = 0;
240
241 //
242 // QEMU provides the number of extra root buses, shortening the exhaustive
243 // search below. If there is no hint, the feature is missing.
244 //
245 Status = QemuFwCfgFindFile ("etc/extra-pci-roots", &FwCfgItem, &FwCfgSize);
246 if (EFI_ERROR (Status) || FwCfgSize != sizeof ExtraRootBridges) {
247 ExtraRootBridges = 0;
248 } else {
249 QemuFwCfgSelectItem (FwCfgItem);
250 QemuFwCfgReadBytes (FwCfgSize, &ExtraRootBridges);
251
252 if (ExtraRootBridges > PCI_MAX_BUS) {
253 DEBUG ((DEBUG_ERROR, "%a: invalid count of extra root buses (%Lu) "
254 "reported by QEMU\n", __FUNCTION__, ExtraRootBridges));
255 return NULL;
256 }
257 DEBUG ((DEBUG_INFO, "%a: %Lu extra root buses reported by QEMU\n",
258 __FUNCTION__, ExtraRootBridges));
259 }
260
261 //
262 // Allocate the "main" root bridge, and any extra root bridges.
263 //
264 Bridges = AllocatePool ((1 + (UINTN)ExtraRootBridges) * sizeof *Bridges);
265 if (Bridges == NULL) {
266 DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES));
267 return NULL;
268 }
269 Initialized = 0;
270
271 //
272 // The "main" root bus is always there.
273 //
274 LastRootBridgeNumber = 0;
275
276 //
277 // Scan all other root buses. If function 0 of any device on a bus returns a
278 // VendorId register value different from all-bits-one, then that bus is
279 // alive.
280 //
281 for (RootBridgeNumber = 1;
282 RootBridgeNumber <= PCI_MAX_BUS && Initialized < ExtraRootBridges;
283 ++RootBridgeNumber) {
284 UINTN Device;
285
286 for (Device = 0; Device <= PCI_MAX_DEVICE; ++Device) {
287 if (PciRead16 (PCI_LIB_ADDRESS (RootBridgeNumber, Device, 0,
288 PCI_VENDOR_ID_OFFSET)) != MAX_UINT16) {
289 break;
290 }
291 }
292 if (Device <= PCI_MAX_DEVICE) {
293 //
294 // Found the next root bus. We can now install the *previous* one,
295 // because now we know how big a bus number range *that* one has, for any
296 // subordinate buses that might exist behind PCI bridges hanging off it.
297 //
298 Status = PciHostBridgeUtilityInitRootBridge (
299 Attributes,
300 Attributes,
301 AllocationAttributes,
302 DmaAbove4G,
303 NoExtendedConfigSpace,
304 (UINT8) LastRootBridgeNumber,
305 (UINT8) (RootBridgeNumber - 1),
306 Io,
307 Mem,
308 MemAbove4G,
309 PMem,
310 PMemAbove4G,
311 &Bridges[Initialized]
312 );
313 if (EFI_ERROR (Status)) {
314 goto FreeBridges;
315 }
316 ++Initialized;
317 LastRootBridgeNumber = RootBridgeNumber;
318 }
319 }
320
321 //
322 // Install the last root bus (which might be the only, ie. main, root bus, if
323 // we've found no extra root buses).
324 //
325 Status = PciHostBridgeUtilityInitRootBridge (
326 Attributes,
327 Attributes,
328 AllocationAttributes,
329 DmaAbove4G,
330 NoExtendedConfigSpace,
331 (UINT8) LastRootBridgeNumber,
332 PCI_MAX_BUS,
333 Io,
334 Mem,
335 MemAbove4G,
336 PMem,
337 PMemAbove4G,
338 &Bridges[Initialized]
339 );
340 if (EFI_ERROR (Status)) {
341 goto FreeBridges;
342 }
343 ++Initialized;
344
345 *Count = Initialized;
346 return Bridges;
347
348 FreeBridges:
349 while (Initialized > 0) {
350 --Initialized;
351 PciHostBridgeUtilityUninitRootBridge (&Bridges[Initialized]);
352 }
353
354 FreePool (Bridges);
355 return NULL;
356 }
357
358
359 /**
360 Utility function to free root bridge instances array from
361 PciHostBridgeUtilityGetRootBridges().
362
363 @param[in] Bridges The root bridge instances array.
364 @param[in] Count The count of the array.
365 **/
366 VOID
367 EFIAPI
368 PciHostBridgeUtilityFreeRootBridges (
369 IN PCI_ROOT_BRIDGE *Bridges,
370 IN UINTN Count
371 )
372 {
373 if (Bridges == NULL && Count == 0) {
374 return;
375 }
376 ASSERT (Bridges != NULL && Count > 0);
377
378 do {
379 --Count;
380 PciHostBridgeUtilityUninitRootBridge (&Bridges[Count]);
381 } while (Count > 0);
382
383 FreePool (Bridges);
384 }
385
386
387 /**
388 Utility function to inform the platform that the resource conflict happens.
389
390 @param[in] Configuration Pointer to PCI I/O and PCI memory resource
391 descriptors. The Configuration contains the
392 resources for all the root bridges. The resource
393 for each root bridge is terminated with END
394 descriptor and an additional END is appended
395 indicating the end of the entire resources. The
396 resource descriptor field values follow the
397 description in
398 EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
399 .SubmitResources().
400 **/
401 VOID
402 EFIAPI
403 PciHostBridgeUtilityResourceConflict (
404 IN VOID *Configuration
405 )
406 {
407 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
408 UINTN RootBridgeIndex;
409 DEBUG ((DEBUG_ERROR, "PciHostBridge: Resource conflict happens!\n"));
410
411 RootBridgeIndex = 0;
412 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
413 while (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
414 DEBUG ((DEBUG_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++));
415 for (; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {
416 ASSERT (Descriptor->ResType <
417 ARRAY_SIZE (mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr)
418 );
419 DEBUG ((DEBUG_ERROR, " %s: Length/Alignment = 0x%lx / 0x%lx\n",
420 mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr[Descriptor->ResType],
421 Descriptor->AddrLen, Descriptor->AddrRangeMax
422 ));
423 if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
424 DEBUG ((DEBUG_ERROR, " Granularity/SpecificFlag = %ld / %02x%s\n",
425 Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag,
426 ((Descriptor->SpecificFlag &
427 EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
428 ) != 0) ? L" (Prefetchable)" : L""
429 ));
430 }
431 }
432 //
433 // Skip the END descriptor for root bridge
434 //
435 ASSERT (Descriptor->Desc == ACPI_END_TAG_DESCRIPTOR);
436 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(
437 (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor + 1
438 );
439 }
440 }
441