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