]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / IncompatiblePciDeviceSupportDxe / IncompatiblePciDeviceSupport.c
1 /** @file
2 This module is one template module for Incompatible PCI Device Support protocol.
3 It includes one incompatible pci devices list template.
4
5 Incompatible PCI Device Support protocol allows the PCI bus driver to support
6 resource allocation for some PCI devices that do not comply with the PCI Specification.
7
8 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
9 SPDX-License-Identifier: BSD-2-Clause-Patent
10
11 **/
12
13 #include <PiDxe.h>
14 #include <Protocol/IncompatiblePciDeviceSupport.h>
15
16 #include <Library/UefiBootServicesTableLib.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Library/DebugLib.h>
19
20 #include <IndustryStandard/Pci.h>
21 #include <IndustryStandard/Acpi.h>
22
23 typedef struct {
24 UINT64 VendorId;
25 UINT64 DeviceId;
26 UINT64 RevisionId;
27 UINT64 SubsystemVendorId;
28 UINT64 SubsystemDeviceId;
29 } EFI_PCI_DEVICE_HEADER_INFO;
30
31 typedef struct {
32 UINT64 ResType;
33 UINT64 GenFlag;
34 UINT64 SpecificFlag;
35 UINT64 AddrSpaceGranularity;
36 UINT64 AddrRangeMin;
37 UINT64 AddrRangeMax;
38 UINT64 AddrTranslationOffset;
39 UINT64 AddrLen;
40 } EFI_PCI_RESOUCE_DESCRIPTOR;
41
42 #define PCI_DEVICE_ID(VendorId, DeviceId, Revision, SubVendorId, SubDeviceId) \
43 VendorId, DeviceId, Revision, SubVendorId, SubDeviceId
44
45 #define DEVICE_INF_TAG 0xFFF2
46 #define DEVICE_RES_TAG 0xFFF1
47 #define LIST_END_TAG 0x0000
48
49 #define EVEN_ALIGN 0xFFFFFFFFFFFFFFFEULL
50
51 /**
52 Returns a list of ACPI resource descriptors that detail the special
53 resource configuration requirements for an incompatible PCI device.
54
55 @param This Pointer to the EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL instance.
56 @param VendorId A unique ID to identify the manufacturer of the PCI device.
57 @param DeviceId A unique ID to identify the particular PCI device.
58 @param RevisionId A PCI device-specific revision identifier.
59 @param SubsystemVendorId Specifies the subsystem vendor ID.
60 @param SubsystemDeviceId Specifies the subsystem device ID.
61 @param Configuration A list of ACPI resource descriptors returned that detail
62 the configuration requirement.
63
64 @retval EFI_SUCCESS Successfully got ACPI resource for specified PCI device.
65 @retval EFI_INVALID_PARAMETER Configuration is NULL.
66 @retval EFI_OUT_OF_RESOURCES No memory available.
67 @retval EFI_UNSUPPORTED The specified PCI device wasn't supported.
68
69 **/
70 EFI_STATUS
71 EFIAPI
72 PCheckDevice (
73 IN EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL *This,
74 IN UINTN VendorId,
75 IN UINTN DeviceId,
76 IN UINTN RevisionId,
77 IN UINTN SubsystemVendorId,
78 IN UINTN SubsystemDeviceId,
79 OUT VOID **Configuration
80 );
81
82 //
83 // Handle onto which the Incompatible PCI Device List is installed
84 //
85 EFI_HANDLE mIncompatiblePciDeviceSupportHandle = NULL;
86
87 //
88 // The Incompatible PCI Device Support Protocol instance produced by this driver
89 //
90 EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL mIncompatiblePciDeviceSupport = {
91 PCheckDevice
92 };
93
94 //
95 // The incompatible PCI devices list template
96 //
97 GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mIncompatiblePciDeviceList[] = {
98 //
99 // DEVICE_INF_TAG,
100 // PCI_DEVICE_ID (VendorID, DeviceID, Revision, SubVendorId, SubDeviceId),
101 // DEVICE_RES_TAG,
102 // ResType, GFlag , SFlag, Granularity, RangeMin,
103 // RangeMax, Offset, AddrLen
104 //
105 //
106 // Device Adaptec 9004
107 //
108 DEVICE_INF_TAG,
109 PCI_DEVICE_ID (0x9004, MAX_UINT64, MAX_UINT64, MAX_UINT64, MAX_UINT64),
110 DEVICE_RES_TAG,
111 ACPI_ADDRESS_SPACE_TYPE_IO,
112 0,
113 0,
114 0,
115 0,
116 EVEN_ALIGN,
117 MAX_UINT64,
118 0,
119 //
120 // Device Adaptec 9005
121 //
122 DEVICE_INF_TAG,
123 PCI_DEVICE_ID (0x9005, MAX_UINT64, MAX_UINT64, MAX_UINT64, MAX_UINT64),
124 DEVICE_RES_TAG,
125 ACPI_ADDRESS_SPACE_TYPE_IO,
126 0,
127 0,
128 0,
129 0,
130 EVEN_ALIGN,
131 MAX_UINT64,
132 0,
133 //
134 // Device QLogic 1007
135 //
136 DEVICE_INF_TAG,
137 PCI_DEVICE_ID (0x1077, MAX_UINT64, MAX_UINT64, MAX_UINT64, MAX_UINT64),
138 DEVICE_RES_TAG,
139 ACPI_ADDRESS_SPACE_TYPE_IO,
140 0,
141 0,
142 0,
143 0,
144 EVEN_ALIGN,
145 MAX_UINT64,
146 0,
147 //
148 // Device Agilent 103C
149 //
150 DEVICE_INF_TAG,
151 PCI_DEVICE_ID (0x103C, MAX_UINT64, MAX_UINT64, MAX_UINT64, MAX_UINT64),
152 DEVICE_RES_TAG,
153 ACPI_ADDRESS_SPACE_TYPE_IO,
154 0,
155 0,
156 0,
157 0,
158 EVEN_ALIGN,
159 MAX_UINT64,
160 0,
161 //
162 // Device Agilent 15BC
163 //
164 DEVICE_INF_TAG,
165 PCI_DEVICE_ID (0x15BC, MAX_UINT64, MAX_UINT64, MAX_UINT64, MAX_UINT64),
166 DEVICE_RES_TAG,
167 ACPI_ADDRESS_SPACE_TYPE_IO,
168 0,
169 0,
170 0,
171 0,
172 EVEN_ALIGN,
173 MAX_UINT64,
174 0,
175 //
176 // The end of the list
177 //
178 LIST_END_TAG
179 };
180
181 /**
182 Entry point of the incompatible pci device support code. Setup an incompatible device list template
183 and install EFI Incompatible PCI Device Support protocol.
184
185 @param ImageHandle A handle for the image that is initializing this driver.
186 @param SystemTable A pointer to the EFI system table.
187
188 @retval EFI_SUCCESS Installed EFI Incompatible PCI Device Support Protocol successfully.
189 @retval others Failed to install protocol.
190
191 **/
192 EFI_STATUS
193 EFIAPI
194 IncompatiblePciDeviceSupportEntryPoint (
195 IN EFI_HANDLE ImageHandle,
196 IN EFI_SYSTEM_TABLE *SystemTable
197 )
198 {
199 EFI_STATUS Status;
200
201 //
202 // Install EFI Incompatible PCI Device Support Protocol on a new handle
203 //
204 Status = gBS->InstallProtocolInterface (
205 &mIncompatiblePciDeviceSupportHandle,
206 &gEfiIncompatiblePciDeviceSupportProtocolGuid,
207 EFI_NATIVE_INTERFACE,
208 &mIncompatiblePciDeviceSupport
209 );
210 ASSERT_EFI_ERROR (Status);
211
212 return Status;
213 }
214
215 /**
216 Returns a list of ACPI resource descriptors that detail the special
217 resource configuration requirements for an incompatible PCI device.
218
219 @param This Pointer to the EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL instance.
220 @param VendorId A unique ID to identify the manufacturer of the PCI device.
221 @param DeviceId A unique ID to identify the particular PCI device.
222 @param RevisionId A PCI device-specific revision identifier.
223 @param SubsystemVendorId Specifies the subsystem vendor ID.
224 @param SubsystemDeviceId Specifies the subsystem device ID.
225 @param Configuration A list of ACPI resource descriptors returned that detail
226 the configuration requirement.
227
228 @retval EFI_SUCCESS Successfully got ACPI resource for specified PCI device.
229 @retval EFI_INVALID_PARAMETER Configuration is NULL.
230 @retval EFI_OUT_OF_RESOURCES No memory available.
231 @retval EFI_UNSUPPORTED The specified PCI device wasn't supported.
232
233 **/
234 EFI_STATUS
235 EFIAPI
236 PCheckDevice (
237 IN EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL *This,
238 IN UINTN VendorId,
239 IN UINTN DeviceId,
240 IN UINTN RevisionId,
241 IN UINTN SubsystemVendorId,
242 IN UINTN SubsystemDeviceId,
243 OUT VOID **Configuration
244 )
245 {
246 UINT64 Tag;
247 UINT64 *ListPtr;
248 UINT64 *TempListPtr;
249 EFI_PCI_DEVICE_HEADER_INFO *Header;
250 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AcpiPtr;
251 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *OldAcpiPtr;
252 EFI_PCI_RESOUCE_DESCRIPTOR *Dsc;
253 EFI_ACPI_END_TAG_DESCRIPTOR *PtrEnd;
254 UINTN Index;
255
256 //
257 // Validate the parameters
258 //
259 if (Configuration == NULL) {
260 return EFI_INVALID_PARAMETER;
261 }
262
263 //
264 // Initialize the return value to NULL
265 //
266 *(VOID **)Configuration = NULL;
267
268 ListPtr = mIncompatiblePciDeviceList;
269 while (*ListPtr != LIST_END_TAG) {
270 Tag = *ListPtr;
271
272 switch (Tag) {
273 case DEVICE_INF_TAG:
274 Header = (EFI_PCI_DEVICE_HEADER_INFO *)(ListPtr + 1);
275 ListPtr = ListPtr + 1 + sizeof (EFI_PCI_DEVICE_HEADER_INFO) / sizeof (UINT64);
276 //
277 // See if the Header matches the parameters passed in
278 //
279 if ((Header->VendorId != MAX_UINT64) && (VendorId != MAX_UINTN)) {
280 if (Header->VendorId != VendorId) {
281 continue;
282 }
283 }
284
285 if ((Header->DeviceId != MAX_UINT64) && (DeviceId != MAX_UINTN)) {
286 if (DeviceId != Header->DeviceId) {
287 continue;
288 }
289 }
290
291 if ((Header->RevisionId != MAX_UINT64) && (RevisionId != MAX_UINTN)) {
292 if (RevisionId != Header->RevisionId) {
293 continue;
294 }
295 }
296
297 if ((Header->SubsystemVendorId != MAX_UINT64) && (SubsystemVendorId != MAX_UINTN)) {
298 if (SubsystemVendorId != Header->SubsystemVendorId) {
299 continue;
300 }
301 }
302
303 if ((Header->SubsystemDeviceId != MAX_UINT64) && (SubsystemDeviceId != MAX_UINTN)) {
304 if (SubsystemDeviceId != Header->SubsystemDeviceId) {
305 continue;
306 }
307 }
308
309 //
310 // Matched an item, so construct the ACPI descriptor for the resource.
311 //
312 //
313 // Count the resource items so that to allocate space
314 //
315 for (Index = 0, TempListPtr = ListPtr; *TempListPtr == DEVICE_RES_TAG; Index++) {
316 TempListPtr = TempListPtr + 1 + ((sizeof (EFI_PCI_RESOUCE_DESCRIPTOR)) / sizeof (UINT64));
317 }
318
319 //
320 // If there is at least one type of resource request,
321 // allocate an acpi resource node
322 //
323 if (Index == 0) {
324 return EFI_UNSUPPORTED;
325 }
326
327 AcpiPtr = AllocateZeroPool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * Index + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
328 if (AcpiPtr == NULL) {
329 return EFI_OUT_OF_RESOURCES;
330 }
331
332 OldAcpiPtr = AcpiPtr;
333 //
334 // Fill the EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR structure
335 // according to the EFI_PCI_RESOUCE_DESCRIPTOR structure
336 //
337 for ( ; *ListPtr == DEVICE_RES_TAG;) {
338 Dsc = (EFI_PCI_RESOUCE_DESCRIPTOR *)(ListPtr + 1);
339
340 AcpiPtr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
341 AcpiPtr->Len = (UINT16)sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
342 AcpiPtr->ResType = (UINT8)Dsc->ResType;
343 AcpiPtr->GenFlag = (UINT8)Dsc->GenFlag;
344 AcpiPtr->SpecificFlag = (UINT8)Dsc->SpecificFlag;
345 AcpiPtr->AddrSpaceGranularity = Dsc->AddrSpaceGranularity;
346 AcpiPtr->AddrRangeMin = Dsc->AddrRangeMin;
347 AcpiPtr->AddrRangeMax = Dsc->AddrRangeMax;
348 AcpiPtr->AddrTranslationOffset = Dsc->AddrTranslationOffset;
349 AcpiPtr->AddrLen = Dsc->AddrLen;
350
351 ListPtr = ListPtr + 1 + ((sizeof (EFI_PCI_RESOUCE_DESCRIPTOR)) / sizeof (UINT64));
352 AcpiPtr++;
353 }
354
355 //
356 // Put the checksum
357 //
358 PtrEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *)(AcpiPtr);
359 PtrEnd->Desc = ACPI_END_TAG_DESCRIPTOR;
360 PtrEnd->Checksum = 0;
361
362 *(VOID **)Configuration = OldAcpiPtr;
363
364 return EFI_SUCCESS;
365
366 case DEVICE_RES_TAG:
367 //
368 // Adjust the pointer to the next PCI resource descriptor item
369 //
370 ListPtr = ListPtr + 1 + ((sizeof (EFI_PCI_RESOUCE_DESCRIPTOR)) / sizeof (UINT64));
371 break;
372
373 default:
374 return EFI_UNSUPPORTED;
375 }
376 }
377
378 return EFI_UNSUPPORTED;
379 }