/* $NoKeywords:$ */ /** * @file * * PCIe link training * * * * @xrefitem bom "File Content Label" "Release Content" * @e project: AGESA * @e sub-project: GNB * @e \$Revision: 85361 $ @e \$Date: 2013-01-07 11:15:28 -0600 (Mon, 07 Jan 2013) $ * */ /* ***************************************************************************** * * Copyright (c) 2008 - 2013, Advanced Micro Devices, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Advanced Micro Devices, Inc. nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *************************************************************************** * */ /*---------------------------------------------------------------------------------------- * M O D U L E S U S E D *---------------------------------------------------------------------------------------- */ #include "AGESA.h" #include "Ids.h" #include "amdlib.h" #include "GeneralServices.h" #include "Gnb.h" #include "GnbPcie.h" #include "GnbCommonLib.h" #include "GnbPcieConfig.h" #include "GnbPcieInitLibV1.h" #include "GnbPcieInitLibV5.h" #include "GnbPcieTrainingV2.h" #include "GnbRegistersCommonV2.h" #include "Filecode.h" #define FILECODE PROC_GNB_MODULES_GNBPCIETRAININGV2_PCIETRAININGV2_FILECODE /*---------------------------------------------------------------------------------------- * D E F I N I T I O N S A N D M A C R O S *---------------------------------------------------------------------------------------- */ /*---------------------------------------------------------------------------------------- * T Y P E D E F S A N D S T R U C T U R E S *---------------------------------------------------------------------------------------- */ /*---------------------------------------------------------------------------------------- * P R O T O T Y P E S O F L O C A L F U N C T I O N S *---------------------------------------------------------------------------------------- */ /*----------------------------------------------------------------------------------------*/ /** * Set link State * * * @param[in] CurrentEngine Pointer to engine config descriptor * @param[in] State State to set * @param[in] UpdateTimeStamp Update time stamp * @param[in] Pcie Pointer to global PCIe configuration * */ VOID PcieTrainingSetPortState ( IN PCIe_ENGINE_CONFIG *CurrentEngine, IN PCIE_LINK_TRAINING_STATE State, IN BOOLEAN UpdateTimeStamp, IN PCIe_PLATFORM_CONFIG *Pcie ) { UINT32 TimeStamp; CurrentEngine->Type.Port.State = (UINT8) State; if (UpdateTimeStamp) { TimeStamp = PcieTimerGetTimeStamp (Pcie); CurrentEngine->Type.Port.TimeStamp = TimeStamp; } } /*----------------------------------------------------------------------------------------*/ /** * Set state for all engines connected to same reset ID * * * * @param[in] Engine Pointer to engine config descriptor * @param[in, out] Buffer Pointer to Reset Id * @param[in] Pcie Pointer to global PCIe configuration * */ STATIC VOID PcieSetResetStateOnEngines ( IN PCIe_ENGINE_CONFIG *Engine, IN OUT VOID *Buffer, IN PCIe_PLATFORM_CONFIG *Pcie ) { UINT8 ResetId; ResetId = *(UINT8 *)Buffer; if (Engine->Type.Port.PortData.ResetId == ResetId && !PcieConfigIsSbPcieEngine (Engine)) { PcieTrainingSetPortState (Engine, LinkStateResetDuration, TRUE, Pcie); GnbLibPciRMW ( Engine->Type.Port.Address.AddressValue | DxFxx68_ADDRESS, AccessWidth32, (UINT32) ~DxFxx68_LinkDis_MASK, 1 << DxFxx68_LinkDis_OFFSET, GnbLibGetHeader (Pcie) ); } } /*----------------------------------------------------------------------------------------*/ /** * Assert GPIO port reset. * * Transition to LinkStateResetDuration state * * @param[in] CurrentEngine Pointer to engine config descriptor * @param[in] Pcie Pointer to global PCIe configuration * */ VOID STATIC PcieTrainingAssertReset ( IN PCIe_ENGINE_CONFIG *CurrentEngine, IN PCIe_PLATFORM_CONFIG *Pcie ) { PCIe_SLOT_RESET_INFO ResetInfo; ResetInfo.ResetControl = AssertSlotReset; ResetInfo.ResetId = CurrentEngine->Type.Port.PortData.ResetId; LibAmdMemCopy (&ResetInfo.StdHeader, GnbLibGetHeader (Pcie), sizeof (AMD_CONFIG_PARAMS), GnbLibGetHeader (Pcie)); PcieConfigRunProcForAllEngines ( DESCRIPTOR_ALLOCATED | DESCRIPTOR_PCIE_ENGINE, PcieSetResetStateOnEngines, (VOID *)&CurrentEngine->Type.Port.PortData.ResetId, Pcie ); AgesaPcieSlotResetControl (0, &ResetInfo); } /*----------------------------------------------------------------------------------------*/ /** * Check for reset duration * * Transition to LinkStateResetDuration state * * @param[in] CurrentEngine Pointer to engine config descriptor * @param[in] Pcie Pointer to global PCIe configuration * */ STATIC VOID PcieTrainingCheckResetDuration ( IN PCIe_ENGINE_CONFIG *CurrentEngine, IN PCIe_PLATFORM_CONFIG *Pcie ) { UINT32 TimeStamp; TimeStamp = PcieTimerGetTimeStamp (Pcie); if (TIMESTAMPS_DELTA (TimeStamp, CurrentEngine->Type.Port.TimeStamp) >= Pcie->LinkGpioResetAssertionTime) { PcieTrainingSetPortState (CurrentEngine, LinkStateResetExit, FALSE, Pcie); } } /*----------------------------------------------------------------------------------------*/ /** * Deassert GPIO port reset. * * Transition to LinkStateResetDuration state * * @param[in] CurrentEngine Pointer to engine config descriptor * @param[in] Pcie Platform configuration * */ STATIC VOID PcieTrainingDeassertReset ( IN PCIe_ENGINE_CONFIG *CurrentEngine, IN PCIe_PLATFORM_CONFIG *Pcie ) { PCIe_SLOT_RESET_INFO ResetInfo; ResetInfo.ResetControl = DeassertSlotReset; ResetInfo.ResetId = CurrentEngine->Type.Port.PortData.ResetId; LibAmdMemCopy (&ResetInfo.StdHeader, GnbLibGetHeader (Pcie), sizeof (AMD_CONFIG_PARAMS), GnbLibGetHeader (Pcie)); AgesaPcieSlotResetControl (0, &ResetInfo); GnbLibPciRMW ( CurrentEngine->Type.Port.Address.AddressValue | DxFxx68_ADDRESS, AccessWidth32, (UINT32) ~DxFxx68_LinkDis_MASK, 0 << DxFxx68_LinkDis_OFFSET, GnbLibGetHeader (Pcie) ); PcieTrainingSetPortState (CurrentEngine, LinkTrainingResetTimeout, TRUE, Pcie); } /*----------------------------------------------------------------------------------------*/ /** * Check for after reset deassertion timeout * * * @param[in] CurrentEngine Pointer to engine config descriptor * @param[in] Pcie Pointer to global PCIe configuration * */ VOID STATIC PcieTrainingCheckResetTimeout ( IN PCIe_ENGINE_CONFIG *CurrentEngine, IN PCIe_PLATFORM_CONFIG *Pcie ) { UINT32 TimeStamp; TimeStamp = PcieTimerGetTimeStamp (Pcie); if (TIMESTAMPS_DELTA (TimeStamp, CurrentEngine->Type.Port.TimeStamp) >= Pcie->LinkResetToTrainingTime) { PcieTrainingSetPortState (CurrentEngine, LinkStateReleaseTraining, FALSE, Pcie); } } /*----------------------------------------------------------------------------------------*/ /** * Release training * * * @param[in] CurrentEngine Pointer to engine config descriptor * @param[in] Pcie Pointer to global PCIe configuration * */ VOID STATIC PcieTrainingRelease ( IN PCIe_ENGINE_CONFIG *CurrentEngine, IN PCIe_PLATFORM_CONFIG *Pcie ) { UINT8 LinkTrainingState; PcieRegisterWriteField ( PcieConfigGetParentWrapper (CurrentEngine), WRAP_SPACE (PcieConfigGetParentWrapper (CurrentEngine)->WrapId, D0F0xE4_WRAP_0800_ADDRESS + 0x100 * CurrentEngine->Type.Port.PortId), D0F0xE4_WRAP_0800_HoldTraining_OFFSET, D0F0xE4_WRAP_0800_HoldTraining_WIDTH, 0, FALSE, Pcie ); if (CurrentEngine->Type.Port.PortData.MiscControls.LinkComplianceMode == 0x1) { LinkTrainingState = LinkStateCompliance; } else { LinkTrainingState = LinkStateDetectPresence; } PcieTrainingSetPortState (CurrentEngine, LinkTrainingState, TRUE, Pcie); } /*----------------------------------------------------------------------------------------*/ /** * Detect presence of any EP on the link * * * @param[in] CurrentEngine Pointer to engine config descriptor * @param[in] Pcie Pointer to global PCIe configuration * */ VOID STATIC PcieTrainingDetectPresence ( IN PCIe_ENGINE_CONFIG *CurrentEngine, IN PCIe_PLATFORM_CONFIG *Pcie ) { UINT8 LinkHwStateHistory[4]; UINT32 TimeStamp; PcieUtilGetLinkHwStateHistory (CurrentEngine, &LinkHwStateHistory[0], 4, Pcie); if (LinkHwStateHistory[0] > 4) { PcieTrainingSetPortState (CurrentEngine, LinkStateDetecting, TRUE, Pcie); return; } TimeStamp = PcieTimerGetTimeStamp (Pcie); if (TIMESTAMPS_DELTA (TimeStamp, CurrentEngine->Type.Port.TimeStamp) >= Pcie->LinkReceiverDetectionPooling) { PcieTrainingSetPortState (CurrentEngine, LinkStateDeviceNotPresent, FALSE, Pcie); } } UINT8 FailPattern1 [] = {0x2a, 0x6}; UINT8 FailPattern2 [] = {0x2a, 0x9}; UINT8 FailPattern3 [] = {0x2a, 0xb}; /*----------------------------------------------------------------------------------------*/ /** * Detect Link State * * * @param[in] CurrentEngine Pointer to engine config descriptor * @param[in] Pcie Pointer to global PCIe configuration * */ VOID STATIC PcieTrainingDetectLinkState ( IN PCIe_ENGINE_CONFIG *CurrentEngine, IN PCIe_PLATFORM_CONFIG *Pcie ) { UINT8 LinkHwStateHistory[16]; UINT32 TimeStamp; UINT8 LinkTrainingState; PcieUtilGetLinkHwStateHistory (CurrentEngine, &LinkHwStateHistory[0], 4, Pcie); if (LinkHwStateHistory[0] == 0x10) { PcieTrainingSetPortState (CurrentEngine, LinkStateL0, FALSE, Pcie); return; }; TimeStamp = PcieTimerGetTimeStamp (Pcie); if (TIMESTAMPS_DELTA (TimeStamp, CurrentEngine->Type.Port.TimeStamp) >= Pcie->LinkL0Pooling) { LinkTrainingState = LinkStateTrainingFail; PcieUtilGetLinkHwStateHistory (CurrentEngine, &LinkHwStateHistory[0], 16, Pcie); if (LinkHwStateHistory[0] == 0x7) { LinkTrainingState = LinkStateCompliance; } else if (PcieUtilSearchArray (LinkHwStateHistory, sizeof (LinkHwStateHistory), FailPattern1, sizeof (FailPattern1))) { LinkTrainingState = LinkStateBrokenLane; } else if (PcieUtilSearchArray (LinkHwStateHistory, sizeof (LinkHwStateHistory), FailPattern2, sizeof (FailPattern2))) { LinkTrainingState = LinkStateGen2Fail; } else if (PcieUtilSearchArray (LinkHwStateHistory, sizeof (LinkHwStateHistory), FailPattern3, sizeof (FailPattern3))) { LinkTrainingState = LinkStateGen2Fail; } PcieTrainingSetPortState (CurrentEngine, LinkTrainingState, FALSE, Pcie); } } /*----------------------------------------------------------------------------------------*/ /** * Broken Lane * * * @param[in] CurrentEngine Pointer to engine config descriptor * @param[in] Pcie Pointer to global PCIe configuration * */ STATIC VOID PcieTrainingBrokenLineV2 ( IN PCIe_ENGINE_CONFIG *CurrentEngine, IN PCIe_PLATFORM_CONFIG *Pcie ) { UINT8 CurrentLinkWidth; UINT8 LinkTrainingState; CurrentLinkWidth = PcieUtilGetLinkWidth (CurrentEngine, Pcie); if (CurrentLinkWidth < PcieConfigGetNumberOfPhyLane (CurrentEngine) && CurrentLinkWidth > 0) { CurrentEngine->InitStatus |= INIT_STATUS_PCIE_PORT_BROKEN_LANE_RECOVERY; PcieTopologyReduceLinkWidthV5 (CurrentLinkWidth, CurrentEngine, Pcie); LinkTrainingState = LinkStateResetAssert; PutEventLog ( AGESA_WARNING, GNB_EVENT_BROKEN_LANE_RECOVERY, CurrentEngine->Type.Port.Address.AddressValue, 0, 0, 0, GnbLibGetHeader (Pcie) ); } else { LinkTrainingState = LinkStateGen2Fail; } PcieTrainingSetPortState (CurrentEngine, LinkTrainingState, FALSE, Pcie); } /*----------------------------------------------------------------------------------------*/ /** * Check if link fail because device does not support Gen2 * * * @param[in] CurrentEngine Pointer to engine config descriptor * @param[in] Pcie Pointer to global PCIe configuration * */ STATIC VOID PcieTrainingGen2Fail ( IN PCIe_ENGINE_CONFIG *CurrentEngine, IN PCIe_PLATFORM_CONFIG *Pcie ) { UINT8 LinkTrainingState; if (CurrentEngine->Type.Port.PortData.MiscControls.LinkSafeMode != PcieGen1) { PcieConfigUpdatePortStatus (CurrentEngine, INIT_STATUS_PCIE_PORT_GEN2_RECOVERY, 0); CurrentEngine->Type.Port.PortData.MiscControls.LinkSafeMode = PcieGen1; PcieLinkSafeMode (CurrentEngine, Pcie); LinkTrainingState = LinkStateResetAssert; PutEventLog ( AGESA_WARNING, GNB_EVENT_BROKEN_LANE_RECOVERY, CurrentEngine->Type.Port.Address.AddressValue, 0, 0, 0, GnbLibGetHeader (Pcie) ); } else { LinkTrainingState = LinkStateTrainingFail; } PcieTrainingSetPortState (CurrentEngine, LinkTrainingState, FALSE, Pcie); } /*----------------------------------------------------------------------------------------*/ /** * Link in L0 * * * @param[in] CurrentEngine Pointer to engine config descriptor * @param[in] Pcie Pointer to global PCIe configuration * */ VOID STATIC PcieCheckLinkL0 ( IN PCIe_ENGINE_CONFIG *CurrentEngine, IN PCIe_PLATFORM_CONFIG *Pcie ) { PcieTrainingSetPortState (CurrentEngine, LinkStateVcoNegotiation, TRUE, Pcie); } /*----------------------------------------------------------------------------------------*/ /** * Check if link fail because device does not support Gen X * * * @param[in] CurrentEngine Pointer to engine config descriptor * @param[in] Pcie Pointer to global PCIe configuration * */ VOID STATIC PcieTrainingCheckVcoNegotiation ( IN PCIe_ENGINE_CONFIG *CurrentEngine, IN PCIe_PLATFORM_CONFIG *Pcie ) { UINT32 TimeStamp; DxFxx128_STRUCT DxFxx128; TimeStamp = PcieTimerGetTimeStamp (Pcie); GnbLibPciRead (CurrentEngine->Type.Port.Address.AddressValue | DxFxx128_ADDRESS, AccessWidth32, &DxFxx128, GnbLibGetHeader (Pcie)); if (DxFxx128.Field.VcNegotiationPending == 0) { UINT16 NumberOfPhyLane; NumberOfPhyLane = PcieConfigGetNumberOfPhyLane (CurrentEngine); if (Pcie->GfxCardWorkaround == GfxWorkaroundEnable && NumberOfPhyLane >= 8) { // Limit exposure of workaround to x8 and x16 port. PcieTrainingSetPortState (CurrentEngine, LinkStateGfxWorkaround, TRUE, Pcie); } else { PcieTrainingSetPortState (CurrentEngine, LinkStateTrainingSuccess, FALSE, Pcie); } return; } if (TIMESTAMPS_DELTA (TimeStamp, CurrentEngine->Type.Port.TimeStamp) >= 1000 * 1000) { PcieTrainingSetPortState (CurrentEngine, LinkStateRetrain, FALSE, Pcie); } } /*----------------------------------------------------------------------------------------*/ /** * Check if for GFX workaround condition * * * @param[in] CurrentEngine Pointer to engine config descriptor * @param[in] Pcie Pointer to global PCIe configuration * */ VOID STATIC PcieTrainingGfxWorkaround ( IN PCIe_ENGINE_CONFIG *CurrentEngine, IN PCIe_PLATFORM_CONFIG *Pcie ) { UINT32 TimeStamp; GFX_WORKAROUND_STATUS GfxWorkaroundStatus; TimeStamp = PcieTimerGetTimeStamp (Pcie); GfxWorkaroundStatus = PcieGfxCardWorkaroundV2 (CurrentEngine->Type.Port.Address, GnbLibGetHeader (Pcie)); switch (GfxWorkaroundStatus) { case GFX_WORKAROUND_DEVICE_NOT_READY: if (TIMESTAMPS_DELTA (TimeStamp, CurrentEngine->Type.Port.TimeStamp) >= (3 * 1000000)) { PcieTrainingSetPortState (CurrentEngine, LinkStateTrainingFail, TRUE, Pcie); } break; case GFX_WORKAROUND_SUCCESS: PcieTrainingSetPortState (CurrentEngine, LinkStateTrainingSuccess, FALSE, Pcie); break; case GFX_WORKAROUND_RESET_DEVICE: if (CurrentEngine->Type.Port.GfxWrkRetryCount < 5) { CurrentEngine->Type.Port.GfxWrkRetryCount++; PcieTrainingSetPortState (CurrentEngine, LinkStateResetAssert, TRUE, Pcie); } else { PcieTrainingSetPortState (CurrentEngine, LinkStateTrainingFail, TRUE, Pcie); } break; default: ASSERT (FALSE); } } /*----------------------------------------------------------------------------------------*/ /** * Retrain link * * * @param[in] CurrentEngine Pointer to engine config descriptor * @param[in] Pcie Pointer to global PCIe configuration * */ VOID STATIC PcieTrainingRetrainLink ( IN PCIe_ENGINE_CONFIG *CurrentEngine, IN PCIe_PLATFORM_CONFIG *Pcie ) { GnbLibPciRMW ( CurrentEngine->Type.Port.Address.AddressValue | DxFxx68_ADDRESS, AccessWidth32, (UINT32) ~DxFxx68_RetrainLink_MASK, 1 << DxFxx68_RetrainLink_OFFSET, GnbLibGetHeader (Pcie) ); PcieTrainingSetPortState (CurrentEngine, LinkStateDetecting, TRUE, Pcie); } /*----------------------------------------------------------------------------------------*/ /** * Training fail on this port * * * @param[in] CurrentEngine Pointer to engine config descriptor * @param[in] Pcie Pointer to global PCIe configuration * */ VOID STATIC PcieTrainingFail ( IN PCIe_ENGINE_CONFIG *CurrentEngine, IN PCIe_PLATFORM_CONFIG *Pcie ) { PcieConfigUpdatePortStatus (CurrentEngine, INIT_STATUS_PCIE_PORT_TRAINING_FAIL, 0); PcieTrainingSetPortState (CurrentEngine, LinkStateDeviceNotPresent, FALSE, Pcie); } /*----------------------------------------------------------------------------------------*/ /** * Links training success * * * @param[in] CurrentEngine Pointer to engine config descriptor * @param[in] Pcie Pointer to global PCIe configuration * */ VOID STATIC PcieTrainingSuccess ( IN PCIe_ENGINE_CONFIG *CurrentEngine, IN PCIe_PLATFORM_CONFIG *Pcie ) { PcieConfigUpdatePortStatus (CurrentEngine, INIT_STATUS_PCIE_TRAINING_SUCCESS, 0); PcieTrainingSetPortState (CurrentEngine, LinkStateTrainingCompleted, FALSE, Pcie); GnbLibPciRMW ( CurrentEngine->Type.Port.Address.AddressValue | DxFxx68_ADDRESS, AccessWidth32, (UINT32) ~DxFxx68_LinkBWManagementStatus_MASK, 1 << DxFxx68_LinkBWManagementStatus_OFFSET, GnbLibGetHeader (Pcie) ); } /*----------------------------------------------------------------------------------------*/ /** * Links in compliance * * * @param[in] CurrentEngine Pointer to engine config descriptor * @param[in] Pcie Pointer to global PCIe configuration * */ VOID STATIC PcieTrainingCompliance ( IN PCIe_ENGINE_CONFIG *CurrentEngine, IN PCIe_PLATFORM_CONFIG *Pcie ) { PcieConfigUpdatePortStatus (CurrentEngine, INIT_STATUS_PCIE_PORT_IN_COMPLIANCE, 0); PcieTrainingSetPortState (CurrentEngine, LinkStateTrainingCompleted, FALSE, Pcie); } /*----------------------------------------------------------------------------------------*/ /** * PCie EP not present * * * @param[in] CurrentEngine Pointer to engine config descriptor * @param[in] Pcie Pointer to global PCIe configuration * */ VOID STATIC PcieTrainingNotPresent ( IN PCIe_ENGINE_CONFIG *CurrentEngine, IN PCIe_PLATFORM_CONFIG *Pcie ) { if ((CurrentEngine->Type.Port.PortData.LinkHotplug == HotplugEnhanced) || (CurrentEngine->Type.Port.PortData.LinkHotplug == HotplugServer)) { } else { PcieRegisterWriteField ( PcieConfigGetParentWrapper (CurrentEngine), WRAP_SPACE (PcieConfigGetParentWrapper (CurrentEngine)->WrapId, D0F0xE4_WRAP_0800_ADDRESS + 0x100 * CurrentEngine->Type.Port.PortId), D0F0xE4_WRAP_0800_HoldTraining_OFFSET, D0F0xE4_WRAP_0800_HoldTraining_WIDTH, 1, FALSE, Pcie ); } PcieTrainingSetPortState (CurrentEngine, LinkStateTrainingCompleted, FALSE, Pcie); } /*----------------------------------------------------------------------------------------*/ /** * Final state. Port training completed. * * Initialization status recorded in PCIe_ENGINE_CONFIG.InitStatus * * @param[in] CurrentEngine Pointer to engine config descriptor * @param[in] Pcie Pointer to global PCIe configuration * */ VOID STATIC PcieTrainingCompleted ( IN PCIe_ENGINE_CONFIG *CurrentEngine, IN PCIe_PLATFORM_CONFIG *Pcie ) { } /*----------------------------------------------------------------------------------------*/ /** * Training state handling * * * * @param[in] Engine Pointer to engine config descriptor * @param[in, out] Buffer Indicate if engine in non final state * @param[in] Pcie Pointer to global PCIe configuration * */ VOID STATIC PcieTrainingPortCallback ( IN PCIe_ENGINE_CONFIG *Engine, IN OUT VOID *Buffer, IN PCIe_PLATFORM_CONFIG *Pcie ) { BOOLEAN *TrainingComplete; TrainingComplete = (BOOLEAN *) Buffer; if (Engine->Type.Port.State < Pcie->TrainingExitState) { *TrainingComplete = FALSE; } else { return; } switch (Engine->Type.Port.State) { case LinkStateResetAssert: PcieTrainingAssertReset (Engine, Pcie); break; case LinkStateResetDuration: PcieTrainingCheckResetDuration (Engine, Pcie); break; case LinkStateResetExit: PcieTrainingDeassertReset (Engine, Pcie); break; case LinkTrainingResetTimeout: PcieTrainingCheckResetTimeout (Engine, Pcie); break; case LinkStateReleaseTraining: PcieTrainingRelease (Engine, Pcie); break; case LinkStateDetectPresence: PcieTrainingDetectPresence (Engine, Pcie); break; case LinkStateDetecting: PcieTrainingDetectLinkState (Engine, Pcie); break; case LinkStateBrokenLane: PcieTrainingBrokenLineV2 (Engine, Pcie); break; case LinkStateGen2Fail: PcieTrainingGen2Fail (Engine, Pcie); break; case LinkStateL0: PcieCheckLinkL0 (Engine, Pcie); break; case LinkStateVcoNegotiation: PcieTrainingCheckVcoNegotiation (Engine, Pcie); break; case LinkStateRetrain: PcieTrainingRetrainLink (Engine, Pcie); break; case LinkStateTrainingFail: PcieTrainingFail (Engine, Pcie); break; case LinkStateGfxWorkaround: PcieTrainingGfxWorkaround (Engine, Pcie); break; case LinkStateTrainingSuccess: PcieTrainingSuccess (Engine, Pcie); break; case LinkStateCompliance: PcieTrainingCompliance (Engine, Pcie); break; case LinkStateDeviceNotPresent: PcieTrainingNotPresent (Engine, Pcie); break; case LinkStateTrainingCompleted: PcieTrainingCompleted (Engine, Pcie); break; default: break; } } /*----------------------------------------------------------------------------------------*/ /** * Main link training procedure * * Port end up in three possible state LinkStateTrainingNotPresent/LinkStateCompliance/ * LinkStateTrainingSuccess * * @param[in] Pcie Pointer to global PCIe configuration * @retval AGESA_STATUS * */ AGESA_STATUS PcieTraining ( IN PCIe_PLATFORM_CONFIG *Pcie ) { AGESA_STATUS Status; BOOLEAN TrainingComplete; IDS_PERF_TIMESTAMP (TP_BEGINGNBPCIETRAINING, GnbLibGetHeader (Pcie)); Status = AGESA_SUCCESS; IDS_HDT_CONSOLE (GNB_TRACE, "PcieTraining Enter\n"); do { TrainingComplete = TRUE; PcieConfigRunProcForAllEngines ( DESCRIPTOR_ALLOCATED | DESCRIPTOR_PCIE_ENGINE, PcieTrainingPortCallback, &TrainingComplete, Pcie ); } while (!TrainingComplete); IDS_HDT_CONSOLE (GNB_TRACE, "PcieTraining Exit [%x]\n", Status); IDS_PERF_TIMESTAMP (TP_ENDGNBPCIETRAINING, GnbLibGetHeader (Pcie)); return Status; }