blob: 28d7016008bbcbc081a9ff716942ef38b94b7d56 [file] [log] [blame]
/** @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;
}