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