summaryrefslogtreecommitdiff
path: root/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c
diff options
context:
space:
mode:
Diffstat (limited to 'Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c')
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c464
1 files changed, 464 insertions, 0 deletions
diff --git a/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c
new file mode 100644
index 0000000000..b4234f649c
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c
@@ -0,0 +1,464 @@
+/** @file
+ PCH Pcie SMM Driver Entry
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that 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 "PchInitSmm.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_PCIE_DEVICE_OVERRIDE *mDevAspmOverride;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mNumOfDevAspmOverride;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mPolicyRevision;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mPchBusNumber;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mTempRootPortBusNumMin;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mTempRootPortBusNumMax;
+
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_PCIE_ROOT_PORT_CONFIG mPcieRootPortConfig[PCH_MAX_PCIE_ROOT_PORTS];
+GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mLtrNonSupportRpBitMap;
+
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mPciePmTrapExecuted = FALSE;
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mAllowNoLtrIccPllShutdownPolicy = FALSE;
+
+extern EFI_GUID gPchDeviceTableHobGuid;
+
+
+/**
+ Program Common Clock and ASPM of Downstream Devices
+
+ @param[in] PortIndex Pcie Root Port Number
+ @param[in] RpDevice Pcie Root Pci Device Number
+ @param[in] RpFunction Pcie Root Pci Function Number
+
+ @retval EFI_SUCCESS Root port complete successfully
+ @retval EFI_UNSUPPORTED PMC has invalid vendor ID
+**/
+EFI_STATUS
+PchPcieSmi (
+ IN UINT8 PortIndex,
+ IN UINT8 RpDevice,
+ IN UINT8 RpFunction
+ )
+{
+ UINT8 SecBus;
+ UINT8 SubBus;
+ EFI_HANDLE Handle;
+ UINT32 PwrmBase;
+ UINTN RpBase;
+ BOOLEAN LtrSupported;
+ BOOLEAN DownstreamDevicePresent;
+
+ Handle = NULL;
+ LtrSupported = TRUE;
+
+ RpBase = MmPciBase (
+ mPchBusNumber,
+ (UINT32) RpDevice,
+ (UINT32) RpFunction
+ );
+
+ if (MmioRead16 (RpBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Check for presence detect state
+ //
+ DownstreamDevicePresent = !!(MmioRead16 (RpBase + R_PCH_PCIE_SLSTS) & B_PCIE_SLSTS_PDS);
+
+ mLtrNonSupportRpBitMap &= ~(1 << PortIndex);
+
+ if (DownstreamDevicePresent) {
+ SecBus = MmioRead8 (RpBase + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
+ SubBus = MmioRead8 (RpBase + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
+ ASSERT (SecBus != 0 && SubBus != 0);
+ PchPcieInitRootPortDownstreamDevices (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ RpDevice,
+ RpFunction,
+ mTempRootPortBusNumMin,
+ mTempRootPortBusNumMax,
+ (BOOLEAN)mPcieRootPortConfig[PortIndex].EnableCpm
+ );
+ if (!LtrSupported) {
+ mLtrNonSupportRpBitMap |= 1 << PortIndex;
+ }
+
+ //
+ // Perform Equalization
+ //
+ MmioOr32 (RpBase + R_PCH_PCIE_EX_LCTL3, B_PCIE_EX_LCTL3_PE);
+ MmioOr32 (RpBase + R_PCH_PCIE_LCTL, B_PCIE_LCTL_RL);
+ }
+
+ //
+ // If not all devices support LTR, set PWRMBASE + 0x3EC [24,16] = 0, 1
+ // This will disable ICC PLL shutdown
+ //
+ if (!mAllowNoLtrIccPllShutdownPolicy) {
+ PchPwrmBaseGet (&PwrmBase);
+ if (mLtrNonSupportRpBitMap != 0) {
+ MmioAndThenOr32 (PwrmBase + R_PCH_PWRM_CS_SD_CTL2, (UINT32) ~BIT24, BIT16);
+ } else {
+ MmioAnd32 (PwrmBase + R_PCH_PWRM_CS_SD_CTL2, (UINT32) ~(BIT24 | BIT16));
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ PCIE Hotplug SMI call back function for each Root port
+
+ @param[in] DispatchHandle Handle of this dispatch function
+ @param[in] RpContext Rootport context, which contains RootPort Index,
+ and RootPort PCI BDF.
+**/
+VOID
+EFIAPI
+PchPcieSmiRpHandlerFunction (
+ IN EFI_HANDLE DispatchHandle,
+ IN PCH_PCIE_SMI_RP_CONTEXT *RpContext
+ )
+{
+ PchPcieSmi (RpContext->RpIndex, RpContext->DevNum, RpContext->FuncNum);
+}
+
+/**
+ PCIE Link Active State Change Hotplug SMI call back function for all Root ports
+
+ @param[in] DispatchHandle Handle of this dispatch function
+ @param[in] RpContext Rootport context, which contains RootPort Index,
+ and RootPort PCI BDF.
+**/
+VOID
+EFIAPI
+PchPcieLinkActiveStateChange (
+ IN EFI_HANDLE DispatchHandle,
+ IN PCH_PCIE_SMI_RP_CONTEXT *RpContext
+ )
+{
+ return;
+}
+
+/**
+ PCIE Link Equalization Request SMI call back function for all Root ports
+
+ @param[in] DispatchHandle Handle of this dispatch function
+ @param[in] RpContext Rootport context, which contains RootPort Index,
+ and RootPort PCI BDF.
+**/
+VOID
+EFIAPI
+PchPcieLinkEqHandlerFunction (
+ IN EFI_HANDLE DispatchHandle,
+ IN PCH_PCIE_SMI_RP_CONTEXT *RpContext
+ )
+{
+ ///
+ /// From PCI Express specification, the PCIe device can request for Link Equalization. When the
+ /// Link Equalization is requested by the device, an SMI will be generated by PCIe RP when
+ /// enabled and the SMI subroutine would invoke the Software Preset/Coefficient Search
+ /// software to re-equalize the link.
+ ///
+
+ return;
+
+}
+
+
+/**
+ An IoTrap callback to config PCIE power management settings
+**/
+VOID
+PchPciePmIoTrapSmiCallback (
+ VOID
+ )
+{
+ UINT32 PwrmBase;
+ UINT32 PortIndex;
+ UINTN RpBase;
+ BOOLEAN L1SubstatesSupportedPerPort;
+ UINT8 MaxPciePortNum;
+ UINTN RpDevice;
+ UINTN RpFunction;
+ PCH_GENERATION PchGen;
+ PCH_SERIES PchSeries;
+ PCH_STEPPING PchStep;
+
+ PchGen = GetPchGeneration ();
+ PchSeries = GetPchSeries ();
+ PchStep = PchStepping ();
+ L1SubstatesSupportedPerPort = FALSE;
+ MaxPciePortNum = GetPchMaxPciePortNum ();
+
+ //
+ // Step 4a
+ // In case not all devices support LTR, disable ICC PLL shutdown
+ // set PWRMBASE + 0x3EC [24,16] = 0, 1
+ // (Note this register should be saved and restored during S3 transitions)
+ //
+ if (!mAllowNoLtrIccPllShutdownPolicy) {
+ PchPwrmBaseGet (&PwrmBase);
+ MmioAndThenOr32 (PwrmBase + R_PCH_PWRM_CS_SD_CTL2, (UINT32) ~BIT24, BIT16);
+ }
+
+ for (PortIndex = 0; PortIndex < MaxPciePortNum; PortIndex++) {
+ GetPchPcieRpDevFun (PortIndex, &RpDevice, &RpFunction);
+ RpBase = MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH, (UINT32) RpDevice, (UINT32) RpFunction);
+ }
+ //
+ // Step 4b
+ // By this time, LTR support map is known.
+ // If all devices support LTR, allow ICC PLL shutdown
+ // (Note this register should be saved and restored during S3 transitions)
+ //
+ if (!mAllowNoLtrIccPllShutdownPolicy) {
+ if (mLtrNonSupportRpBitMap == 0) {
+ PchPwrmBaseGet (&PwrmBase);
+ MmioAnd32 (PwrmBase + R_PCH_PWRM_CS_SD_CTL2, (UINT32) ~(BIT24 | BIT16));
+ }
+ }
+
+ //
+ // Program the remapped root port's ASPM based on endpoint's ASPM
+ //
+ if ((PchGen == SklPch) &&
+ (((PchSeries == PchLp) && (PchStep < PchLpC0)) ||
+ ((PchSeries == PchH) && (PchStep < PchHD0)))) {
+ return;
+ }
+}
+
+/**
+ An IoTrap callback to config PCIE power management settings
+
+ @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
+PchPcieIoTrapSmiCallback (
+ IN EFI_HANDLE DispatchHandle,
+ IN EFI_SMM_IO_TRAP_CONTEXT *CallbackContext,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommBufferSize
+ )
+{
+ if (CallbackContext->WriteData == PciePmTrap) {
+ if (mPciePmTrapExecuted == FALSE) {
+ PchPciePmIoTrapSmiCallback ();
+ mPciePmTrapExecuted = TRUE;
+ }
+ } else {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ }
+}
+
+/**
+ This function clear the Io trap executed flag before enter S3
+
+ @param[in] Handle Handle of the callback
+ @param[in] Context The dispatch context
+
+ @retval EFI_SUCCESS PCH register saved
+**/
+EFI_STATUS
+EFIAPI
+PchPcieS3EntryCallBack (
+ IN EFI_HANDLE Handle,
+ IN CONST VOID *Context OPTIONAL,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ mPciePmTrapExecuted = FALSE;
+ return EFI_SUCCESS;
+}
+/**
+ Register PCIE Hotplug SMI dispatch function to handle Hotplug enabling
+
+ @param[in] ImageHandle The image handle of this module
+ @param[in] SystemTable The EFI System Table
+
+ @retval EFI_SUCCESS The function completes successfully
+**/
+EFI_STATUS
+EFIAPI
+InitializePchPcieSmm (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINT8 PortIndex;
+ UINT8 Data8;
+ UINT32 Data32Or;
+ UINT32 Data32And;
+ UINTN RpBase;
+ UINTN RpDevice;
+ UINTN RpFunction;
+ EFI_HANDLE PcieHandle;
+ PCH_PCIE_SMI_DISPATCH_PROTOCOL *PchPcieSmiDispatchProtocol;
+ EFI_HOB_GUID_TYPE* Hob;
+ UINT32 DevTableSize;
+ EFI_HANDLE PchIoTrapHandle;
+ EFI_SMM_IO_TRAP_REGISTER_CONTEXT PchIoTrapContext;
+ EFI_SMM_SX_REGISTER_CONTEXT SxDispatchContext;
+ PCH_PCIE_IOTRAP_PROTOCOL *PchPcieIoTrapProtocol;
+ EFI_HANDLE SxDispatchHandle;
+ UINT8 MaxPciePortNum;
+
+ DEBUG ((DEBUG_INFO, "InitializePchPcieSmm () Start\n"));
+
+ MaxPciePortNum = GetPchMaxPciePortNum ();
+
+ //
+ // Locate Pch Pcie Smi Dispatch Protocol
+ //
+ Status = gSmst->SmmLocateProtocol (&gPchPcieSmiDispatchProtocolGuid, NULL, (VOID**)&PchPcieSmiDispatchProtocol);
+ ASSERT_EFI_ERROR (Status);
+
+ mPolicyRevision = mSiConfigHob->Header.Revision;
+ mPchBusNumber = DEFAULT_PCI_BUS_NUMBER_PCH;
+ mTempRootPortBusNumMin = mSiConfigHob->TempPciBusMin;
+ mTempRootPortBusNumMax = mSiConfigHob->TempPciBusMax;
+ mAllowNoLtrIccPllShutdownPolicy = (BOOLEAN) mPchConfigHob->PcieRp.AllowNoLtrIccPllShutdown;
+
+ ASSERT (sizeof mPcieRootPortConfig == sizeof mPchConfigHob->PcieRp.RootPort);
+ CopyMem (
+ mPcieRootPortConfig,
+ &(mPchConfigHob->PcieRp.RootPort),
+ sizeof (mPcieRootPortConfig)
+ );
+
+ mDevAspmOverride = NULL;
+ mNumOfDevAspmOverride = 0;
+ mLtrNonSupportRpBitMap = 0;
+
+ Hob = GetFirstGuidHob (&gPchDeviceTableHobGuid);
+ if (Hob != NULL) {
+ DevTableSize = GET_GUID_HOB_DATA_SIZE (Hob);
+ ASSERT ((DevTableSize % sizeof (PCH_PCIE_DEVICE_OVERRIDE)) == 0);
+ mNumOfDevAspmOverride = DevTableSize / sizeof (PCH_PCIE_DEVICE_OVERRIDE);
+ DEBUG ((DEBUG_INFO, "Found PcieDeviceTable HOB (%d entries)\n", mNumOfDevAspmOverride));
+ Status = gSmst->SmmAllocatePool (
+ EfiRuntimeServicesData,
+ DevTableSize,
+ (VOID **) &mDevAspmOverride
+ );
+ CopyMem (mDevAspmOverride, GET_GUID_HOB_DATA (Hob), DevTableSize);
+ }
+
+ //
+ // Throught all PCIE root port function and register the SMI Handler for enabled ports.
+ //
+ for (PortIndex = 0; PortIndex < MaxPciePortNum; PortIndex++) {
+ GetPchPcieRpDevFun (PortIndex, &RpDevice, &RpFunction);
+ RpBase = MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH, (UINT32) RpDevice, (UINT32) RpFunction);
+ //
+ // Skip the root port function which is not enabled
+ //
+ if (MmioRead32 (RpBase) == 0xFFFFFFFF) {
+ continue;
+ }
+
+ if (!mPcieRootPortConfig[PortIndex].EnableHotplugSmi) {
+ continue;
+ }
+ //
+ // Register SMI Handlers for Hot Plug and Link Active State Change
+ //
+ Data8 = MmioRead8 (RpBase + R_PCH_PCIE_SLCAP);
+ if (Data8 & B_PCIE_SLCAP_HPC) {
+ PcieHandle = NULL;
+ Status = PchPcieSmiDispatchProtocol->HotPlugRegister (
+ PchPcieSmiDispatchProtocol,
+ PchPcieSmiRpHandlerFunction,
+ PortIndex,
+ &PcieHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = PchPcieSmiDispatchProtocol->LinkActiveRegister (
+ PchPcieSmiDispatchProtocol,
+ PchPcieLinkActiveStateChange,
+ PortIndex,
+ &PcieHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Data32Or = B_PCH_PCIE_MPC_HPME;
+ Data32And = (UINT32) ~B_PCH_PCIE_MPC_HPME;
+ S3BootScriptSaveMemReadWrite (
+ S3BootScriptWidthUint32,
+ (UINTN) (RpBase + R_PCH_PCIE_MPC),
+ &Data32Or, /// Data to be ORed
+ &Data32And /// Data to be ANDed
+ );
+ }
+
+ //
+ // Register SMI Handler for Link Equalization Request from Gen 3 Devices.
+ //
+ Data8 = MmioRead8 (RpBase + R_PCH_PCIE_LCAP);
+ if ((Data8 & B_PCIE_LCAP_MLS) == V_PCIE_LCAP_MLS_GEN3) {
+ Status = PchPcieSmiDispatchProtocol->LinkEqRegister (
+ PchPcieSmiDispatchProtocol,
+ PchPcieLinkEqHandlerFunction,
+ PortIndex,
+ &PcieHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ ASSERT_EFI_ERROR (Status);
+
+ PchIoTrapContext.Type = WriteTrap;
+ PchIoTrapContext.Length = 4;
+ PchIoTrapContext.Address = 0;
+ Status = mPchIoTrap->Register (
+ mPchIoTrap,
+ (EFI_SMM_HANDLER_ENTRY_POINT2) PchPcieIoTrapSmiCallback,
+ &PchIoTrapContext,
+ &PchIoTrapHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install the PCH Pcie IoTrap protocol
+ //
+ (gBS->AllocatePool) (EfiBootServicesData, sizeof (PCH_PCIE_IOTRAP_PROTOCOL), (VOID **)&PchPcieIoTrapProtocol);
+ PchPcieIoTrapProtocol->PcieTrapAddress = PchIoTrapContext.Address;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gPchPcieIoTrapProtocolGuid,
+ PchPcieIoTrapProtocol,
+ NULL
+ );
+
+ //
+ // Register the callback for S3 entry
+ //
+ SxDispatchContext.Type = SxS3;
+ SxDispatchContext.Phase = SxEntry;
+ Status = mSxDispatch->Register (
+ mSxDispatch,
+ PchPcieS3EntryCallBack,
+ &SxDispatchContext,
+ &SxDispatchHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((DEBUG_INFO, "InitializePchPcieSmm () End\n"));
+
+ return EFI_SUCCESS;
+}