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