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