From 646b243c0e3ef49b98071ca2c3fec15299b4d72f Mon Sep 17 00:00:00 2001 From: Jiewen Yao Date: Mon, 19 Jun 2017 10:55:06 +0800 Subject: Add KabylakeSiliconPkg reviewed-by: Jiewen Yao reviewed-by: Michael A Kubacki reviewed-by: Amy Chan reviewed-by: Rangasai V Chaganty reviewed-by: Chasel Chiu Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao Signed-off-by: Chasel Chiu --- .../Pch/PchInit/Smm/PchPcieSmm.c | 464 +++++++++++++++++++++ 1 file changed, 464 insertions(+) create mode 100644 Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c (limited to 'Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c') 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.
+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; +} -- cgit v1.2.3