Context: Following a reset of the RTC (Real Time Clock),
subr_rtc.c:inittoddr is invoked to reset the system clock. The FBclock
is reset by a call to tc_setclock, then the FFclock by a call to
ffclock_reset_clock. The current implemention has several issues that
this commit corrects. Recall that the system clock can be powered by
either the FBclock or FFclock and that this can be changed at any time,
it is important that the two be as aligned as practicable, in particular
with respect to uptime.
sysclock alignment :
To manage FFclock resets within a coherent framework, with maximum
consistency with the FBclock, all reset intelligence has been relocated
within a reset_FBbootime branch of ffclock_windup. This had multiple
advantages:
i) integration of reset control: flow of control for FBclock reset is
inittoddr tc_setclock mtx_lock_spin(&tc_setclock_mtx); tc_windup(&new_boottimebin); mtx_unlock_spin(&tc_setclock_mtx); In addition to new_boottimebin, tc_windup calculates the corresponding FBclock reset UTC value. The call to ffclock_windup has been repositioned within tc_windup and expanded to : ffclock_windup(delta, *reset_FBbootime, *reset_UTC) to take avantage of both of these. Within ffclock_windup, the reset case is now explicitly captured by the reset_FBbootime branch. Within it all FFclock absolute time clocks are set to correspond exactly to the FBclock UTC clock. Uptime setting however now depends on the active value of sysclock, as explained in the comments, in order to minimize issues under sysclock changes. As a result, FFclock code has been removed from subr_rtc.c, and both FB and FF clock families are reset together within the same tc-tick, effectively synchronously due to the tc_setclock_mtx protection. Verbosity is added to track the UTC and uptime impacts of the reset, a rare event. NOTE: even diffFFC is jumped following a reset. This is because a reset typically implies a sleep even where the counter itself stops. This breaks the diffFFC paradigm. The diffFFC should not be used to calculate time differences across a reset event.
ii) elimination of delayed signalling logic: previously the reset case
was signalled to ffclock_windup via a special value (ffclock_updated = INT8_MAX;) set within ffclock_reset_clock. This was detected in the ffclock_updated>0 branch on a subsequent tick, but not all of the reinitializations required were performed, some calculations were superfluous, and the ffclock_updated based management could fail in some corner cases. Now a dedicated full reinitialization is performed within the reset_FBbootime branch, the logic is clearer and corner cases are eliminated.
iii) bug fix: previously in ffclock_reset_clock ffclock_boottime was
set to the RTC reset value. This caused uptime values to jump to erroneous values that could cause kernel freezes when sysclock was switched from FBclock to FFclock. The new structure prevents this.
monoFFC jumping code:
The monoFFC exceptional case jumping code has been enhanced:
- removal of the FFCLOCK_STA_WARMUP test, since a RTC reset can occur at any time and will typically trigger the need for this case.
- verbosity allowing uptime continuity to be tracked across a jump.
FF daemon feedback:
The FFclock reset events in ffclock_windup (RTC resets) and
ffclock_change_tc (counter change) each modify the current value of the
natFFC data in fftimehands->cest . To communicate these important (and
hopefully very rare) events to the FFclock daemon (for example by the
test secs_to_nextupdate == 0), pushing of the reset structure to the
global ffclock_estimate has been added.
Each of these functions is called within tc_windup, where the spin lock
tc_setclock_mtx is held. This requires that ffclock_mtx be changed to a
spinlock (since a non-spin lock can sleep, which generates a kernel
panic). This should not increase overheads since tc_setclock_mtx has
already blocked interrupts, and the critical section for ffclock_mtx is
just a memcpy and an assignment and so will execute deterministically.