]>
Commit | Line | Data |
---|---|---|
7a6172f8 JC |
1 | /** @file\r |
2 | Provide common utility functions to PciHostBridgeLib instances in\r | |
3 | ArmVirtPkg and OvmfPkg.\r | |
4 | \r | |
5 | Copyright (C) 2016, Red Hat, Inc.\r | |
6 | Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r | |
7 | Copyright (c) 2020, Huawei Corporation. All rights reserved.<BR>\r | |
8 | \r | |
9 | SPDX-License-Identifier: BSD-2-Clause-Patent\r | |
10 | \r | |
11 | **/\r | |
12 | \r | |
13 | #include <IndustryStandard/Acpi10.h>\r | |
4edba296 | 14 | #include <IndustryStandard/Pci.h>\r |
3f5b1b91 | 15 | #include <Library/BaseLib.h>\r |
7ac1f28d | 16 | #include <Library/BaseMemoryLib.h>\r |
7a6172f8 | 17 | #include <Library/DebugLib.h>\r |
7ac1f28d | 18 | #include <Library/DevicePathLib.h>\r |
3f5b1b91 | 19 | #include <Library/HardwareInfoLib.h>\r |
7ac1f28d | 20 | #include <Library/MemoryAllocationLib.h>\r |
7a6172f8 | 21 | #include <Library/PciHostBridgeUtilityLib.h>\r |
4edba296 JC |
22 | #include <Library/PciLib.h>\r |
23 | #include <Library/QemuFwCfgLib.h>\r | |
3f5b1b91 | 24 | #include <Protocol/PciHostBridgeResourceAllocation.h>\r |
7a6172f8 | 25 | \r |
7ac1f28d JC |
26 | #pragma pack(1)\r |
27 | typedef struct {\r | |
ac0a286f MK |
28 | ACPI_HID_DEVICE_PATH AcpiDevicePath;\r |
29 | EFI_DEVICE_PATH_PROTOCOL EndDevicePath;\r | |
7ac1f28d JC |
30 | } OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH;\r |
31 | #pragma pack ()\r | |
32 | \r | |
7a6172f8 | 33 | GLOBAL_REMOVE_IF_UNREFERENCED\r |
ac0a286f | 34 | CHAR16 *mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr[] = {\r |
7a6172f8 JC |
35 | L"Mem", L"I/O", L"Bus"\r |
36 | };\r | |
37 | \r | |
7ac1f28d JC |
38 | STATIC\r |
39 | CONST\r | |
ac0a286f | 40 | OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH mRootBridgeDevicePathTemplate = {\r |
7ac1f28d JC |
41 | {\r |
42 | {\r | |
43 | ACPI_DEVICE_PATH,\r | |
44 | ACPI_DP,\r | |
45 | {\r | |
ac0a286f MK |
46 | (UINT8)(sizeof (ACPI_HID_DEVICE_PATH)),\r |
47 | (UINT8)((sizeof (ACPI_HID_DEVICE_PATH)) >> 8)\r | |
7ac1f28d JC |
48 | }\r |
49 | },\r | |
ac0a286f MK |
50 | EISA_PNP_ID (0x0A03), // HID\r |
51 | 0 // UID\r | |
7ac1f28d JC |
52 | },\r |
53 | \r | |
54 | {\r | |
55 | END_DEVICE_PATH_TYPE,\r | |
56 | END_ENTIRE_DEVICE_PATH_SUBTYPE,\r | |
57 | {\r | |
58 | END_DEVICE_PATH_LENGTH,\r | |
59 | 0\r | |
60 | }\r | |
61 | }\r | |
62 | };\r | |
63 | \r | |
7ac1f28d JC |
64 | /**\r |
65 | Utility function to initialize a PCI_ROOT_BRIDGE structure.\r | |
66 | \r | |
e1b259da | 67 | @param[in] Supports Supported attributes.\r |
7ac1f28d | 68 | \r |
e1b259da | 69 | @param[in] Attributes Initial attributes.\r |
7ac1f28d | 70 | \r |
e1b259da | 71 | @param[in] AllocAttributes Allocation attributes.\r |
7ac1f28d | 72 | \r |
e1b259da | 73 | @param[in] DmaAbove4G DMA above 4GB memory.\r |
7ac1f28d | 74 | \r |
e1b259da | 75 | @param[in] NoExtendedConfigSpace No Extended Config Space.\r |
7ac1f28d | 76 | \r |
e1b259da | 77 | @param[in] RootBusNumber The bus number to store in RootBus.\r |
7ac1f28d | 78 | \r |
e1b259da JC |
79 | @param[in] MaxSubBusNumber The inclusive maximum bus number that can\r |
80 | be assigned to any subordinate bus found\r | |
81 | behind any PCI bridge hanging off this\r | |
82 | root bus.\r | |
7ac1f28d | 83 | \r |
e1b259da JC |
84 | The caller is repsonsible for ensuring\r |
85 | that RootBusNumber <= MaxSubBusNumber. If\r | |
86 | RootBusNumber equals MaxSubBusNumber, then\r | |
87 | the root bus has no room for subordinate\r | |
88 | buses.\r | |
7ac1f28d | 89 | \r |
e1b259da | 90 | @param[in] Io IO aperture.\r |
7ac1f28d | 91 | \r |
e1b259da | 92 | @param[in] Mem MMIO aperture.\r |
7ac1f28d | 93 | \r |
e1b259da | 94 | @param[in] MemAbove4G MMIO aperture above 4G.\r |
7ac1f28d | 95 | \r |
e1b259da | 96 | @param[in] PMem Prefetchable MMIO aperture.\r |
7ac1f28d | 97 | \r |
e1b259da | 98 | @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.\r |
7ac1f28d | 99 | \r |
e1b259da JC |
100 | @param[out] RootBus The PCI_ROOT_BRIDGE structure (allocated\r |
101 | by the caller) that should be filled in by\r | |
102 | this function.\r | |
103 | \r | |
104 | @retval EFI_SUCCESS Initialization successful. A device path\r | |
105 | consisting of an ACPI device path node,\r | |
106 | with UID = RootBusNumber, has been\r | |
107 | allocated and linked into RootBus.\r | |
108 | \r | |
109 | @retval EFI_OUT_OF_RESOURCES Memory allocation failed.\r | |
7ac1f28d JC |
110 | **/\r |
111 | EFI_STATUS\r | |
112 | EFIAPI\r | |
113 | PciHostBridgeUtilityInitRootBridge (\r | |
ac0a286f MK |
114 | IN UINT64 Supports,\r |
115 | IN UINT64 Attributes,\r | |
116 | IN UINT64 AllocAttributes,\r | |
117 | IN BOOLEAN DmaAbove4G,\r | |
118 | IN BOOLEAN NoExtendedConfigSpace,\r | |
119 | IN UINT8 RootBusNumber,\r | |
120 | IN UINT8 MaxSubBusNumber,\r | |
121 | IN PCI_ROOT_BRIDGE_APERTURE *Io,\r | |
122 | IN PCI_ROOT_BRIDGE_APERTURE *Mem,\r | |
123 | IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G,\r | |
124 | IN PCI_ROOT_BRIDGE_APERTURE *PMem,\r | |
125 | IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G,\r | |
126 | OUT PCI_ROOT_BRIDGE *RootBus\r | |
7ac1f28d JC |
127 | )\r |
128 | {\r | |
ac0a286f | 129 | OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH *DevicePath;\r |
7ac1f28d JC |
130 | \r |
131 | //\r | |
132 | // Be safe if other fields are added to PCI_ROOT_BRIDGE later.\r | |
133 | //\r | |
134 | ZeroMem (RootBus, sizeof *RootBus);\r | |
135 | \r | |
136 | RootBus->Segment = 0;\r | |
137 | \r | |
138 | RootBus->Supports = Supports;\r | |
139 | RootBus->Attributes = Attributes;\r | |
140 | \r | |
e1b259da | 141 | RootBus->DmaAbove4G = DmaAbove4G;\r |
7ac1f28d JC |
142 | \r |
143 | RootBus->AllocationAttributes = AllocAttributes;\r | |
ac0a286f MK |
144 | RootBus->Bus.Base = RootBusNumber;\r |
145 | RootBus->Bus.Limit = MaxSubBusNumber;\r | |
7ac1f28d JC |
146 | CopyMem (&RootBus->Io, Io, sizeof (*Io));\r |
147 | CopyMem (&RootBus->Mem, Mem, sizeof (*Mem));\r | |
148 | CopyMem (&RootBus->MemAbove4G, MemAbove4G, sizeof (*MemAbove4G));\r | |
149 | CopyMem (&RootBus->PMem, PMem, sizeof (*PMem));\r | |
150 | CopyMem (&RootBus->PMemAbove4G, PMemAbove4G, sizeof (*PMemAbove4G));\r | |
151 | \r | |
e1b259da | 152 | RootBus->NoExtendedConfigSpace = NoExtendedConfigSpace;\r |
7ac1f28d | 153 | \r |
ac0a286f MK |
154 | DevicePath = AllocateCopyPool (\r |
155 | sizeof mRootBridgeDevicePathTemplate,\r | |
156 | &mRootBridgeDevicePathTemplate\r | |
157 | );\r | |
7ac1f28d JC |
158 | if (DevicePath == NULL) {\r |
159 | DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES));\r | |
160 | return EFI_OUT_OF_RESOURCES;\r | |
161 | }\r | |
ac0a286f | 162 | \r |
7ac1f28d | 163 | DevicePath->AcpiDevicePath.UID = RootBusNumber;\r |
ac0a286f | 164 | RootBus->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;\r |
7ac1f28d | 165 | \r |
ac0a286f MK |
166 | DEBUG ((\r |
167 | DEBUG_INFO,\r | |
7ac1f28d | 168 | "%a: populated root bus %d, with room for %d subordinate bus(es)\n",\r |
ac0a286f MK |
169 | __FUNCTION__,\r |
170 | RootBusNumber,\r | |
171 | MaxSubBusNumber - RootBusNumber\r | |
172 | ));\r | |
7ac1f28d JC |
173 | return EFI_SUCCESS;\r |
174 | }\r | |
175 | \r | |
7ac1f28d JC |
176 | /**\r |
177 | Utility function to uninitialize a PCI_ROOT_BRIDGE structure set up with\r | |
178 | PciHostBridgeUtilityInitRootBridge().\r | |
179 | \r | |
180 | @param[in] RootBus The PCI_ROOT_BRIDGE structure, allocated by the caller and\r | |
181 | initialized with PciHostBridgeUtilityInitRootBridge(),\r | |
182 | that should be uninitialized. This function doesn't free\r | |
183 | RootBus.\r | |
184 | **/\r | |
185 | VOID\r | |
186 | EFIAPI\r | |
187 | PciHostBridgeUtilityUninitRootBridge (\r | |
ac0a286f | 188 | IN PCI_ROOT_BRIDGE *RootBus\r |
7ac1f28d JC |
189 | )\r |
190 | {\r | |
191 | FreePool (RootBus->DevicePath);\r | |
192 | }\r | |
193 | \r | |
4edba296 | 194 | /**\r |
3f5b1b91 NOL |
195 | Utility function to scan PCI root bridges and create instances for those\r |
196 | that are found not empty. Populate their resources from the default\r | |
197 | provided parameters and return all the root bridge instances in an array.\r | |
4edba296 | 198 | \r |
14d4b6be | 199 | @param[out] Count The number of root bridge instances.\r |
4edba296 | 200 | \r |
14d4b6be | 201 | @param[in] Attributes Initial attributes.\r |
4edba296 | 202 | \r |
14d4b6be | 203 | @param[in] AllocAttributes Allocation attributes.\r |
4edba296 | 204 | \r |
14d4b6be | 205 | @param[in] DmaAbove4G DMA above 4GB memory.\r |
4edba296 | 206 | \r |
14d4b6be | 207 | @param[in] NoExtendedConfigSpace No Extended Config Space.\r |
4edba296 | 208 | \r |
f4a257a3 JC |
209 | @param[in] BusMin Minimum Bus number, inclusive.\r |
210 | \r | |
211 | @param[in] BusMax Maximum Bus number, inclusive.\r | |
212 | \r | |
14d4b6be | 213 | @param[in] Io IO aperture.\r |
4edba296 | 214 | \r |
14d4b6be | 215 | @param[in] Mem MMIO aperture.\r |
4edba296 | 216 | \r |
14d4b6be | 217 | @param[in] MemAbove4G MMIO aperture above 4G.\r |
4edba296 | 218 | \r |
14d4b6be JC |
219 | @param[in] PMem Prefetchable MMIO aperture.\r |
220 | \r | |
221 | @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.\r | |
222 | \r | |
223 | @return All the root bridge instances in an array.\r | |
4edba296 | 224 | **/\r |
3f5b1b91 | 225 | STATIC\r |
4edba296 | 226 | PCI_ROOT_BRIDGE *\r |
3f5b1b91 | 227 | PciHostBridgeUtilityGetRootBridgesBusScan (\r |
ac0a286f MK |
228 | OUT UINTN *Count,\r |
229 | IN UINT64 Attributes,\r | |
230 | IN UINT64 AllocationAttributes,\r | |
231 | IN BOOLEAN DmaAbove4G,\r | |
232 | IN BOOLEAN NoExtendedConfigSpace,\r | |
233 | IN UINTN BusMin,\r | |
234 | IN UINTN BusMax,\r | |
235 | IN PCI_ROOT_BRIDGE_APERTURE *Io,\r | |
236 | IN PCI_ROOT_BRIDGE_APERTURE *Mem,\r | |
237 | IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G,\r | |
238 | IN PCI_ROOT_BRIDGE_APERTURE *PMem,\r | |
239 | IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G\r | |
4edba296 JC |
240 | )\r |
241 | {\r | |
ac0a286f MK |
242 | EFI_STATUS Status;\r |
243 | FIRMWARE_CONFIG_ITEM FwCfgItem;\r | |
244 | UINTN FwCfgSize;\r | |
245 | UINT64 ExtraRootBridges;\r | |
246 | PCI_ROOT_BRIDGE *Bridges;\r | |
247 | UINTN Initialized;\r | |
248 | UINTN LastRootBridgeNumber;\r | |
249 | UINTN RootBridgeNumber;\r | |
4edba296 | 250 | \r |
ac0a286f MK |
251 | if ((BusMin > BusMax) || (BusMax > PCI_MAX_BUS)) {\r |
252 | DEBUG ((\r | |
253 | DEBUG_ERROR,\r | |
254 | "%a: invalid bus range with BusMin %Lu and BusMax "\r | |
255 | "%Lu\n",\r | |
256 | __FUNCTION__,\r | |
257 | (UINT64)BusMin,\r | |
258 | (UINT64)BusMax\r | |
259 | ));\r | |
f4a257a3 JC |
260 | return NULL;\r |
261 | }\r | |
262 | \r | |
4edba296 JC |
263 | //\r |
264 | // QEMU provides the number of extra root buses, shortening the exhaustive\r | |
265 | // search below. If there is no hint, the feature is missing.\r | |
266 | //\r | |
267 | Status = QemuFwCfgFindFile ("etc/extra-pci-roots", &FwCfgItem, &FwCfgSize);\r | |
ac0a286f | 268 | if (EFI_ERROR (Status) || (FwCfgSize != sizeof ExtraRootBridges)) {\r |
4edba296 JC |
269 | ExtraRootBridges = 0;\r |
270 | } else {\r | |
271 | QemuFwCfgSelectItem (FwCfgItem);\r | |
272 | QemuFwCfgReadBytes (FwCfgSize, &ExtraRootBridges);\r | |
273 | \r | |
f4a257a3 JC |
274 | //\r |
275 | // Validate the number of extra root bridges. As BusMax is inclusive, the\r | |
276 | // max bus count is (BusMax - BusMin + 1). From that, the "main" root bus\r | |
277 | // is always a given, so the max count for the "extra" root bridges is one\r | |
278 | // less, i.e. (BusMax - BusMin). If the QEMU hint exceeds that, we have\r | |
279 | // invalid behavior.\r | |
280 | //\r | |
281 | if (ExtraRootBridges > BusMax - BusMin) {\r | |
ac0a286f MK |
282 | DEBUG ((\r |
283 | DEBUG_ERROR,\r | |
284 | "%a: invalid count of extra root buses (%Lu) "\r | |
285 | "reported by QEMU\n",\r | |
286 | __FUNCTION__,\r | |
287 | ExtraRootBridges\r | |
288 | ));\r | |
4edba296 JC |
289 | return NULL;\r |
290 | }\r | |
ac0a286f MK |
291 | \r |
292 | DEBUG ((\r | |
293 | DEBUG_INFO,\r | |
294 | "%a: %Lu extra root buses reported by QEMU\n",\r | |
295 | __FUNCTION__,\r | |
296 | ExtraRootBridges\r | |
297 | ));\r | |
4edba296 JC |
298 | }\r |
299 | \r | |
300 | //\r | |
301 | // Allocate the "main" root bridge, and any extra root bridges.\r | |
302 | //\r | |
303 | Bridges = AllocatePool ((1 + (UINTN)ExtraRootBridges) * sizeof *Bridges);\r | |
304 | if (Bridges == NULL) {\r | |
305 | DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES));\r | |
306 | return NULL;\r | |
307 | }\r | |
ac0a286f | 308 | \r |
4edba296 JC |
309 | Initialized = 0;\r |
310 | \r | |
311 | //\r | |
312 | // The "main" root bus is always there.\r | |
313 | //\r | |
f4a257a3 | 314 | LastRootBridgeNumber = BusMin;\r |
4edba296 JC |
315 | \r |
316 | //\r | |
317 | // Scan all other root buses. If function 0 of any device on a bus returns a\r | |
318 | // VendorId register value different from all-bits-one, then that bus is\r | |
319 | // alive.\r | |
320 | //\r | |
f4a257a3 JC |
321 | for (RootBridgeNumber = BusMin + 1;\r |
322 | RootBridgeNumber <= BusMax && Initialized < ExtraRootBridges;\r | |
ac0a286f MK |
323 | ++RootBridgeNumber)\r |
324 | {\r | |
325 | UINTN Device;\r | |
4edba296 JC |
326 | \r |
327 | for (Device = 0; Device <= PCI_MAX_DEVICE; ++Device) {\r | |
ac0a286f MK |
328 | if (PciRead16 (\r |
329 | PCI_LIB_ADDRESS (\r | |
330 | RootBridgeNumber,\r | |
331 | Device,\r | |
332 | 0,\r | |
333 | PCI_VENDOR_ID_OFFSET\r | |
334 | )\r | |
335 | ) != MAX_UINT16)\r | |
336 | {\r | |
4edba296 JC |
337 | break;\r |
338 | }\r | |
339 | }\r | |
ac0a286f | 340 | \r |
4edba296 JC |
341 | if (Device <= PCI_MAX_DEVICE) {\r |
342 | //\r | |
343 | // Found the next root bus. We can now install the *previous* one,\r | |
344 | // because now we know how big a bus number range *that* one has, for any\r | |
345 | // subordinate buses that might exist behind PCI bridges hanging off it.\r | |
346 | //\r | |
347 | Status = PciHostBridgeUtilityInitRootBridge (\r | |
ac0a286f MK |
348 | Attributes,\r |
349 | Attributes,\r | |
350 | AllocationAttributes,\r | |
351 | DmaAbove4G,\r | |
352 | NoExtendedConfigSpace,\r | |
353 | (UINT8)LastRootBridgeNumber,\r | |
354 | (UINT8)(RootBridgeNumber - 1),\r | |
355 | Io,\r | |
356 | Mem,\r | |
357 | MemAbove4G,\r | |
358 | PMem,\r | |
359 | PMemAbove4G,\r | |
360 | &Bridges[Initialized]\r | |
361 | );\r | |
4edba296 JC |
362 | if (EFI_ERROR (Status)) {\r |
363 | goto FreeBridges;\r | |
364 | }\r | |
ac0a286f | 365 | \r |
4edba296 JC |
366 | ++Initialized;\r |
367 | LastRootBridgeNumber = RootBridgeNumber;\r | |
368 | }\r | |
369 | }\r | |
370 | \r | |
371 | //\r | |
372 | // Install the last root bus (which might be the only, ie. main, root bus, if\r | |
373 | // we've found no extra root buses).\r | |
374 | //\r | |
375 | Status = PciHostBridgeUtilityInitRootBridge (\r | |
ac0a286f MK |
376 | Attributes,\r |
377 | Attributes,\r | |
378 | AllocationAttributes,\r | |
379 | DmaAbove4G,\r | |
380 | NoExtendedConfigSpace,\r | |
381 | (UINT8)LastRootBridgeNumber,\r | |
382 | (UINT8)BusMax,\r | |
383 | Io,\r | |
384 | Mem,\r | |
385 | MemAbove4G,\r | |
386 | PMem,\r | |
387 | PMemAbove4G,\r | |
388 | &Bridges[Initialized]\r | |
389 | );\r | |
4edba296 JC |
390 | if (EFI_ERROR (Status)) {\r |
391 | goto FreeBridges;\r | |
392 | }\r | |
ac0a286f | 393 | \r |
4edba296 JC |
394 | ++Initialized;\r |
395 | \r | |
396 | *Count = Initialized;\r | |
397 | return Bridges;\r | |
398 | \r | |
399 | FreeBridges:\r | |
400 | while (Initialized > 0) {\r | |
401 | --Initialized;\r | |
402 | PciHostBridgeUtilityUninitRootBridge (&Bridges[Initialized]);\r | |
403 | }\r | |
404 | \r | |
405 | FreePool (Bridges);\r | |
406 | return NULL;\r | |
407 | }\r | |
408 | \r | |
3f5b1b91 NOL |
409 | /**\r |
410 | Utility function to read root bridges information from host-provided fw-cfg\r | |
411 | file and return them in an array.\r | |
412 | \r | |
413 | @param[out] Count The number of root bridge instances.\r | |
414 | \r | |
415 | @return All the root bridge instances in an array parsed from\r | |
416 | host-provided fw-cfg file (hardware-info).\r | |
417 | **/\r | |
418 | STATIC\r | |
419 | PCI_ROOT_BRIDGE *\r | |
420 | PciHostBridgeUtilityGetRootBridgesHostProvided (\r | |
421 | OUT UINTN *Count\r | |
422 | )\r | |
423 | {\r | |
424 | EFI_STATUS Status;\r | |
425 | FIRMWARE_CONFIG_ITEM FwCfgItem;\r | |
426 | UINTN FwCfgSize;\r | |
427 | PCI_ROOT_BRIDGE *Bridges;\r | |
428 | UINTN Initialized;\r | |
429 | UINTN LastRootBridgeNumber;\r | |
430 | UINTN RootBridgeNumber;\r | |
431 | UINTN PciHostBridgeCount;\r | |
432 | UINT8 *HardwareInfoBlob;\r | |
433 | LIST_ENTRY HwInfoList;\r | |
434 | LIST_ENTRY *HwLink;\r | |
435 | HARDWARE_INFO *HwInfo;\r | |
436 | UINT64 Attributes;\r | |
437 | UINT64 AllocationAttributes;\r | |
438 | BOOLEAN DmaAbove4G;\r | |
439 | BOOLEAN NoExtendedConfigSpace;\r | |
440 | BOOLEAN CombineMemPMem;\r | |
441 | PCI_ROOT_BRIDGE_APERTURE Io;\r | |
442 | PCI_ROOT_BRIDGE_APERTURE Mem;\r | |
443 | PCI_ROOT_BRIDGE_APERTURE MemAbove4G;\r | |
444 | PCI_ROOT_BRIDGE_APERTURE PMem;\r | |
445 | PCI_ROOT_BRIDGE_APERTURE PMemAbove4G;\r | |
446 | \r | |
447 | //\r | |
448 | // Initialize the Hardware Info list head to start with an empty but valid\r | |
449 | // list head.\r | |
450 | //\r | |
451 | InitializeListHead (&HwInfoList);\r | |
452 | HardwareInfoBlob = NULL;\r | |
453 | Initialized = 0;\r | |
454 | Bridges = NULL;\r | |
455 | PciHostBridgeCount = 0;\r | |
456 | \r | |
457 | //\r | |
458 | // Hypervisor can provide the specifications (resources) for one or more\r | |
459 | // PCI host bridges. Such information comes through fw-cfg as part of\r | |
460 | // the hardware-info file.\r | |
461 | //\r | |
462 | Status = QemuFwCfgFindFile ("etc/hardware-info", &FwCfgItem, &FwCfgSize);\r | |
463 | \r | |
464 | if (EFI_ERROR (Status)) {\r | |
465 | return NULL;\r | |
466 | }\r | |
467 | \r | |
468 | HardwareInfoBlob = AllocatePool (FwCfgSize);\r | |
469 | \r | |
470 | if (HardwareInfoBlob == NULL) {\r | |
471 | DEBUG ((\r | |
472 | DEBUG_ERROR,\r | |
473 | "%a: Failed to allocate memory for hardware resources info\n",\r | |
474 | __FUNCTION__\r | |
475 | ));\r | |
476 | return NULL;\r | |
477 | }\r | |
478 | \r | |
479 | QemuFwCfgSelectItem (FwCfgItem);\r | |
480 | QemuFwCfgReadBytes (FwCfgSize, HardwareInfoBlob);\r | |
481 | \r | |
482 | //\r | |
483 | // Create the list of hardware info devices filtering for PCI host\r | |
484 | // bridges\r | |
485 | //\r | |
486 | Status = CreateHardwareInfoList (\r | |
487 | HardwareInfoBlob,\r | |
488 | FwCfgSize,\r | |
489 | HardwareInfoTypeHostBridge,\r | |
490 | &HwInfoList\r | |
491 | );\r | |
492 | \r | |
493 | if (EFI_ERROR (Status)) {\r | |
494 | DEBUG ((\r | |
495 | DEBUG_ERROR,\r | |
496 | "%a: Failed to create hardware info list to retrieve host "\r | |
497 | "bridges information from fw-cfg\n",\r | |
498 | __FUNCTION__\r | |
499 | ));\r | |
500 | \r | |
501 | goto FreeBridges;\r | |
502 | }\r | |
503 | \r | |
504 | PciHostBridgeCount = GetHardwareInfoCountByType (\r | |
505 | &HwInfoList,\r | |
506 | HardwareInfoTypeHostBridge,\r | |
507 | sizeof (HOST_BRIDGE_INFO)\r | |
508 | );\r | |
509 | \r | |
510 | if (PciHostBridgeCount == 0) {\r | |
511 | goto FreeBridges;\r | |
512 | }\r | |
513 | \r | |
514 | DEBUG ((\r | |
515 | DEBUG_INFO,\r | |
516 | "%a: Host provided description for %Lu root bridges\n",\r | |
517 | __FUNCTION__,\r | |
518 | PciHostBridgeCount\r | |
519 | ));\r | |
520 | \r | |
521 | //\r | |
522 | // Allocate the root bridges\r | |
523 | //\r | |
524 | Bridges = AllocatePool (((UINTN)PciHostBridgeCount) * sizeof *Bridges);\r | |
525 | if (Bridges == NULL) {\r | |
526 | DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES));\r | |
527 | goto FreeBridges;\r | |
528 | }\r | |
529 | \r | |
530 | //\r | |
531 | // If Host Bridges' specification was obtained from fw-cfg, the list\r | |
532 | // contains information to populate all root bridges in the system\r | |
533 | // including resources and attributes.\r | |
534 | //\r | |
535 | HwLink = GetFirstHardwareInfoByType (\r | |
536 | &HwInfoList,\r | |
537 | HardwareInfoTypeHostBridge,\r | |
538 | sizeof (HOST_BRIDGE_INFO)\r | |
539 | );\r | |
540 | \r | |
541 | while (!EndOfHardwareInfoList (&HwInfoList, HwLink)) {\r | |
542 | HwInfo = HARDWARE_INFO_FROM_LINK (HwLink);\r | |
543 | \r | |
544 | Status = HardwareInfoPciHostBridgeGet (\r | |
545 | HwInfo->Data.PciHostBridge,\r | |
546 | (UINTN)HwInfo->Header.Size,\r | |
547 | &RootBridgeNumber,\r | |
548 | &LastRootBridgeNumber,\r | |
549 | &Attributes,\r | |
550 | &DmaAbove4G,\r | |
551 | &NoExtendedConfigSpace,\r | |
552 | &CombineMemPMem,\r | |
553 | &Io,\r | |
554 | &Mem,\r | |
555 | &MemAbove4G,\r | |
556 | &PMem,\r | |
557 | &PMemAbove4G,\r | |
558 | NULL\r | |
559 | );\r | |
560 | \r | |
561 | if (EFI_ERROR (Status)) {\r | |
562 | goto FreeBridges;\r | |
563 | }\r | |
564 | \r | |
565 | if ((RootBridgeNumber > LastRootBridgeNumber) || (LastRootBridgeNumber > PCI_MAX_BUS)) {\r | |
566 | DEBUG ((\r | |
567 | DEBUG_ERROR,\r | |
568 | "%a: invalid bus range with BusMin %Lu and BusMax "\r | |
569 | "%Lu\n",\r | |
570 | __FUNCTION__,\r | |
571 | (UINT64)RootBridgeNumber,\r | |
572 | (UINT64)LastRootBridgeNumber\r | |
573 | ));\r | |
574 | goto FreeBridges;\r | |
575 | }\r | |
576 | \r | |
577 | AllocationAttributes = 0;\r | |
578 | if (CombineMemPMem) {\r | |
579 | AllocationAttributes |= EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM;\r | |
580 | }\r | |
581 | \r | |
582 | if ((MemAbove4G.Limit > MemAbove4G.Base) ||\r | |
583 | (PMemAbove4G.Limit > PMemAbove4G.Base))\r | |
584 | {\r | |
585 | AllocationAttributes |= EFI_PCI_HOST_BRIDGE_MEM64_DECODE;\r | |
586 | }\r | |
587 | \r | |
588 | Status = PciHostBridgeUtilityInitRootBridge (\r | |
589 | Attributes,\r | |
590 | Attributes,\r | |
591 | AllocationAttributes,\r | |
592 | DmaAbove4G,\r | |
593 | NoExtendedConfigSpace,\r | |
594 | (UINT8)RootBridgeNumber,\r | |
595 | (UINT8)LastRootBridgeNumber,\r | |
596 | &Io,\r | |
597 | &Mem,\r | |
598 | &MemAbove4G,\r | |
599 | &PMem,\r | |
600 | &PMemAbove4G,\r | |
601 | &Bridges[Initialized]\r | |
602 | );\r | |
603 | \r | |
604 | if (EFI_ERROR (Status)) {\r | |
605 | goto FreeBridges;\r | |
606 | }\r | |
607 | \r | |
608 | ++Initialized;\r | |
609 | \r | |
610 | HwLink = GetNextHardwareInfoByType (\r | |
611 | &HwInfoList,\r | |
612 | HwLink,\r | |
613 | HardwareInfoTypeHostBridge,\r | |
614 | sizeof (HOST_BRIDGE_INFO)\r | |
615 | );\r | |
616 | }\r | |
617 | \r | |
618 | *Count = Initialized;\r | |
619 | \r | |
620 | //\r | |
621 | // If resources were allocated for host bridges info, release them\r | |
622 | //\r | |
623 | if (HardwareInfoBlob) {\r | |
624 | FreePool (HardwareInfoBlob);\r | |
625 | }\r | |
626 | \r | |
627 | FreeHardwareInfoList (&HwInfoList);\r | |
628 | return Bridges;\r | |
629 | \r | |
630 | FreeBridges:\r | |
631 | while (Initialized > 0) {\r | |
632 | --Initialized;\r | |
633 | PciHostBridgeUtilityUninitRootBridge (&Bridges[Initialized]);\r | |
634 | }\r | |
635 | \r | |
636 | if (Bridges) {\r | |
637 | FreePool (Bridges);\r | |
638 | }\r | |
639 | \r | |
640 | if (HardwareInfoBlob) {\r | |
641 | FreePool (HardwareInfoBlob);\r | |
642 | }\r | |
643 | \r | |
644 | FreeHardwareInfoList (&HwInfoList);\r | |
645 | return NULL;\r | |
646 | }\r | |
647 | \r | |
648 | /**\r | |
649 | Utility function to return all the root bridge instances in an array.\r | |
650 | \r | |
651 | @param[out] Count The number of root bridge instances.\r | |
652 | \r | |
653 | @param[in] Attributes Initial attributes.\r | |
654 | \r | |
655 | @param[in] AllocAttributes Allocation attributes.\r | |
656 | \r | |
657 | @param[in] DmaAbove4G DMA above 4GB memory.\r | |
658 | \r | |
659 | @param[in] NoExtendedConfigSpace No Extended Config Space.\r | |
660 | \r | |
661 | @param[in] BusMin Minimum Bus number, inclusive.\r | |
662 | \r | |
663 | @param[in] BusMax Maximum Bus number, inclusive.\r | |
664 | \r | |
665 | @param[in] Io IO aperture.\r | |
666 | \r | |
667 | @param[in] Mem MMIO aperture.\r | |
668 | \r | |
669 | @param[in] MemAbove4G MMIO aperture above 4G.\r | |
670 | \r | |
671 | @param[in] PMem Prefetchable MMIO aperture.\r | |
672 | \r | |
673 | @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.\r | |
674 | \r | |
675 | @return All the root bridge instances in an array.\r | |
676 | **/\r | |
677 | PCI_ROOT_BRIDGE *\r | |
678 | EFIAPI\r | |
679 | PciHostBridgeUtilityGetRootBridges (\r | |
680 | OUT UINTN *Count,\r | |
681 | IN UINT64 Attributes,\r | |
682 | IN UINT64 AllocationAttributes,\r | |
683 | IN BOOLEAN DmaAbove4G,\r | |
684 | IN BOOLEAN NoExtendedConfigSpace,\r | |
685 | IN UINTN BusMin,\r | |
686 | IN UINTN BusMax,\r | |
687 | IN PCI_ROOT_BRIDGE_APERTURE *Io,\r | |
688 | IN PCI_ROOT_BRIDGE_APERTURE *Mem,\r | |
689 | IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G,\r | |
690 | IN PCI_ROOT_BRIDGE_APERTURE *PMem,\r | |
691 | IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G\r | |
692 | )\r | |
693 | {\r | |
694 | PCI_ROOT_BRIDGE *Bridges;\r | |
695 | \r | |
696 | *Count = 0;\r | |
697 | \r | |
698 | //\r | |
699 | // First attempt to get the host provided descriptions of the Root Bridges\r | |
700 | // if available.\r | |
701 | //\r | |
702 | Bridges = PciHostBridgeUtilityGetRootBridgesHostProvided (Count);\r | |
703 | \r | |
704 | //\r | |
705 | // If host did not provide Root Bridge information, scan the buses and\r | |
706 | // auto populate them with default resources.\r | |
707 | //\r | |
708 | if (Bridges == NULL) {\r | |
709 | Bridges = PciHostBridgeUtilityGetRootBridgesBusScan (\r | |
710 | Count,\r | |
711 | Attributes,\r | |
712 | AllocationAttributes,\r | |
713 | DmaAbove4G,\r | |
714 | NoExtendedConfigSpace,\r | |
715 | BusMin,\r | |
716 | BusMax,\r | |
717 | Io,\r | |
718 | Mem,\r | |
719 | MemAbove4G,\r | |
720 | PMem,\r | |
721 | PMemAbove4G\r | |
722 | );\r | |
723 | }\r | |
724 | \r | |
725 | return Bridges;\r | |
726 | }\r | |
727 | \r | |
4edba296 JC |
728 | /**\r |
729 | Utility function to free root bridge instances array from\r | |
730 | PciHostBridgeUtilityGetRootBridges().\r | |
731 | \r | |
732 | @param[in] Bridges The root bridge instances array.\r | |
733 | @param[in] Count The count of the array.\r | |
734 | **/\r | |
735 | VOID\r | |
736 | EFIAPI\r | |
737 | PciHostBridgeUtilityFreeRootBridges (\r | |
ac0a286f MK |
738 | IN PCI_ROOT_BRIDGE *Bridges,\r |
739 | IN UINTN Count\r | |
4edba296 JC |
740 | )\r |
741 | {\r | |
ac0a286f | 742 | if ((Bridges == NULL) && (Count == 0)) {\r |
4edba296 JC |
743 | return;\r |
744 | }\r | |
ac0a286f | 745 | \r |
4edba296 JC |
746 | ASSERT (Bridges != NULL && Count > 0);\r |
747 | \r | |
748 | do {\r | |
749 | --Count;\r | |
750 | PciHostBridgeUtilityUninitRootBridge (&Bridges[Count]);\r | |
751 | } while (Count > 0);\r | |
752 | \r | |
753 | FreePool (Bridges);\r | |
754 | }\r | |
755 | \r | |
7a6172f8 JC |
756 | /**\r |
757 | Utility function to inform the platform that the resource conflict happens.\r | |
758 | \r | |
759 | @param[in] Configuration Pointer to PCI I/O and PCI memory resource\r | |
760 | descriptors. The Configuration contains the\r | |
761 | resources for all the root bridges. The resource\r | |
762 | for each root bridge is terminated with END\r | |
763 | descriptor and an additional END is appended\r | |
764 | indicating the end of the entire resources. The\r | |
765 | resource descriptor field values follow the\r | |
766 | description in\r | |
767 | EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL\r | |
768 | .SubmitResources().\r | |
769 | **/\r | |
770 | VOID\r | |
771 | EFIAPI\r | |
772 | PciHostBridgeUtilityResourceConflict (\r | |
773 | IN VOID *Configuration\r | |
774 | )\r | |
775 | {\r | |
ac0a286f MK |
776 | EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r |
777 | UINTN RootBridgeIndex;\r | |
778 | \r | |
7a6172f8 JC |
779 | DEBUG ((DEBUG_ERROR, "PciHostBridge: Resource conflict happens!\n"));\r |
780 | \r | |
781 | RootBridgeIndex = 0;\r | |
ac0a286f | 782 | Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Configuration;\r |
7a6172f8 JC |
783 | while (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) {\r |
784 | DEBUG ((DEBUG_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++));\r | |
ac0a286f MK |
785 | for ( ; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {\r |
786 | ASSERT (\r | |
787 | Descriptor->ResType <\r | |
788 | ARRAY_SIZE (mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr)\r | |
789 | );\r | |
790 | DEBUG ((\r | |
791 | DEBUG_ERROR,\r | |
792 | " %s: Length/Alignment = 0x%lx / 0x%lx\n",\r | |
793 | mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr[Descriptor->ResType],\r | |
794 | Descriptor->AddrLen,\r | |
795 | Descriptor->AddrRangeMax\r | |
796 | ));\r | |
7a6172f8 | 797 | if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {\r |
ac0a286f MK |
798 | DEBUG ((\r |
799 | DEBUG_ERROR,\r | |
800 | " Granularity/SpecificFlag = %ld / %02x%s\n",\r | |
801 | Descriptor->AddrSpaceGranularity,\r | |
802 | Descriptor->SpecificFlag,\r | |
803 | ((Descriptor->SpecificFlag &\r | |
804 | EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE\r | |
805 | ) != 0) ? L" (Prefetchable)" : L""\r | |
806 | ));\r | |
7a6172f8 JC |
807 | }\r |
808 | }\r | |
ac0a286f | 809 | \r |
7a6172f8 JC |
810 | //\r |
811 | // Skip the END descriptor for root bridge\r | |
812 | //\r | |
813 | ASSERT (Descriptor->Desc == ACPI_END_TAG_DESCRIPTOR);\r | |
814 | Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(\r | |
ac0a286f MK |
815 | (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor + 1\r |
816 | );\r | |
7a6172f8 JC |
817 | }\r |
818 | }\r |