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