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