PcAtChipsetPkg: Write RTC time in PcRtcInit() only when it is needed

In PcRtcInit(), it always read RTC time and then write it back. It could
potentially cause two issues:
1) There is time gap between read RTC and write RTC, writing RTC time on
every boot could cause RTC time drift after many reboot cycles

2) Writing RTC registers on every boot could cause some unnecessary delay,
slightly impact the boot performance.

The change is only writing RTC time when 1) the current RTC time is not
valid or 2) the RegisterB value is changed.

Signed-off-by: Chen Lin Z <lin.z.chen@intel.com>
This commit is contained in:
Chen Lin Z 2024-10-31 12:46:14 +08:00 committed by mergify[bot]
parent df6b43f61b
commit 2839fed575
1 changed files with 81 additions and 37 deletions

View File

@ -188,6 +188,67 @@ RtcWrite (
}
}
/**
Sets the current local timezone & daylight information.
@param TimeZone Timezone info.
@param Daylight Daylight info.
@param Global For global use inside this module.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_DEVICE_ERROR The variable could not be set due due to hardware error.
**/
EFI_STATUS
PcRtcSetTimeZone (
IN INT16 TimeZone,
IN UINT8 Daylight,
IN PC_RTC_MODULE_GLOBALS *Global
)
{
EFI_STATUS Status;
UINT32 TimerVar;
ASSERT ((TimeZone == EFI_UNSPECIFIED_TIMEZONE) || ((TimeZone >= -1440) && (TimeZone <= 1440)));
ASSERT ((Daylight & (~(EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT))) == 0);
//
// Write timezone and daylight to RTC variable
//
if ((TimeZone == EFI_UNSPECIFIED_TIMEZONE) && (Daylight == 0)) {
Status = EfiSetVariable (
mTimeZoneVariableName,
&gEfiCallerIdGuid,
0,
0,
NULL
);
if (Status == EFI_NOT_FOUND) {
Status = EFI_SUCCESS;
}
} else {
TimerVar = Daylight;
TimerVar = (UINT32)((TimerVar << 16) | (UINT16)(TimeZone));
Status = EfiSetVariable (
mTimeZoneVariableName,
&gEfiCallerIdGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
sizeof (TimerVar),
&TimerVar
);
}
//
// Set the variable that contains the TimeZone and Daylight fields
//
if (!EFI_ERROR (Status)) {
Global->SavedTimeZone = TimeZone;
Global->Daylight = Daylight;
}
return Status;
}
/**
Initialize RTC.
@ -211,6 +272,9 @@ PcRtcInit (
UINT32 TimerVar;
BOOLEAN Enabled;
BOOLEAN Pending;
BOOLEAN NeedRtcUpdate;
NeedRtcUpdate = FALSE;
//
// Acquire RTC Lock to make access to RTC atomic
@ -324,21 +388,32 @@ PcRtcInit (
Time.Nanosecond = 0;
Time.TimeZone = EFI_UNSPECIFIED_TIMEZONE;
Time.Daylight = 0;
NeedRtcUpdate = TRUE;
}
//
// Set RTC configuration after get original time
// The value of bit AIE should be reserved.
//
RegisterB.Data = FixedPcdGet8 (PcdInitialValueRtcRegisterB) | (RegisterB.Data & BIT5);
RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);
if ((RegisterB.Data | BIT5) != (FixedPcdGet8 (PcdInitialValueRtcRegisterB) | BIT5)) {
RegisterB.Data = FixedPcdGet8 (PcdInitialValueRtcRegisterB) | (RegisterB.Data & BIT5);
RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);
NeedRtcUpdate = TRUE;
}
//
// Reset time value according to new RTC configuration
//
Status = PcRtcSetTime (&Time, Global);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
if (NeedRtcUpdate) {
Status = PcRtcSetTime (&Time, Global);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
} else {
Status = PcRtcSetTimeZone (Time.TimeZone, Time.Daylight, Global);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
}
//
@ -563,7 +638,6 @@ PcRtcSetTime (
EFI_TIME RtcTime;
RTC_REGISTER_A RegisterA;
RTC_REGISTER_B RegisterB;
UINT32 TimerVar;
if (Time == NULL) {
return EFI_INVALID_PARAMETER;
@ -598,31 +672,7 @@ PcRtcSetTime (
return Status;
}
//
// Write timezone and daylight to RTC variable
//
if ((Time->TimeZone == EFI_UNSPECIFIED_TIMEZONE) && (Time->Daylight == 0)) {
Status = EfiSetVariable (
mTimeZoneVariableName,
&gEfiCallerIdGuid,
0,
0,
NULL
);
if (Status == EFI_NOT_FOUND) {
Status = EFI_SUCCESS;
}
} else {
TimerVar = Time->Daylight;
TimerVar = (UINT32)((TimerVar << 16) | (UINT16)(Time->TimeZone));
Status = EfiSetVariable (
mTimeZoneVariableName,
&gEfiCallerIdGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
sizeof (TimerVar),
&TimerVar
);
}
Status = PcRtcSetTimeZone (Time->TimeZone, Time->Daylight, Global);
if (EFI_ERROR (Status)) {
if (!EfiAtRuntime ()) {
@ -677,12 +727,6 @@ PcRtcSetTime (
EfiReleaseLock (&Global->RtcLock);
}
//
// Set the variable that contains the TimeZone and Daylight fields
//
Global->SavedTimeZone = Time->TimeZone;
Global->Daylight = Time->Daylight;
return EFI_SUCCESS;
}