Skip to content

Commit

Permalink
PcAtChipsetPkg: Write RTC time in PcRtcInit() only when it is needed
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
chenlin3 authored and mergify[bot] committed Nov 13, 2024
1 parent df6b43f commit 2839fed
Showing 1 changed file with 81 additions and 37 deletions.
118 changes: 81 additions & 37 deletions PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -211,6 +272,9 @@ PcRtcInit (
UINT32 TimerVar;
BOOLEAN Enabled;
BOOLEAN Pending;
BOOLEAN NeedRtcUpdate;

NeedRtcUpdate = FALSE;

//
// Acquire RTC Lock to make access to RTC atomic
Expand Down Expand Up @@ -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;
}
}

//
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 ()) {
Expand Down Expand Up @@ -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;
}

Expand Down

0 comments on commit 2839fed

Please sign in to comment.