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