[TGL] Fix infinite reset loop caused by bad DSO

This patch solves an infinite reset loop issue caused
by bad DSO with the scenario:
  After platform reset (due to WDT timeout), FSPm asks
  for another reset, but before that, WDT_FLAG_TCC_DSO_IN_PROGRESS
  is already cleaned. As a result, in the thrid reset, stage1B
  will have no idea about the DSO is corrupted and it
  continues boot with Tcc Tuning flow, which causes WDT
  timeout reset again.

This patch introduces a WDT_FLAG_TCC_BAD_DSO flag in WDT
scrachpad (bit 18). The flag is a marker that is set when
a bad DSO is detected. The new booting flow for "bad DSO" case
if Tcc_Tuning enabled will be:

  1st boot: (after fwupdate)
     - TCC_DSO and WDT set by stage1b and stage2
     - FSP hangs and trigger WDT reset
  2nd boot:
     - Stage1b detects "bad DSO" because of WDT and
       TCC_DSO_IN_PROGRESS. For this case:
         Clear TCC_DSO_IN_PROGRESS and WDT.
         Set TCC_BAD_DSO.
       Then it continues boot that will skip Tcc Tuning
       (because of TCC_DSO_IN_PROGRESS unset)
     - FSPm asks for a reset
  3rd boot:
     - Stage1b detects "bad DSO" because of TCC_BAD_DSO
       It continues boot that will skip Tcc Tuning
       (because of TCC_DSO_IN_PROGRESS unset)

The patch does not remove the 200-sec abnormal boot-up symptom
because the symptom is noticeable to user. So user can be aware
of something wrong (bad DSO).

The "bad DSO" flag will be clear before fwupdate, so a fwupdate
with a correct DSO can solve the 200 sec abnormal boot up time.

Signed-off-by: Stanley Chang <stanley.chang@intel.com>
This commit is contained in:
Stanley Chang 2021-12-09 12:25:38 +08:00 committed by Maurice Ma
parent 1e5a04030c
commit bfbc7943e0
4 changed files with 65 additions and 21 deletions

View File

@ -108,13 +108,15 @@ TccModePreMemConfig (
DEBUG ((DEBUG_INFO, "S0ix is turned off when TCC is enabled\n"));
}
if (IsWdtFlagsSet(WDT_FLAG_TCC_DSO) && IsWdtTimeout()) {
DEBUG ((DEBUG_INFO, "Incorrect TCC tuning parameters. Platform rebooted with default values.\n"));
WdtClearFlags (WDT_FLAG_TCC_DSO);
if (IsWdtFlagsSet(WDT_FLAG_TCC_BAD_DSO) ||
(IsWdtFlagsSet(WDT_FLAG_TCC_DSO_IN_PROGRESS) && IsWdtTimeout())) {
DEBUG ((DEBUG_ERROR, "Incorrect TCC tuning parameters. Platform rebooted with default values.\n"));
WdtClearScratchpad (WDT_FLAG_TCC_DSO_IN_PROGRESS);
WdtSetScratchpad (WDT_FLAG_TCC_BAD_DSO);
FspmUpd->FspmConfig.TccStreamCfgStatusPreMem = 1;
} else if (TccCfgData->TccTuning != 0) {
// Setup Watch dog timer
WdtReloadAndStart (WDT_TIMEOUT_TCC_DSO, WDT_FLAG_TCC_DSO);
WdtReloadAndStart (WDT_TIMEOUT_TCC_DSO, WDT_FLAG_TCC_DSO_IN_PROGRESS);
// Load TCC stream config from container
TccStreamBase = NULL;

View File

@ -902,8 +902,8 @@ BoardInit (
Status = PcdSet32S (PcdAcpiTableTemplatePtr, (UINT32)(UINTN)mPlatformAcpiTables);
break;
case PostSiliconInit:
if (IsWdtFlagsSet(WDT_FLAG_TCC_DSO)) {
WdtDisable (WDT_FLAG_TCC_DSO);
if (IsWdtFlagsSet(WDT_FLAG_TCC_DSO_IN_PROGRESS)) {
WdtDisable (WDT_FLAG_TCC_DSO_IN_PROGRESS);
}
// Set TSEG base/size PCD
TsegBase = MmioRead32 (TO_MM_PCI_ADDRESS (0x00000000) + R_SA_TSEGMB) & ~0xF;
@ -1024,6 +1024,9 @@ BoardInit (
case ReadyToBoot:
if ((GetBootMode() != BOOT_ON_FLASH_UPDATE) && (GetPayloadId() == 0)) {
ProgramSecuritySetting ();
} else if (GetBootMode() == BOOT_ON_FLASH_UPDATE) {
/* clear bad DSO mark (if have), so next boot is a fresh restart */
WdtClearScratchpad (WDT_FLAG_TCC_BAD_DSO);
}
break;
@ -1190,7 +1193,7 @@ TccModePostMemConfig (
FspsUpd->FspsConfig.TccErrorLogEn = TccCfgData->TccErrorLog;
FspsUpd->FspsConfig.IfuEnable = 0;
if (!IsWdtFlagsSet(WDT_FLAG_TCC_DSO)) {
if (!IsWdtFlagsSet(WDT_FLAG_TCC_DSO_IN_PROGRESS)) {
//
// If FSPM doesn't enable TCC DSO timer, FSPS should also skip TCC DSO.
//
@ -1198,7 +1201,7 @@ TccModePostMemConfig (
FspsUpd->FspsConfig.TccStreamCfgStatus = 1;
} else if (TccCfgData->TccTuning != 0) {
// Reload Watch dog timer
WdtReloadAndStart (WDT_TIMEOUT_TCC_DSO, WDT_FLAG_TCC_DSO);
WdtReloadAndStart (WDT_TIMEOUT_TCC_DSO, WDT_FLAG_TCC_DSO_IN_PROGRESS);
// Load TCC stream config from container
TccStreamBase = NULL;

View File

@ -8,9 +8,9 @@
#ifndef WATCH_DOG_TIMBER_LIB_H_
#define WATCH_DOG_TIMBER_LIB_H_
#define WDT_TIMEOUT_TCC_DSO 200 // 200 seconds
#define WDT_FLAG_TCC_DSO BIT17
#define WDT_FLAG_MASK BIT17
#define WDT_TIMEOUT_TCC_DSO 200 // 200 seconds
#define WDT_FLAG_TCC_DSO_IN_PROGRESS BIT17
#define WDT_FLAG_TCC_BAD_DSO BIT18
/**
@ -44,14 +44,26 @@ WdtDisable (
/**
Clear WDT timer flags.
Clear WDT flags in scratchpad
@param[in] Flags The timer flags that would be cleared.
@param[in] Flags The scratchpad flags that would be cleared.
**/
VOID
EFIAPI
WdtClearFlags (
WdtClearScratchpad (
IN UINT32 Flags
);
/**
Set WDT flags in scratchpad
@param[in] Flags The scratchpad flags that would be set.
**/
VOID
EFIAPI
WdtSetScratchpad (
IN UINT32 Flags
);

View File

@ -22,6 +22,7 @@
#define B_ACPI_IO_OC_WDT_CTL_ICCSURV BIT13
#define B_ACPI_IO_OC_WDT_CTL_LCK BIT12
#define B_ACPI_IO_OC_WDT_CTL_TOV_MASK 0x3FF
#define B_ACPI_IO_OC_WDT_CTL_SCRATCHPAD_MASK 0xFF0000
/**
@ -62,7 +63,8 @@ WdtReloadAndStart (
}
Readback = IoRead32 (WdtGetAddress ());
Readback |= (B_ACPI_IO_OC_WDT_CTL_EN | B_ACPI_IO_OC_WDT_CTL_ICCSURV | (Flags & WDT_FLAG_MASK));
Readback |= (B_ACPI_IO_OC_WDT_CTL_EN | B_ACPI_IO_OC_WDT_CTL_ICCSURV |
(Flags & B_ACPI_IO_OC_WDT_CTL_SCRATCHPAD_MASK));
Readback &= ~(B_ACPI_IO_OC_WDT_CTL_TOV_MASK);
Readback |= ((TimeoutValue - 1) & B_ACPI_IO_OC_WDT_CTL_TOV_MASK);
@ -88,7 +90,7 @@ WdtDisable (
UINT32 Readback;
Readback = IoRead32 (WdtGetAddress ());
Readback &= ~(B_ACPI_IO_OC_WDT_CTL_EN | (Flags & WDT_FLAG_MASK));
Readback &= ~(B_ACPI_IO_OC_WDT_CTL_EN | (Flags & B_ACPI_IO_OC_WDT_CTL_SCRATCHPAD_MASK));
// Clear the status bits
Readback |= (B_ACPI_IO_OC_WDT_CTL_ICCSURV_STS | B_ACPI_IO_OC_WDT_CTL_NO_ICCSURV_STS);
@ -98,21 +100,46 @@ WdtDisable (
/**
Clear WDT timer flags.
Clear WDT flags in scratchpad
@param[in] Flags The timer flags that would be cleared.
@param[in] Flags The scratchpad flags that would be cleared.
**/
VOID
EFIAPI
WdtClearFlags (
WdtClearScratchpad (
IN UINT32 Flags
)
{
UINT32 Readback;
Readback = IoRead32 (WdtGetAddress ());
Readback &= ~(Flags & WDT_FLAG_MASK);
/* only clear flags in scratchpad */
Readback &= ~(Flags & B_ACPI_IO_OC_WDT_CTL_SCRATCHPAD_MASK);
/* exclude status fields */
Readback &= ~(B_ACPI_IO_OC_WDT_CTL_ICCSURV_STS | B_ACPI_IO_OC_WDT_CTL_NO_ICCSURV_STS);
IoWrite32 (WdtGetAddress (), Readback);
}
/**
Set WDT flags in scratchpad
@param[in] Flags The scratchpad flags that would be set.
**/
VOID
EFIAPI
WdtSetScratchpad (
IN UINT32 Flags
)
{
UINT32 Readback;
Readback = IoRead32 (WdtGetAddress ());
/* only set flags in scratchpad */
Readback |= (Flags & B_ACPI_IO_OC_WDT_CTL_SCRATCHPAD_MASK);
/* exclude status fields */
Readback &= ~(B_ACPI_IO_OC_WDT_CTL_ICCSURV_STS | B_ACPI_IO_OC_WDT_CTL_NO_ICCSURV_STS);
IoWrite32 (WdtGetAddress (), Readback);
}
@ -160,7 +187,7 @@ IsWdtFlagsSet (
Readback = IoRead32 (WdtGetAddress ());
if ((Readback & (Flags & WDT_FLAG_MASK)) != 0) {
if ((Readback & Flags) != 0) {
return TRUE;
} else {
return FALSE;