]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Library/PciIncompatibleDeviceSupportLib/PciIncompatibleDeviceSupportLib.c
Clean up ECC.
[mirror_edk2.git] / IntelFrameworkModulePkg / Library / PciIncompatibleDeviceSupportLib / PciIncompatibleDeviceSupportLib.c
CommitLineData
54bd896e 1/** @file\r
8e8227d1 2 The template of PCI incompatible device support libary.\r
54bd896e 3\r
8e8227d1 4Copyright (c) 2006 - 2009, Intel Corporation\r
5All rights reserved. This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
54bd896e 12\r
13**/\r
14\r
54bd896e 15#include "IncompatiblePciDeviceList.h"\r
16\r
ae358cb2 17//\r
18// the incompatible PCI devices list template for ACPI resource\r
19//\r
20GLOBAL_REMOVE_IF_UNREFERENCED UINT64 gIncompatiblePciDeviceListForResource[] = {\r
21 //\r
22 // DEVICE_INF_TAG,\r
23 // PCI_DEVICE_ID (VendorID, DeviceID, Revision, SubVendorId, SubDeviceId),\r
24 // DEVICE_RES_TAG,\r
25 // ResType, GFlag , SFlag, Granularity, RangeMin,\r
26 // RangeMax, Offset, AddrLen\r
27 //\r
28\r
29 //\r
30 // Sample Device 1\r
31 //\r
32 //DEVICE_INF_TAG,\r
33 //PCI_DEVICE_ID(0xXXXX, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE),\r
34 //DEVICE_RES_TAG,\r
35 //PCI_BAR_TYPE_IO,\r
36 //PCI_ACPI_UNUSED,\r
37 //PCI_ACPI_UNUSED,\r
38 //PCI_ACPI_UNUSED,\r
39 //PCI_ACPI_UNUSED,\r
40 //PCI_BAR_EVEN_ALIGN,\r
41 //PCI_BAR_ALL,\r
42 //PCI_BAR_NOCHANGE,\r
43\r
44 //\r
45 // Sample Device 2\r
46 //\r
47 //DEVICE_INF_TAG,\r
48 //PCI_DEVICE_ID(0xXXXX, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE),\r
49 //DEVICE_RES_TAG,\r
50 //PCI_BAR_TYPE_IO,\r
51 //PCI_ACPI_UNUSED,\r
52 //PCI_ACPI_UNUSED,\r
53 //PCI_ACPI_UNUSED,\r
54 //PCI_ACPI_UNUSED,\r
55 //PCI_BAR_EVEN_ALIGN,\r
56 //PCI_BAR_ALL,\r
57 //PCI_BAR_NOCHANGE,\r
58\r
59 //\r
60 // The end of the list\r
61 //\r
62 LIST_END_TAG\r
63};\r
64\r
65//\r
66// the incompatible PCI devices list template for the values of configuration registers\r
67//\r
68GLOBAL_REMOVE_IF_UNREFERENCED UINT64 gIncompatiblePciDeviceListForRegister[] = {\r
69 //\r
70 // DEVICE_INF_TAG,\r
71 // PCI_DEVICE_ID (VendorID, DeviceID, Revision, SubVendorId, SubDeviceId),\r
72 // PCI_RES_TAG,\r
73 // PCI_ACCESS_TYPE, PCI_CONFIG_ADDRESS,\r
74 // AND_VALUE, OR_VALUE\r
75\r
76 //\r
77 // Sample Device 1\r
78 //\r
79 //DEVICE_INF_TAG,\r
80 //PCI_DEVICE_ID(0xXXXX, 0xXXXX, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE),\r
81 //DEVICE_RES_TAG,\r
82 //PCI_REGISTER_READ,\r
83 //PCI_CAPBILITY_POINTER_OFFSET,\r
84 //0xffffff00,\r
85 //VALUE_NOCARE,\r
86\r
87 //\r
88 // Sample Device 2\r
89 //\r
90 //DEVICE_INF_TAG,\r
91 //PCI_DEVICE_ID(0xXXXX, 0xXXXX, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE),\r
92 //DEVICE_RES_TAG,\r
93 //PCI_REGISTER_READ,\r
94 //PCI_CAPBILITY_POINTER_OFFSET,\r
95 //0xffffff00,\r
96 //VALUE_NOCARE,\r
97\r
98 //\r
99 // The end of the list\r
100 //\r
101 LIST_END_TAG\r
102};\r
103\r
104//\r
105// the incompatible PCI devices list template for the access width of configuration registers\r
106//\r
107GLOBAL_REMOVE_IF_UNREFERENCED UINT64 gDeviceListForAccessWidth[] = {\r
108 //\r
109 // DEVICE_INF_TAG,\r
110 // PCI_DEVICE_ID (VendorID, DeviceID, Revision, SubVendorId, SubDeviceId),\r
111 // DEVICE_RES_TAG,\r
112 // PCI_ACCESS_TYPE, PCI_ACCESS_WIDTH,\r
113 // START_ADDRESS, END_ADDRESS,\r
114 // ACTUAL_PCI_ACCESS_WIDTH,\r
115 //\r
116\r
117 //\r
118 // Sample Device\r
119 //\r
120 //DEVICE_INF_TAG,\r
121 //PCI_DEVICE_ID(0xXXXX, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE),\r
122 //DEVICE_RES_TAG,\r
123 //PCI_REGISTER_READ,\r
124 //EfiPciWidthUint8,\r
125 //0,\r
126 //0xFF,\r
127 //EfiPciWidthUint32,\r
128 //\r
129\r
130 //\r
131 // The end of the list\r
132 //\r
133 LIST_END_TAG\r
134};\r
135\r
136GLOBAL_REMOVE_IF_UNREFERENCED EFI_PCI_REGISTER_ACCESS_DATA mPciRegisterAccessData = {0, 0, 0}; \r
137GLOBAL_REMOVE_IF_UNREFERENCED EFI_PCI_REGISTER_VALUE_DATA mPciRegisterValueData = {0, 0};\r
8e8227d1 138 \r
139\r
54bd896e 140/**\r
8e8227d1 141 Check whether two PCI devices matched.\r
54bd896e 142\r
8e8227d1 143 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.\r
144 @param Header A pointer to EFI_PCI_DEVICE_INFO.\r
145\r
146 @retval EFI_SUCCESS Two PCI devices matched.\r
147 @retval EFI_UNSUPPORTED Two PCI devices don't match.\r
54bd896e 148\r
54bd896e 149**/\r
54bd896e 150EFI_STATUS\r
151DeviceCheck (\r
152 IN EFI_PCI_DEVICE_INFO *PciDeviceInfo,\r
153 IN EFI_PCI_DEVICE_INFO *Header\r
154 )\r
155{\r
156 //\r
157 // See if the Header matches the parameters passed in\r
158 //\r
159 if (Header->VendorID != DEVICE_ID_NOCARE) {\r
160 if (PciDeviceInfo->VendorID != Header->VendorID) {\r
161 return EFI_UNSUPPORTED;\r
162 }\r
163 }\r
164\r
165 if (Header->DeviceID != DEVICE_ID_NOCARE) {\r
166 if (PciDeviceInfo->DeviceID != Header->DeviceID) {\r
167 return EFI_UNSUPPORTED;\r
168 }\r
169 }\r
170\r
171 if (Header->RevisionID != DEVICE_ID_NOCARE) {\r
172 if (PciDeviceInfo->RevisionID != Header->RevisionID) {\r
173 return EFI_UNSUPPORTED;\r
174 }\r
175 }\r
176\r
177 if (Header->SubsystemVendorID != DEVICE_ID_NOCARE) {\r
178 if (PciDeviceInfo->SubsystemVendorID != Header->SubsystemVendorID) {\r
179 return EFI_UNSUPPORTED;\r
180 }\r
181 }\r
182\r
183 if (Header->SubsystemID != DEVICE_ID_NOCARE) {\r
184 if (PciDeviceInfo->SubsystemID != Header->SubsystemID) {\r
185 return EFI_UNSUPPORTED;\r
186 }\r
187 }\r
188\r
189 return EFI_SUCCESS;\r
190}\r
191\r
192\r
193/**\r
194 Check the incompatible device list for ACPI resource update and return\r
8e8227d1 195 the configuration.\r
54bd896e 196\r
197 This function searches the incompatible device list according to request\r
198 information. If the PCI device belongs to the devices list, corresponding\r
199 configuration informtion will be returned, in the meantime return EFI_SUCCESS.\r
200\r
8e8227d1 201 @param PciDeviceInfo A pointer to PCI device information.\r
202 @param Configuration Returned information.\r
203\r
204 @retval EFI_SUCCESS If check incompatible device successfully.\r
205 @retval EFI_ABORTED No any resource type.\r
206 @retval EFI_OUT_OF_RESOURCES No memory available.\r
207 @retval EFI_UNSUPPORTED Invalid Tag encounted.\r
54bd896e 208\r
54bd896e 209**/\r
8e8227d1 210EFI_STATUS\r
54bd896e 211EFIAPI\r
212PciResourceUpdateCheck (\r
213 IN EFI_PCI_DEVICE_INFO *PciDeviceInfo,\r
214 OUT VOID *Configuration\r
215 )\r
216{\r
217 UINT64 Tag;\r
218 UINT64 *ListPtr;\r
219 UINT64 *TempListPtr;\r
220 EFI_PCI_DEVICE_INFO *Header;\r
221 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AcpiPtr;\r
222 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *OldAcpiPtr;\r
223 EFI_PCI_RESOUCE_DESCRIPTOR *Dsc;\r
224 EFI_ACPI_END_TAG_DESCRIPTOR *PtrEnd;\r
225 UINTN Index;\r
226\r
227 ASSERT (PciDeviceInfo != NULL);\r
228\r
229 //\r
230 // Initialize the return value to NULL\r
231 //\r
232 * (VOID **) Configuration = NULL;\r
233\r
8e8227d1 234 ListPtr = gIncompatiblePciDeviceListForResource;\r
54bd896e 235 while (*ListPtr != LIST_END_TAG) {\r
236\r
237 Tag = *ListPtr;\r
238\r
239 switch (Tag) {\r
240 case DEVICE_INF_TAG:\r
241 Header = (EFI_PCI_DEVICE_INFO *) (ListPtr + 1);\r
242 ListPtr = ListPtr + 1 + sizeof (EFI_PCI_DEVICE_INFO) / sizeof (UINT64);\r
243\r
244 if (DeviceCheck (PciDeviceInfo, Header) != EFI_SUCCESS) {\r
245 continue;\r
246 }\r
247\r
248 //\r
249 // Matched an item, so construct the ACPI descriptor for the resource.\r
250 //\r
251 //\r
252 // Count the resource items so that to allocate space\r
253 //\r
254 for (Index = 0, TempListPtr = ListPtr; *TempListPtr == DEVICE_RES_TAG; Index++) {\r
255 TempListPtr = TempListPtr + 1 + ((sizeof (EFI_PCI_RESOUCE_DESCRIPTOR)) / sizeof (UINT64));\r
256 }\r
257 //\r
258 // If there is at least one type of resource request,\r
259 // allocate a acpi resource node\r
260 //\r
261 if (Index == 0) {\r
262 return EFI_ABORTED;\r
263 }\r
264\r
265 AcpiPtr = AllocateZeroPool (\r
266 sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * Index + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)\r
8e8227d1 267 );\r
261136bc 268 if (AcpiPtr == NULL) {\r
269 return EFI_OUT_OF_RESOURCES;\r
270 }\r
54bd896e 271\r
272 OldAcpiPtr = AcpiPtr;\r
273\r
274 //\r
275 // Fill the EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR structure\r
276 // according to the EFI_PCI_RESOUCE_DESCRIPTOR structure\r
277 //\r
278 for (; *ListPtr == DEVICE_RES_TAG;) {\r
279\r
280 Dsc = (EFI_PCI_RESOUCE_DESCRIPTOR *) (ListPtr + 1);\r
281\r
282 AcpiPtr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
283 AcpiPtr->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);\r
284 AcpiPtr->ResType = (UINT8) Dsc->ResType;\r
285 AcpiPtr->GenFlag = (UINT8) Dsc->GenFlag;\r
286 AcpiPtr->SpecificFlag = (UINT8) Dsc->SpecificFlag;\r
287 AcpiPtr->AddrSpaceGranularity = Dsc->AddrSpaceGranularity;;\r
288 AcpiPtr->AddrRangeMin = Dsc->AddrRangeMin;\r
289 AcpiPtr->AddrRangeMax = Dsc->AddrRangeMax;\r
290 AcpiPtr->AddrTranslationOffset = Dsc->AddrTranslationOffset;\r
291 AcpiPtr->AddrLen = Dsc->AddrLen;\r
292\r
293 ListPtr = ListPtr + 1 + ((sizeof (EFI_PCI_RESOUCE_DESCRIPTOR)) / sizeof (UINT64));\r
294 AcpiPtr++;\r
295 }\r
296 //\r
297 // put the checksum\r
298 //\r
299 PtrEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *) (AcpiPtr);\r
300 PtrEnd->Desc = ACPI_END_TAG_DESCRIPTOR;\r
301 PtrEnd->Checksum = 0;\r
302\r
303 *(VOID **) Configuration = OldAcpiPtr;\r
304\r
305 return EFI_SUCCESS;\r
306\r
307 case DEVICE_RES_TAG:\r
308 //\r
309 // Adjust the pointer to the next PCI resource descriptor item\r
310 //\r
311 ListPtr = ListPtr + 1 + ((sizeof (EFI_PCI_RESOUCE_DESCRIPTOR)) / sizeof (UINT64));\r
312 break;\r
313\r
314 default:\r
315 return EFI_UNSUPPORTED;\r
316 }\r
317 }\r
318\r
319 return EFI_UNSUPPORTED;\r
320\r
321}\r
322\r
323/**\r
324 Check the incompatible device list and return configuraton register mask values.\r
325\r
326 This function searches the incompatible device list according to request\r
327 information. If the PCI device belongs to the devices list, corresponding\r
328 configuration informtion will be returned, in the meantime return EFI_SUCCESS.\r
329\r
330 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.\r
331 @param AccessType Access Type, READ or WRITE.\r
332 @param Offset The address within the PCI configuration space.\r
333 @param Configuration Returned information.\r
334\r
8e8227d1 335 @retval EFI_SUCCESS If check incompatible device successfully.\r
336 @retval EFI_UNSUPPORTED Failed to check incompatibility device.\r
337\r
54bd896e 338**/\r
8e8227d1 339EFI_STATUS\r
54bd896e 340EFIAPI\r
341PciRegisterUpdateCheck (\r
342 IN EFI_PCI_DEVICE_INFO *PciDeviceInfo,\r
343 IN UINT64 AccessType,\r
344 IN UINT64 Offset,\r
345 OUT VOID *Configuration\r
346 )\r
347{\r
348 EFI_PCI_DEVICE_INFO *Header;\r
349 UINT64 Tag;\r
350 UINT64 *ListPtr;\r
351 EFI_PCI_REGISTER_VALUE_DATA *RegisterPtr;\r
352 EFI_PCI_REGISTER_VALUE_DATA *Dsc;\r
353\r
354 ASSERT (PciDeviceInfo != NULL);\r
355\r
8e8227d1 356 ListPtr = gIncompatiblePciDeviceListForRegister;\r
54bd896e 357\r
358 //\r
359 // Initialize the return value to NULL\r
360 //\r
361 * (VOID **) Configuration = NULL;\r
362\r
363 while (*ListPtr != LIST_END_TAG) {\r
364\r
365 Tag = *ListPtr;\r
366\r
367 switch (Tag) {\r
368 case DEVICE_INF_TAG:\r
369 Header = (EFI_PCI_DEVICE_INFO *) (ListPtr + 1);\r
370 ListPtr = ListPtr + 1 + sizeof (EFI_PCI_DEVICE_INFO) / sizeof (UINT64);\r
371\r
372 //\r
373 // Check whether the PCI device matches the device in the incompatible devices list?\r
374 // If not, ship next\r
375 //\r
376 if (DeviceCheck (PciDeviceInfo, Header) != EFI_SUCCESS) {\r
377 continue;\r
378 }\r
379\r
380 //\r
381 // Matched an item, check whether access matches?\r
382 //\r
383 for (; *ListPtr == DEVICE_RES_TAG;) {\r
384 ListPtr ++;\r
385 if (((EFI_PCI_REGISTER_VALUE_DESCRIPTOR *)ListPtr)->Offset == (Offset & 0xfc)) {\r
386 if (((EFI_PCI_REGISTER_VALUE_DESCRIPTOR *)ListPtr)->AccessType == AccessType) {\r
387\r
388 Dsc = (EFI_PCI_REGISTER_VALUE_DATA *) (ListPtr + 2);\r
8e8227d1 389 \r
390 RegisterPtr = &mPciRegisterValueData;\r
54bd896e 391\r
392 RegisterPtr->AndValue = Dsc->AndValue;\r
393 RegisterPtr->OrValue = Dsc->OrValue;\r
394\r
395 *(VOID **) Configuration = RegisterPtr;\r
396\r
397 return EFI_SUCCESS;\r
398 }\r
399 }\r
400 ListPtr += sizeof (EFI_PCI_REGISTER_VALUE_DESCRIPTOR) / (sizeof (UINT64));\r
401 }\r
402 return EFI_UNSUPPORTED;\r
403\r
404 case DEVICE_RES_TAG:\r
405 //\r
406 // Adjust the pointer to the next item\r
407 //\r
408 ListPtr = ListPtr + 1 + ((sizeof (EFI_PCI_REGISTER_VALUE_DESCRIPTOR)) / sizeof (UINT64));\r
409 break;\r
410\r
411 default:\r
412 return EFI_UNSUPPORTED;\r
413 }\r
414 }\r
415\r
416 return EFI_UNSUPPORTED;\r
417}\r
418\r
419/**\r
420 Check the incompatible device list for access width incompatibility and\r
ae358cb2 421 return the configuration.\r
54bd896e 422\r
423 This function searches the incompatible device list for access width\r
424 incompatibility according to request information. If the PCI device\r
425 belongs to the devices list, corresponding configuration informtion\r
426 will be returned, in the meantime return EFI_SUCCESS.\r
427\r
428 @param PciDeviceInfo A pointer to PCI device information.\r
429 @param AccessType Access type, READ or WRITE.\r
430 @param Offset The address within the PCI configuration space.\r
431 @param AccessWidth Access width needs to check incompatibility.\r
432 @param Configuration Returned information.\r
433\r
8e8227d1 434 @retval EFI_SUCCESS If check incompatible device successfully.\r
435 @retval EFI_UNSUPPORTED Failed to check incompatibility device.\r
436\r
54bd896e 437**/\r
8e8227d1 438EFI_STATUS\r
54bd896e 439EFIAPI\r
440PciRegisterAccessCheck (\r
441 IN EFI_PCI_DEVICE_INFO *PciDeviceInfo,\r
442 IN UINT64 AccessType,\r
443 IN UINT64 Offset,\r
444 IN UINT64 AccessWidth,\r
445 OUT VOID *Configuration\r
446 )\r
447{\r
448 EFI_PCI_DEVICE_INFO *Header;\r
449 UINT64 Tag;\r
450 UINT64 *ListPtr;\r
451 EFI_PCI_REGISTER_ACCESS_DATA *RegisterPtr;\r
452 EFI_PCI_REGISTER_ACCESS_DATA *Dsc;\r
453\r
454 ASSERT (PciDeviceInfo != NULL);\r
455\r
8e8227d1 456 ListPtr = gDeviceListForAccessWidth;\r
54bd896e 457\r
458 //\r
459 // Initialize the return value to NULL\r
460 //\r
461 * (VOID **) Configuration = NULL;\r
462\r
463 while (*ListPtr != LIST_END_TAG) {\r
464\r
465 Tag = *ListPtr;\r
466\r
467 switch (Tag) {\r
468 case DEVICE_INF_TAG:\r
469 Header = (EFI_PCI_DEVICE_INFO *) (ListPtr + 1);\r
470 ListPtr = ListPtr + 1 + sizeof (EFI_PCI_DEVICE_INFO) / sizeof (UINT64);\r
471\r
472 //\r
473 // Check whether the PCI device matches the device in the incompatible devices list?\r
474 // If not, ship next\r
475 //\r
476 if (DeviceCheck (PciDeviceInfo, Header) != EFI_SUCCESS) {\r
477 continue;\r
478 }\r
479\r
480 //\r
481 // Matched an item, check whether access matches?\r
482 //\r
483 for (; *ListPtr == DEVICE_RES_TAG;) {\r
484 ListPtr ++;\r
485 if (((EFI_PCI_REGISTER_ACCESS_DESCRIPTOR *) ListPtr)->AccessType == AccessType &&\r
486 ((EFI_PCI_REGISTER_ACCESS_DESCRIPTOR *) ListPtr)->AccessWidth == AccessWidth ) {\r
487\r
488 Dsc = (EFI_PCI_REGISTER_ACCESS_DATA *) (ListPtr + 2);\r
489\r
490 if((Dsc->StartOffset <= Offset) && (Dsc->EndOffset > Offset)) {\r
491\r
8e8227d1 492 RegisterPtr = &mPciRegisterAccessData;\r
54bd896e 493\r
494 RegisterPtr->StartOffset = Dsc->StartOffset;\r
495 RegisterPtr->EndOffset = Dsc->EndOffset;\r
496 RegisterPtr->Width = Dsc->Width;\r
497\r
498 *(VOID **) Configuration = RegisterPtr;\r
499\r
500 return EFI_SUCCESS;\r
501 }\r
502 }\r
503 ListPtr += sizeof (EFI_PCI_REGISTER_ACCESS_DESCRIPTOR) / (sizeof (UINT64));\r
504 }\r
505 return EFI_UNSUPPORTED;\r
506\r
507 case DEVICE_RES_TAG:\r
508 //\r
509 // Adjust the pointer to the next item\r
510 //\r
511 ListPtr = ListPtr + 1 + ((sizeof (EFI_PCI_REGISTER_ACCESS_DESCRIPTOR)) / sizeof (UINT64));\r
512 break;\r
513\r
514 default:\r
515 return EFI_UNSUPPORTED;\r
516 }\r
517 }\r
518\r
519 return EFI_UNSUPPORTED;\r
520}\r
521\r