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