Complete the library instances in IntelFrameworkModulePkg
[mirror_edk2.git] / IntelFrameworkModulePkg / Library / PciIncompatibleDeviceSupportLib / PciIncompatibleDeviceSupportLib.c
1 /** @file
2 The implementation of PCI incompatible device support libary.
3
4 Copyright (c) 2007 Intel Corporation. All rights reserved. <BR>
5 This software and associated documentation (if any) is furnished
6 under a license and may only be used or copied in accordance
7 with the terms of the license. Except as permitted by such
8 license, no part of this software or documentation may be
9 reproduced, stored in a retrieval system, or transmitted in any
10 form or by any means without the express written consent of
11 Intel Corporation.
12
13 **/
14
15 //
16 // Include common header file for this module.
17 //
18 #include "CommonHeader.h"
19
20 #include "IncompatiblePciDeviceList.h"
21
22 /**
23 Check whether two PCI devices matched
24
25 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.
26 @param Header A pointer to EFI_PCI_DEVICE_INFO.
27
28 @retval returns EFI_SUCCESS if two PCI device matched.
29 **/
30 STATIC
31 EFI_STATUS
32 DeviceCheck (
33 IN EFI_PCI_DEVICE_INFO *PciDeviceInfo,
34 IN EFI_PCI_DEVICE_INFO *Header
35 )
36 {
37 //
38 // See if the Header matches the parameters passed in
39 //
40 if (Header->VendorID != DEVICE_ID_NOCARE) {
41 if (PciDeviceInfo->VendorID != Header->VendorID) {
42 return EFI_UNSUPPORTED;
43 }
44 }
45
46 if (Header->DeviceID != DEVICE_ID_NOCARE) {
47 if (PciDeviceInfo->DeviceID != Header->DeviceID) {
48 return EFI_UNSUPPORTED;
49 }
50 }
51
52 if (Header->RevisionID != DEVICE_ID_NOCARE) {
53 if (PciDeviceInfo->RevisionID != Header->RevisionID) {
54 return EFI_UNSUPPORTED;
55 }
56 }
57
58 if (Header->SubsystemVendorID != DEVICE_ID_NOCARE) {
59 if (PciDeviceInfo->SubsystemVendorID != Header->SubsystemVendorID) {
60 return EFI_UNSUPPORTED;
61 }
62 }
63
64 if (Header->SubsystemID != DEVICE_ID_NOCARE) {
65 if (PciDeviceInfo->SubsystemID != Header->SubsystemID) {
66 return EFI_UNSUPPORTED;
67 }
68 }
69
70 return EFI_SUCCESS;
71 }
72
73
74 /**
75 Check the incompatible device list for ACPI resource update and return
76 the configuration
77
78 This function searches the incompatible device list according to request
79 information. If the PCI device belongs to the devices list, corresponding
80 configuration informtion will be returned, in the meantime return EFI_SUCCESS.
81
82 @param PciDeviceInfo A pointer to PCI device information.
83 @param Configuration Returned information.
84
85 @retval returns EFI_SUCCESS if check incompatible device ok.
86 Otherwise return EFI_UNSUPPORTED.
87 **/
88 RETURN_STATUS
89 EFIAPI
90 PciResourceUpdateCheck (
91 IN EFI_PCI_DEVICE_INFO *PciDeviceInfo,
92 OUT VOID *Configuration
93 )
94 {
95 UINT64 Tag;
96 UINT64 *ListPtr;
97 UINT64 *TempListPtr;
98 EFI_PCI_DEVICE_INFO *Header;
99 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AcpiPtr;
100 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *OldAcpiPtr;
101 EFI_PCI_RESOUCE_DESCRIPTOR *Dsc;
102 EFI_ACPI_END_TAG_DESCRIPTOR *PtrEnd;
103 UINTN Index;
104
105 ASSERT (PciDeviceInfo != NULL);
106
107 //
108 // Initialize the return value to NULL
109 //
110 * (VOID **) Configuration = NULL;
111
112 ListPtr = IncompatiblePciDeviceListForResource;
113 while (*ListPtr != LIST_END_TAG) {
114
115 Tag = *ListPtr;
116
117 switch (Tag) {
118 case DEVICE_INF_TAG:
119 Header = (EFI_PCI_DEVICE_INFO *) (ListPtr + 1);
120 ListPtr = ListPtr + 1 + sizeof (EFI_PCI_DEVICE_INFO) / sizeof (UINT64);
121
122 if (DeviceCheck (PciDeviceInfo, Header) != EFI_SUCCESS) {
123 continue;
124 }
125
126 //
127 // Matched an item, so construct the ACPI descriptor for the resource.
128 //
129 //
130 // Count the resource items so that to allocate space
131 //
132 for (Index = 0, TempListPtr = ListPtr; *TempListPtr == DEVICE_RES_TAG; Index++) {
133 TempListPtr = TempListPtr + 1 + ((sizeof (EFI_PCI_RESOUCE_DESCRIPTOR)) / sizeof (UINT64));
134 }
135 //
136 // If there is at least one type of resource request,
137 // allocate a acpi resource node
138 //
139 if (Index == 0) {
140 return EFI_ABORTED;
141 }
142
143 AcpiPtr = AllocateZeroPool (
144 sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * Index + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)
145 );
146
147 OldAcpiPtr = AcpiPtr;
148
149 //
150 // Fill the EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR structure
151 // according to the EFI_PCI_RESOUCE_DESCRIPTOR structure
152 //
153 for (; *ListPtr == DEVICE_RES_TAG;) {
154
155 Dsc = (EFI_PCI_RESOUCE_DESCRIPTOR *) (ListPtr + 1);
156
157 AcpiPtr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
158 AcpiPtr->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
159 AcpiPtr->ResType = (UINT8) Dsc->ResType;
160 AcpiPtr->GenFlag = (UINT8) Dsc->GenFlag;
161 AcpiPtr->SpecificFlag = (UINT8) Dsc->SpecificFlag;
162 AcpiPtr->AddrSpaceGranularity = Dsc->AddrSpaceGranularity;;
163 AcpiPtr->AddrRangeMin = Dsc->AddrRangeMin;
164 AcpiPtr->AddrRangeMax = Dsc->AddrRangeMax;
165 AcpiPtr->AddrTranslationOffset = Dsc->AddrTranslationOffset;
166 AcpiPtr->AddrLen = Dsc->AddrLen;
167
168 ListPtr = ListPtr + 1 + ((sizeof (EFI_PCI_RESOUCE_DESCRIPTOR)) / sizeof (UINT64));
169 AcpiPtr++;
170 }
171 //
172 // put the checksum
173 //
174 PtrEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *) (AcpiPtr);
175 PtrEnd->Desc = ACPI_END_TAG_DESCRIPTOR;
176 PtrEnd->Checksum = 0;
177
178 *(VOID **) Configuration = OldAcpiPtr;
179
180 return EFI_SUCCESS;
181
182 case DEVICE_RES_TAG:
183 //
184 // Adjust the pointer to the next PCI resource descriptor item
185 //
186 ListPtr = ListPtr + 1 + ((sizeof (EFI_PCI_RESOUCE_DESCRIPTOR)) / sizeof (UINT64));
187 break;
188
189 default:
190 return EFI_UNSUPPORTED;
191 }
192 }
193
194 return EFI_UNSUPPORTED;
195
196 }
197
198 /**
199 Check the incompatible device list and return configuraton register mask values.
200
201 This function searches the incompatible device list according to request
202 information. If the PCI device belongs to the devices list, corresponding
203 configuration informtion will be returned, in the meantime return EFI_SUCCESS.
204
205 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.
206 @param AccessType Access Type, READ or WRITE.
207 @param Offset The address within the PCI configuration space.
208 @param Configuration Returned information.
209
210 @retval returns EFI_SUCCESS if check incompatible device ok.
211 Otherwise return EFI_UNSUPPORTED.
212 **/
213 RETURN_STATUS
214 EFIAPI
215 PciRegisterUpdateCheck (
216 IN EFI_PCI_DEVICE_INFO *PciDeviceInfo,
217 IN UINT64 AccessType,
218 IN UINT64 Offset,
219 OUT VOID *Configuration
220 )
221 {
222 EFI_PCI_DEVICE_INFO *Header;
223 UINT64 Tag;
224 UINT64 *ListPtr;
225 EFI_PCI_REGISTER_VALUE_DATA *RegisterPtr;
226 EFI_PCI_REGISTER_VALUE_DATA *Dsc;
227
228 ASSERT (PciDeviceInfo != NULL);
229
230 ListPtr = IncompatiblePciDeviceListForRegister;
231
232 //
233 // Initialize the return value to NULL
234 //
235 * (VOID **) Configuration = NULL;
236
237 while (*ListPtr != LIST_END_TAG) {
238
239 Tag = *ListPtr;
240
241 switch (Tag) {
242 case DEVICE_INF_TAG:
243 Header = (EFI_PCI_DEVICE_INFO *) (ListPtr + 1);
244 ListPtr = ListPtr + 1 + sizeof (EFI_PCI_DEVICE_INFO) / sizeof (UINT64);
245
246 //
247 // Check whether the PCI device matches the device in the incompatible devices list?
248 // If not, ship next
249 //
250 if (DeviceCheck (PciDeviceInfo, Header) != EFI_SUCCESS) {
251 continue;
252 }
253
254 //
255 // Matched an item, check whether access matches?
256 //
257 for (; *ListPtr == DEVICE_RES_TAG;) {
258 ListPtr ++;
259 if (((EFI_PCI_REGISTER_VALUE_DESCRIPTOR *)ListPtr)->Offset == (Offset & 0xfc)) {
260 if (((EFI_PCI_REGISTER_VALUE_DESCRIPTOR *)ListPtr)->AccessType == AccessType) {
261
262 Dsc = (EFI_PCI_REGISTER_VALUE_DATA *) (ListPtr + 2);
263 RegisterPtr = AllocateZeroPool (sizeof (EFI_PCI_REGISTER_VALUE_DATA));
264
265 RegisterPtr->AndValue = Dsc->AndValue;
266 RegisterPtr->OrValue = Dsc->OrValue;
267
268 *(VOID **) Configuration = RegisterPtr;
269
270 return EFI_SUCCESS;
271 }
272 }
273 ListPtr += sizeof (EFI_PCI_REGISTER_VALUE_DESCRIPTOR) / (sizeof (UINT64));
274 }
275 return EFI_UNSUPPORTED;
276
277 case DEVICE_RES_TAG:
278 //
279 // Adjust the pointer to the next item
280 //
281 ListPtr = ListPtr + 1 + ((sizeof (EFI_PCI_REGISTER_VALUE_DESCRIPTOR)) / sizeof (UINT64));
282 break;
283
284 default:
285 return EFI_UNSUPPORTED;
286 }
287 }
288
289 return EFI_UNSUPPORTED;
290 }
291
292 /**
293 Check the incompatible device list for access width incompatibility and
294 return the configuration
295
296 This function searches the incompatible device list for access width
297 incompatibility according to request information. If the PCI device
298 belongs to the devices list, corresponding configuration informtion
299 will be returned, in the meantime return EFI_SUCCESS.
300
301 @param PciDeviceInfo A pointer to PCI device information.
302 @param AccessType Access type, READ or WRITE.
303 @param Offset The address within the PCI configuration space.
304 @param AccessWidth Access width needs to check incompatibility.
305 @param Configuration Returned information.
306
307 @retval returns EFI_SUCCESS if check incompatible device ok.
308 Otherwise return EFI_UNSUPPORTED.
309 **/
310 RETURN_STATUS
311 EFIAPI
312 PciRegisterAccessCheck (
313 IN EFI_PCI_DEVICE_INFO *PciDeviceInfo,
314 IN UINT64 AccessType,
315 IN UINT64 Offset,
316 IN UINT64 AccessWidth,
317 OUT VOID *Configuration
318 )
319 {
320 EFI_PCI_DEVICE_INFO *Header;
321 UINT64 Tag;
322 UINT64 *ListPtr;
323 EFI_PCI_REGISTER_ACCESS_DATA *RegisterPtr;
324 EFI_PCI_REGISTER_ACCESS_DATA *Dsc;
325
326 ASSERT (PciDeviceInfo != NULL);
327
328 ListPtr = DeviceListForAccessWidth;
329
330 //
331 // Initialize the return value to NULL
332 //
333 * (VOID **) Configuration = NULL;
334
335 while (*ListPtr != LIST_END_TAG) {
336
337 Tag = *ListPtr;
338
339 switch (Tag) {
340 case DEVICE_INF_TAG:
341 Header = (EFI_PCI_DEVICE_INFO *) (ListPtr + 1);
342 ListPtr = ListPtr + 1 + sizeof (EFI_PCI_DEVICE_INFO) / sizeof (UINT64);
343
344 //
345 // Check whether the PCI device matches the device in the incompatible devices list?
346 // If not, ship next
347 //
348 if (DeviceCheck (PciDeviceInfo, Header) != EFI_SUCCESS) {
349 continue;
350 }
351
352 //
353 // Matched an item, check whether access matches?
354 //
355 for (; *ListPtr == DEVICE_RES_TAG;) {
356 ListPtr ++;
357 if (((EFI_PCI_REGISTER_ACCESS_DESCRIPTOR *) ListPtr)->AccessType == AccessType &&
358 ((EFI_PCI_REGISTER_ACCESS_DESCRIPTOR *) ListPtr)->AccessWidth == AccessWidth ) {
359
360 Dsc = (EFI_PCI_REGISTER_ACCESS_DATA *) (ListPtr + 2);
361
362 if((Dsc->StartOffset <= Offset) && (Dsc->EndOffset > Offset)) {
363
364 RegisterPtr = AllocateZeroPool (sizeof (EFI_PCI_REGISTER_ACCESS_DATA));
365
366 RegisterPtr->StartOffset = Dsc->StartOffset;
367 RegisterPtr->EndOffset = Dsc->EndOffset;
368 RegisterPtr->Width = Dsc->Width;
369
370 *(VOID **) Configuration = RegisterPtr;
371
372 return EFI_SUCCESS;
373 }
374 }
375 ListPtr += sizeof (EFI_PCI_REGISTER_ACCESS_DESCRIPTOR) / (sizeof (UINT64));
376 }
377 return EFI_UNSUPPORTED;
378
379 case DEVICE_RES_TAG:
380 //
381 // Adjust the pointer to the next item
382 //
383 ListPtr = ListPtr + 1 + ((sizeof (EFI_PCI_REGISTER_ACCESS_DESCRIPTOR)) / sizeof (UINT64));
384 break;
385
386 default:
387 return EFI_UNSUPPORTED;
388 }
389 }
390
391 return EFI_UNSUPPORTED;
392 }
393