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