• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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. All rights reserved.<BR>
9 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
IncompatiblePciDeviceSupportEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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
PCheckDevice(IN EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL * This,IN UINTN VendorId,IN UINTN DeviceId,IN UINTN RevisionId,IN UINTN SubsystemVendorId,IN UINTN SubsystemDeviceId,OUT VOID ** Configuration)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 = (UINT16) 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 
388