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