]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/QemuBootOrderLib/ExtraRootBusMap.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / Library / QemuBootOrderLib / ExtraRootBusMap.c
CommitLineData
6b40e66a
RN
1/** @file\r
2 Map positions of extra PCI root buses to bus numbers.\r
3\r
4 Copyright (C) 2015, Red Hat, Inc.\r
5\r
b26f0cf9 6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
6b40e66a
RN
7**/\r
8\r
9#include <Library/DebugLib.h>\r
10#include <Library/DevicePathLib.h>\r
11#include <Library/MemoryAllocationLib.h>\r
12#include <Library/OrderedCollectionLib.h>\r
13#include <Library/UefiBootServicesTableLib.h>\r
14#include <Protocol/DevicePath.h>\r
15#include <Protocol/PciRootBridgeIo.h>\r
16\r
17#include "ExtraRootBusMap.h"\r
18\r
19//\r
20// The BusNumbers field is an array with Count elements. The elements increase\r
21// strictry monotonically. Zero is not an element (because the zero bus number\r
22// belongs to the "main" root bus, never to an extra root bus). Offset N in the\r
23// array maps the extra root bus with position (N+1) to its bus number (because\r
24// the root bus with position 0 is always the main root bus, therefore we don't\r
25// store it).\r
26//\r
27// If there are no extra root buses in the system, then Count is 0, and\r
28// BusNumbers is NULL.\r
29//\r
30struct EXTRA_ROOT_BUS_MAP_STRUCT {\r
ac0a286f
MK
31 UINT32 *BusNumbers;\r
32 UINTN Count;\r
6b40e66a
RN
33};\r
34\r
6b40e66a
RN
35/**\r
36 An ORDERED_COLLECTION_USER_COMPARE function that compares root bridge\r
37 protocol device paths based on UID.\r
38\r
39 @param[in] UserStruct1 Pointer to the first ACPI_HID_DEVICE_PATH.\r
40\r
41 @param[in] UserStruct2 Pointer to the second ACPI_HID_DEVICE_PATH.\r
42\r
43 @retval <0 If UserStruct1 compares less than UserStruct2.\r
44\r
45 @retval 0 If UserStruct1 compares equal to UserStruct2.\r
46\r
47 @retval >0 If UserStruct1 compares greater than UserStruct2.\r
48**/\r
49STATIC\r
50INTN\r
51EFIAPI\r
52RootBridgePathCompare (\r
ac0a286f
MK
53 IN CONST VOID *UserStruct1,\r
54 IN CONST VOID *UserStruct2\r
6b40e66a
RN
55 )\r
56{\r
ac0a286f
MK
57 CONST ACPI_HID_DEVICE_PATH *Acpi1;\r
58 CONST ACPI_HID_DEVICE_PATH *Acpi2;\r
6b40e66a
RN
59\r
60 Acpi1 = UserStruct1;\r
61 Acpi2 = UserStruct2;\r
62\r
63 return Acpi1->UID < Acpi2->UID ? -1 :\r
64 Acpi1->UID > Acpi2->UID ? 1 :\r
65 0;\r
66}\r
67\r
6b40e66a
RN
68/**\r
69 An ORDERED_COLLECTION_KEY_COMPARE function that compares a root bridge\r
70 protocol device path against a UID.\r
71\r
72 @param[in] StandaloneKey Pointer to the bare UINT32 UID.\r
73\r
74 @param[in] UserStruct Pointer to the ACPI_HID_DEVICE_PATH with the\r
75 embedded UINT32 UID.\r
76\r
77 @retval <0 If StandaloneKey compares less than UserStruct's key.\r
78\r
79 @retval 0 If StandaloneKey compares equal to UserStruct's key.\r
80\r
81 @retval >0 If StandaloneKey compares greater than UserStruct's key.\r
82**/\r
83STATIC\r
84INTN\r
85EFIAPI\r
86RootBridgePathKeyCompare (\r
ac0a286f
MK
87 IN CONST VOID *StandaloneKey,\r
88 IN CONST VOID *UserStruct\r
6b40e66a
RN
89 )\r
90{\r
ac0a286f
MK
91 CONST UINT32 *Uid;\r
92 CONST ACPI_HID_DEVICE_PATH *Acpi;\r
6b40e66a
RN
93\r
94 Uid = StandaloneKey;\r
95 Acpi = UserStruct;\r
96\r
97 return *Uid < Acpi->UID ? -1 :\r
98 *Uid > Acpi->UID ? 1 :\r
99 0;\r
100}\r
101\r
6b40e66a
RN
102/**\r
103 Create a structure that maps the relative positions of PCI root buses to bus\r
104 numbers.\r
105\r
106 In the "bootorder" fw_cfg file, QEMU refers to extra PCI root buses by their\r
107 positions, in relative root bus number order, not by their actual PCI bus\r
108 numbers. The ACPI HID device path nodes however that are associated with\r
109 PciRootBridgeIo protocol instances in the system have their UID fields set to\r
110 the bus numbers. Create a map that gives, for each extra PCI root bus's\r
111 position (ie. "serial number") its actual PCI bus number.\r
112\r
113 @param[out] ExtraRootBusMap The data structure implementing the map.\r
114\r
115 @retval EFI_SUCCESS ExtraRootBusMap has been populated.\r
116\r
117 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.\r
118\r
119 @retval EFI_ALREADY_STARTED A duplicate root bus number has been found in\r
120 the system. (This should never happen.)\r
121\r
122 @return Error codes returned by\r
123 gBS->LocateHandleBuffer() and\r
124 gBS->HandleProtocol().\r
125\r
126**/\r
127EFI_STATUS\r
128CreateExtraRootBusMap (\r
ac0a286f 129 OUT EXTRA_ROOT_BUS_MAP **ExtraRootBusMap\r
6b40e66a
RN
130 )\r
131{\r
ac0a286f
MK
132 EFI_STATUS Status;\r
133 UINTN NumHandles;\r
134 EFI_HANDLE *Handles;\r
135 ORDERED_COLLECTION *Collection;\r
136 EXTRA_ROOT_BUS_MAP *Map;\r
137 UINTN Idx;\r
138 ORDERED_COLLECTION_ENTRY *Entry, *Entry2;\r
6b40e66a
RN
139\r
140 //\r
141 // Handles and Collection are temporary / helper variables, while in Map we\r
142 // build the return value.\r
143 //\r
144\r
ac0a286f
MK
145 Status = gBS->LocateHandleBuffer (\r
146 ByProtocol,\r
147 &gEfiPciRootBridgeIoProtocolGuid,\r
148 NULL /* SearchKey */,\r
149 &NumHandles,\r
150 &Handles\r
151 );\r
152 if (EFI_ERROR (Status)) {\r
6b40e66a
RN
153 return Status;\r
154 }\r
155\r
ac0a286f
MK
156 Collection = OrderedCollectionInit (\r
157 RootBridgePathCompare,\r
158 RootBridgePathKeyCompare\r
159 );\r
6b40e66a
RN
160 if (Collection == NULL) {\r
161 Status = EFI_OUT_OF_RESOURCES;\r
162 goto FreeHandles;\r
163 }\r
164\r
165 Map = AllocateZeroPool (sizeof *Map);\r
166 if (Map == NULL) {\r
167 Status = EFI_OUT_OF_RESOURCES;\r
168 goto FreeCollection;\r
169 }\r
170\r
171 //\r
172 // Collect the ACPI device path protocols of the root bridges.\r
173 //\r
174 for (Idx = 0; Idx < NumHandles; ++Idx) {\r
ac0a286f 175 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
6b40e66a 176\r
ac0a286f
MK
177 Status = gBS->HandleProtocol (\r
178 Handles[Idx],\r
179 &gEfiDevicePathProtocolGuid,\r
180 (VOID **)&DevicePath\r
181 );\r
6b40e66a
RN
182 if (EFI_ERROR (Status)) {\r
183 goto FreeMap;\r
184 }\r
185\r
186 //\r
187 // Examine if the device path is an ACPI HID one, and if so, if UID is\r
188 // nonzero (ie. the root bridge that the bus number belongs to is "extra",\r
189 // not the main one). In that case, link the device path into Collection.\r
190 //\r
ac0a286f
MK
191 if ((DevicePathType (DevicePath) == ACPI_DEVICE_PATH) &&\r
192 (DevicePathSubType (DevicePath) == ACPI_DP) &&\r
193 (((ACPI_HID_DEVICE_PATH *)DevicePath)->HID == EISA_PNP_ID (0x0A03)) &&\r
194 (((ACPI_HID_DEVICE_PATH *)DevicePath)->UID > 0))\r
195 {\r
6b40e66a
RN
196 Status = OrderedCollectionInsert (Collection, NULL, DevicePath);\r
197 if (EFI_ERROR (Status)) {\r
198 goto FreeMap;\r
199 }\r
ac0a286f 200\r
6b40e66a
RN
201 ++Map->Count;\r
202 }\r
203 }\r
204\r
205 if (Map->Count > 0) {\r
206 //\r
207 // At least one extra PCI root bus exists.\r
208 //\r
209 Map->BusNumbers = AllocatePool (Map->Count * sizeof *Map->BusNumbers);\r
210 if (Map->BusNumbers == NULL) {\r
211 Status = EFI_OUT_OF_RESOURCES;\r
212 goto FreeMap;\r
213 }\r
214 }\r
215\r
216 //\r
217 // Now collect the bus numbers of the extra PCI root buses into Map.\r
218 //\r
ac0a286f 219 Idx = 0;\r
6b40e66a
RN
220 Entry = OrderedCollectionMin (Collection);\r
221 while (Idx < Map->Count) {\r
ac0a286f 222 ACPI_HID_DEVICE_PATH *Acpi;\r
6b40e66a
RN
223\r
224 ASSERT (Entry != NULL);\r
ac0a286f 225 Acpi = OrderedCollectionUserStruct (Entry);\r
6b40e66a 226 Map->BusNumbers[Idx] = Acpi->UID;\r
ac0a286f
MK
227 DEBUG ((\r
228 DEBUG_VERBOSE,\r
6b40e66a 229 "%a: extra bus position 0x%Lx maps to bus number (UID) 0x%x\n",\r
ac0a286f
MK
230 __FUNCTION__,\r
231 (UINT64)(Idx + 1),\r
232 Acpi->UID\r
233 ));\r
6b40e66a
RN
234 ++Idx;\r
235 Entry = OrderedCollectionNext (Entry);\r
236 }\r
ac0a286f 237\r
6b40e66a
RN
238 ASSERT (Entry == NULL);\r
239\r
240 *ExtraRootBusMap = Map;\r
ac0a286f 241 Status = EFI_SUCCESS;\r
6b40e66a
RN
242\r
243 //\r
244 // Fall through in order to release temporaries.\r
245 //\r
246\r
247FreeMap:\r
248 if (EFI_ERROR (Status)) {\r
249 if (Map->BusNumbers != NULL) {\r
250 FreePool (Map->BusNumbers);\r
251 }\r
ac0a286f 252\r
6b40e66a
RN
253 FreePool (Map);\r
254 }\r
255\r
256FreeCollection:\r
257 for (Entry = OrderedCollectionMin (Collection); Entry != NULL;\r
ac0a286f
MK
258 Entry = Entry2)\r
259 {\r
6b40e66a
RN
260 Entry2 = OrderedCollectionNext (Entry);\r
261 OrderedCollectionDelete (Collection, Entry, NULL);\r
262 }\r
ac0a286f 263\r
6b40e66a
RN
264 OrderedCollectionUninit (Collection);\r
265\r
266FreeHandles:\r
267 FreePool (Handles);\r
268\r
269 return Status;\r
270}\r
271\r
6b40e66a
RN
272/**\r
273 Release a map created with CreateExtraRootBusMap().\r
274\r
275 @param[in] ExtraRootBusMap The map to release.\r
276*/\r
277VOID\r
278DestroyExtraRootBusMap (\r
ac0a286f 279 IN EXTRA_ROOT_BUS_MAP *ExtraRootBusMap\r
6b40e66a
RN
280 )\r
281{\r
282 if (ExtraRootBusMap->BusNumbers != NULL) {\r
283 FreePool (ExtraRootBusMap->BusNumbers);\r
284 }\r
ac0a286f 285\r
6b40e66a
RN
286 FreePool (ExtraRootBusMap);\r
287}\r
288\r
289/**\r
290 Map the position (serial number) of an extra PCI root bus to its bus number.\r
291\r
292 @param[in] ExtraRootBusMap The map created with CreateExtraRootBusMap();\r
293\r
294 @param[in] RootBusPos The extra PCI root bus position to map.\r
295\r
296 @param[out] RootBusNr The bus number belonging to the extra PCI root\r
297 bus identified by RootBusPos.\r
298\r
299 @retval EFI_INVALID_PARAMETER RootBusPos is zero. The zero position\r
300 identifies the main root bus, whose bus number\r
301 is always zero, and is therefore never\r
302 maintained in ExtraRootBusMap.\r
303\r
304 @retval EFI_NOT_FOUND RootBusPos is not found in ExtraRootBusMap.\r
305\r
306 @retval EFI_SUCCESS Mapping successful.\r
307**/\r
308EFI_STATUS\r
309MapRootBusPosToBusNr (\r
ac0a286f
MK
310 IN CONST EXTRA_ROOT_BUS_MAP *ExtraRootBusMap,\r
311 IN UINT64 RootBusPos,\r
312 OUT UINT32 *RootBusNr\r
6b40e66a
RN
313 )\r
314{\r
315 if (RootBusPos == 0) {\r
316 return EFI_INVALID_PARAMETER;\r
317 }\r
ac0a286f 318\r
6b40e66a
RN
319 if (RootBusPos > ExtraRootBusMap->Count) {\r
320 return EFI_NOT_FOUND;\r
321 }\r
ac0a286f 322\r
8d127a5a 323 *RootBusNr = ExtraRootBusMap->BusNumbers[(UINTN)RootBusPos - 1];\r
6b40e66a
RN
324 return EFI_SUCCESS;\r
325}\r