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