]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/PciHostBridgeLib/PciHostBridgeLib.c
OvmfPkg: PciHostBridgeLib: install 64-bit PCI host aperture
[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
74 /**
75 Initialize a PCI_ROOT_BRIDGE structure.
76
77 param[in] RootBusNumber The bus number to store in RootBus.
78
79 param[in] MaxSubBusNumber The inclusive maximum bus number that can be
80 assigned to any subordinate bus found behind any
81 PCI bridge hanging off this root bus.
82
83 The caller is repsonsible for ensuring that
84 RootBusNumber <= MaxSubBusNumber. If
85 RootBusNumber equals MaxSubBusNumber, then the
86 root bus has no room for subordinate buses.
87
88 param[out] RootBus The PCI_ROOT_BRIDGE structure (allocated by the
89 caller) that should be filled in by this
90 function.
91
92 @retval EFI_SUCCESS Initialization successful. A device path
93 consisting of an ACPI device path node, with
94 UID = RootBusNumber, has been allocated and
95 linked into RootBus.
96
97 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
98 **/
99 STATIC
100 EFI_STATUS
101 InitRootBridge (
102 IN UINT8 RootBusNumber,
103 IN UINT8 MaxSubBusNumber,
104 OUT PCI_ROOT_BRIDGE *RootBus
105 )
106 {
107 OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH *DevicePath;
108
109 //
110 // Be safe if other fields are added to PCI_ROOT_BRIDGE later.
111 //
112 ZeroMem (RootBus, sizeof *RootBus);
113
114 RootBus->Segment = 0;
115
116 RootBus->Supports = EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO |
117 EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO |
118 EFI_PCI_ATTRIBUTE_ISA_IO_16 |
119 EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO |
120 EFI_PCI_ATTRIBUTE_VGA_MEMORY |
121 EFI_PCI_ATTRIBUTE_VGA_IO_16 |
122 EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16;
123 RootBus->Attributes = RootBus->Supports;
124
125 RootBus->DmaAbove4G = FALSE;
126
127 RootBus->AllocationAttributes = EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM;
128 RootBus->PMem.Base = 0;
129 RootBus->PMem.Limit = 0;
130 RootBus->PMemAbove4G.Base = 0;
131 RootBus->PMemAbove4G.Limit = 0;
132 RootBus->MemAbove4G.Base = 0;
133 RootBus->MemAbove4G.Limit = 0;
134
135 if (PcdGet64 (PcdPciMmio64Size) > 0) {
136 RootBus->AllocationAttributes |= EFI_PCI_HOST_BRIDGE_MEM64_DECODE;
137 RootBus->MemAbove4G.Base = PcdGet64 (PcdPciMmio64Base);
138 RootBus->MemAbove4G.Limit = PcdGet64 (PcdPciMmio64Base) +
139 (PcdGet64 (PcdPciMmio64Size) - 1);
140 }
141
142 RootBus->Bus.Base = RootBusNumber;
143 RootBus->Bus.Limit = MaxSubBusNumber;
144 RootBus->Io.Base = PcdGet64 (PcdPciIoBase);
145 RootBus->Io.Limit = PcdGet64 (PcdPciIoBase) + (PcdGet64 (PcdPciIoSize) - 1);
146 RootBus->Mem.Base = PcdGet64 (PcdPciMmio32Base);
147 RootBus->Mem.Limit = PcdGet64 (PcdPciMmio32Base) +
148 (PcdGet64 (PcdPciMmio32Size) - 1);
149
150 RootBus->NoExtendedConfigSpace = (PcdGet16 (PcdOvmfHostBridgePciDevId) !=
151 INTEL_Q35_MCH_DEVICE_ID);
152
153 DevicePath = AllocateCopyPool (sizeof mRootBridgeDevicePathTemplate,
154 &mRootBridgeDevicePathTemplate);
155 if (DevicePath == NULL) {
156 DEBUG ((EFI_D_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES));
157 return EFI_OUT_OF_RESOURCES;
158 }
159 DevicePath->AcpiDevicePath.UID = RootBusNumber;
160 RootBus->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;
161
162 DEBUG ((EFI_D_INFO,
163 "%a: populated root bus %d, with room for %d subordinate bus(es)\n",
164 __FUNCTION__, RootBusNumber, MaxSubBusNumber - RootBusNumber));
165 return EFI_SUCCESS;
166 }
167
168
169 /**
170 Uninitialize a PCI_ROOT_BRIDGE structure set up with InitRootBridge().
171
172 param[in] RootBus The PCI_ROOT_BRIDGE structure, allocated by the caller and
173 initialized with InitRootBridge(), that should be
174 uninitialized. This function doesn't free RootBus.
175 **/
176 STATIC
177 VOID
178 UninitRootBridge (
179 IN PCI_ROOT_BRIDGE *RootBus
180 )
181 {
182 FreePool (RootBus->DevicePath);
183 }
184
185
186 /**
187 Return all the root bridge instances in an array.
188
189 @param Count Return the count of root bridge instances.
190
191 @return All the root bridge instances in an array.
192 The array should be passed into PciHostBridgeFreeRootBridges()
193 when it's not used.
194 **/
195 PCI_ROOT_BRIDGE *
196 EFIAPI
197 PciHostBridgeGetRootBridges (
198 UINTN *Count
199 )
200 {
201 EFI_STATUS Status;
202 FIRMWARE_CONFIG_ITEM FwCfgItem;
203 UINTN FwCfgSize;
204 UINT64 ExtraRootBridges;
205 PCI_ROOT_BRIDGE *Bridges;
206 UINTN Initialized;
207 UINTN LastRootBridgeNumber;
208 UINTN RootBridgeNumber;
209
210 *Count = 0;
211
212 //
213 // QEMU provides the number of extra root buses, shortening the exhaustive
214 // search below. If there is no hint, the feature is missing.
215 //
216 Status = QemuFwCfgFindFile ("etc/extra-pci-roots", &FwCfgItem, &FwCfgSize);
217 if (EFI_ERROR (Status) || FwCfgSize != sizeof ExtraRootBridges) {
218 ExtraRootBridges = 0;
219 } else {
220 QemuFwCfgSelectItem (FwCfgItem);
221 QemuFwCfgReadBytes (FwCfgSize, &ExtraRootBridges);
222
223 if (ExtraRootBridges > PCI_MAX_BUS) {
224 DEBUG ((EFI_D_ERROR, "%a: invalid count of extra root buses (%Lu) "
225 "reported by QEMU\n", __FUNCTION__, ExtraRootBridges));
226 return NULL;
227 }
228 DEBUG ((EFI_D_INFO, "%a: %Lu extra root buses reported by QEMU\n",
229 __FUNCTION__, ExtraRootBridges));
230 }
231
232 //
233 // Allocate the "main" root bridge, and any extra root bridges.
234 //
235 Bridges = AllocatePool ((1 + (UINTN)ExtraRootBridges) * sizeof *Bridges);
236 if (Bridges == NULL) {
237 DEBUG ((EFI_D_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES));
238 return NULL;
239 }
240 Initialized = 0;
241
242 //
243 // The "main" root bus is always there.
244 //
245 LastRootBridgeNumber = 0;
246
247 //
248 // Scan all other root buses. If function 0 of any device on a bus returns a
249 // VendorId register value different from all-bits-one, then that bus is
250 // alive.
251 //
252 for (RootBridgeNumber = 1;
253 RootBridgeNumber <= PCI_MAX_BUS && Initialized < ExtraRootBridges;
254 ++RootBridgeNumber) {
255 UINTN Device;
256
257 for (Device = 0; Device <= PCI_MAX_DEVICE; ++Device) {
258 if (PciRead16 (PCI_LIB_ADDRESS (RootBridgeNumber, Device, 0,
259 PCI_VENDOR_ID_OFFSET)) != MAX_UINT16) {
260 break;
261 }
262 }
263 if (Device <= PCI_MAX_DEVICE) {
264 //
265 // Found the next root bus. We can now install the *previous* one,
266 // because now we know how big a bus number range *that* one has, for any
267 // subordinate buses that might exist behind PCI bridges hanging off it.
268 //
269 Status = InitRootBridge ((UINT8)LastRootBridgeNumber,
270 (UINT8)(RootBridgeNumber - 1), &Bridges[Initialized]);
271 if (EFI_ERROR (Status)) {
272 goto FreeBridges;
273 }
274 ++Initialized;
275 LastRootBridgeNumber = RootBridgeNumber;
276 }
277 }
278
279 //
280 // Install the last root bus (which might be the only, ie. main, root bus, if
281 // we've found no extra root buses).
282 //
283 Status = InitRootBridge ((UINT8)LastRootBridgeNumber, PCI_MAX_BUS,
284 &Bridges[Initialized]);
285 if (EFI_ERROR (Status)) {
286 goto FreeBridges;
287 }
288 ++Initialized;
289
290 *Count = Initialized;
291 return Bridges;
292
293 FreeBridges:
294 while (Initialized > 0) {
295 --Initialized;
296 UninitRootBridge (&Bridges[Initialized]);
297 }
298
299 FreePool (Bridges);
300 return NULL;
301 }
302
303
304 /**
305 Free the root bridge instances array returned from
306 PciHostBridgeGetRootBridges().
307
308 @param The root bridge instances array.
309 @param The count of the array.
310 **/
311 VOID
312 EFIAPI
313 PciHostBridgeFreeRootBridges (
314 PCI_ROOT_BRIDGE *Bridges,
315 UINTN Count
316 )
317 {
318 if (Bridges == NULL && Count == 0) {
319 return;
320 }
321 ASSERT (Bridges != NULL && Count > 0);
322
323 do {
324 --Count;
325 UninitRootBridge (&Bridges[Count]);
326 } while (Count > 0);
327
328 FreePool (Bridges);
329 }
330
331
332 /**
333 Inform the platform that the resource conflict happens.
334
335 @param HostBridgeHandle Handle of the Host Bridge.
336 @param Configuration Pointer to PCI I/O and PCI memory resource
337 descriptors. The Configuration contains the resources
338 for all the root bridges. The resource for each root
339 bridge is terminated with END descriptor and an
340 additional END is appended indicating the end of the
341 entire resources. The resource descriptor field
342 values follow the description in
343 EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
344 .SubmitResources().
345 **/
346 VOID
347 EFIAPI
348 PciHostBridgeResourceConflict (
349 EFI_HANDLE HostBridgeHandle,
350 VOID *Configuration
351 )
352 {
353 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
354 UINTN RootBridgeIndex;
355 DEBUG ((EFI_D_ERROR, "PciHostBridge: Resource conflict happens!\n"));
356
357 RootBridgeIndex = 0;
358 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
359 while (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
360 DEBUG ((EFI_D_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++));
361 for (; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {
362 ASSERT (Descriptor->ResType <
363 (sizeof (mPciHostBridgeLibAcpiAddressSpaceTypeStr) /
364 sizeof (mPciHostBridgeLibAcpiAddressSpaceTypeStr[0])
365 )
366 );
367 DEBUG ((EFI_D_ERROR, " %s: Length/Alignment = 0x%lx / 0x%lx\n",
368 mPciHostBridgeLibAcpiAddressSpaceTypeStr[Descriptor->ResType],
369 Descriptor->AddrLen, Descriptor->AddrRangeMax
370 ));
371 if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
372 DEBUG ((EFI_D_ERROR, " Granularity/SpecificFlag = %ld / %02x%s\n",
373 Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag,
374 ((Descriptor->SpecificFlag &
375 EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
376 ) != 0) ? L" (Prefetchable)" : L""
377 ));
378 }
379 }
380 //
381 // Skip the END descriptor for root bridge
382 //
383 ASSERT (Descriptor->Desc == ACPI_END_TAG_DESCRIPTOR);
384 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(
385 (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor + 1
386 );
387 }
388 }