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