- TURE -> TRUE - reseting -> resetting - retore -> restore - boundry -> boundary - tempory -> temporary Cc: Michael D Kinney <michael.d.kinney@intel.com> Cc: Kelly Steele <kelly.steele@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Gary Lin <glin@suse.com> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com>
		
			
				
	
	
		
			1409 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1409 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
Update the _PRT and _PRW method for pci devices
 | 
						|
 | 
						|
Copyright (c) 2013-2016 Intel Corporation.
 | 
						|
 | 
						|
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 "AcpiPlatform.h"
 | 
						|
 | 
						|
PCI_DEVICE_INFO *mQNCPciInfo = NULL;
 | 
						|
 | 
						|
/**
 | 
						|
  Init Pci Device Structure
 | 
						|
  @param mConfigData    - Pointer of Pci Device information Structure
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
InitPciDeviceInfoStructure (
 | 
						|
  PCI_DEVICE_SETTING            *mConfigData
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // Return 0 given that function unsupported.
 | 
						|
  // Would need to parse ACPI tables and build mQNCPciInfo above
 | 
						|
  // with found _PRT & _PRW methods for PCI devices.
 | 
						|
  //
 | 
						|
  mConfigData->PciDeviceInfoNumber = 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  return Integer value.
 | 
						|
 | 
						|
  @param Data    - AML data buffer
 | 
						|
  @param Integer - integer value.
 | 
						|
 | 
						|
  @return Data size processed.
 | 
						|
**/
 | 
						|
UINTN
 | 
						|
SdtGetInteger (
 | 
						|
  IN  UINT8  *Data,
 | 
						|
  OUT UINT64 *Integer
 | 
						|
  )
 | 
						|
{
 | 
						|
  *Integer = 0;
 | 
						|
  switch (*Data) {
 | 
						|
  case AML_ZERO_OP:
 | 
						|
    return 1;
 | 
						|
  case AML_ONE_OP:
 | 
						|
    *Integer = 1;
 | 
						|
    return 1;
 | 
						|
  case AML_ONES_OP:
 | 
						|
    *Integer = (UINTN)-1;
 | 
						|
    return 1;
 | 
						|
  case AML_BYTE_PREFIX:
 | 
						|
    CopyMem (Integer, Data + 1, sizeof(UINT8));
 | 
						|
    return 1 + sizeof(UINT8);
 | 
						|
  case AML_WORD_PREFIX:
 | 
						|
    CopyMem (Integer, Data + 1, sizeof(UINT16));
 | 
						|
    return 1 + sizeof(UINT16);
 | 
						|
  case AML_DWORD_PREFIX:
 | 
						|
    CopyMem (Integer, Data + 1, sizeof(UINT32));
 | 
						|
    return 1 + sizeof(UINT32);
 | 
						|
  case AML_QWORD_PREFIX:
 | 
						|
    CopyMem (Integer, Data + 1, sizeof(UINT64));
 | 
						|
    return 1 + sizeof(UINT64);
 | 
						|
  default:
 | 
						|
    // Something wrong
 | 
						|
    ASSERT (FALSE);
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Check if this handle has expected opcode.
 | 
						|
 | 
						|
  @param AcpiSdt    Pointer to Acpi SDT protocol
 | 
						|
  @param Handle     ACPI handle
 | 
						|
  @param OpCode     Expected OpCode
 | 
						|
  @param SubOpCode  Expected SubOpCode
 | 
						|
 | 
						|
  @retval TRUE  This handle has expected opcode
 | 
						|
  @retval FALSE This handle does not have expected opcode
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
SdtIsThisTypeObject (
 | 
						|
  IN EFI_ACPI_SDT_PROTOCOL *AcpiSdt,
 | 
						|
  IN EFI_ACPI_HANDLE Handle,
 | 
						|
  IN UINT8           OpCode,
 | 
						|
  IN UINT8           SubOpCode
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS         Status;
 | 
						|
  EFI_ACPI_DATA_TYPE DataType;
 | 
						|
  UINT8              *Data;
 | 
						|
  UINTN              DataSize;
 | 
						|
 | 
						|
  Status = AcpiSdt->GetOption (Handle, 0, &DataType, (CONST VOID **)&Data, &DataSize);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  ASSERT (DataType == EFI_ACPI_DATA_TYPE_OPCODE);
 | 
						|
 | 
						|
  if (OpCode == AML_EXT_OP) {
 | 
						|
    if (Data[1] == SubOpCode) {
 | 
						|
      return TRUE;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    if (Data[0] == OpCode) {
 | 
						|
      return TRUE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check if this handle has expected name and name value.
 | 
						|
 | 
						|
  @param AcpiSdt    Pointer to Acpi SDT protocol
 | 
						|
  @param Handle     ACPI handle
 | 
						|
  @param Name       Expected name
 | 
						|
  @param Value      Expected name value
 | 
						|
 | 
						|
  @retval TRUE  This handle has expected name and name value.
 | 
						|
  @retval FALSE This handle does not have expected name and name value.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
SdtIsNameIntegerValueEqual (
 | 
						|
  IN EFI_ACPI_SDT_PROTOCOL *AcpiSdt,
 | 
						|
  IN EFI_ACPI_HANDLE Handle,
 | 
						|
  IN CHAR8           *Name,
 | 
						|
  IN UINT64          Value
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS         Status;
 | 
						|
  EFI_ACPI_DATA_TYPE DataType;
 | 
						|
  UINT8              *Data;
 | 
						|
  UINTN              DataSize;
 | 
						|
  UINT64             Integer;
 | 
						|
 | 
						|
  Status = AcpiSdt->GetOption (Handle, 1, &DataType, (CONST VOID **)&Data, &DataSize);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  ASSERT (DataType == EFI_ACPI_DATA_TYPE_NAME_STRING);
 | 
						|
 | 
						|
  if (CompareMem (Data, Name, 4) != 0) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Name match check object
 | 
						|
  //
 | 
						|
  Status = AcpiSdt->GetOption (Handle, 2, &DataType, (CONST VOID **)&Data, &DataSize);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  Integer = 0;
 | 
						|
  SdtGetInteger (Data, &Integer);
 | 
						|
  if (Integer != Value) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  // All match
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check if this handle's children has expected name and name value.
 | 
						|
 | 
						|
  @param AcpiSdt          Pointer to Acpi SDT protocol
 | 
						|
  @param ParentHandle     ACPI parent handle
 | 
						|
  @param Name             Expected name
 | 
						|
  @param Value            Expected name value
 | 
						|
 | 
						|
  @retval TRUE  This handle's children has expected name and name value.
 | 
						|
  @retval FALSE This handle's children does not have expected name and name value.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
SdtCheckNameIntegerValue (
 | 
						|
  IN EFI_ACPI_SDT_PROTOCOL *AcpiSdt,
 | 
						|
  IN EFI_ACPI_HANDLE ParentHandle,
 | 
						|
  IN CHAR8           *Name,
 | 
						|
  IN UINT64          Value
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_ACPI_HANDLE PreviousHandle;
 | 
						|
  EFI_ACPI_HANDLE Handle;
 | 
						|
  EFI_STATUS      Status;
 | 
						|
 | 
						|
  Handle = NULL;
 | 
						|
  while (TRUE) {
 | 
						|
    PreviousHandle = Handle;
 | 
						|
    Status = AcpiSdt->GetChild (ParentHandle, &Handle);
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
    if (PreviousHandle != NULL) {
 | 
						|
      Status = AcpiSdt->Close (PreviousHandle);
 | 
						|
      ASSERT_EFI_ERROR (Status);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Done
 | 
						|
    //
 | 
						|
    if (Handle == NULL) {
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Check this name
 | 
						|
    //
 | 
						|
    if (SdtIsThisTypeObject (AcpiSdt, Handle, AML_NAME_OP, 0)) {
 | 
						|
      if (SdtIsNameIntegerValueEqual (AcpiSdt, Handle, Name, Value)) {
 | 
						|
        return TRUE;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Should not run here
 | 
						|
  //
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Convert the pci address from VPD (bus,dev,fun) into the address that acpi table
 | 
						|
  can recognize.
 | 
						|
 | 
						|
  @param PciAddress    Pci address from VPD
 | 
						|
 | 
						|
  @retval return the address that acpi table can recognize
 | 
						|
**/
 | 
						|
UINT32
 | 
						|
SdtConvertToAcpiPciAdress (
 | 
						|
  IN UINT32 PciAddress
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32 ReturnAddress;
 | 
						|
 | 
						|
  ReturnAddress = ((PciAddress & 0x0000FF00) << 8) | (PciAddress & 0x000000FF);
 | 
						|
 | 
						|
  if ((PciAddress & 0x000000FF) == 0x000000FF)
 | 
						|
    ReturnAddress |= 0x0000FFFF;
 | 
						|
 | 
						|
  return ReturnAddress;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  return AML NameString size.
 | 
						|
 | 
						|
  @param Buffer - AML name string
 | 
						|
 | 
						|
  @return AML name string size
 | 
						|
**/
 | 
						|
UINTN
 | 
						|
SdtGetNameStringSize (
 | 
						|
  IN UINT8              *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                 SegCount;
 | 
						|
  UINTN                 Length;
 | 
						|
 | 
						|
  Length = 0;
 | 
						|
 | 
						|
  //
 | 
						|
  // Parse root or prefix
 | 
						|
  //
 | 
						|
  if (*Buffer == AML_ROOT_CHAR) {
 | 
						|
    //
 | 
						|
    // RootChar
 | 
						|
    //
 | 
						|
    Buffer ++;
 | 
						|
    Length ++;
 | 
						|
  } else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
 | 
						|
    //
 | 
						|
    // ParentPrefixChar
 | 
						|
    //
 | 
						|
    Buffer ++;
 | 
						|
    Length ++;
 | 
						|
    while (*Buffer == AML_PARENT_PREFIX_CHAR) {
 | 
						|
      Buffer ++;
 | 
						|
      Length ++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Parse name segment
 | 
						|
  //
 | 
						|
  if (*Buffer == AML_DUAL_NAME_PREFIX) {
 | 
						|
    //
 | 
						|
    // DualName
 | 
						|
    //
 | 
						|
    Buffer ++;
 | 
						|
    Length ++;
 | 
						|
    SegCount = 2;
 | 
						|
  } else if (*Buffer == AML_MULTI_NAME_PREFIX) {
 | 
						|
    //
 | 
						|
    // MultiName
 | 
						|
    //
 | 
						|
    Buffer ++;
 | 
						|
    Length ++;
 | 
						|
    SegCount = *Buffer;
 | 
						|
    Buffer ++;
 | 
						|
    Length ++;
 | 
						|
  } else if (*Buffer == 0) {
 | 
						|
    //
 | 
						|
    // NULL Name
 | 
						|
    //
 | 
						|
    SegCount = 0;
 | 
						|
    Length ++;
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // NameSeg
 | 
						|
    //
 | 
						|
    SegCount = 1;
 | 
						|
  }
 | 
						|
 | 
						|
  Buffer += 4 * SegCount;
 | 
						|
  Length += 4 * SegCount;
 | 
						|
 | 
						|
  return Length;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  The routine to check if this device is PCI root bridge.
 | 
						|
 | 
						|
  @param AcpiSdt       Pointer to Acpi SDT protocol
 | 
						|
  @param DeviceHandle  ACPI device handle
 | 
						|
  @param Context       Context info - not used here
 | 
						|
 | 
						|
  @retval TRUE  This is PCI root bridge
 | 
						|
  @retval FALSE This is not PCI root bridge
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
SdtFindRootBridgeHandle (
 | 
						|
  IN EFI_ACPI_SDT_PROTOCOL  *AcpiSdt,
 | 
						|
  IN EFI_ACPI_HANDLE        CheckHandle,
 | 
						|
  IN VOID                   *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN            Result;
 | 
						|
  EFI_ACPI_DATA_TYPE DataType;
 | 
						|
  UINT8              *Data;
 | 
						|
  UINTN              DataSize;
 | 
						|
  EFI_STATUS         Status;
 | 
						|
 | 
						|
  if (!SdtIsThisTypeObject (AcpiSdt, CheckHandle, AML_EXT_OP, AML_EXT_DEVICE_OP))
 | 
						|
    return FALSE;
 | 
						|
 | 
						|
  Result = SdtCheckNameIntegerValue (AcpiSdt,CheckHandle, "_HID", (UINT64)0x080AD041); // PNP0A08
 | 
						|
  if (!Result) {
 | 
						|
    Result = SdtCheckNameIntegerValue (AcpiSdt, CheckHandle, "_CID", (UINT64)0x030AD041); // PNP0A03
 | 
						|
    if (!Result) {
 | 
						|
      return Result;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Found
 | 
						|
  //
 | 
						|
  Status = AcpiSdt->GetOption (CheckHandle, 1, &DataType, (CONST VOID **)&Data, &DataSize);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  ASSERT (DataType == EFI_ACPI_DATA_TYPE_NAME_STRING);
 | 
						|
 | 
						|
  return Result;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  The routine to check if this device is wanted.
 | 
						|
 | 
						|
  @param AcpiSdt       Pointer to Acpi SDT protocol
 | 
						|
  @param DeviceHandle  ACPI device handle
 | 
						|
  @param Context       Context info - not used here
 | 
						|
 | 
						|
  @retval TRUE  This is PCI device wanted
 | 
						|
  @retval FALSE This is not PCI device wanted
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
SdtFindPciDeviceHandle (
 | 
						|
  IN EFI_ACPI_SDT_PROTOCOL  *AcpiSdt,
 | 
						|
  IN EFI_ACPI_HANDLE        CheckHandle,
 | 
						|
  IN VOID                   *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN            Result;
 | 
						|
  EFI_ACPI_DATA_TYPE DataType;
 | 
						|
  UINT8              *Data;
 | 
						|
  UINTN              DataSize;
 | 
						|
  EFI_STATUS         Status;
 | 
						|
 | 
						|
  if (!SdtIsThisTypeObject (AcpiSdt, CheckHandle, AML_EXT_OP, AML_EXT_DEVICE_OP))
 | 
						|
    return FALSE;
 | 
						|
 | 
						|
  Result = SdtCheckNameIntegerValue (AcpiSdt,CheckHandle, "_ADR", (UINT64)*(UINT32 *)Context);
 | 
						|
  if (!Result) {
 | 
						|
    return Result;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Found
 | 
						|
  //
 | 
						|
  Status = AcpiSdt->GetOption (CheckHandle, 1, &DataType, (CONST VOID **)&Data, &DataSize);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  ASSERT (DataType == EFI_ACPI_DATA_TYPE_NAME_STRING);
 | 
						|
 | 
						|
  return Result;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Go through the parent handle and find the handle which pass CheckHandleInfo.
 | 
						|
 | 
						|
  @param AcpiSdt          Pointer to Acpi SDT protocol
 | 
						|
  @param ParentHandle     ACPI parent handle
 | 
						|
  @param CheckHandleInfo  The callback routine to check if this handle meet the requirement
 | 
						|
  @param Context          The context of CheckHandleInfo
 | 
						|
 | 
						|
  @return the handle which is first one can pass CheckHandleInfo.
 | 
						|
**/
 | 
						|
EFI_ACPI_HANDLE
 | 
						|
SdtGetHandleByScanAllChilds (
 | 
						|
  IN EFI_ACPI_SDT_PROTOCOL  *AcpiSdt,
 | 
						|
  IN EFI_ACPI_HANDLE        ParentHandle,
 | 
						|
  IN CHECK_HANDLE_INFO      CheckHandleInfo,
 | 
						|
  IN VOID                   *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_ACPI_HANDLE    PreviousHandle;
 | 
						|
  EFI_ACPI_HANDLE    Handle;
 | 
						|
  EFI_STATUS         Status;
 | 
						|
  EFI_ACPI_HANDLE    ReturnHandle;
 | 
						|
 | 
						|
  //
 | 
						|
  // Use deep first algo to enumerate all ACPI object
 | 
						|
  //
 | 
						|
  Handle = NULL;
 | 
						|
  while (TRUE) {
 | 
						|
    PreviousHandle = Handle;
 | 
						|
    Status = AcpiSdt->GetChild (ParentHandle, &Handle);
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
    if (PreviousHandle != NULL) {
 | 
						|
      Status = AcpiSdt->Close (PreviousHandle);
 | 
						|
      ASSERT_EFI_ERROR (Status);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Done
 | 
						|
    //
 | 
						|
    if (Handle == NULL) {
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Check this handle
 | 
						|
    //
 | 
						|
    if (CheckHandleInfo (AcpiSdt, Handle, Context)) {
 | 
						|
      return Handle;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Enumerate
 | 
						|
    //
 | 
						|
    ReturnHandle = SdtGetHandleByScanAllChilds (AcpiSdt, Handle, CheckHandleInfo, Context);
 | 
						|
    if (ReturnHandle != NULL) {
 | 
						|
      return ReturnHandle;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Should not run here
 | 
						|
  //
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Check whether the INTx package is matched
 | 
						|
 | 
						|
  @param AcpiSdt          Pointer to Acpi SDT protocol
 | 
						|
  @param INTxPkgHandle    ACPI INTx package handle
 | 
						|
  @param PciAddress       Acpi pci address
 | 
						|
  @param INTx             Index of INTx pin
 | 
						|
  @param IsAPIC           Tell whether the returned INTx package is for APIC or not
 | 
						|
 | 
						|
  @retval       TRUE      the INTx package is matched
 | 
						|
  @retval       FALSE     the INTx package is not matched
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
SdtCheckINTxPkgIsMatch (
 | 
						|
  IN EFI_ACPI_SDT_PROTOCOL  *AcpiSdt,
 | 
						|
  IN EFI_ACPI_HANDLE        INTxPkgHandle,
 | 
						|
  IN UINT32                 PciAddress,
 | 
						|
  IN UINT8                  INTx,
 | 
						|
  IN BOOLEAN                *IsAPIC
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_ACPI_HANDLE    PreviousHandle;
 | 
						|
  EFI_STATUS         Status;
 | 
						|
  EFI_ACPI_HANDLE    MemberHandle;
 | 
						|
  EFI_ACPI_DATA_TYPE DataType;
 | 
						|
  UINT8              *Data;
 | 
						|
  UINTN              DataSize;
 | 
						|
  UINT64             CurrentPciAddress;
 | 
						|
  UINT64             CurrentINTx;
 | 
						|
  UINTN              ChildSize;
 | 
						|
 | 
						|
 | 
						|
  //
 | 
						|
  // Check the pci address
 | 
						|
  //
 | 
						|
  MemberHandle = NULL;
 | 
						|
  Status = AcpiSdt->GetChild (INTxPkgHandle, &MemberHandle);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  ASSERT (MemberHandle != NULL);
 | 
						|
 | 
						|
  Status = AcpiSdt->GetOption (MemberHandle, 0, &DataType, (CONST VOID **)&Data, &DataSize);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  ASSERT (DataType == EFI_ACPI_DATA_TYPE_OPCODE);
 | 
						|
 | 
						|
  CurrentPciAddress = 0;
 | 
						|
  SdtGetInteger (Data, &CurrentPciAddress);
 | 
						|
 | 
						|
  if (CurrentPciAddress != PciAddress) {
 | 
						|
 | 
						|
    Status = AcpiSdt->Close (MemberHandle);
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check the pci interrupt pin
 | 
						|
  //
 | 
						|
  PreviousHandle = MemberHandle;
 | 
						|
  Status = AcpiSdt->GetChild (INTxPkgHandle, &MemberHandle);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  ASSERT (MemberHandle != NULL);
 | 
						|
 | 
						|
  if (PreviousHandle != NULL) {
 | 
						|
    Status = AcpiSdt->Close (PreviousHandle);
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
  }
 | 
						|
 | 
						|
  Status = AcpiSdt->GetOption (MemberHandle, 0, &DataType, (CONST VOID **)&Data, &DataSize);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  ASSERT (DataType == EFI_ACPI_DATA_TYPE_OPCODE);
 | 
						|
 | 
						|
  CurrentINTx = 0;
 | 
						|
  ChildSize = SdtGetInteger (Data, &CurrentINTx);
 | 
						|
 | 
						|
  Status = AcpiSdt->Close (MemberHandle);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  if (CurrentINTx != INTx)
 | 
						|
    return FALSE;
 | 
						|
 | 
						|
  Data += ChildSize;
 | 
						|
 | 
						|
  if (*Data == AML_BYTE_PREFIX)
 | 
						|
    Data += 1;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check the pci interrupt source
 | 
						|
  //
 | 
						|
  if (*Data  != 0)
 | 
						|
    *IsAPIC = FALSE;
 | 
						|
  else
 | 
						|
    *IsAPIC = TRUE;
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Get the wanted INTx package inside the parent package
 | 
						|
 | 
						|
  @param AcpiSdt          Pointer to Acpi SDT protocol
 | 
						|
  @param ParentPkgHandle  ACPI parent package handle
 | 
						|
  @param PciAddress       Acpi pci address
 | 
						|
  @param INTx             Index of INTx pin
 | 
						|
  @param INTxPkgHandle    ACPI INTx package handle
 | 
						|
  @param IsAPIC           Tell whether the returned INTx package is for APIC or not
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SdtGetINTxPkgHandle (
 | 
						|
  IN EFI_ACPI_SDT_PROTOCOL  *AcpiSdt,
 | 
						|
  IN EFI_ACPI_HANDLE        ParentPkgHandle,
 | 
						|
  IN UINT32                 PciAddress,
 | 
						|
  IN UINT8                  INTx,
 | 
						|
  IN EFI_ACPI_HANDLE        *INTxPkgHandle,
 | 
						|
  IN BOOLEAN                *IsAPIC
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_ACPI_HANDLE    PreviousHandle;
 | 
						|
  EFI_STATUS         Status;
 | 
						|
  EFI_ACPI_HANDLE    ChildPkgHandle;
 | 
						|
 | 
						|
  ChildPkgHandle = NULL;
 | 
						|
  while (TRUE) {
 | 
						|
    PreviousHandle = ChildPkgHandle;
 | 
						|
    Status = AcpiSdt->GetChild (ParentPkgHandle, &ChildPkgHandle);
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
    if (PreviousHandle != NULL) {
 | 
						|
      Status = AcpiSdt->Close (PreviousHandle);
 | 
						|
      ASSERT_EFI_ERROR (Status);
 | 
						|
    }
 | 
						|
 | 
						|
    if (ChildPkgHandle == NULL) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    if (SdtCheckINTxPkgIsMatch(AcpiSdt, ChildPkgHandle, PciAddress, INTx, IsAPIC)) {
 | 
						|
      *INTxPkgHandle = ChildPkgHandle;
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Update the INTx package with the correct pirq value
 | 
						|
 | 
						|
  @param AcpiSdt          Pointer to Acpi SDT protocol
 | 
						|
  @param INTxPkgHandle    ACPI INTx package handle
 | 
						|
  @param PirqValue        Correct pirq value
 | 
						|
  @param IsAPIC           Tell whether the INTx package is for APIC or not
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SdtUpdateINTxPkg (
 | 
						|
  IN EFI_ACPI_SDT_PROTOCOL  *AcpiSdt,
 | 
						|
  IN EFI_ACPI_HANDLE        INTxPkgHandle,
 | 
						|
  IN UINT8                  PirqValue,
 | 
						|
  IN BOOLEAN                IsAPIC
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_ACPI_HANDLE    PreviousHandle;
 | 
						|
  EFI_STATUS         Status;
 | 
						|
  EFI_ACPI_HANDLE    MemberHandle;
 | 
						|
  EFI_ACPI_DATA_TYPE DataType;
 | 
						|
  UINT8              *Data;
 | 
						|
  UINTN              DataSize;
 | 
						|
  UINT64             TempValue;
 | 
						|
  UINTN              ChildSize;
 | 
						|
 | 
						|
 | 
						|
  //
 | 
						|
  // Check the pci address
 | 
						|
  //
 | 
						|
  MemberHandle = NULL;
 | 
						|
  Status = AcpiSdt->GetChild (INTxPkgHandle, &MemberHandle);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  ASSERT (MemberHandle != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // Check the pci interrupt pin
 | 
						|
  //
 | 
						|
  PreviousHandle = MemberHandle;
 | 
						|
  Status = AcpiSdt->GetChild (INTxPkgHandle, &MemberHandle);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  ASSERT (MemberHandle != NULL);
 | 
						|
 | 
						|
  if (PreviousHandle != NULL) {
 | 
						|
    Status = AcpiSdt->Close (PreviousHandle);
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
  }
 | 
						|
 | 
						|
  Status = AcpiSdt->GetOption (MemberHandle, 0, &DataType, (CONST VOID **)&Data, &DataSize);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  ASSERT (DataType == EFI_ACPI_DATA_TYPE_OPCODE);
 | 
						|
 | 
						|
  ChildSize = SdtGetInteger (Data, &TempValue);
 | 
						|
 | 
						|
  Status = AcpiSdt->Close (MemberHandle);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  Data += ChildSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // update the pci interrupt source or source index
 | 
						|
  //
 | 
						|
  if (!IsAPIC) {
 | 
						|
    ChildSize = SdtGetNameStringSize (Data);
 | 
						|
    Data += (ChildSize - 1);
 | 
						|
 | 
						|
    PirqValue += 0x40;   // change to ascii char
 | 
						|
    if (*Data != PirqValue)
 | 
						|
      *Data = PirqValue;
 | 
						|
  } else {
 | 
						|
 | 
						|
    ChildSize = SdtGetInteger (Data, &TempValue);
 | 
						|
    Data += ChildSize;
 | 
						|
 | 
						|
    Data += 1;
 | 
						|
 | 
						|
    if (*Data != PirqValue)
 | 
						|
      *Data = PirqValue;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check every child package inside this interested parent package for update PRT
 | 
						|
 | 
						|
  @param AcpiSdt          Pointer to Acpi SDT protocol
 | 
						|
  @param ParentPkgHandle  ACPI parent package handle
 | 
						|
  @param PciDeviceInfo    Pointer to PCI_DEVICE_INFO
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SdtCheckParentPackage (
 | 
						|
  IN EFI_ACPI_SDT_PROTOCOL  *AcpiSdt,
 | 
						|
  IN EFI_ACPI_HANDLE        ParentPkgHandle,
 | 
						|
  IN PCI_DEVICE_INFO        *PciDeviceInfo
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_ACPI_HANDLE    INTAPkgHandle;
 | 
						|
  EFI_ACPI_HANDLE    INTBPkgHandle;
 | 
						|
  EFI_ACPI_HANDLE    INTCPkgHandle;
 | 
						|
  EFI_ACPI_HANDLE    INTDPkgHandle;
 | 
						|
  UINT32             PciAddress = 0;
 | 
						|
  BOOLEAN            IsAllFunctions = FALSE;
 | 
						|
  UINT8              IsAPIC = 0;
 | 
						|
  EFI_STATUS         Status;
 | 
						|
 | 
						|
  INTAPkgHandle = INTBPkgHandle = INTCPkgHandle = INTDPkgHandle = NULL;
 | 
						|
 | 
						|
  PciAddress   = SdtConvertToAcpiPciAdress(PciDeviceInfo->DeviceAddress);
 | 
						|
 | 
						|
  if ((PciAddress & 0xFFFF) == 0xFFFF) {
 | 
						|
    IsAllFunctions = TRUE;
 | 
						|
  } else {
 | 
						|
    IsAllFunctions = FALSE;
 | 
						|
    PciAddress = (PciAddress | 0xFFFF);
 | 
						|
  }
 | 
						|
 | 
						|
  SdtGetINTxPkgHandle (AcpiSdt, ParentPkgHandle, PciAddress, 0, &INTAPkgHandle, (BOOLEAN *)&IsAPIC);
 | 
						|
  SdtGetINTxPkgHandle (AcpiSdt, ParentPkgHandle, PciAddress, 1, &INTBPkgHandle, (BOOLEAN *)&IsAPIC);
 | 
						|
  SdtGetINTxPkgHandle (AcpiSdt, ParentPkgHandle, PciAddress, 2, &INTCPkgHandle, (BOOLEAN *)&IsAPIC);
 | 
						|
  SdtGetINTxPkgHandle (AcpiSdt, ParentPkgHandle, PciAddress, 3, &INTDPkgHandle, (BOOLEAN *)&IsAPIC);
 | 
						|
 | 
						|
  //
 | 
						|
  // Check INTA
 | 
						|
  //
 | 
						|
  if ((PciDeviceInfo->INTA[IsAPIC] != 0xFF) && (INTAPkgHandle != NULL)) {
 | 
						|
    //
 | 
						|
    // Find INTA package and there is valid INTA update item, update it
 | 
						|
    //
 | 
						|
    SdtUpdateINTxPkg (AcpiSdt, INTAPkgHandle, (PciDeviceInfo->INTA[IsAPIC]), IsAPIC);
 | 
						|
  } else if ((PciDeviceInfo->INTA[IsAPIC] != 0xFF) && (INTAPkgHandle == NULL)) {
 | 
						|
    //
 | 
						|
    // There is valid INTA update item, but no INA package exist, should add it
 | 
						|
    //
 | 
						|
    DEBUG ((EFI_D_ERROR, "\n\nShould add INTA item for this device(0x%x)\n\n", PciAddress));
 | 
						|
 | 
						|
  } else if ((PciDeviceInfo->INTA[IsAPIC] == 0xFF) && (INTAPkgHandle != NULL) && IsAllFunctions) {
 | 
						|
    //
 | 
						|
    // For all functions senario, if there is invalid INTA update item, but INTA package does exist, should delete it
 | 
						|
    //
 | 
						|
    DEBUG ((EFI_D_ERROR, "\n\nShould remove INTA item for this device(0x%x)\n\n", PciAddress));
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check INTB
 | 
						|
  //
 | 
						|
  if ((PciDeviceInfo->INTB[IsAPIC] != 0xFF) && (INTBPkgHandle != NULL)) {
 | 
						|
    //
 | 
						|
    // Find INTB package and there is valid INTB update item, update it
 | 
						|
    //
 | 
						|
    SdtUpdateINTxPkg (AcpiSdt, INTBPkgHandle, (PciDeviceInfo->INTB[IsAPIC]), IsAPIC);
 | 
						|
  } else if ((PciDeviceInfo->INTB[IsAPIC] != 0xFF) && (INTBPkgHandle == NULL)) {
 | 
						|
    //
 | 
						|
    // There is valid INTB update item, but no INTB package exist, should add it
 | 
						|
    //
 | 
						|
    DEBUG ((EFI_D_ERROR, "\n\nShould add INTB item for this device(0x%x)\n\n", PciAddress));
 | 
						|
 | 
						|
  } else if ((PciDeviceInfo->INTB[IsAPIC] == 0xFF) && (INTBPkgHandle != NULL) && IsAllFunctions) {
 | 
						|
    //
 | 
						|
    // For all functions senario, if there is invalid INTB update item, but INTB package does exist, should delete it
 | 
						|
    //
 | 
						|
    DEBUG ((EFI_D_ERROR, "\n\nShould remove INTB item for this device(0x%x)\n\n", PciAddress));
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check INTC
 | 
						|
  //
 | 
						|
  if ((PciDeviceInfo->INTC[IsAPIC] != 0xFF) && (INTCPkgHandle != NULL)) {
 | 
						|
    //
 | 
						|
    // Find INTC package and there is valid INTC update item, update it
 | 
						|
    //
 | 
						|
    SdtUpdateINTxPkg (AcpiSdt, INTCPkgHandle, (PciDeviceInfo->INTC[IsAPIC]), IsAPIC);
 | 
						|
  } else if ((PciDeviceInfo->INTC[IsAPIC] != 0xFF) && (INTCPkgHandle == NULL)) {
 | 
						|
    //
 | 
						|
    // There is valid INTC update item, but no INTC package exist, should add it
 | 
						|
    //
 | 
						|
    DEBUG ((EFI_D_ERROR, "\n\nShould add INTC item for this device(0x%x)\n\n", PciAddress));
 | 
						|
 | 
						|
  } else if ((PciDeviceInfo->INTC[IsAPIC] == 0xFF) && (INTCPkgHandle != NULL) && IsAllFunctions) {
 | 
						|
    //
 | 
						|
    // For all functions senario, if there is invalid INTC update item, but INTC package does exist, should delete it
 | 
						|
    //
 | 
						|
    DEBUG ((EFI_D_ERROR, "\n\nShould remove INTC item for this device(0x%x)\n\n", PciAddress));
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check INTD
 | 
						|
  //
 | 
						|
  if ((PciDeviceInfo->INTD[IsAPIC] != 0xFF) && (INTDPkgHandle != NULL)) {
 | 
						|
    //
 | 
						|
    // Find INTD package and there is valid INTD update item, update it
 | 
						|
    //
 | 
						|
    SdtUpdateINTxPkg (AcpiSdt, INTDPkgHandle, (PciDeviceInfo->INTD[IsAPIC]), IsAPIC);
 | 
						|
  } else if ((PciDeviceInfo->INTD[IsAPIC] != 0xFF) && (INTDPkgHandle == NULL)) {
 | 
						|
    //
 | 
						|
    // There is valid INTD update item, but no INTD package exist, should add it
 | 
						|
    //
 | 
						|
    DEBUG ((EFI_D_ERROR, "\n\nShould add INTD item for this device(0x%x)\n\n", PciAddress));
 | 
						|
 | 
						|
  }  else if ((PciDeviceInfo->INTD[IsAPIC] == 0xFF) && (INTDPkgHandle != NULL) && IsAllFunctions) {
 | 
						|
    //
 | 
						|
    // For all functions senario, if there is invalid INTD update item, but INTD package does exist, should delete it
 | 
						|
    //
 | 
						|
    DEBUG ((EFI_D_ERROR, "\n\nShould remove INTD item for this device(0x%x)\n\n", PciAddress));
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  if (INTAPkgHandle != NULL) {
 | 
						|
    Status = AcpiSdt->Close (INTAPkgHandle);
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
  }
 | 
						|
 | 
						|
  if (INTBPkgHandle != NULL) {
 | 
						|
    Status = AcpiSdt->Close (INTBPkgHandle);
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
  }
 | 
						|
 | 
						|
  if (INTCPkgHandle != NULL) {
 | 
						|
    Status = AcpiSdt->Close (INTCPkgHandle);
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
  }
 | 
						|
 | 
						|
  if (INTDPkgHandle != NULL) {
 | 
						|
    Status = AcpiSdt->Close (INTDPkgHandle);
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
  }
 | 
						|
 | 
						|
  return;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check every return package for update PRT
 | 
						|
 | 
						|
  @param AcpiSdt          Pointer to Acpi SDT protocol
 | 
						|
  @param ParentHandle     ACPI pci device handle
 | 
						|
  @param PciDeviceInfo    Pointer to PCI_DEVICE_INFO
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SdtCheckReturnPackage (
 | 
						|
  IN EFI_ACPI_SDT_PROTOCOL  *AcpiSdt,
 | 
						|
  IN EFI_ACPI_HANDLE        MethodHandle,
 | 
						|
  IN PCI_DEVICE_INFO        *PciDeviceInfo
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_ACPI_HANDLE    PreviousHandle;
 | 
						|
  EFI_ACPI_HANDLE    ReturnHandle;
 | 
						|
  EFI_ACPI_HANDLE    PackageHandle;
 | 
						|
  EFI_ACPI_HANDLE    NamePkgHandle;
 | 
						|
  EFI_STATUS         Status;
 | 
						|
  EFI_ACPI_DATA_TYPE DataType;
 | 
						|
  UINT8              *Data;
 | 
						|
  UINTN              DataSize;
 | 
						|
  CHAR8              NameStr[128];
 | 
						|
 | 
						|
  ReturnHandle = NULL;
 | 
						|
  while (TRUE) {
 | 
						|
    PreviousHandle = ReturnHandle;
 | 
						|
    Status = AcpiSdt->GetChild (MethodHandle, &ReturnHandle);
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
    if (PreviousHandle != NULL) {
 | 
						|
      Status = AcpiSdt->Close (PreviousHandle);
 | 
						|
      ASSERT_EFI_ERROR (Status);
 | 
						|
    }
 | 
						|
 | 
						|
    if (ReturnHandle == NULL) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = AcpiSdt->GetOption (ReturnHandle, 0, &DataType, (CONST VOID **)&Data, &DataSize);
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
    ASSERT (DataType == EFI_ACPI_DATA_TYPE_OPCODE);
 | 
						|
 | 
						|
    if (*Data == AML_RETURN_OP) {
 | 
						|
      //
 | 
						|
      // Find the return method handle, then look for the returned package data
 | 
						|
      //
 | 
						|
      Status = AcpiSdt->GetOption (ReturnHandle, 1, &DataType, (CONST VOID **)&Data, &DataSize);
 | 
						|
      ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
 | 
						|
      if (DataType == EFI_ACPI_DATA_TYPE_NAME_STRING) {
 | 
						|
        ZeroMem (NameStr, 128);
 | 
						|
        AsciiStrCpy (NameStr, "\\_SB.");
 | 
						|
        DataSize = SdtGetNameStringSize (Data);
 | 
						|
        AsciiStrnCat (NameStr, (CHAR8 *)Data, DataSize);
 | 
						|
 | 
						|
        NamePkgHandle = NULL;
 | 
						|
        Status = AcpiSdt->FindPath (mDsdtHandle, NameStr, &NamePkgHandle);
 | 
						|
        ASSERT_EFI_ERROR (Status);
 | 
						|
        ASSERT (NamePkgHandle != NULL);
 | 
						|
 | 
						|
        Status = AcpiSdt->GetOption (NamePkgHandle, 0, &DataType, (CONST VOID **)&Data, &DataSize);
 | 
						|
        ASSERT_EFI_ERROR (Status);
 | 
						|
        ASSERT (DataType == EFI_ACPI_DATA_TYPE_OPCODE);
 | 
						|
        ASSERT (*Data == AML_NAME_OP);
 | 
						|
 | 
						|
        Status = AcpiSdt->GetOption (NamePkgHandle, 2, &DataType, (CONST VOID **)&Data, &DataSize);
 | 
						|
        ASSERT_EFI_ERROR (Status);
 | 
						|
        ASSERT (DataType == EFI_ACPI_DATA_TYPE_CHILD);
 | 
						|
      }
 | 
						|
 | 
						|
      ASSERT (DataType == EFI_ACPI_DATA_TYPE_CHILD);
 | 
						|
 | 
						|
      //
 | 
						|
      // Get the parent package handle
 | 
						|
      //
 | 
						|
      PackageHandle = NULL;
 | 
						|
      Status = AcpiSdt->Open (Data, &PackageHandle);
 | 
						|
      ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
      //
 | 
						|
      // Check the parent package for update pci routing
 | 
						|
      //
 | 
						|
      SdtCheckParentPackage (AcpiSdt, PackageHandle, PciDeviceInfo);
 | 
						|
 | 
						|
      Status = AcpiSdt->Close (PackageHandle);
 | 
						|
      ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
      Status = AcpiSdt->Close (ReturnHandle);
 | 
						|
      ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Not ReturnOp, search it as parent
 | 
						|
    //
 | 
						|
    SdtCheckReturnPackage (AcpiSdt, ReturnHandle, PciDeviceInfo);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Done
 | 
						|
  //
 | 
						|
  return;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  update interrupt info inside the PRT method for the given pci device handle
 | 
						|
 | 
						|
  @param AcpiSdt       Pointer to Acpi SDT protocol
 | 
						|
  @param PciHandle     ACPI pci device handle
 | 
						|
  @param PciDeviceInfo Pointer to PCI_DEVICE_INFO
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
SdtUpdatePrtMethod (
 | 
						|
  IN EFI_ACPI_SDT_PROTOCOL  *AcpiSdt,
 | 
						|
  IN EFI_ACPI_HANDLE        PciHandle,
 | 
						|
  IN PCI_DEVICE_INFO        *PciDeviceInfo
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS         Status;
 | 
						|
  EFI_ACPI_HANDLE    PrtMethodHandle;
 | 
						|
 | 
						|
  //
 | 
						|
  // Find the PRT method under this pci device
 | 
						|
  //
 | 
						|
  PrtMethodHandle = NULL;
 | 
						|
  Status = AcpiSdt->FindPath (PciHandle, "_PRT", &PrtMethodHandle);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (PrtMethodHandle == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  SdtCheckReturnPackage(AcpiSdt, PrtMethodHandle, PciDeviceInfo);
 | 
						|
 | 
						|
  Status = AcpiSdt->Close (PrtMethodHandle);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Update the package inside name op with correct wakeup resources
 | 
						|
 | 
						|
  @param AcpiSdt          Pointer to Acpi SDT protocol
 | 
						|
  @param InPkgHandle      ACPI inside package handle
 | 
						|
  @param GPEPin           Correct gpe pin
 | 
						|
  @param SxNum            Correct system state the device can wake up from
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SdtUpdatePackageInName (
 | 
						|
  IN EFI_ACPI_SDT_PROTOCOL  *AcpiSdt,
 | 
						|
  IN EFI_ACPI_HANDLE        INTxPkgHandle,
 | 
						|
  IN UINT8                  GPEPin,
 | 
						|
  IN UINT8                  SxNum
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_ACPI_HANDLE    PreviousHandle;
 | 
						|
  EFI_STATUS         Status;
 | 
						|
  EFI_ACPI_HANDLE    MemberHandle;
 | 
						|
  EFI_ACPI_DATA_TYPE DataType;
 | 
						|
  UINT8              *Data;
 | 
						|
  UINTN              DataSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check the gpe pin
 | 
						|
  //
 | 
						|
  MemberHandle = NULL;
 | 
						|
  Status = AcpiSdt->GetChild (INTxPkgHandle, &MemberHandle);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  ASSERT (MemberHandle != NULL);
 | 
						|
 | 
						|
  Status = AcpiSdt->GetOption (MemberHandle, 0, &DataType, (CONST VOID **)&Data, &DataSize);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  ASSERT (DataType == EFI_ACPI_DATA_TYPE_OPCODE);
 | 
						|
 | 
						|
  //
 | 
						|
  // Skip byte prefix
 | 
						|
  //
 | 
						|
  Data += 1;
 | 
						|
 | 
						|
  if (*Data != GPEPin) {
 | 
						|
 | 
						|
    *Data = GPEPin;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check the sx number
 | 
						|
  //
 | 
						|
  PreviousHandle = MemberHandle;
 | 
						|
  Status = AcpiSdt->GetChild (INTxPkgHandle, &MemberHandle);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  ASSERT (MemberHandle != NULL);
 | 
						|
 | 
						|
  if (PreviousHandle != NULL) {
 | 
						|
    Status = AcpiSdt->Close (PreviousHandle);
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
  }
 | 
						|
 | 
						|
  Status = AcpiSdt->GetOption (MemberHandle, 0, &DataType, (CONST VOID **)&Data, &DataSize);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  ASSERT (DataType == EFI_ACPI_DATA_TYPE_OPCODE);
 | 
						|
 | 
						|
  //
 | 
						|
  // Skip byte prefix
 | 
						|
  //
 | 
						|
  Data += 1;
 | 
						|
 | 
						|
  if (*Data != SxNum) {
 | 
						|
 | 
						|
    *Data = SxNum;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = AcpiSdt->Close (MemberHandle);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check the name package belonged to PRW
 | 
						|
 | 
						|
  @param AcpiSdt          Pointer to Acpi SDT protocol
 | 
						|
  @param PrwPkgHandle     ACPI PRW package handle
 | 
						|
  @param PciDeviceInfo    Pointer to PCI_DEVICE_INFO
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SdtCheckNamePackage (
 | 
						|
  IN EFI_ACPI_SDT_PROTOCOL  *AcpiSdt,
 | 
						|
  IN EFI_ACPI_HANDLE        PrwPkgHandle,
 | 
						|
  IN PCI_DEVICE_INFO        *PciDeviceInfo
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_ACPI_HANDLE    InPkgHandle;
 | 
						|
  EFI_STATUS         Status;
 | 
						|
  EFI_ACPI_DATA_TYPE DataType;
 | 
						|
  UINT8              *Data;
 | 
						|
  UINTN              DataSize;
 | 
						|
 | 
						|
  Status = AcpiSdt->GetOption (PrwPkgHandle, 0, &DataType, (CONST VOID **)&Data, &DataSize);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  ASSERT (DataType == EFI_ACPI_DATA_TYPE_OPCODE);
 | 
						|
  ASSERT (*Data == AML_NAME_OP);
 | 
						|
 | 
						|
  Status = AcpiSdt->GetOption (PrwPkgHandle, 2, &DataType, (CONST VOID **)&Data, &DataSize);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  ASSERT (DataType == EFI_ACPI_DATA_TYPE_CHILD);
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the inside package handle
 | 
						|
  //
 | 
						|
  InPkgHandle = NULL;
 | 
						|
  Status = AcpiSdt->Open (Data, &InPkgHandle);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  //
 | 
						|
  // update the package in name op for wakeup info
 | 
						|
  //
 | 
						|
  if ((PciDeviceInfo->GPEPin != 0xFF) && (PciDeviceInfo->SxNum != 0xFF))
 | 
						|
    SdtUpdatePackageInName (AcpiSdt, InPkgHandle, PciDeviceInfo->GPEPin, PciDeviceInfo->SxNum);
 | 
						|
 | 
						|
  Status = AcpiSdt->Close (InPkgHandle);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  return;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  update wakeup info inside the PRW method for the given pci device handle
 | 
						|
 | 
						|
  @param AcpiSdt       Pointer to Acpi SDT protocol
 | 
						|
  @param PciHandle     ACPI pci device handle
 | 
						|
  @param PciDeviceInfo Pointer to PCI_DEVICE_INFO
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
SdtUpdatePrwPackage (
 | 
						|
  IN EFI_ACPI_SDT_PROTOCOL  *AcpiSdt,
 | 
						|
  IN EFI_ACPI_HANDLE        PciHandle,
 | 
						|
  IN PCI_DEVICE_INFO        *PciDeviceInfo
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS         Status;
 | 
						|
  EFI_ACPI_HANDLE    PrwPkgHandle;
 | 
						|
 | 
						|
  //
 | 
						|
  // Find the PRT method under this pci device
 | 
						|
  //
 | 
						|
  PrwPkgHandle = NULL;
 | 
						|
  Status = AcpiSdt->FindPath (PciHandle, "_PRW", &PrwPkgHandle);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (PrwPkgHandle == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  SdtCheckNamePackage(AcpiSdt, PrwPkgHandle, PciDeviceInfo);
 | 
						|
 | 
						|
  Status = AcpiSdt->Close (PrwPkgHandle);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  update pci routing information in acpi table based on pcd settings
 | 
						|
 | 
						|
  @param AcpiSdt          Pointer to Acpi SDT protocol
 | 
						|
  @param PciRootHandle       ACPI root bridge handle
 | 
						|
  @param PciDeviceInfo    Pointer to PCI_DEVICE_INFO
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
SdtUpdatePciRouting (
 | 
						|
  IN EFI_ACPI_SDT_PROTOCOL  *AcpiSdt,
 | 
						|
  IN EFI_ACPI_HANDLE        PciRootHandle,
 | 
						|
  IN PCI_DEVICE_INFO        *PciDeviceInfo
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS         Status;
 | 
						|
  EFI_ACPI_HANDLE    PciBridgeHandle;
 | 
						|
  UINT32             PciAddress;
 | 
						|
 | 
						|
 | 
						|
  PciBridgeHandle = NULL;
 | 
						|
  if (PciDeviceInfo->BridgeAddress == 0x00000000) {
 | 
						|
    //
 | 
						|
    // Its bridge is the host root bridge
 | 
						|
    //
 | 
						|
    PciBridgeHandle = PciRootHandle;
 | 
						|
 | 
						|
  } else {
 | 
						|
 | 
						|
    //
 | 
						|
    // Its bridge is just a pci device under the host bridge
 | 
						|
    //
 | 
						|
 | 
						|
    //
 | 
						|
    // Conver the bridge address into one that acpi table can recognize
 | 
						|
    //
 | 
						|
    PciAddress = SdtConvertToAcpiPciAdress (PciDeviceInfo->BridgeAddress);
 | 
						|
 | 
						|
    //
 | 
						|
    // Scan the whole table to find the pci device
 | 
						|
    //
 | 
						|
    PciBridgeHandle = SdtGetHandleByScanAllChilds(AcpiSdt, PciRootHandle, SdtFindPciDeviceHandle, &PciAddress);
 | 
						|
    if (PciBridgeHandle == NULL) {
 | 
						|
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Status = SdtUpdatePrtMethod(AcpiSdt, PciBridgeHandle, PciDeviceInfo);
 | 
						|
 | 
						|
  if (PciDeviceInfo->BridgeAddress != 0x00000000) {
 | 
						|
    Status = AcpiSdt->Close (PciBridgeHandle);
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  update power resource wake up information in acpi table based on pcd settings
 | 
						|
 | 
						|
  @param AcpiSdt          Pointer to Acpi SDT protocol
 | 
						|
  @param PciRootHandle    ACPI root bridge handle
 | 
						|
  @param PciDeviceInfo    Pointer to PCI_DEVICE_INFO
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
SdtUpdatePowerWake (
 | 
						|
  IN EFI_ACPI_SDT_PROTOCOL  *AcpiSdt,
 | 
						|
  IN EFI_ACPI_HANDLE        PciRootHandle,
 | 
						|
  IN PCI_DEVICE_INFO        *PciDeviceInfo
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS         Status;
 | 
						|
  EFI_ACPI_HANDLE    PciBridgeHandle;
 | 
						|
  EFI_ACPI_HANDLE    PciDeviceHandle;
 | 
						|
  UINT32             PciAddress;
 | 
						|
 | 
						|
  PciBridgeHandle = NULL;
 | 
						|
  if (PciDeviceInfo->BridgeAddress == 0x00000000) {
 | 
						|
    //
 | 
						|
    // Its bridge is the host root bridge
 | 
						|
    //
 | 
						|
    PciBridgeHandle = PciRootHandle;
 | 
						|
 | 
						|
  } else {
 | 
						|
 | 
						|
    //
 | 
						|
    // Its bridge is just a pci device under the host bridge
 | 
						|
    //
 | 
						|
 | 
						|
    //
 | 
						|
    // Conver the bridge address into one that acpi table can recognize
 | 
						|
    //
 | 
						|
    PciAddress = SdtConvertToAcpiPciAdress (PciDeviceInfo->BridgeAddress);
 | 
						|
 | 
						|
    //
 | 
						|
    // Scan the whole table to find the pci device
 | 
						|
    //
 | 
						|
    PciBridgeHandle = SdtGetHandleByScanAllChilds(AcpiSdt, PciRootHandle, SdtFindPciDeviceHandle, &PciAddress);
 | 
						|
 | 
						|
    if (PciBridgeHandle == NULL) {
 | 
						|
 | 
						|
      Status = AcpiSdt->Close (PciRootHandle);
 | 
						|
      ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  PciDeviceHandle = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Conver the device address into one that acpi table can recognize
 | 
						|
  //
 | 
						|
  PciAddress = SdtConvertToAcpiPciAdress (PciDeviceInfo->DeviceAddress);
 | 
						|
 | 
						|
  //
 | 
						|
  // Scan the whole table to find the pci device
 | 
						|
  //
 | 
						|
  PciDeviceHandle = SdtGetHandleByScanAllChilds(AcpiSdt, PciBridgeHandle, SdtFindPciDeviceHandle, &PciAddress);
 | 
						|
 | 
						|
  if (PciDeviceHandle == NULL) {
 | 
						|
    if (PciDeviceInfo->BridgeAddress != 0x00000000) {
 | 
						|
      Status = AcpiSdt->Close (PciBridgeHandle);
 | 
						|
      ASSERT_EFI_ERROR (Status);
 | 
						|
    }
 | 
						|
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = SdtUpdatePrwPackage(AcpiSdt, PciDeviceHandle, PciDeviceInfo);
 | 
						|
 | 
						|
  Status = AcpiSdt->Close (PciDeviceHandle);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  if (PciDeviceInfo->BridgeAddress != 0x00000000) {
 | 
						|
    Status = AcpiSdt->Close (PciBridgeHandle);
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Get the root bridge handle by scanning the acpi table
 | 
						|
 | 
						|
  @param AcpiSdt          Pointer to Acpi SDT protocol
 | 
						|
  @param DsdtHandle       ACPI root handle
 | 
						|
 | 
						|
  @retval EFI_ACPI_HANDLE the handle of the root bridge
 | 
						|
**/
 | 
						|
EFI_ACPI_HANDLE
 | 
						|
SdtGetRootBridgeHandle (
 | 
						|
  IN EFI_ACPI_SDT_PROTOCOL  *AcpiSdt,
 | 
						|
  IN EFI_ACPI_HANDLE        DsdtHandle
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_ACPI_HANDLE    PciRootHandle;
 | 
						|
 | 
						|
  //
 | 
						|
  // Scan the whole table to find the root bridge
 | 
						|
  //
 | 
						|
  PciRootHandle = NULL;
 | 
						|
  PciRootHandle = SdtGetHandleByScanAllChilds(AcpiSdt, DsdtHandle, SdtFindRootBridgeHandle, NULL);
 | 
						|
  ASSERT (PciRootHandle != NULL);
 | 
						|
 | 
						|
  return PciRootHandle;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Check input Pci device info is changed from the default values
 | 
						|
  @param PciDeviceInfo    Pointer to PCI_DEVICE_INFO
 | 
						|
  @param UpdatePRT        Pointer to BOOLEAN
 | 
						|
  @param UpdatePRW        Pointer to BOOLEAN
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SdtCheckPciDeviceInfoChanged (
 | 
						|
  IN PCI_DEVICE_INFO        *PciDeviceInfo,
 | 
						|
  IN BOOLEAN                *UpdatePRT,
 | 
						|
  IN BOOLEAN                *UpdatePRW
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN Index = 0;
 | 
						|
 | 
						|
  if (mQNCPciInfo == NULL) {
 | 
						|
    *UpdatePRT = FALSE;
 | 
						|
    *UpdatePRW = FALSE;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  *UpdatePRT = TRUE;
 | 
						|
  *UpdatePRW = TRUE;
 | 
						|
 | 
						|
  for (Index = 0;Index < CURRENT_PCI_DEVICE_NUM; Index++) {
 | 
						|
    if ((mQNCPciInfo[Index].BridgeAddress == PciDeviceInfo->BridgeAddress)
 | 
						|
      && (mQNCPciInfo[Index].DeviceAddress == PciDeviceInfo->DeviceAddress)) {
 | 
						|
      //
 | 
						|
      // Find one matched entry
 | 
						|
      //
 | 
						|
      if (CompareMem (&(mQNCPciInfo[Index].INTA[0]), &PciDeviceInfo->INTA[0], 10) == 0) {
 | 
						|
        *UpdatePRT = FALSE;
 | 
						|
        *UpdatePRW = FALSE;
 | 
						|
        //DEBUG ((EFI_D_ERROR, "Find one matched entry[%d] and no change\n", Index));
 | 
						|
      } else {
 | 
						|
        if (CompareMem (&(mQNCPciInfo[Index].INTA[0]), &PciDeviceInfo->INTA[0], 8) == 0)
 | 
						|
          *UpdatePRT = FALSE;
 | 
						|
 | 
						|
        if (CompareMem (&(mQNCPciInfo[Index].GPEPin), &PciDeviceInfo->GPEPin, 2) == 0)
 | 
						|
          *UpdatePRW = FALSE;
 | 
						|
 | 
						|
        if (*(UINT64 *)(&PciDeviceInfo->INTA[0]) == 0xFFFFFFFFFFFFFFFFULL)
 | 
						|
          *UpdatePRT = FALSE;
 | 
						|
 | 
						|
        if (*(UINT16 *)(&PciDeviceInfo->GPEPin) == 0xFFFF)
 | 
						|
          *UpdatePRW = FALSE;
 | 
						|
 | 
						|
        //DEBUG ((EFI_D_ERROR, "Find one matched entry[%d] and but need update PRT:0x%x PRW:0x%x\n", Index, *UpdatePRT, *UpdatePRW));
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //if (Index == 42) {
 | 
						|
  //  DEBUG ((EFI_D_ERROR, "Find No matched entry\n"));
 | 
						|
  //}
 | 
						|
 | 
						|
  return;
 | 
						|
}
 |