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