/** @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; | |
} |