|
@@ -0,0 +1,1402 @@
|
|
|
+/** @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;
|
|
|
+}
|