summaryrefslogtreecommitdiff
path: root/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingPhase3.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingPhase3.c')
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingPhase3.c657
1 files changed, 657 insertions, 0 deletions
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingPhase3.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingPhase3.c
new file mode 100644
index 0000000..6123968
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingPhase3.c
@@ -0,0 +1,657 @@
+/** @file
+ This driver trains the PEG interface.
+
+@copyright
+ Copyright (c) 2012 - 2014 Intel Corporation. All rights reserved
+ This software and associated documentation (if any) is furnished
+ under a license and may only be used or copied in accordance
+ with the terms of the license. Except as permitted by such
+ license, no part of this software or documentation may be
+ reproduced, stored in a retrieval system, or transmitted in any
+ form or by any means without the express written consent of
+ Intel Corporation.
+
+ This file contains an 'Intel Peripheral Driver' and 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
+**/
+
+#include "PcieTraining.h"
+
+#ifdef PEG_FLAG
+
+#include EFI_PPI_DEFINITION (PchMeUma)
+#include "PchMeUma.h"
+
+typedef struct _MARGIN_DATA {
+ UINT8 Preset;
+ INT32 TimingMargin[SA_PEG_MAX_LANE];
+} MARGIN_DATA;
+
+UINT8
+SelectBestPresetForLane (
+ IN PORT_INFO *PortInfo,
+ IN UINT8 Lane,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN SA_DATA_HOB *SaDataHob,
+ IN UINT8 TrainingPreset
+ )
+{
+ UINT8 BestPreset;
+
+ ///
+ /// Init to EV default
+ ///
+ BestPreset = 7;
+
+ ///
+ /// EnableMargin FoundUsablePreset SaDataHob
+ /// Y Y !NULL -> Use training results; update SaDataHob
+ /// Y Y NULL -> Use training results
+ /// Y N !NULL -> Use Policy value; update SaDataHob
+ /// X N NULL -> Use Policy value
+ /// N X !NULL -> Restore from SaDataHob
+ ///
+ if (Lane < SA_PEG_MAX_LANE) {
+ DEBUG ((EFI_D_INFO, "Preset for Lane %2d: ", Lane));
+ if ((PortInfo->EnableMargin) && (PortInfo->FoundUsablePreset)) {
+ ///
+ /// Use the best preset found during training
+ ///
+ BestPreset = TrainingPreset;
+ DEBUG ((EFI_D_INFO, "Search Result: P%d", BestPreset));
+ if (SaDataHob != NULL) {
+ DEBUG ((EFI_D_INFO, ". Saving value for next boot."));
+ SaDataHob->PegData.BestPreset[Lane] = BestPreset;
+ }
+ } else if ((PortInfo->EnableMargin) && (!PortInfo->FoundUsablePreset) && (SaDataHob != NULL)) {
+ ///
+ /// Use the policy value; update SaDataHob
+ ///
+ BestPreset = (UINT8) SaPlatformPolicyPpi->PcieConfig->Gen3EndPointPreset[Lane];
+ DEBUG ((EFI_D_INFO, "Applying Policy value: P%d. Saving value for next boot.", BestPreset));
+ SaDataHob->PegData.BestPreset[Lane] = BestPreset;
+ } else if ((!PortInfo->FoundUsablePreset) && (SaDataHob == NULL)) {
+ ///
+ /// Use the policy value
+ ///
+ BestPreset = (UINT8) SaPlatformPolicyPpi->PcieConfig->Gen3EndPointPreset[Lane];
+ DEBUG ((EFI_D_INFO, "Applying Policy value: P%d", BestPreset));
+ } else if ((!PortInfo->EnableMargin) && (SaDataHob != NULL)) {
+ ///
+ /// Use the preset found on a previous boot
+ ///
+ BestPreset = (UINT8) SaDataHob->PegData.BestPreset[Lane];
+ DEBUG ((EFI_D_INFO, "Restoring previous value: P%d", BestPreset));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+ } else {
+ ///
+ /// Error: Non-existent lane
+ ///
+ DEBUG ((EFI_D_ERROR, "Illegal Lane: %d", Lane));
+ }
+
+ return BestPreset;
+}
+
+VOID
+PegGen3PresetSearch (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN PEI_STALL_PPI *StallPpi,
+ SA_DATA_HOB *SaDataHob
+ )
+{
+ UINT8 Index;
+ INT32 MarginScore;
+ UINT8 PegBus;
+ UINT8 PegDev;
+ UINT8 PegFunc;
+ UINT16 LinkStatus;
+ BOOLEAN LoadedSavedPreset;
+ BOOLEAN EndpointDeviceChanged;
+ UINT8 TempIndex;
+ BOOLEAN SkipBundle0;
+ CPU_FAMILY CpuFamilyId;
+ CPU_STEPPING CpuSteppingId;
+ MARGIN_DATA MarginData[MAX_PRESETS];
+ PORT_INFO PortInfoList[SA_PEG_MAX_FUN];
+ INT32 LaneScores[SA_PEG_MAX_LANE];
+ INT32 BestScores[SA_PEG_MAX_LANE];
+ UINT8 BestPresets[SA_PEG_MAX_LANE];
+ EFI_STATUS Status;
+ UINT32 MonitorPort;
+ UINT8 PortInfoListLength;
+ UINT8 PortIndex;
+ UINT8 Lane;
+ BOOLEAN AnyGen3CapableLinks;
+ BOOLEAN AnyMarginingNeeded;
+ UINT8 PreCursor;
+ UINT8 Cursor;
+ UINT8 PostCursor;
+ UINT8 FullSwing;
+ UINT32 NominalRecoveryCount;
+ UINT8 FirstSkippedLane;
+ UINT8 LastSkippedLane;
+ UINT32 Data32;
+ BOOLEAN SlotResetNeeded;
+ PCH_ME_UMA_PPI *PchMeUmaPpi;
+ UINT8 DetectedReplacedCpu;
+
+ AnyMarginingNeeded = FALSE;
+ CpuFamilyId = GetCpuFamily();
+ CpuSteppingId = GetCpuStepping();
+
+ ///
+ /// Setup default presets to search
+ ///
+ MarginData[0].Preset = 7;
+ MarginData[1].Preset = 3;
+ MarginData[2].Preset = 5;
+
+ ///
+ /// Initialize Arrays
+ ///
+ for (Lane = 0; Lane < SA_PEG_MAX_LANE; Lane++) {
+ LaneScores[Lane] = -1;
+ BestScores[Lane] = -1;
+ BestPresets[Lane] = MarginData[0].Preset;
+ }
+
+ DEBUG ((EFI_D_INFO, "PEG Gen3 Preset Search\n"));
+
+ if (!SaPolicyEnablesGen3 (SaPlatformPolicyPpi)) {
+ DEBUG ((EFI_D_INFO, " Gen3 is disabled by policy\n"));
+ return;
+ }
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId < EnumHswB0)) {
+ DEBUG ((EFI_D_WARN, " Gen3 preset search is not supported on this stepping\n"));
+ return;
+ }
+ Data32 = (McD1PciCfg32 (R_SA_PEG_PEGTST_OFFSET) & BIT20) >> 20;
+ if (Data32 != 0) {
+ DEBUG ((EFI_D_WARN, " Gen3 preset search does not support lane reversal\n"));
+ return;
+ }
+
+ ///
+ /// If ME is supported and the CPU has been replaced, redo the Preset Search.
+ /// Note that calling CpuReplacementCheck() can induce an ME-required warm reset.
+ ///
+ DetectedReplacedCpu = 0;
+ Status = EFI_SUCCESS;
+
+ if ((SaDataHob != NULL) && (SaDataHob->PegDataValid)) {
+ Status = (*PeiServices)->LocatePpi (PeiServices, &gPchMeUmaPpiGuid, 0, NULL, &PchMeUmaPpi);
+ ASSERT_EFI_ERROR (Status);
+ DEBUG ((EFI_D_INFO, "Calling CpuReplacementCheck\n"));
+ Status = PchMeUmaPpi->CpuReplacementCheck (PeiServices, NULL, &DetectedReplacedCpu);
+ ASSERT_EFI_ERROR (Status);
+ DEBUG ((EFI_D_INFO, " ME reported CPU Replacement value: %x\n", DetectedReplacedCpu));
+ }
+
+ ///
+ /// Get the furcation setup and port information
+ ///
+ GetPortInfo (&(PortInfoList[0]), &PortInfoListLength, &SkipBundle0);
+
+ ///
+ /// Make sure we at Gen3 before starting, if not attempt reset and see if that helps
+ ///
+ SlotResetNeeded = FALSE;
+ for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) {
+ PegBus = (PortInfoList[PortIndex]).PegPort.Bus;
+ PegDev = (PortInfoList[PortIndex]).PegPort.Device;
+ PegFunc = (PortInfoList[PortIndex]).PegPort.Function;
+ LinkStatus = MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_LSTS_OFFSET);
+ if (((LinkStatus & 0x0F) != 3) && ((PortInfoList[PortIndex]).LinkIsGen3Capable)) {
+ SlotResetNeeded = TRUE;
+ break;
+ }
+ }
+ if (SlotResetNeeded) {
+ ///
+ /// Bypass phase2 and assert slot reset
+ ///
+ McD1PciCfg32Or (R_SA_PEG_EQCFG_OFFSET, BIT15);
+ Status = TogglePegSlotReset (PeiServices, StallPpi, SaPlatformPolicyPpi);
+ if (!EFI_ERROR (Status)) {
+ for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) {
+ PegBus = (PortInfoList[PortIndex]).PegPort.Bus;
+ PegDev = (PortInfoList[PortIndex]).PegPort.Device;
+ PegFunc = (PortInfoList[PortIndex]).PegPort.Function;
+ ///
+ /// Wait for Equalization Done
+ ///
+ while (((MmPci32 (0, PegBus, PegDev, PegFunc, R_SA_PEG_LSTS2_OFFSET) >> 1) & 0x1) != 0x1);
+ ///
+ /// Wait for flow control credits exchange
+ ///
+ WaitForVc0Negotiation (PeiServices, StallPpi, PegBus, PegDev, PegFunc);
+ }
+ }
+ }
+
+ ///
+ /// Determine which PEG ports require testing
+ ///
+ AnyGen3CapableLinks = FALSE;
+ for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) {
+ PegBus = (PortInfoList[PortIndex]).PegPort.Bus;
+ PegDev = (PortInfoList[PortIndex]).PegPort.Device;
+ PegFunc = (PortInfoList[PortIndex]).PegPort.Function;
+
+ ///
+ /// If we already have Best Preset value from previous boot, use it and skip PresetSearch when end point device no change
+ ///
+ LoadedSavedPreset = FALSE;
+ EndpointDeviceChanged = TRUE;
+ if (SaDataHob != NULL) {
+ if (SaDataHob->PegDataValid) {
+ LoadedSavedPreset = TRUE;
+ if (SaDataHob->PegData.EndPointVendorIdDeviceId[PegFunc] == (PortInfoList[PortIndex]).EndPointVendorIdDeviceId) {
+ EndpointDeviceChanged = FALSE;
+ }
+ }
+ if (EndpointDeviceChanged) {
+ ///
+ /// Save new device ID vendor ID
+ ///
+ SaDataHob->PegData.EndPointVendorIdDeviceId[PegFunc] = (PortInfoList[PortIndex]).EndPointVendorIdDeviceId;
+ }
+ }
+ DEBUG ((EFI_D_INFO, " PEG%x%x (%x:%x:%x) - LoadedSavedPreset = %d. EndpointDeviceChanged = %d.\n",
+ PegDev, PegFunc, PegBus, PegDev, PegFunc, LoadedSavedPreset, EndpointDeviceChanged));
+
+ ReportPcieLinkStatus (PegBus, PegDev, PegFunc);
+
+ if ( (!LoadedSavedPreset) ||
+ (EndpointDeviceChanged) ||
+ (DetectedReplacedCpu != 0) ||
+ ((SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_2) &&
+ (SaPlatformPolicyPpi->PcieConfig->PegGen3ForcePresetSearch == 1 ))) {
+ (PortInfoList[PortIndex]).EnableMargin = TRUE;
+ } else {
+ (PortInfoList[PortIndex]).EnableMargin = FALSE;
+ }
+
+ if (!(PortInfoList[PortIndex]).LinkIsGen3Capable) {
+ (PortInfoList[PortIndex]).EnableMargin = FALSE;
+ } else {
+ AnyGen3CapableLinks = TRUE;
+ }
+ } ///< PegFunc Loop end
+
+ if (!AnyGen3CapableLinks) {
+ DEBUG ((EFI_D_INFO, "Skipping Preset Search - No Gen3 capable links\n"));
+ return;
+ }
+
+ ///
+ /// Determine if any ports need to be trained.
+ /// If any ports are trained, the corresponding endpoint should also be reset with PERST#.
+ ///
+ for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) {
+ if ((PortInfoList[PortIndex]).EnableMargin == TRUE) {
+ AnyMarginingNeeded = TRUE;
+ break;
+ }
+ }
+
+ if (AnyMarginingNeeded) {
+ MonitorPort = OpenMonitor (PeiServices, SaPlatformPolicyPpi, StallPpi);
+
+ McD1PciCfg32Or (R_SA_PEG_REUT_PH_CTR_OFFSET, B_SA_PEG_REUT_PH_CTR_AUTOCOMP_MASK);
+
+ ///
+ /// Presets Loop start
+ ///
+ for (Index = 0; Index < MAX_PRESETS; Index++) {
+ ///
+ /// Clear out old values
+ ///
+ for (TempIndex = 0; TempIndex < SA_PEG_MAX_LANE; TempIndex++) {
+ MarginData[Index].TimingMargin[TempIndex] = 0;
+ } ///< End of for each Lane
+
+
+ for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) {
+ (PortInfoList[PortIndex]).SkipMargin = FALSE;
+ PegBus = (PortInfoList[PortIndex]).PegPort.Bus;
+ PegDev = (PortInfoList[PortIndex]).PegPort.Device;
+ PegFunc = (PortInfoList[PortIndex]).PegPort.Function;
+
+ if (!(PortInfoList[PortIndex]).LinkIsGen3Capable) {
+ DEBUG ((EFI_D_INFO, "Skipping PEG%d%d - Not Gen3 capable\n", PegDev, PegFunc));
+ continue;
+ }
+
+ ///
+ /// Find first lane of the port for coefficient programming
+ ///
+ switch (PegFunc) {
+ default:
+ case 0:
+ Lane = 0;
+ FirstSkippedLane = 0;
+ LastSkippedLane = 1;
+ break;
+ case 1:
+ Lane = 8;
+ FirstSkippedLane = 8;
+ LastSkippedLane = 9;
+ break;
+ case 2:
+ Lane = 12;
+ FirstSkippedLane = 12;
+ LastSkippedLane = 13;
+ break;
+ }
+
+ ///
+ /// Get FullSwing
+ ///
+ GetLinkPartnerFullSwing (Lane, &FullSwing);
+
+ ///
+ /// Get Coefficients
+ ///
+ GetCoefficientsFromPreset (MarginData[Index].Preset, FullSwing, &PreCursor, &Cursor, &PostCursor);
+
+ ///
+ /// Set Lane's Coefficients
+ ///
+ if (SkipBundle0) {
+ for (TempIndex = FirstSkippedLane; TempIndex <= LastSkippedLane; TempIndex++) {
+ SetPartnerTxCoefficients (TempIndex, &PreCursor, &Cursor, &PostCursor);
+ ProgramPreset (1, MarginData[Index].Preset, PegFunc, TempIndex);
+ }
+ }
+ for (TempIndex = 0; TempIndex < (PortInfoList[PortIndex]).LaneListLength; TempIndex++) {
+ SetPartnerTxCoefficients ((PortInfoList[PortIndex]).LaneList[TempIndex], &PreCursor, &Cursor, &PostCursor);
+ ProgramPreset (1, MarginData[Index].Preset, PegFunc, (PortInfoList[PortIndex]).LaneList[TempIndex]);
+ }
+
+ ///
+ /// Set DOEQ bit
+ ///
+ MmPci32Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCTL3_OFFSET, BIT0);
+ RetrainLink (PeiServices, StallPpi, &((PortInfoList[PortIndex]).PegPort));
+
+ ///
+ /// Get the current link status
+ ///
+ LinkStatus = MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_LSTS_OFFSET);
+ ///
+ /// No need to margin if couldn't get to Gen3 with this preset
+ ///
+ if ((LinkStatus & 0x0F) != 3) {
+ RecoverLinkFailure (PeiServices, SaPlatformPolicyPpi, SaDataHob, StallPpi,
+ &((PortInfoList[PortIndex]).PegPort), 3,
+ GetNegotiatedWidth (&((PortInfoList[PortIndex]).PegPort)));
+ LinkStatus = MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_LSTS_OFFSET);
+ if ((LinkStatus & 0x0F) != 3) {
+ (PortInfoList[PortIndex]).SkipMargin = TRUE;
+ continue;
+ }
+ }
+
+ NominalRecoveryCount = SaPcieGetErrorCount (MonitorPort, PegFunc);
+ StallPpi->Stall (PeiServices, StallPpi, SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearchDwellTime * STALL_ONE_MICRO_SECOND);
+ NominalRecoveryCount = SaPcieGetErrorCount (MonitorPort, PegFunc) - NominalRecoveryCount;
+ if (NominalRecoveryCount > 0) {
+ (PortInfoList[PortIndex]).SkipMargin = TRUE;
+ continue;
+ }
+ (PortInfoList[PortIndex]).FoundUsablePreset = TRUE;
+ } ///< End of for each Port
+
+ Status = RunMarginTest (
+ PeiServices,
+ SaPlatformPolicyPpi,
+ SaDataHob,
+ StallPpi,
+ MonitorPort,
+ &(PortInfoList[0]),
+ PortInfoListLength,
+ LaneLevelRxJitter,
+ MarginData[Index].TimingMargin
+ );
+
+ if (EFI_ERROR (Status)) {
+ for (TempIndex = 0; TempIndex < SA_PEG_MAX_LANE; TempIndex++) {
+ MarginData[Index].TimingMargin[TempIndex] = 0;
+ }
+ }
+ } ///< Presets Loop end
+
+ McD1PciCfg32And (R_SA_PEG_REUT_PH_CTR_OFFSET, ~B_SA_PEG_REUT_PH_CTR_AUTOCOMP_MASK);
+ CloseMonitor (SaPlatformPolicyPpi, MonitorPort);
+
+ ///
+ /// Find the preset with the maximum margin (largest of all margin values)
+ ///
+ for (Index = 0; Index < sizeof (MarginData) / sizeof (MarginData[0]); Index++) {
+ for (Lane = 0; Lane < SA_PEG_MAX_LANE; Lane++) {
+ LaneScores[Lane] = -1;
+ }
+ for (Lane = 0; Lane < SA_PEG_MAX_LANE; Lane++) {
+ if (MarginData[Index].TimingMargin[Lane] != -1) {
+ MarginScore = MarginData[Index].TimingMargin[Lane];
+ LaneScores[Lane] = MarginScore;
+ }
+ if (LaneScores[Lane] > BestScores[Lane]) {
+ BestScores[Lane] = LaneScores[Lane];
+ BestPresets[Lane] = MarginData[Index].Preset;
+ }
+ } ///< End of for each Lane
+ } ///< End of for each Preset
+
+ ///
+ /// If Lanes 0-1 were skipped, copy the values from Lane 2
+ ///
+ if (SkipBundle0) {
+ for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) {
+ PegFunc = (PortInfoList[PortIndex]).PegPort.Function;
+ switch (PegFunc) {
+ default:
+ case 0:
+ Lane = 2;
+ FirstSkippedLane = 0;
+ LastSkippedLane = 1;
+ break;
+ case 1:
+ Lane = 10;
+ FirstSkippedLane = 8;
+ LastSkippedLane = 9;
+ break;
+ case 2:
+ Lane = 14;
+ FirstSkippedLane = 12;
+ LastSkippedLane = 13;
+ break;
+ }
+ if (BestScores[Lane] != -1) {
+ DEBUG ((EFI_D_INFO, "Using Lane %2d's Best Preset for Lanes %2d-%2d.\n", Lane, FirstSkippedLane, LastSkippedLane));
+ for (TempIndex = FirstSkippedLane; TempIndex <= LastSkippedLane; TempIndex++) {
+ BestScores[TempIndex] = BestScores[Lane];
+ BestPresets[TempIndex] = BestPresets[Lane];
+ }
+ }
+ } ///< End of for each port
+ } ///< End of SkipBundle0
+ } ///< End of AnyMarginingNeeded
+
+ for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) {
+ PegBus = (PortInfoList[PortIndex]).PegPort.Bus;
+ PegDev = (PortInfoList[PortIndex]).PegPort.Device;
+ PegFunc = (PortInfoList[PortIndex]).PegPort.Function;
+ if (!(PortInfoList[PortIndex]).LinkIsGen3Capable) {
+ continue;
+ }
+ if (SkipBundle0) {
+ switch (PegFunc) {
+ default:
+ case 0:
+ FirstSkippedLane = 0;
+ LastSkippedLane = 1;
+ break;
+ case 1:
+ FirstSkippedLane = 8;
+ LastSkippedLane = 9;
+ break;
+ case 2:
+ FirstSkippedLane = 12;
+ LastSkippedLane = 13;
+ break;
+ }
+ for (TempIndex = FirstSkippedLane; TempIndex <= LastSkippedLane; TempIndex++) {
+ BestPresets[TempIndex] = SelectBestPresetForLane (
+ &(PortInfoList[PortIndex]),
+ TempIndex,
+ SaPlatformPolicyPpi,
+ SaDataHob,
+ BestPresets[TempIndex]
+ );
+ }
+ }
+ for (TempIndex = 0; TempIndex < (PortInfoList[PortIndex]).LaneListLength; TempIndex++) {
+ BestPresets[(PortInfoList[PortIndex]).LaneList[TempIndex]] = SelectBestPresetForLane (
+ &(PortInfoList[PortIndex]),
+ (PortInfoList[PortIndex]).LaneList[TempIndex],
+ SaPlatformPolicyPpi,
+ SaDataHob,
+ BestPresets[(PortInfoList[PortIndex]).LaneList[TempIndex]]
+ );
+ }
+ }
+
+ ///
+ /// Program the presets. If any link was margined, also reset the
+ /// endpoints in order to return the endpoints to a known-good state.
+ ///
+ if (AnyMarginingNeeded) {
+ for (TempIndex = 0; TempIndex < SA_PEG_MAX_FUN; TempIndex++) {
+ MmPci16Or (0, SA_PEG_BUS_NUM, SA_PEG_DEV_NUM, TempIndex, R_SA_PEG_LCTL_OFFSET, BIT4);
+ }
+ AssertPegSlotReset (SaPlatformPolicyPpi);
+ }
+ for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) {
+ PegBus = (PortInfoList[PortIndex]).PegPort.Bus;
+ PegDev = (PortInfoList[PortIndex]).PegPort.Device;
+ PegFunc = (PortInfoList[PortIndex]).PegPort.Function;
+ if (!(PortInfoList[PortIndex]).LinkIsGen3Capable) {
+ DEBUG ((EFI_D_INFO, "PEG%d%d - Not Gen3 capable, skip coefficient programming.\n", PegDev, PegFunc));
+ continue;
+ }
+ ///
+ /// Find first lane of the port for coefficient programming
+ ///
+ switch (PegFunc) {
+ default:
+ case 0:
+ Lane = 0;
+ FirstSkippedLane = 0;
+ LastSkippedLane = 1;
+ break;
+ case 1:
+ Lane = 8;
+ FirstSkippedLane = 8;
+ LastSkippedLane = 9;
+ break;
+ case 2:
+ Lane = 12;
+ FirstSkippedLane = 12;
+ LastSkippedLane = 13;
+ break;
+ }
+ ///
+ /// Get FullSwing
+ ///
+ GetLinkPartnerFullSwing (Lane, &FullSwing);
+
+ if (SkipBundle0) {
+ for (TempIndex = FirstSkippedLane; TempIndex <= LastSkippedLane; TempIndex++) {
+ GetCoefficientsFromPreset (BestPresets[TempIndex], FullSwing, &PreCursor, &Cursor, &PostCursor);
+ SetPartnerTxCoefficients (TempIndex, &PreCursor, &Cursor, &PostCursor);
+ ProgramPreset (1, BestPresets[TempIndex], PegFunc, TempIndex);
+ }
+ }
+ for (TempIndex = 0; TempIndex < (PortInfoList[PortIndex]).LaneListLength; TempIndex++) {
+ ///
+ /// Get Coefficients
+ ///
+ GetCoefficientsFromPreset (BestPresets[((PortInfoList[PortIndex]).LaneList[TempIndex])], FullSwing, &PreCursor, &Cursor, &PostCursor);
+
+ ///
+ /// Set Lane's Coefficients
+ ///
+ SetPartnerTxCoefficients ((PortInfoList[PortIndex]).LaneList[TempIndex], &PreCursor, &Cursor, &PostCursor);
+
+ ///
+ /// Set Phase 1 Presets
+ ///
+ ProgramPreset (1, BestPresets[((PortInfoList[PortIndex]).LaneList[TempIndex])], PegFunc, (PortInfoList[PortIndex]).LaneList[TempIndex]);
+ }
+
+ MmPci32Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCTL3_OFFSET, BIT0); ///< DOEQ
+ MmPci16Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCTL_OFFSET, BIT5); ///< Retrain link
+ }
+
+ if (AnyMarginingNeeded) {
+ StallPpi->Stall (PeiServices, StallPpi, 100 * STALL_ONE_MICRO_SECOND);
+ for (TempIndex = 0; TempIndex < SA_PEG_MAX_FUN; TempIndex++) {
+ MmPci16And (0, SA_PEG_BUS_NUM, SA_PEG_DEV_NUM, TempIndex, R_SA_PEG_LCTL_OFFSET, (UINT16) ~(BIT4));
+ }
+ DeassertPegSlotReset (SaPlatformPolicyPpi);
+ }
+
+ for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) {
+ PegBus = (PortInfoList[PortIndex]).PegPort.Bus;
+ PegDev = (PortInfoList[PortIndex]).PegPort.Device;
+ PegFunc = (PortInfoList[PortIndex]).PegPort.Function;
+ WaitForL0 (PeiServices, StallPpi, &(PortInfoList[PortIndex].PegPort), FALSE);
+ ReportPcieLinkStatus (PegBus, PegDev, PegFunc);
+ }
+
+ DEBUG ((EFI_D_INFO, "PEG Gen3 Preset Search done\n\n"));
+
+ return;
+}
+
+BOOLEAN
+SaPolicyEnablesGen3 (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+{
+ UINTN PegPortGenx;
+ BOOLEAN Gen3Enabled;
+ UINT8 Index;
+
+ Gen3Enabled = FALSE;
+
+ ///
+ /// Check if Gen3 is enabled on PEG10/11/12
+ ///
+ for (Index = 0; Index < SA_PEG_MAX_FUN; Index++) {
+ ///
+ /// PegPortGenx: 0 = Auto, 1 = Gen1, 2 = Gen2, 3 = Gen3
+ ///
+ PegPortGenx = SaPlatformPolicyPpi->PcieConfig->PegGenx[Index];
+
+ ///
+ /// Check if the root port is present and the speed is not limited to Gen1/Gen2
+ ///
+ if ((PegPortGenx == PEG_AUTO) || (PegPortGenx == PEG_GEN3)) {
+ Gen3Enabled = TRUE;
+ break;
+ }
+ }
+ return Gen3Enabled;
+}
+
+#endif // PEG_FLAG