git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10877 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			388 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			388 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  This module is one template module for Incompatible PCI Device Support protocol.
 | 
						|
  It includes one incompatile pci devices list template.
 | 
						|
  
 | 
						|
  Incompatible PCI Device Support protocol allows the PCI bus driver to support
 | 
						|
  resource allocation for some PCI devices that do not comply with the PCI Specification.
 | 
						|
 | 
						|
Copyright (c) 2009, Intel Corporation. All rights reserved.<BR>
 | 
						|
This program and the accompanying materials
 | 
						|
are licensed and made available under the terms and conditions of the BSD License
 | 
						|
which accompanies this distribution.  The full text of the license may be found at
 | 
						|
http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include <PiDxe.h>
 | 
						|
#include <Protocol/IncompatiblePciDeviceSupport.h>
 | 
						|
 | 
						|
#include <Library/UefiBootServicesTableLib.h>
 | 
						|
#include <Library/MemoryAllocationLib.h>
 | 
						|
#include <Library/DebugLib.h>
 | 
						|
 | 
						|
#include <IndustryStandard/Pci.h>
 | 
						|
#include <IndustryStandard/Acpi.h>
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  UINT64  VendorId;
 | 
						|
  UINT64  DeviceId;
 | 
						|
  UINT64  RevisionId;
 | 
						|
  UINT64  SubsystemVendorId;
 | 
						|
  UINT64  SubsystemDeviceId;
 | 
						|
} EFI_PCI_DEVICE_HEADER_INFO;
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  UINT64  ResType;
 | 
						|
  UINT64  GenFlag;
 | 
						|
  UINT64  SpecificFlag;
 | 
						|
  UINT64  AddrSpaceGranularity;
 | 
						|
  UINT64  AddrRangeMin;
 | 
						|
  UINT64  AddrRangeMax;
 | 
						|
  UINT64  AddrTranslationOffset;
 | 
						|
  UINT64  AddrLen;
 | 
						|
} EFI_PCI_RESOUCE_DESCRIPTOR;
 | 
						|
 | 
						|
#define PCI_DEVICE_ID(VendorId, DeviceId, Revision, SubVendorId, SubDeviceId) \
 | 
						|
    VendorId, DeviceId, Revision, SubVendorId, SubDeviceId
 | 
						|
 | 
						|
#define PCI_BAR_TYPE_IO   ACPI_ADDRESS_SPACE_TYPE_IO
 | 
						|
#define PCI_BAR_TYPE_MEM  ACPI_ADDRESS_SPACE_TYPE_MEM
 | 
						|
 | 
						|
#define DEVICE_INF_TAG    0xFFF2
 | 
						|
#define DEVICE_RES_TAG    0xFFF1
 | 
						|
#define LIST_END_TAG      0x0000
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Returns a list of ACPI resource descriptors that detail the special
 | 
						|
  resource configuration requirements for an incompatible PCI device.
 | 
						|
 | 
						|
  @param  This                  Pointer to the EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL instance.
 | 
						|
  @param  VendorId              A unique ID to identify the manufacturer of the PCI device.
 | 
						|
  @param  DeviceId              A unique ID to identify the particular PCI device.
 | 
						|
  @param  RevisionId            A PCI device-specific revision identifier.
 | 
						|
  @param  SubsystemVendorId     Specifies the subsystem vendor ID.
 | 
						|
  @param  SubsystemDeviceId     Specifies the subsystem device ID.
 | 
						|
  @param  Configuration         A list of ACPI resource descriptors returned that detail
 | 
						|
                                the configuration requirement.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           Successfully got ACPI resource for specified PCI device.
 | 
						|
  @retval EFI_INVALID_PARAMETER Configuration is NULL. 
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  No memory available.
 | 
						|
  @retval EFI_UNSUPPORTED       The specified PCI device wasn't supported.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
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
 | 
						|
  );
 | 
						|
 | 
						|
//
 | 
						|
// Handle onto which the Incompatible PCI Device List is installed
 | 
						|
//
 | 
						|
EFI_HANDLE                                    mIncompatiblePciDeviceSupportHandle = NULL;
 | 
						|
 | 
						|
//
 | 
						|
// The Incompatible PCI Device Support Protocol instance produced by this driver
 | 
						|
//
 | 
						|
EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL  mIncompatiblePciDeviceSupport = {
 | 
						|
  PCheckDevice
 | 
						|
};
 | 
						|
 | 
						|
//
 | 
						|
// The incompatible PCI devices list template
 | 
						|
//
 | 
						|
GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mIncompatiblePciDeviceList[] = {
 | 
						|
  //
 | 
						|
  // DEVICE_INF_TAG,
 | 
						|
  // PCI_DEVICE_ID (VendorID, DeviceID, Revision, SubVendorId, SubDeviceId),
 | 
						|
  // DEVICE_RES_TAG,
 | 
						|
  // ResType,  GFlag , SFlag,   Granularity,  RangeMin,
 | 
						|
  // RangeMax, Offset, AddrLen
 | 
						|
  //
 | 
						|
  //
 | 
						|
  // Device Adaptec 9004
 | 
						|
  //
 | 
						|
  DEVICE_INF_TAG,
 | 
						|
  PCI_DEVICE_ID(0x9004, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE),
 | 
						|
  DEVICE_RES_TAG,
 | 
						|
  PCI_BAR_TYPE_IO,
 | 
						|
  PCI_ACPI_UNUSED,
 | 
						|
  PCI_ACPI_UNUSED,
 | 
						|
  PCI_ACPI_UNUSED,
 | 
						|
  PCI_ACPI_UNUSED,
 | 
						|
  PCI_BAR_EVEN_ALIGN,
 | 
						|
  PCI_BAR_ALL,
 | 
						|
  PCI_BAR_NOCHANGE,
 | 
						|
  //
 | 
						|
  // Device Adaptec 9005
 | 
						|
  //
 | 
						|
  DEVICE_INF_TAG,
 | 
						|
  PCI_DEVICE_ID(0x9005, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE),
 | 
						|
  DEVICE_RES_TAG,
 | 
						|
  PCI_BAR_TYPE_IO,
 | 
						|
  PCI_ACPI_UNUSED,
 | 
						|
  PCI_ACPI_UNUSED,
 | 
						|
  PCI_ACPI_UNUSED,
 | 
						|
  PCI_ACPI_UNUSED,
 | 
						|
  PCI_BAR_EVEN_ALIGN,
 | 
						|
  PCI_BAR_ALL,
 | 
						|
  PCI_BAR_NOCHANGE,
 | 
						|
  //
 | 
						|
  // Device QLogic  1007
 | 
						|
  //
 | 
						|
  DEVICE_INF_TAG,
 | 
						|
  PCI_DEVICE_ID(0x1077, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE),
 | 
						|
  DEVICE_RES_TAG,
 | 
						|
  PCI_BAR_TYPE_IO,
 | 
						|
  PCI_ACPI_UNUSED,
 | 
						|
  PCI_ACPI_UNUSED,
 | 
						|
  PCI_ACPI_UNUSED,
 | 
						|
  PCI_ACPI_UNUSED,
 | 
						|
  PCI_BAR_EVEN_ALIGN,
 | 
						|
  PCI_BAR_ALL,
 | 
						|
  PCI_BAR_NOCHANGE,
 | 
						|
  //
 | 
						|
  // Device Agilent 103C
 | 
						|
  //
 | 
						|
  DEVICE_INF_TAG,
 | 
						|
  PCI_DEVICE_ID(0x103C, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE),
 | 
						|
  DEVICE_RES_TAG,
 | 
						|
  PCI_BAR_TYPE_IO,
 | 
						|
  PCI_ACPI_UNUSED,
 | 
						|
  PCI_ACPI_UNUSED,
 | 
						|
  PCI_ACPI_UNUSED,
 | 
						|
  PCI_ACPI_UNUSED,
 | 
						|
  PCI_BAR_EVEN_ALIGN,
 | 
						|
  PCI_BAR_ALL,
 | 
						|
  PCI_BAR_NOCHANGE,
 | 
						|
  //
 | 
						|
  // Device Agilent 15BC
 | 
						|
  //
 | 
						|
  DEVICE_INF_TAG,
 | 
						|
  PCI_DEVICE_ID(0x15BC, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE, DEVICE_ID_NOCARE),
 | 
						|
  DEVICE_RES_TAG,
 | 
						|
  PCI_BAR_TYPE_IO,
 | 
						|
  PCI_ACPI_UNUSED,
 | 
						|
  PCI_ACPI_UNUSED,
 | 
						|
  PCI_ACPI_UNUSED,
 | 
						|
  PCI_ACPI_UNUSED,
 | 
						|
  PCI_BAR_EVEN_ALIGN,
 | 
						|
  PCI_BAR_ALL,
 | 
						|
  PCI_BAR_NOCHANGE,
 | 
						|
  //
 | 
						|
  // The end of the list
 | 
						|
  //
 | 
						|
  LIST_END_TAG
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Entry point of the incompatible pci device support code. Setup an incompatible device list template
 | 
						|
  and install EFI Incompatible PCI Device Support protocol.
 | 
						|
 | 
						|
  @param ImageHandle             A handle for the image that is initializing this driver.
 | 
						|
  @param SystemTable             A pointer to the EFI system table.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            Installed EFI Incompatible PCI Device Support Protocol successfully.
 | 
						|
  @retval others                 Failed to install protocol.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
IncompatiblePciDeviceSupportEntryPoint (
 | 
						|
  IN EFI_HANDLE                   ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE             *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                         Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Install EFI Incompatible PCI Device Support Protocol on a new handle
 | 
						|
  //
 | 
						|
  Status = gBS->InstallProtocolInterface (
 | 
						|
                  &mIncompatiblePciDeviceSupportHandle,
 | 
						|
                  &gEfiIncompatiblePciDeviceSupportProtocolGuid,
 | 
						|
                  EFI_NATIVE_INTERFACE,
 | 
						|
                  &mIncompatiblePciDeviceSupport
 | 
						|
                  );
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Returns a list of ACPI resource descriptors that detail the special
 | 
						|
  resource configuration requirements for an incompatible PCI device.
 | 
						|
 | 
						|
  @param  This                  Pointer to the EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL instance.
 | 
						|
  @param  VendorId              A unique ID to identify the manufacturer of the PCI device.
 | 
						|
  @param  DeviceId              A unique ID to identify the particular PCI device.
 | 
						|
  @param  RevisionId            A PCI device-specific revision identifier.
 | 
						|
  @param  SubsystemVendorId     Specifies the subsystem vendor ID.
 | 
						|
  @param  SubsystemDeviceId     Specifies the subsystem device ID.
 | 
						|
  @param  Configuration         A list of ACPI resource descriptors returned that detail
 | 
						|
                                the configuration requirement.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           Successfully got ACPI resource for specified PCI device.
 | 
						|
  @retval EFI_INVALID_PARAMETER Configuration is NULL. 
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  No memory available.
 | 
						|
  @retval EFI_UNSUPPORTED       The specified PCI device wasn't supported.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
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
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT64                            Tag;
 | 
						|
  UINT64                            *ListPtr;
 | 
						|
  UINT64                            *TempListPtr;
 | 
						|
  EFI_PCI_DEVICE_HEADER_INFO        *Header;
 | 
						|
  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AcpiPtr;
 | 
						|
  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *OldAcpiPtr;
 | 
						|
  EFI_PCI_RESOUCE_DESCRIPTOR        *Dsc;
 | 
						|
  EFI_ACPI_END_TAG_DESCRIPTOR       *PtrEnd;
 | 
						|
  UINTN                             Index;
 | 
						|
 | 
						|
  //
 | 
						|
  // Validate the parameters
 | 
						|
  //
 | 
						|
  if (Configuration == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Initialize the return value to NULL
 | 
						|
  //
 | 
						|
  * (VOID **) Configuration = NULL;
 | 
						|
 | 
						|
  ListPtr                   = mIncompatiblePciDeviceList;
 | 
						|
  while (*ListPtr != LIST_END_TAG) {
 | 
						|
 | 
						|
    Tag = *ListPtr;
 | 
						|
 | 
						|
    switch (Tag) {
 | 
						|
    case DEVICE_INF_TAG:
 | 
						|
      Header  = (EFI_PCI_DEVICE_HEADER_INFO *) (ListPtr + 1);
 | 
						|
      ListPtr = ListPtr + 1 + sizeof (EFI_PCI_DEVICE_HEADER_INFO) / sizeof (UINT64);
 | 
						|
      //
 | 
						|
      // See if the Header matches the parameters passed in
 | 
						|
      //
 | 
						|
      if (Header->VendorId != DEVICE_ID_NOCARE) {
 | 
						|
        if (Header->VendorId != VendorId) {
 | 
						|
          continue;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      if (Header->DeviceId != DEVICE_ID_NOCARE) {
 | 
						|
        if (DeviceId != Header->DeviceId) {
 | 
						|
          continue;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      if (Header->RevisionId != DEVICE_ID_NOCARE) {
 | 
						|
        if (RevisionId != Header->RevisionId) {
 | 
						|
          continue;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      if (Header->SubsystemVendorId != DEVICE_ID_NOCARE) {
 | 
						|
        if (SubsystemVendorId != Header->SubsystemVendorId) {
 | 
						|
          continue;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      if (Header->SubsystemDeviceId != DEVICE_ID_NOCARE) {
 | 
						|
        if (SubsystemDeviceId != Header->SubsystemDeviceId) {
 | 
						|
          continue;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // Matched an item, so construct the ACPI descriptor for the resource.
 | 
						|
      //
 | 
						|
      //
 | 
						|
      // Count the resource items so that to allocate space
 | 
						|
      //
 | 
						|
      for (Index = 0, TempListPtr = ListPtr; *TempListPtr == DEVICE_RES_TAG; Index++) {
 | 
						|
        TempListPtr = TempListPtr + 1 + ((sizeof (EFI_PCI_RESOUCE_DESCRIPTOR)) / sizeof (UINT64));
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // If there is at least one type of resource request,
 | 
						|
      // allocate an acpi resource node
 | 
						|
      //
 | 
						|
      if (Index == 0) {
 | 
						|
        return EFI_UNSUPPORTED;
 | 
						|
      }
 | 
						|
 | 
						|
      AcpiPtr = AllocateZeroPool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * Index + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
 | 
						|
      if (AcpiPtr == NULL) {
 | 
						|
        return EFI_OUT_OF_RESOURCES;
 | 
						|
      }
 | 
						|
 | 
						|
      OldAcpiPtr = AcpiPtr;
 | 
						|
      //
 | 
						|
      // Fill the EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR structure
 | 
						|
      // according to the EFI_PCI_RESOUCE_DESCRIPTOR structure
 | 
						|
      //
 | 
						|
      for (; *ListPtr == DEVICE_RES_TAG;) {
 | 
						|
 | 
						|
        Dsc = (EFI_PCI_RESOUCE_DESCRIPTOR *) (ListPtr + 1);
 | 
						|
 | 
						|
        AcpiPtr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
 | 
						|
        AcpiPtr->Len = (UINT16) sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
 | 
						|
        AcpiPtr->ResType = (UINT8) Dsc->ResType;
 | 
						|
        AcpiPtr->GenFlag = (UINT8) Dsc->GenFlag;
 | 
						|
        AcpiPtr->SpecificFlag = (UINT8) Dsc->SpecificFlag;
 | 
						|
        AcpiPtr->AddrSpaceGranularity = Dsc->AddrSpaceGranularity;;
 | 
						|
        AcpiPtr->AddrRangeMin = Dsc->AddrRangeMin;
 | 
						|
        AcpiPtr->AddrRangeMax = Dsc->AddrRangeMax;
 | 
						|
        AcpiPtr->AddrTranslationOffset = Dsc->AddrTranslationOffset;
 | 
						|
        AcpiPtr->AddrLen = Dsc->AddrLen;
 | 
						|
 | 
						|
        ListPtr = ListPtr + 1 + ((sizeof (EFI_PCI_RESOUCE_DESCRIPTOR)) / sizeof (UINT64));
 | 
						|
        AcpiPtr++;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // Put the checksum
 | 
						|
      //
 | 
						|
      PtrEnd                    = (EFI_ACPI_END_TAG_DESCRIPTOR *) (AcpiPtr);
 | 
						|
      PtrEnd->Desc              = ACPI_END_TAG_DESCRIPTOR;
 | 
						|
      PtrEnd->Checksum          = 0;
 | 
						|
 | 
						|
      *(VOID **) Configuration  = OldAcpiPtr;
 | 
						|
 | 
						|
      return EFI_SUCCESS;
 | 
						|
 | 
						|
    case DEVICE_RES_TAG:
 | 
						|
      //
 | 
						|
      // Adjust the pointer to the next PCI resource descriptor item
 | 
						|
      //
 | 
						|
      ListPtr = ListPtr + 1 + ((sizeof (EFI_PCI_RESOUCE_DESCRIPTOR)) / sizeof (UINT64));
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      return EFI_UNSUPPORTED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_UNSUPPORTED;
 | 
						|
}
 | 
						|
 |