659 lines
26 KiB
C
659 lines
26 KiB
C
/** @file
|
|
This SMM driver will handle SA relevant late initialization
|
|
|
|
@copyright
|
|
INTEL CONFIDENTIAL
|
|
Copyright 2012 - 2021 Intel Corporation.
|
|
|
|
The source code contained or described herein and all documents related to the
|
|
source code ("Material") are owned by Intel Corporation or its suppliers or
|
|
licensors. Title to the Material remains with Intel Corporation or its suppliers
|
|
and licensors. The Material may contain trade secrets and proprietary and
|
|
confidential information of Intel Corporation and its suppliers and licensors,
|
|
and is protected by worldwide copyright and trade secret laws and treaty
|
|
provisions. No part of the Material may be used, copied, reproduced, modified,
|
|
published, uploaded, posted, transmitted, distributed, or disclosed in any way
|
|
without Intel's prior express written permission.
|
|
|
|
No license under any patent, copyright, trade secret or other intellectual
|
|
property right is granted to or conferred upon you by disclosure or delivery
|
|
of the Materials, either expressly, by implication, inducement, estoppel or
|
|
otherwise. Any license under such intellectual property rights must be
|
|
express and approved by Intel in writing.
|
|
|
|
Unless otherwise agreed by Intel in writing, you may not remove or alter
|
|
this notice or any other notice embedded in Materials by Intel or
|
|
Intel's suppliers or licensors in any way.
|
|
|
|
This file contains an 'Intel Peripheral Driver' and is uniquely identified as
|
|
"Intel Reference Module" and is licensed for Intel CPUs and chipsets under
|
|
the terms of your license agreement with Intel or your vendor. This file may
|
|
be modified by the user, subject to additional terms of the license agreement.
|
|
|
|
@par Specification Reference:
|
|
**/
|
|
#include <Library/BaseLib.h>
|
|
#include <Base.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/DxeServicesTableLib.h>
|
|
#include <Library/SmmServicesTableLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/PcdLib.h>
|
|
#include <Library/IoLib.h>
|
|
#include <Library/HobLib.h>
|
|
#include <Library/SaPlatformLib.h>
|
|
#include <Protocol/SmmIoTrapDispatch2.h>
|
|
#include "SaLateInitSmm.h"
|
|
#include <CpuRegs.h>
|
|
#include <Library/PciSegmentLib.h>
|
|
#include <CpuDataStruct.h>
|
|
#include <CpuPcieHob.h>
|
|
#include <CpuPcieHobGen3.h>
|
|
#include <Protocol/SaIotrapSmi.h>
|
|
#include <PchPcieRpConfig.h>
|
|
#include <Library/GraphicsInfoFruLib.h>
|
|
#include <SaConfigHob.h>
|
|
#include "CpuPcieInfo.h"
|
|
#include <Register/CpuPcieRegs.h>
|
|
#include <Library/CpuPlatformLib.h>
|
|
#include <IndustryStandard/Pci30.h>
|
|
#include <Register/IgdRegs.h>
|
|
#include <Register/SaPcieDmiRegs.h>
|
|
#include <Register/CommonMsr.h>
|
|
#include <Library/CpuPcieRpLib.h>
|
|
|
|
typedef enum {
|
|
EnumSaSmiCallbackForMaxPayLoad,
|
|
EnumSaSmiCallbackForSaSaveRestore,
|
|
EnumSaSmiCallbackForLateInit,
|
|
EnumSaSmiCallbackForS3resume,
|
|
EnumSaSmiCallbackMax
|
|
} SMI_OPERATION;
|
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mSaSmiCallbackPhase = EnumSaSmiCallbackForMaxPayLoad;
|
|
GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *mPchIoTrap;
|
|
GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_SX_DISPATCH2_PROTOCOL *mSxDispatch;
|
|
|
|
|
|
typedef struct {
|
|
UINT64 BaseAddr;
|
|
UINT32 Offset;
|
|
UINT32 AndMask;
|
|
UINT32 OrMask;
|
|
} BOOT_SCRIPT_REGISTER_SETTING;
|
|
|
|
typedef union {
|
|
struct {
|
|
UINT32 Low;
|
|
UINT32 High;
|
|
} Data32;
|
|
UINT64 Data;
|
|
} UINT64_STRUCT;
|
|
|
|
///
|
|
/// SA PCI Registers to save for S3 resume
|
|
///
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSaChipsetPciRegistersTable[] = {
|
|
R_SA_DEVEN,
|
|
};
|
|
//
|
|
// Address values for mSaChipsetPciRegistersSaveTable will be initialized at Runtime inside function
|
|
// CpuPcieInitPolicy(). The Address uses the Register Offset from table mSaChipsetPciRegistersTable
|
|
//
|
|
GLOBAL_REMOVE_IF_UNREFERENCED BOOT_SCRIPT_PCI_REGISTER_SAVE mSaChipsetPciRegistersSaveTable[] = {
|
|
{0, S3BootScriptWidthUint32, 0}, // R_SA_DEVEN
|
|
};
|
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mDeviceCapMmBaseSave [CPU_PCIE_MAX_ROOT_PORTS][MAX_SUPPORTED_DEVICE_NUMBER];
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mDeviceExtCapLtrOffsetSave [CPU_PCIE_MAX_ROOT_PORTS][MAX_SUPPORTED_DEVICE_NUMBER];
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mDeviceExtCapVcOffsetSave [CPU_PCIE_MAX_ROOT_PORTS][MAX_SUPPORTED_DEVICE_NUMBER];
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mDeviceBusNumberSave [CPU_PCIE_MAX_ROOT_PORTS][MAX_SUPPORTED_DEVICE_NUMBER];
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mDeviceAspmSave [CPU_PCIE_MAX_ROOT_PORTS][MAX_SUPPORTED_DEVICE_NUMBER];
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mDeviceLtrObffSave [CPU_PCIE_MAX_ROOT_PORTS][MAX_SUPPORTED_DEVICE_NUMBER];
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mDeviceMaxSnoopLatencySave [CPU_PCIE_MAX_ROOT_PORTS][MAX_SUPPORTED_DEVICE_NUMBER];
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mDeviceMaxNoSnoopLatencySave [CPU_PCIE_MAX_ROOT_PORTS][MAX_SUPPORTED_DEVICE_NUMBER];
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mDeviceTcxVc0MappingSave [CPU_PCIE_MAX_ROOT_PORTS][MAX_SUPPORTED_DEVICE_NUMBER];
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mCommonClock [CPU_PCIE_MAX_ROOT_PORTS] = {0, 0, 0};
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mDeviceControlRegisterSave [CPU_PCIE_MAX_ROOT_PORTS][MAX_SUPPORTED_DEVICE_NUMBER];
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mNumberOfDeviceFound [CPU_PCIE_MAX_ROOT_PORTS] = {0, 0, 0};
|
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mPAMSave [MAX_PAM_REG_COUNT];
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSaChipsetPciRegistersSave [sizeof (mSaChipsetPciRegistersSaveTable) / sizeof (BOOT_SCRIPT_PCI_REGISTER_SAVE)];
|
|
|
|
///
|
|
/// Store required policy setting in global variables.
|
|
///
|
|
GLOBAL_REMOVE_IF_UNREFERENCED CPU_PCIE_ASPM_CONFIG mPegAspmPerPort[CPU_PCIE_MAX_ROOT_PORTS];
|
|
GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mCridEnable;
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mSnoopLatencyOvrValue;
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mNonSnoopLatencyOvrValue;
|
|
GLOBAL_REMOVE_IF_UNREFERENCED CPU_PCIE_PWR_OPT mPegPwrOpt[SA_PEG_MAX_FUN];
|
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mMaxBusNumberSupported;
|
|
GLOBAL_REMOVE_IF_UNREFERENCED EFI_STATUS mEnumStatus;
|
|
|
|
/**
|
|
This function programs the LTR Override values
|
|
**/
|
|
VOID
|
|
PcieILtrOverride (
|
|
VOID
|
|
)
|
|
{
|
|
UINT64_STRUCT MchBar;
|
|
UINT32 Data32And;
|
|
UINT32 Data32Or;
|
|
MchBar.Data32.High = PciSegmentRead32 (PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, SA_MC_BUS, 0, 0, R_SA_MCHBAR + 4));
|
|
MchBar.Data32.Low = PciSegmentRead32 (PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, SA_MC_BUS, 0, 0, R_SA_MCHBAR));
|
|
MchBar.Data &= (UINT64) ~BIT0;
|
|
Data32And = 0x0;
|
|
|
|
///
|
|
/// Configure Snoop Latency value
|
|
///
|
|
if (mSnoopLatencyOvrValue != 0) {
|
|
mSnoopLatencyOvrValue |= BIT14;
|
|
}
|
|
Data32Or = ((UINT32) (mSnoopLatencyOvrValue << 16));
|
|
|
|
|
|
///
|
|
/// Configure Non-Snoop Latency value
|
|
///
|
|
if (mNonSnoopLatencyOvrValue != 0) {
|
|
mNonSnoopLatencyOvrValue |= BIT14;
|
|
}
|
|
Data32Or |= (UINT32) mNonSnoopLatencyOvrValue;
|
|
|
|
///
|
|
/// Program ILTR_OVRD with latency values
|
|
///
|
|
MmioAndThenOr32 (MchBar.Data + R_SA_MCHBAR_ILTR_OVRD_OFFSET, Data32And, Data32Or);
|
|
S3BootScriptSaveMemReadWrite (
|
|
S3BootScriptWidthUint32,
|
|
(UINTN) (MchBar.Data + R_SA_MCHBAR_ILTR_OVRD_OFFSET),
|
|
&Data32Or, /// Data to be ORed
|
|
&Data32And /// Data to be ANDed
|
|
);
|
|
}
|
|
|
|
/**
|
|
This function apply additional settings before ASPM enabling
|
|
|
|
@param[in] RootBridgeIndex - Root Bridge Index to select mDeviceCapMmBaseSave array elements for ASPM capability calculation.
|
|
**/
|
|
VOID
|
|
PcieAdditionalSettingBeforeASPM (
|
|
IN UINT8 RootBridgeIndex
|
|
)
|
|
{
|
|
UINT32 Data32Or;
|
|
UINT32 Data32And;
|
|
|
|
if ((mPegAspmPerPort[RootBridgeIndex] != PcieAspmDisabled) && (mCommonClock [RootBridgeIndex] == 1)) {
|
|
///
|
|
/// Enable support for L0s and L1 by programming the `Active State Link
|
|
/// PM Support' field of the LCAP register at D.F.R 0ACh [11:10] = `11b'.
|
|
///
|
|
PciSegmentOr32 ((mDeviceCapMmBaseSave[RootBridgeIndex][0] & (UINTN) ~0xFF) + 0x0AC, BIT11 | BIT10);
|
|
Data32Or = (BIT11 | BIT10);
|
|
Data32And = (UINT32) ~(BIT11 | BIT10);
|
|
S3BootScriptSaveMemReadWrite (
|
|
S3BootScriptWidthUint32,
|
|
PcdGet64 (PcdSiPciExpressBaseAddress) + (mDeviceCapMmBaseSave [RootBridgeIndex][0] & (UINT64) ~0xFF) + 0x0AC,
|
|
&Data32Or, ///< Data to be ORed
|
|
&Data32And ///< Data to be ANDed
|
|
);
|
|
|
|
///
|
|
/// Set D.F.R 0200h [27:26] to `00b'.
|
|
///
|
|
PciSegmentAnd32 ((mDeviceCapMmBaseSave[RootBridgeIndex][0] & (UINTN) ~0xFF) + 0x200, (UINT32) ~(BIT27 | BIT26));
|
|
Data32Or = 0;
|
|
Data32And = (UINT32) ~(BIT27 | BIT26);
|
|
S3BootScriptSaveMemReadWrite (
|
|
S3BootScriptWidthUint32,
|
|
PcdGet64 (PcdSiPciExpressBaseAddress) + (mDeviceCapMmBaseSave [RootBridgeIndex][0] & (UINT64) ~0xFFu) + 0x200,
|
|
&Data32Or, ///< Data to be ORed
|
|
&Data32And ///< Data to be ANDed
|
|
);
|
|
|
|
///
|
|
/// Set D.F.R 0258 [2] to '1b' for PCI Express 2.0 compliance
|
|
/// Note: Other fields within this register must not be changed
|
|
/// while writing to D1.F0.R 0258h [2]
|
|
///
|
|
PciSegmentOr16 ((mDeviceCapMmBaseSave [RootBridgeIndex][0] & (UINT64) ~0xFF) + R_SA_PEG_CFG4_OFFSET, BIT2);
|
|
Data32Or = BIT2;
|
|
Data32And = (UINT32) ~(BIT2);
|
|
S3BootScriptSaveMemReadWrite (
|
|
S3BootScriptWidthUint32,
|
|
PcdGet64 (PcdSiPciExpressBaseAddress) + (mDeviceCapMmBaseSave [RootBridgeIndex][0] & (UINT64) ~0xFF) + R_SA_PEG_CFG4_OFFSET,
|
|
&Data32Or, ///< Data to be ORed
|
|
&Data32And ///< Data to be ANDed
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
This function saves/restores Chipset registers
|
|
|
|
@param[in] IsSaving - TRUE for saving and FALSE for restoring
|
|
@param[in] PciRegistersSaveTable[] - The register table that has to be saved/restored
|
|
@param[in] PciRegistersSaveTableSize - Size of above table
|
|
@param[in] PciRegistersSaveBuffer - A saving/restoring buffer for those register settings.
|
|
**/
|
|
VOID
|
|
SaSaveRestoreChipset (
|
|
IN BOOLEAN IsSaving,
|
|
IN BOOT_SCRIPT_PCI_REGISTER_SAVE PciRegistersSaveTable[],
|
|
IN UINTN PciRegistersSaveTableSize,
|
|
IN OUT UINTN *PciRegistersSaveBuffer
|
|
)
|
|
{
|
|
UINT8 Index;
|
|
|
|
if (IsSaving == TRUE) {
|
|
DEBUG ((DEBUG_INFO, "SA Save PCI register settings\n"));
|
|
///
|
|
/// Save SA PCI Registers for S3 resume
|
|
///
|
|
for (Index = 0; Index < PciRegistersSaveTableSize; Index++) {
|
|
PciRegistersSaveBuffer[Index] = PciSegmentRead32 (PciRegistersSaveTable[Index].Address);
|
|
S3BootScriptSaveMemWrite (
|
|
S3BootScriptWidthUint32,
|
|
PcdGet64 (PcdSiPciExpressBaseAddress) + PciRegistersSaveTable[Index].Address,
|
|
1,
|
|
&PciRegistersSaveBuffer[Index]
|
|
);
|
|
DEBUG ((DEBUG_INFO, "SA Register = %X, SaPciRegSave = %08X\n", PciRegistersSaveTable[Index].Address, PciRegistersSaveBuffer[Index]));
|
|
}
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "SA Restore PCI register settings\n"));
|
|
///
|
|
/// Restore SA PCI Registers for S3 resume
|
|
///
|
|
for (Index = 0; Index < PciRegistersSaveTableSize; Index++) {
|
|
PciSegmentWrite32 (PciRegistersSaveTable[Index].Address, (UINT32) PciRegistersSaveBuffer[Index]);
|
|
DEBUG ((DEBUG_INFO, "SA Register = %X, SaPciRegSave = %08X\n", PciRegistersSaveTable[Index].Address, PciRegistersSaveBuffer[Index]));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
This function saves/restores platform relative registers
|
|
|
|
@param[in] IsSaving - TRUE for saving and FALSE for restoring
|
|
**/
|
|
VOID
|
|
SaSaveRestorePlatform (
|
|
IN BOOLEAN IsSaving
|
|
)
|
|
{
|
|
UINTN McBaseAddress;
|
|
UINT8 Index;
|
|
|
|
McBaseAddress = PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, SA_MC_BUS, SA_MC_DEV, SA_MC_FUN, 0);
|
|
if (IsSaving == TRUE) {
|
|
DEBUG ((DEBUG_INFO, "SA Save platform register settings\n"));
|
|
///
|
|
/// Save PAM register
|
|
///
|
|
for (Index = 0; Index < MAX_PAM_REG_COUNT; Index++) {
|
|
mPAMSave[Index] = PciSegmentRead8 (McBaseAddress + (PAM_REG_BASE + Index));
|
|
S3BootScriptSaveMemWrite (
|
|
S3BootScriptWidthUint8,
|
|
PcdGet64 (PcdSiPciExpressBaseAddress) + McBaseAddress + (PAM_REG_BASE + Index),
|
|
1,
|
|
&mPAMSave[Index]
|
|
);
|
|
}
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "SA Restore platform register settings\n"));
|
|
///
|
|
/// Restore PAM register
|
|
///
|
|
for (Index = 0; Index < MAX_PAM_REG_COUNT; Index++) {
|
|
PciSegmentWrite8 (McBaseAddress + (PAM_REG_BASE + Index), mPAMSave [Index]);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
This function handles SA S3 resume
|
|
**/
|
|
VOID
|
|
SaS3Resume (
|
|
VOID
|
|
)
|
|
{
|
|
UINT8 PegComplete;
|
|
UINT8 EndpointCompleted;
|
|
UINT32 PegBaseAddress;
|
|
|
|
DEBUG ((DEBUG_INFO, "SA S3 resume\n"));
|
|
if (mEnumStatus == EFI_SUCCESS) {
|
|
///
|
|
/// Restore Bus number assignment first
|
|
///
|
|
for (PegComplete = 0; PegComplete < CPU_PCIE_MAX_ROOT_PORTS; PegComplete++) {
|
|
if (mDeviceCapMmBaseSave [PegComplete][0] == 0) {
|
|
continue;
|
|
}
|
|
EndpointCompleted = 0;
|
|
while (EndpointCompleted < mNumberOfDeviceFound [PegComplete]) {
|
|
PegBaseAddress = (mDeviceCapMmBaseSave [PegComplete][EndpointCompleted] & (UINTN) ~0xFF);
|
|
PciSegmentWrite32 (PegBaseAddress + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, mDeviceBusNumberSave [PegComplete][EndpointCompleted]);
|
|
DEBUG ((DEBUG_INFO, " Restore Bus number [%X] = %08X\n", PegBaseAddress + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, PciSegmentRead32 (PegBaseAddress + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET)));
|
|
EndpointCompleted ++;
|
|
}
|
|
}
|
|
for (PegComplete = 0; PegComplete < CPU_PCIE_MAX_ROOT_PORTS; PegComplete++) {
|
|
if (mDeviceCapMmBaseSave [PegComplete][0] == 0) {
|
|
continue;
|
|
}
|
|
PcieAdditionalSettingBeforeASPM (PegComplete);
|
|
EndpointCompleted = 0;
|
|
while (EndpointCompleted < mNumberOfDeviceFound [PegComplete]) {
|
|
PegBaseAddress = (mDeviceCapMmBaseSave [PegComplete][EndpointCompleted] & (UINTN) ~0xFF);
|
|
///
|
|
/// Restore Max Pay Load and Extended Tag
|
|
///
|
|
PciSegmentWrite16 (mDeviceCapMmBaseSave [PegComplete][EndpointCompleted] + 0x8, mDeviceControlRegisterSave [PegComplete][EndpointCompleted]);
|
|
DEBUG ((DEBUG_INFO, "[B%X|D%X|F%X|R%X] DCTL=%X\n",
|
|
(mDeviceCapMmBaseSave [PegComplete][EndpointCompleted] >> 20) & mMaxBusNumberSupported,
|
|
(mDeviceCapMmBaseSave [PegComplete][EndpointCompleted] >> 15) & 0x1F,
|
|
(mDeviceCapMmBaseSave [PegComplete][EndpointCompleted] >> 12) & 0x07,
|
|
(mDeviceCapMmBaseSave [PegComplete][EndpointCompleted] + 0x08) & 0xFFF,
|
|
mDeviceControlRegisterSave [PegComplete][EndpointCompleted]));
|
|
///
|
|
/// Restore ASPM and Common Clock
|
|
///
|
|
PciSegmentWrite8 ((mDeviceCapMmBaseSave [PegComplete][EndpointCompleted] + 0x010), mDeviceAspmSave [PegComplete][EndpointCompleted]);
|
|
DEBUG ((DEBUG_INFO, "[B%X|D%X|F%X|R%X] ASPM/CommonClock=%X\n",
|
|
(mDeviceCapMmBaseSave [PegComplete][EndpointCompleted] >> 20) & mMaxBusNumberSupported,
|
|
(mDeviceCapMmBaseSave [PegComplete][EndpointCompleted] >> 15) & 0x1F,
|
|
(mDeviceCapMmBaseSave [PegComplete][EndpointCompleted] >> 12) & 0x07,
|
|
(mDeviceCapMmBaseSave [PegComplete][EndpointCompleted] + 0x10) & 0xFFF,
|
|
mDeviceAspmSave [PegComplete][EndpointCompleted]));
|
|
///
|
|
/// Restore PEG power optimization.
|
|
///
|
|
PciSegmentAndThenOr16 (mDeviceCapMmBaseSave [PegComplete][EndpointCompleted] + 0x28, (UINT16) ~(BIT10 + BIT13 + BIT14), mDeviceLtrObffSave [PegComplete][EndpointCompleted]);
|
|
DEBUG ((DEBUG_INFO, "[B%X|D%X|F%X|R%X] LTR/OBFF=%X\n",
|
|
(mDeviceCapMmBaseSave [PegComplete][EndpointCompleted] >> 20) & mMaxBusNumberSupported,
|
|
(mDeviceCapMmBaseSave [PegComplete][EndpointCompleted] >> 15) & 0x1F,
|
|
(mDeviceCapMmBaseSave [PegComplete][EndpointCompleted] >> 12) & 0x07,
|
|
(mDeviceCapMmBaseSave [PegComplete][EndpointCompleted] + 0x28) & 0xFFF,
|
|
mDeviceLtrObffSave [PegComplete][EndpointCompleted]));
|
|
|
|
if (mDeviceExtCapLtrOffsetSave [PegComplete][EndpointCompleted] != 0) {
|
|
PciSegmentAndThenOr16 (PegBaseAddress + mDeviceExtCapLtrOffsetSave [PegComplete][EndpointCompleted] + 0x4, (UINT16) (~0x1FFF), mDeviceMaxSnoopLatencySave [PegComplete][EndpointCompleted]);
|
|
DEBUG ((DEBUG_INFO, "[B%X|D%X|F%X|R%X] Max snoop latency=%X\n",
|
|
((PegBaseAddress + mDeviceExtCapLtrOffsetSave [PegComplete][EndpointCompleted]) >> 20) & mMaxBusNumberSupported,
|
|
((PegBaseAddress + mDeviceExtCapLtrOffsetSave [PegComplete][EndpointCompleted]) >> 15) & 0x1F,
|
|
((PegBaseAddress + mDeviceExtCapLtrOffsetSave [PegComplete][EndpointCompleted]) >> 12) & 0x07,
|
|
(PegBaseAddress + mDeviceExtCapLtrOffsetSave [PegComplete][EndpointCompleted] + 0x4) & 0xFFF,
|
|
mDeviceMaxSnoopLatencySave [PegComplete][EndpointCompleted]));
|
|
|
|
PciSegmentAndThenOr16 ((PegBaseAddress + mDeviceExtCapLtrOffsetSave [PegComplete][EndpointCompleted] + 0x6), (UINT16) (~0x1FFF), mDeviceMaxNoSnoopLatencySave [PegComplete][EndpointCompleted]);
|
|
DEBUG ((DEBUG_INFO, "[B%X|D%X|F%X|R%X] Max No-snoop latency=%X\n",
|
|
((PegBaseAddress + mDeviceExtCapLtrOffsetSave [PegComplete][EndpointCompleted]) >> 20) & mMaxBusNumberSupported,
|
|
((PegBaseAddress + mDeviceExtCapLtrOffsetSave [PegComplete][EndpointCompleted]) >> 15) & 0x1F,
|
|
((PegBaseAddress + mDeviceExtCapLtrOffsetSave [PegComplete][EndpointCompleted]) >> 12) & 0x07,
|
|
(PegBaseAddress + mDeviceExtCapLtrOffsetSave [PegComplete][EndpointCompleted] + 0x6) & 0xFFF,
|
|
mDeviceMaxNoSnoopLatencySave [PegComplete][EndpointCompleted]));
|
|
}
|
|
if (mDeviceExtCapVcOffsetSave [PegComplete][EndpointCompleted]) {
|
|
PciSegmentAndThenOr8 ((mDeviceExtCapVcOffsetSave [PegComplete][EndpointCompleted] + 0x14), 0, mDeviceTcxVc0MappingSave [PegComplete][EndpointCompleted]);
|
|
DEBUG ((DEBUG_INFO, "[B%X|D%X|F%X|R%X] TCx/VC0 mapping=%X\n",
|
|
((PegBaseAddress + mDeviceExtCapLtrOffsetSave [PegComplete][EndpointCompleted]) >> 20) & mMaxBusNumberSupported,
|
|
((PegBaseAddress + mDeviceExtCapLtrOffsetSave [PegComplete][EndpointCompleted]) >> 15) & 0x1F,
|
|
((PegBaseAddress + mDeviceExtCapLtrOffsetSave [PegComplete][EndpointCompleted]) >> 12) & 0x07,
|
|
(PegBaseAddress + mDeviceExtCapLtrOffsetSave [PegComplete][EndpointCompleted] + 0x14) & 0xFFF,
|
|
mDeviceTcxVc0MappingSave [PegComplete][EndpointCompleted]));
|
|
}
|
|
EndpointCompleted ++;
|
|
}
|
|
///
|
|
/// If common clock supported on root port and endpoint, retrain link
|
|
///
|
|
if (mCommonClock [PegComplete] == 1) {
|
|
DEBUG ((DEBUG_INFO, "Retrain Link for Common Clock\n"));
|
|
///
|
|
/// Retrain the Link per PCI Express Specification.
|
|
///
|
|
PciSegmentOr8 (mDeviceCapMmBaseSave [PegComplete][0] + 0x010, BIT5);
|
|
|
|
///
|
|
/// Wait until Re-Training has completed.
|
|
///
|
|
while ((PciSegmentRead16 (mDeviceCapMmBaseSave [PegComplete][0] + 0x012) & BIT11) != 0) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
///
|
|
/// Re-do this during S3 resume
|
|
///
|
|
PcieILtrOverride ();
|
|
}
|
|
|
|
/**
|
|
Wrapper function for all SA S3 resume tasks which can be a callback function.
|
|
**/
|
|
VOID
|
|
SaS3ResumeCallback (
|
|
VOID
|
|
)
|
|
{
|
|
SaS3Resume ();
|
|
SaSaveRestoreChipset (FALSE, mSaChipsetPciRegistersSaveTable, sizeof (mSaChipsetPciRegistersSaveTable) / sizeof (BOOT_SCRIPT_PCI_REGISTER_SAVE), mSaChipsetPciRegistersSave);
|
|
SaSaveRestorePlatform (FALSE);
|
|
}
|
|
|
|
/**
|
|
A SMI callback to do SA relevant late initialization
|
|
|
|
@param[in] DispatchHandle - The handle of this callback, obtained when registering
|
|
@param[in] DispatchContext - Pointer to the EFI_SMM_IO_TRAP_DISPATCH_CALLBACK_CONTEXT
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
SaIoTrapSmiCallback (
|
|
IN EFI_HANDLE DispatchHandle,
|
|
IN CONST VOID *CallbackContext,
|
|
IN OUT VOID *CommBuffer,
|
|
IN OUT UINTN *CommBufferSize
|
|
)
|
|
{
|
|
|
|
if (mSaSmiCallbackPhase == EnumSaSmiCallbackMax) {
|
|
return;
|
|
}
|
|
if (mSaSmiCallbackPhase == EnumSaSmiCallbackForMaxPayLoad) {
|
|
///
|
|
/// Switch to next phase
|
|
///
|
|
mSaSmiCallbackPhase = EnumSaSmiCallbackForSaSaveRestore;
|
|
} else if (mSaSmiCallbackPhase == EnumSaSmiCallbackForSaSaveRestore) {
|
|
///
|
|
/// Save platform registers including IGFX BAR & COMMAND registers and PAM
|
|
///
|
|
SaSaveRestorePlatform (TRUE);
|
|
///
|
|
/// Switch to next phase
|
|
///
|
|
mSaSmiCallbackPhase = EnumSaSmiCallbackForLateInit;
|
|
} else if (mSaSmiCallbackPhase == EnumSaSmiCallbackForLateInit) {
|
|
///
|
|
/// Switch to next phase
|
|
///
|
|
mSaSmiCallbackPhase = EnumSaSmiCallbackForS3resume;
|
|
} else if (mSaSmiCallbackPhase == EnumSaSmiCallbackForS3resume) {
|
|
///
|
|
/// Expected to execute in end of S3 resume flow
|
|
///
|
|
SaS3ResumeCallback ();
|
|
}
|
|
}
|
|
|
|
/**
|
|
This function will initialize all required policy into global veriables so no need to locate policy protocol during runtime.
|
|
**/
|
|
VOID
|
|
CpuPcieInitPolicy (
|
|
IN SA_POLICY_PROTOCOL *SaPolicy
|
|
)
|
|
{
|
|
UINT8 RootPortCount;
|
|
UINT8 Index;
|
|
SA_CONFIG_HOB *SaConfigHob;
|
|
EFI_STATUS Status;
|
|
PCIE_DXE_CONFIG *PcieDxeConfig;
|
|
|
|
Status = GetConfigBlock ((VOID *) SaPolicy, &gPcieDxeConfigGuid, (VOID *)&PcieDxeConfig);
|
|
ASSERT_EFI_ERROR (Status);
|
|
SaConfigHob = NULL;
|
|
|
|
SaConfigHob = GetFirstGuidHob (&gSaConfigHobGuid);
|
|
///
|
|
/// Initialize module global variables - Stepping ID and Policy
|
|
///
|
|
for (Index = 0; (Index < (sizeof (mSaChipsetPciRegistersSaveTable) / sizeof (BOOT_SCRIPT_PCI_REGISTER_SAVE))) && (Index < (sizeof (mSaChipsetPciRegistersTable) / sizeof (UINTN))); Index++) {
|
|
mSaChipsetPciRegistersSaveTable[Index].Address = PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, SA_MC_BUS, SA_MC_DEV, SA_MC_FUN, mSaChipsetPciRegistersTable[Index]);
|
|
}
|
|
|
|
for (RootPortCount = 0; RootPortCount < CPU_PCIE_MAX_ROOT_PORTS; RootPortCount++) {
|
|
mPegAspmPerPort[RootPortCount] = PcieDxeConfig->PegAspm[RootPortCount];
|
|
mPegPwrOpt[RootPortCount] = PcieDxeConfig->PegPwrOpt[RootPortCount];
|
|
}
|
|
|
|
if (SaConfigHob != NULL) {
|
|
mCridEnable = SaConfigHob->CridEnable;
|
|
}
|
|
|
|
///
|
|
/// Initialize Snoop and Non-Snoop Latencies
|
|
///
|
|
mSnoopLatencyOvrValue = 0;
|
|
mNonSnoopLatencyOvrValue = 0;
|
|
|
|
}
|
|
|
|
/**
|
|
Initializes the SA SMM handler
|
|
|
|
@param[in] ImageHandle - The image handle of Wake On Lan driver
|
|
@param[in] SystemTable - The standard EFI system table
|
|
|
|
@retval EFI_SUCCESS - SA SMM handler was installed or not necessary
|
|
@retval EFI_NOT_FOUND - Fail to register SMI callback or required protocol/hob missing.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SaLateInitSmmEntryPoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
#if FixedPcdGetBool(PcdCpuPcieEnable) == 1
|
|
EFI_SMM_IO_TRAP_REGISTER_CONTEXT PchIoTrapContext;
|
|
EFI_HANDLE PchIoTrapHandle;
|
|
CPU_PCIE_HOB *CpuPcieHob = NULL;
|
|
SA_POLICY_PROTOCOL *SaPolicy;
|
|
SA_IOTRAP_SMI_PROTOCOL *SaIotrapSmiProtocol;
|
|
EFI_STATUS Status;
|
|
BOOLEAN InitPcieAspmAfterOprom = FALSE;
|
|
#endif
|
|
|
|
DEBUG ((DEBUG_INFO, "SaLateInitSmmEntryPoint()\n"));
|
|
|
|
//
|
|
// Force RC6 for DisplayOnly SKU
|
|
//
|
|
if (IsDisplayOnlySku()) {
|
|
ForceGtRc6 ();
|
|
}
|
|
|
|
#if FixedPcdGetBool(PcdCpuPcieEnable) == 1
|
|
CpuPcieHob = (CPU_PCIE_HOB *) GetFirstGuidHob (&gCpuPcieHobGuid);
|
|
Status = EFI_NOT_FOUND;
|
|
if (CpuPcieHob == NULL) {
|
|
DEBUG ((DEBUG_INFO, "CPU PCIE HOB Not found\n"));
|
|
ASSERT (CpuPcieHob != NULL);
|
|
return Status;
|
|
}
|
|
InitPcieAspmAfterOprom = CpuPcieHob->InitPcieAspmAfterOprom;
|
|
|
|
///
|
|
/// Locate the PCH Trap dispatch protocol
|
|
///
|
|
Status = gSmst->SmmLocateProtocol (&gEfiSmmIoTrapDispatch2ProtocolGuid, NULL, (VOID **) &mPchIoTrap);
|
|
ASSERT_EFI_ERROR (Status);
|
|
Status = gSmst->SmmLocateProtocol (&gEfiSmmSxDispatch2ProtocolGuid, NULL, (VOID**) &mSxDispatch);
|
|
ASSERT_EFI_ERROR (Status);
|
|
if (Status == EFI_SUCCESS) {
|
|
if (InitPcieAspmAfterOprom == TRUE) {
|
|
///
|
|
/// Register SMI callback to initialize PCIe ASPM after OPROM
|
|
///
|
|
PchIoTrapContext.Type = ReadWriteTrap;
|
|
PchIoTrapContext.Length = 4;
|
|
PchIoTrapContext.Address = 0;
|
|
Status = mPchIoTrap->Register (
|
|
mPchIoTrap,
|
|
(EFI_SMM_HANDLER_ENTRY_POINT2) SaIoTrapSmiCallback,
|
|
&PchIoTrapContext,
|
|
&PchIoTrapHandle
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
if (Status == EFI_SUCCESS) {
|
|
///
|
|
/// Initialize module global variables - Stepping ID and Policy for runtime SMI handler
|
|
/// Get the platform setup policy.
|
|
///
|
|
Status = gBS->LocateProtocol (&gSaPolicyProtocolGuid, NULL, (VOID **) &SaPolicy);
|
|
ASSERT_EFI_ERROR (Status);
|
|
if (SaPolicy != NULL) {
|
|
CpuPcieInitPolicy (SaPolicy);
|
|
}
|
|
///
|
|
/// Install the SA IOTRAP SMI protocol
|
|
///
|
|
(gBS->AllocatePool) (EfiBootServicesData, sizeof (SA_IOTRAP_SMI_PROTOCOL), (VOID **)&SaIotrapSmiProtocol);
|
|
SaIotrapSmiProtocol->SaIotrapSmiAddress = PchIoTrapContext.Address;
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&ImageHandle,
|
|
&gSaIotrapSmiProtocolGuid,
|
|
SaIotrapSmiProtocol,
|
|
NULL
|
|
);
|
|
DEBUG ((DEBUG_INFO, "SA Iotrap address=%X\n", SaIotrapSmiProtocol->SaIotrapSmiAddress));
|
|
}
|
|
} else {
|
|
///
|
|
/// If ASPM policy is set to "Before OPROM", this SMI callback is not necessary
|
|
/// Ensure the SMI callback handler will directly return and continue the POST.
|
|
///
|
|
mSaSmiCallbackPhase = EnumSaSmiCallbackMax;
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
Status = InitializeCpuPcieSmm (ImageHandle, SystemTable);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
if (Status != EFI_SUCCESS) {
|
|
DEBUG ((DEBUG_ERROR, "Failed to register SaIotrapSmiCallback!\n"));
|
|
///
|
|
/// System will halt when failing to register required SMI handler
|
|
///
|
|
CpuDeadLoop ();
|
|
}
|
|
#endif
|
|
return EFI_SUCCESS;
|
|
}
|