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