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