]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/PciHostBridgeLib/PciHostBridgeLib.c
OvmfPkg: replace old EFI_D_ debug levels with new DEBUG_ ones
[mirror_edk2.git] / OvmfPkg / Library / PciHostBridgeLib / PciHostBridgeLib.c
CommitLineData
d85861d7
LE
1/** @file\r
2 OVMF's instance of the PCI Host Bridge Library.\r
3\r
4 Copyright (C) 2016, Red Hat, Inc.\r
5 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
6\r
b26f0cf9 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
d85861d7
LE
8\r
9**/\r
10#include <PiDxe.h>\r
46e46eaf
LE
11\r
12#include <IndustryStandard/Pci.h>\r
7daf2401 13#include <IndustryStandard/Q35MchIch9.h>\r
46e46eaf 14\r
0dcd1b1b 15#include <Protocol/PciHostBridgeResourceAllocation.h>\r
a5ece62d
LE
16#include <Protocol/PciRootBridgeIo.h>\r
17\r
65de2ef5 18#include <Library/BaseMemoryLib.h>\r
d85861d7 19#include <Library/DebugLib.h>\r
1f4e2299 20#include <Library/DevicePathLib.h>\r
46e46eaf
LE
21#include <Library/MemoryAllocationLib.h>\r
22#include <Library/PciHostBridgeLib.h>\r
23#include <Library/PciLib.h>\r
24#include <Library/QemuFwCfgLib.h>\r
49effaf2 25#include "PciHostBridge.h"\r
46e46eaf 26\r
d85861d7 27\r
1f4e2299
LE
28#pragma pack(1)\r
29typedef struct {\r
30 ACPI_HID_DEVICE_PATH AcpiDevicePath;\r
31 EFI_DEVICE_PATH_PROTOCOL EndDevicePath;\r
32} OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH;\r
33#pragma pack ()\r
34\r
35\r
d85861d7
LE
36GLOBAL_REMOVE_IF_UNREFERENCED\r
37CHAR16 *mPciHostBridgeLibAcpiAddressSpaceTypeStr[] = {\r
38 L"Mem", L"I/O", L"Bus"\r
39};\r
40\r
46e46eaf 41\r
1f4e2299
LE
42STATIC\r
43CONST\r
44OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH mRootBridgeDevicePathTemplate = {\r
45 {\r
46 {\r
47 ACPI_DEVICE_PATH,\r
48 ACPI_DP,\r
49 {\r
50 (UINT8) (sizeof(ACPI_HID_DEVICE_PATH)),\r
51 (UINT8) ((sizeof(ACPI_HID_DEVICE_PATH)) >> 8)\r
52 }\r
53 },\r
54 EISA_PNP_ID(0x0A03), // HID\r
55 0 // UID\r
56 },\r
57\r
58 {\r
59 END_DEVICE_PATH_TYPE,\r
60 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
61 {\r
62 END_DEVICE_PATH_LENGTH,\r
63 0\r
64 }\r
65 }\r
66};\r
67\r
c0a2591b 68STATIC PCI_ROOT_BRIDGE_APERTURE mNonExistAperture = { MAX_UINT64, 0 };\r
1f4e2299 69\r
46e46eaf
LE
70/**\r
71 Initialize a PCI_ROOT_BRIDGE structure.\r
72\r
c0a2591b 73 @param[in] Supports Supported attributes.\r
46e46eaf 74\r
c0a2591b
RN
75 @param[in] Attributes Initial attributes.\r
76\r
77 @param[in] AllocAttributes Allocation attributes.\r
78\r
79 @param[in] RootBusNumber The bus number to store in RootBus.\r
80\r
81 @param[in] MaxSubBusNumber The inclusive maximum bus number that can be\r
46e46eaf
LE
82 assigned to any subordinate bus found behind any\r
83 PCI bridge hanging off this root bus.\r
84\r
85 The caller is repsonsible for ensuring that\r
86 RootBusNumber <= MaxSubBusNumber. If\r
87 RootBusNumber equals MaxSubBusNumber, then the\r
88 root bus has no room for subordinate buses.\r
89\r
c0a2591b
RN
90 @param[in] Io IO aperture.\r
91\r
92 @param[in] Mem MMIO aperture.\r
93\r
94 @param[in] MemAbove4G MMIO aperture above 4G.\r
95\r
96 @param[in] PMem Prefetchable MMIO aperture.\r
97\r
98 @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.\r
99\r
100 @param[out] RootBus The PCI_ROOT_BRIDGE structure (allocated by the\r
46e46eaf
LE
101 caller) that should be filled in by this\r
102 function.\r
103\r
104 @retval EFI_SUCCESS Initialization successful. A device path\r
105 consisting of an ACPI device path node, with\r
106 UID = RootBusNumber, has been allocated and\r
107 linked into RootBus.\r
108\r
109 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.\r
110**/\r
46e46eaf
LE
111EFI_STATUS\r
112InitRootBridge (\r
c0a2591b
RN
113 IN UINT64 Supports,\r
114 IN UINT64 Attributes,\r
115 IN UINT64 AllocAttributes,\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
46e46eaf
LE
124 )\r
125{\r
1f4e2299
LE
126 OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH *DevicePath;\r
127\r
65de2ef5
LE
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
c0a2591b
RN
135 RootBus->Supports = Supports;\r
136 RootBus->Attributes = Attributes;\r
a5ece62d 137\r
c789d61d
LE
138 RootBus->DmaAbove4G = FALSE;\r
139\r
c0a2591b 140 RootBus->AllocationAttributes = AllocAttributes;\r
390951c2
LE
141 RootBus->Bus.Base = RootBusNumber;\r
142 RootBus->Bus.Limit = MaxSubBusNumber;\r
c0a2591b
RN
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
390951c2 148\r
7daf2401
LE
149 RootBus->NoExtendedConfigSpace = (PcdGet16 (PcdOvmfHostBridgePciDevId) !=\r
150 INTEL_Q35_MCH_DEVICE_ID);\r
cb81595b 151\r
1f4e2299
LE
152 DevicePath = AllocateCopyPool (sizeof mRootBridgeDevicePathTemplate,\r
153 &mRootBridgeDevicePathTemplate);\r
154 if (DevicePath == NULL) {\r
70d5086c 155 DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES));\r
1f4e2299
LE
156 return EFI_OUT_OF_RESOURCES;\r
157 }\r
158 DevicePath->AcpiDevicePath.UID = RootBusNumber;\r
159 RootBus->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;\r
160\r
70d5086c 161 DEBUG ((DEBUG_INFO,\r
1f4e2299
LE
162 "%a: populated root bus %d, with room for %d subordinate bus(es)\n",\r
163 __FUNCTION__, RootBusNumber, MaxSubBusNumber - RootBusNumber));\r
164 return EFI_SUCCESS;\r
46e46eaf
LE
165}\r
166\r
167\r
168/**\r
169 Uninitialize a PCI_ROOT_BRIDGE structure set up with InitRootBridge().\r
170\r
171 param[in] RootBus The PCI_ROOT_BRIDGE structure, allocated by the caller and\r
172 initialized with InitRootBridge(), that should be\r
173 uninitialized. This function doesn't free RootBus.\r
174**/\r
175STATIC\r
176VOID\r
177UninitRootBridge (\r
178 IN PCI_ROOT_BRIDGE *RootBus\r
179 )\r
180{\r
1f4e2299 181 FreePool (RootBus->DevicePath);\r
46e46eaf
LE
182}\r
183\r
184\r
d85861d7
LE
185/**\r
186 Return all the root bridge instances in an array.\r
187\r
188 @param Count Return the count of root bridge instances.\r
189\r
190 @return All the root bridge instances in an array.\r
191 The array should be passed into PciHostBridgeFreeRootBridges()\r
192 when it's not used.\r
193**/\r
194PCI_ROOT_BRIDGE *\r
195EFIAPI\r
196PciHostBridgeGetRootBridges (\r
197 UINTN *Count\r
198 )\r
199{\r
46e46eaf
LE
200 EFI_STATUS Status;\r
201 FIRMWARE_CONFIG_ITEM FwCfgItem;\r
202 UINTN FwCfgSize;\r
203 UINT64 ExtraRootBridges;\r
204 PCI_ROOT_BRIDGE *Bridges;\r
205 UINTN Initialized;\r
206 UINTN LastRootBridgeNumber;\r
207 UINTN RootBridgeNumber;\r
c0a2591b
RN
208 UINT64 Attributes;\r
209 UINT64 AllocationAttributes;\r
210 PCI_ROOT_BRIDGE_APERTURE Io;\r
211 PCI_ROOT_BRIDGE_APERTURE Mem;\r
212 PCI_ROOT_BRIDGE_APERTURE MemAbove4G;\r
213\r
49effaf2
RN
214 if (PcdGetBool (PcdPciDisableBusEnumeration)) {\r
215 return ScanForRootBridges (Count);\r
216 }\r
217\r
e33305ea
HG
218 ZeroMem (&Io, sizeof (Io));\r
219 ZeroMem (&Mem, sizeof (Mem));\r
220 ZeroMem (&MemAbove4G, sizeof (MemAbove4G));\r
221\r
c0a2591b
RN
222 Attributes = EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO |\r
223 EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO |\r
224 EFI_PCI_ATTRIBUTE_ISA_IO_16 |\r
225 EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO |\r
226 EFI_PCI_ATTRIBUTE_VGA_MEMORY |\r
227 EFI_PCI_ATTRIBUTE_VGA_IO_16 |\r
228 EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16;\r
229\r
230 AllocationAttributes = EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM;\r
231 if (PcdGet64 (PcdPciMmio64Size) > 0) {\r
232 AllocationAttributes |= EFI_PCI_HOST_BRIDGE_MEM64_DECODE;\r
233 MemAbove4G.Base = PcdGet64 (PcdPciMmio64Base);\r
234 MemAbove4G.Limit = PcdGet64 (PcdPciMmio64Base) +\r
235 PcdGet64 (PcdPciMmio64Size) - 1;\r
236 } else {\r
237 CopyMem (&MemAbove4G, &mNonExistAperture, sizeof (mNonExistAperture));\r
238 }\r
239\r
240 Io.Base = PcdGet64 (PcdPciIoBase);\r
241 Io.Limit = PcdGet64 (PcdPciIoBase) + (PcdGet64 (PcdPciIoSize) - 1);\r
242 Mem.Base = PcdGet64 (PcdPciMmio32Base);\r
243 Mem.Limit = PcdGet64 (PcdPciMmio32Base) + (PcdGet64 (PcdPciMmio32Size) - 1);\r
46e46eaf 244\r
d85861d7 245 *Count = 0;\r
46e46eaf
LE
246\r
247 //\r
248 // QEMU provides the number of extra root buses, shortening the exhaustive\r
249 // search below. If there is no hint, the feature is missing.\r
250 //\r
251 Status = QemuFwCfgFindFile ("etc/extra-pci-roots", &FwCfgItem, &FwCfgSize);\r
252 if (EFI_ERROR (Status) || FwCfgSize != sizeof ExtraRootBridges) {\r
253 ExtraRootBridges = 0;\r
254 } else {\r
255 QemuFwCfgSelectItem (FwCfgItem);\r
256 QemuFwCfgReadBytes (FwCfgSize, &ExtraRootBridges);\r
257\r
258 if (ExtraRootBridges > PCI_MAX_BUS) {\r
70d5086c 259 DEBUG ((DEBUG_ERROR, "%a: invalid count of extra root buses (%Lu) "\r
46e46eaf
LE
260 "reported by QEMU\n", __FUNCTION__, ExtraRootBridges));\r
261 return NULL;\r
262 }\r
70d5086c 263 DEBUG ((DEBUG_INFO, "%a: %Lu extra root buses reported by QEMU\n",\r
46e46eaf
LE
264 __FUNCTION__, ExtraRootBridges));\r
265 }\r
266\r
267 //\r
268 // Allocate the "main" root bridge, and any extra root bridges.\r
269 //\r
270 Bridges = AllocatePool ((1 + (UINTN)ExtraRootBridges) * sizeof *Bridges);\r
271 if (Bridges == NULL) {\r
70d5086c 272 DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES));\r
46e46eaf
LE
273 return NULL;\r
274 }\r
275 Initialized = 0;\r
276\r
277 //\r
278 // The "main" root bus is always there.\r
279 //\r
280 LastRootBridgeNumber = 0;\r
281\r
282 //\r
283 // Scan all other root buses. If function 0 of any device on a bus returns a\r
284 // VendorId register value different from all-bits-one, then that bus is\r
285 // alive.\r
286 //\r
287 for (RootBridgeNumber = 1;\r
288 RootBridgeNumber <= PCI_MAX_BUS && Initialized < ExtraRootBridges;\r
289 ++RootBridgeNumber) {\r
290 UINTN Device;\r
291\r
292 for (Device = 0; Device <= PCI_MAX_DEVICE; ++Device) {\r
293 if (PciRead16 (PCI_LIB_ADDRESS (RootBridgeNumber, Device, 0,\r
294 PCI_VENDOR_ID_OFFSET)) != MAX_UINT16) {\r
295 break;\r
296 }\r
297 }\r
298 if (Device <= PCI_MAX_DEVICE) {\r
299 //\r
300 // Found the next root bus. We can now install the *previous* one,\r
301 // because now we know how big a bus number range *that* one has, for any\r
302 // subordinate buses that might exist behind PCI bridges hanging off it.\r
303 //\r
c0a2591b
RN
304 Status = InitRootBridge (\r
305 Attributes,\r
306 Attributes,\r
307 AllocationAttributes,\r
308 (UINT8) LastRootBridgeNumber,\r
309 (UINT8) (RootBridgeNumber - 1),\r
310 &Io,\r
311 &Mem,\r
312 &MemAbove4G,\r
313 &mNonExistAperture,\r
314 &mNonExistAperture,\r
315 &Bridges[Initialized]\r
316 );\r
46e46eaf
LE
317 if (EFI_ERROR (Status)) {\r
318 goto FreeBridges;\r
319 }\r
320 ++Initialized;\r
321 LastRootBridgeNumber = RootBridgeNumber;\r
322 }\r
323 }\r
324\r
325 //\r
326 // Install the last root bus (which might be the only, ie. main, root bus, if\r
327 // we've found no extra root buses).\r
328 //\r
c0a2591b
RN
329 Status = InitRootBridge (\r
330 Attributes,\r
331 Attributes,\r
332 AllocationAttributes,\r
333 (UINT8) LastRootBridgeNumber,\r
334 PCI_MAX_BUS,\r
335 &Io,\r
336 &Mem,\r
337 &MemAbove4G,\r
338 &mNonExistAperture,\r
339 &mNonExistAperture,\r
340 &Bridges[Initialized]\r
341 );\r
46e46eaf
LE
342 if (EFI_ERROR (Status)) {\r
343 goto FreeBridges;\r
344 }\r
345 ++Initialized;\r
346\r
347 *Count = Initialized;\r
348 return Bridges;\r
349\r
350FreeBridges:\r
351 while (Initialized > 0) {\r
352 --Initialized;\r
353 UninitRootBridge (&Bridges[Initialized]);\r
354 }\r
355\r
356 FreePool (Bridges);\r
d85861d7
LE
357 return NULL;\r
358}\r
359\r
46e46eaf 360\r
d85861d7
LE
361/**\r
362 Free the root bridge instances array returned from\r
363 PciHostBridgeGetRootBridges().\r
364\r
365 @param The root bridge instances array.\r
366 @param The count of the array.\r
367**/\r
368VOID\r
369EFIAPI\r
370PciHostBridgeFreeRootBridges (\r
371 PCI_ROOT_BRIDGE *Bridges,\r
372 UINTN Count\r
373 )\r
374{\r
dc4d6467
LE
375 if (Bridges == NULL && Count == 0) {\r
376 return;\r
377 }\r
378 ASSERT (Bridges != NULL && Count > 0);\r
379\r
380 do {\r
381 --Count;\r
382 UninitRootBridge (&Bridges[Count]);\r
383 } while (Count > 0);\r
384\r
385 FreePool (Bridges);\r
d85861d7
LE
386}\r
387\r
46e46eaf 388\r
d85861d7
LE
389/**\r
390 Inform the platform that the resource conflict happens.\r
391\r
392 @param HostBridgeHandle Handle of the Host Bridge.\r
393 @param Configuration Pointer to PCI I/O and PCI memory resource\r
394 descriptors. The Configuration contains the resources\r
395 for all the root bridges. The resource for each root\r
396 bridge is terminated with END descriptor and an\r
397 additional END is appended indicating the end of the\r
398 entire resources. The resource descriptor field\r
399 values follow the description in\r
400 EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL\r
401 .SubmitResources().\r
402**/\r
403VOID\r
404EFIAPI\r
405PciHostBridgeResourceConflict (\r
406 EFI_HANDLE HostBridgeHandle,\r
407 VOID *Configuration\r
408 )\r
409{\r
410 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
411 UINTN RootBridgeIndex;\r
70d5086c 412 DEBUG ((DEBUG_ERROR, "PciHostBridge: Resource conflict happens!\n"));\r
d85861d7
LE
413\r
414 RootBridgeIndex = 0;\r
415 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;\r
416 while (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) {\r
70d5086c 417 DEBUG ((DEBUG_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++));\r
d85861d7
LE
418 for (; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {\r
419 ASSERT (Descriptor->ResType <\r
5a5025e4 420 ARRAY_SIZE (mPciHostBridgeLibAcpiAddressSpaceTypeStr)\r
d85861d7 421 );\r
70d5086c 422 DEBUG ((DEBUG_ERROR, " %s: Length/Alignment = 0x%lx / 0x%lx\n",\r
d85861d7
LE
423 mPciHostBridgeLibAcpiAddressSpaceTypeStr[Descriptor->ResType],\r
424 Descriptor->AddrLen, Descriptor->AddrRangeMax\r
425 ));\r
426 if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {\r
70d5086c 427 DEBUG ((DEBUG_ERROR, " Granularity/SpecificFlag = %ld / %02x%s\n",\r
d85861d7
LE
428 Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag,\r
429 ((Descriptor->SpecificFlag &\r
430 EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE\r
431 ) != 0) ? L" (Prefetchable)" : L""\r
432 ));\r
433 }\r
434 }\r
435 //\r
436 // Skip the END descriptor for root bridge\r
437 //\r
438 ASSERT (Descriptor->Desc == ACPI_END_TAG_DESCRIPTOR);\r
439 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(\r
440 (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor + 1\r
441 );\r
442 }\r
443}\r