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