]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/PciHostBridgeLib/PciHostBridgeLib.c
OvmfPkg: PciHostBridgeLib: set RootBus->AllocationAttributes
[mirror_edk2.git] / OvmfPkg / Library / PciHostBridgeLib / PciHostBridgeLib.c
CommitLineData
d85861d7
LE
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
46e46eaf
LE
17\r
18#include <IndustryStandard/Pci.h>\r
19\r
0dcd1b1b 20#include <Protocol/PciHostBridgeResourceAllocation.h>\r
a5ece62d
LE
21#include <Protocol/PciRootBridgeIo.h>\r
22\r
65de2ef5 23#include <Library/BaseMemoryLib.h>\r
d85861d7 24#include <Library/DebugLib.h>\r
46e46eaf
LE
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
d85861d7
LE
30\r
31GLOBAL_REMOVE_IF_UNREFERENCED\r
32CHAR16 *mPciHostBridgeLibAcpiAddressSpaceTypeStr[] = {\r
33 L"Mem", L"I/O", L"Bus"\r
34};\r
35\r
46e46eaf
LE
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
65de2ef5
LE
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
a5ece62d
LE
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
c789d61d
LE
86 RootBus->DmaAbove4G = FALSE;\r
87\r
0dcd1b1b
LE
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
46e46eaf
LE
96 return EFI_OUT_OF_RESOURCES;\r
97}\r
98\r
99\r
100/**\r
101 Uninitialize a PCI_ROOT_BRIDGE structure set up with InitRootBridge().\r
102\r
103 param[in] RootBus The PCI_ROOT_BRIDGE structure, allocated by the caller and\r
104 initialized with InitRootBridge(), that should be\r
105 uninitialized. This function doesn't free RootBus.\r
106**/\r
107STATIC\r
108VOID\r
109UninitRootBridge (\r
110 IN PCI_ROOT_BRIDGE *RootBus\r
111 )\r
112{\r
113}\r
114\r
115\r
d85861d7
LE
116/**\r
117 Return all the root bridge instances in an array.\r
118\r
119 @param Count Return the count of root bridge instances.\r
120\r
121 @return All the root bridge instances in an array.\r
122 The array should be passed into PciHostBridgeFreeRootBridges()\r
123 when it's not used.\r
124**/\r
125PCI_ROOT_BRIDGE *\r
126EFIAPI\r
127PciHostBridgeGetRootBridges (\r
128 UINTN *Count\r
129 )\r
130{\r
46e46eaf
LE
131 EFI_STATUS Status;\r
132 FIRMWARE_CONFIG_ITEM FwCfgItem;\r
133 UINTN FwCfgSize;\r
134 UINT64 ExtraRootBridges;\r
135 PCI_ROOT_BRIDGE *Bridges;\r
136 UINTN Initialized;\r
137 UINTN LastRootBridgeNumber;\r
138 UINTN RootBridgeNumber;\r
139\r
d85861d7 140 *Count = 0;\r
46e46eaf
LE
141\r
142 //\r
143 // QEMU provides the number of extra root buses, shortening the exhaustive\r
144 // search below. If there is no hint, the feature is missing.\r
145 //\r
146 Status = QemuFwCfgFindFile ("etc/extra-pci-roots", &FwCfgItem, &FwCfgSize);\r
147 if (EFI_ERROR (Status) || FwCfgSize != sizeof ExtraRootBridges) {\r
148 ExtraRootBridges = 0;\r
149 } else {\r
150 QemuFwCfgSelectItem (FwCfgItem);\r
151 QemuFwCfgReadBytes (FwCfgSize, &ExtraRootBridges);\r
152\r
153 if (ExtraRootBridges > PCI_MAX_BUS) {\r
154 DEBUG ((EFI_D_ERROR, "%a: invalid count of extra root buses (%Lu) "\r
155 "reported by QEMU\n", __FUNCTION__, ExtraRootBridges));\r
156 return NULL;\r
157 }\r
158 DEBUG ((EFI_D_INFO, "%a: %Lu extra root buses reported by QEMU\n",\r
159 __FUNCTION__, ExtraRootBridges));\r
160 }\r
161\r
162 //\r
163 // Allocate the "main" root bridge, and any extra root bridges.\r
164 //\r
165 Bridges = AllocatePool ((1 + (UINTN)ExtraRootBridges) * sizeof *Bridges);\r
166 if (Bridges == NULL) {\r
167 DEBUG ((EFI_D_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES));\r
168 return NULL;\r
169 }\r
170 Initialized = 0;\r
171\r
172 //\r
173 // The "main" root bus is always there.\r
174 //\r
175 LastRootBridgeNumber = 0;\r
176\r
177 //\r
178 // Scan all other root buses. If function 0 of any device on a bus returns a\r
179 // VendorId register value different from all-bits-one, then that bus is\r
180 // alive.\r
181 //\r
182 for (RootBridgeNumber = 1;\r
183 RootBridgeNumber <= PCI_MAX_BUS && Initialized < ExtraRootBridges;\r
184 ++RootBridgeNumber) {\r
185 UINTN Device;\r
186\r
187 for (Device = 0; Device <= PCI_MAX_DEVICE; ++Device) {\r
188 if (PciRead16 (PCI_LIB_ADDRESS (RootBridgeNumber, Device, 0,\r
189 PCI_VENDOR_ID_OFFSET)) != MAX_UINT16) {\r
190 break;\r
191 }\r
192 }\r
193 if (Device <= PCI_MAX_DEVICE) {\r
194 //\r
195 // Found the next root bus. We can now install the *previous* one,\r
196 // because now we know how big a bus number range *that* one has, for any\r
197 // subordinate buses that might exist behind PCI bridges hanging off it.\r
198 //\r
199 Status = InitRootBridge ((UINT8)LastRootBridgeNumber,\r
200 (UINT8)(RootBridgeNumber - 1), &Bridges[Initialized]);\r
201 if (EFI_ERROR (Status)) {\r
202 goto FreeBridges;\r
203 }\r
204 ++Initialized;\r
205 LastRootBridgeNumber = RootBridgeNumber;\r
206 }\r
207 }\r
208\r
209 //\r
210 // Install the last root bus (which might be the only, ie. main, root bus, if\r
211 // we've found no extra root buses).\r
212 //\r
213 Status = InitRootBridge ((UINT8)LastRootBridgeNumber, PCI_MAX_BUS,\r
214 &Bridges[Initialized]);\r
215 if (EFI_ERROR (Status)) {\r
216 goto FreeBridges;\r
217 }\r
218 ++Initialized;\r
219\r
220 *Count = Initialized;\r
221 return Bridges;\r
222\r
223FreeBridges:\r
224 while (Initialized > 0) {\r
225 --Initialized;\r
226 UninitRootBridge (&Bridges[Initialized]);\r
227 }\r
228\r
229 FreePool (Bridges);\r
d85861d7
LE
230 return NULL;\r
231}\r
232\r
46e46eaf 233\r
d85861d7
LE
234/**\r
235 Free the root bridge instances array returned from\r
236 PciHostBridgeGetRootBridges().\r
237\r
238 @param The root bridge instances array.\r
239 @param The count of the array.\r
240**/\r
241VOID\r
242EFIAPI\r
243PciHostBridgeFreeRootBridges (\r
244 PCI_ROOT_BRIDGE *Bridges,\r
245 UINTN Count\r
246 )\r
247{\r
dc4d6467
LE
248 if (Bridges == NULL && Count == 0) {\r
249 return;\r
250 }\r
251 ASSERT (Bridges != NULL && Count > 0);\r
252\r
253 do {\r
254 --Count;\r
255 UninitRootBridge (&Bridges[Count]);\r
256 } while (Count > 0);\r
257\r
258 FreePool (Bridges);\r
d85861d7
LE
259}\r
260\r
46e46eaf 261\r
d85861d7
LE
262/**\r
263 Inform the platform that the resource conflict happens.\r
264\r
265 @param HostBridgeHandle Handle of the Host Bridge.\r
266 @param Configuration Pointer to PCI I/O and PCI memory resource\r
267 descriptors. The Configuration contains the resources\r
268 for all the root bridges. The resource for each root\r
269 bridge is terminated with END descriptor and an\r
270 additional END is appended indicating the end of the\r
271 entire resources. The resource descriptor field\r
272 values follow the description in\r
273 EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL\r
274 .SubmitResources().\r
275**/\r
276VOID\r
277EFIAPI\r
278PciHostBridgeResourceConflict (\r
279 EFI_HANDLE HostBridgeHandle,\r
280 VOID *Configuration\r
281 )\r
282{\r
283 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
284 UINTN RootBridgeIndex;\r
285 DEBUG ((EFI_D_ERROR, "PciHostBridge: Resource conflict happens!\n"));\r
286\r
287 RootBridgeIndex = 0;\r
288 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;\r
289 while (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) {\r
290 DEBUG ((EFI_D_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++));\r
291 for (; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {\r
292 ASSERT (Descriptor->ResType <\r
293 (sizeof (mPciHostBridgeLibAcpiAddressSpaceTypeStr) /\r
294 sizeof (mPciHostBridgeLibAcpiAddressSpaceTypeStr[0])\r
295 )\r
296 );\r
297 DEBUG ((EFI_D_ERROR, " %s: Length/Alignment = 0x%lx / 0x%lx\n",\r
298 mPciHostBridgeLibAcpiAddressSpaceTypeStr[Descriptor->ResType],\r
299 Descriptor->AddrLen, Descriptor->AddrRangeMax\r
300 ));\r
301 if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {\r
302 DEBUG ((EFI_D_ERROR, " Granularity/SpecificFlag = %ld / %02x%s\n",\r
303 Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag,\r
304 ((Descriptor->SpecificFlag &\r
305 EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE\r
306 ) != 0) ? L" (Prefetchable)" : L""\r
307 ));\r
308 }\r
309 }\r
310 //\r
311 // Skip the END descriptor for root bridge\r
312 //\r
313 ASSERT (Descriptor->Desc == ACPI_END_TAG_DESCRIPTOR);\r
314 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(\r
315 (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor + 1\r
316 );\r
317 }\r
318}\r