audk/QuarkPlatformPkg/Acpi/Dxe/AcpiPlatform/AcpiPciUpdate.c

1403 lines
36 KiB
C

/** @file
Update the _PRT and _PRW method for pci devices
Copyright (c) 2013-2016 Intel Corporation.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#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;
}