diff --git a/clock.c b/clock.c index cc692e9..eceedc5 100644 --- a/clock.c +++ b/clock.c @@ -1070,6 +1070,8 @@ enum servo_state clock_synchronize(struct clock *c, break; case SERVO_LOCKED: clockadj_set_freq(c->clkid, -adj); + if (c->clkid == CLOCK_REALTIME) + sysclk_set_sync(); break; } return state; diff --git a/clockadj.c b/clockadj.c index 74963c8..b0505b7 100644 --- a/clockadj.c +++ b/clockadj.c @@ -25,6 +25,8 @@ #define NS_PER_SEC 1000000000LL +static int realtime_leap_bit; + void clockadj_set_freq(clockid_t clkid, double freq) { struct timex tx; @@ -94,6 +96,7 @@ void sysclk_set_leap(int leap) pr_err("failed to set the clock status: %m"); else if (m) pr_notice(m); + realtime_leap_bit = tx.status; } int sysclk_max_freq(void) @@ -110,3 +113,17 @@ int sysclk_max_freq(void) f = 500000; return f; } + +void sysclk_set_sync(void) +{ + clockid_t clkid = CLOCK_REALTIME; + struct timex tx; + memset(&tx, 0, sizeof(tx)); + /* Clear the STA_UNSYNC flag from the status and keep the maxerror + value (which is increased automatically by 500 ppm) below 16 seconds + to avoid getting the STA_UNSYNC flag back. */ + tx.modes = ADJ_STATUS | ADJ_MAXERROR; + tx.status = realtime_leap_bit; + if (clock_adjtime(clkid, &tx) < 0) + pr_err("failed to set clock status and maximum error: %m"); +} diff --git a/clockadj.h b/clockadj.h index 3779f03..79ae80d 100644 --- a/clockadj.h +++ b/clockadj.h @@ -57,4 +57,9 @@ void sysclk_set_leap(int leap); */ int sysclk_max_freq(void); +/** + * Mark the system clock as synchronized to let the kernel synchronize + * the real-time clock (RTC) to it. + */ +void sysclk_set_sync(void); #endif diff --git a/phc2sys.c b/phc2sys.c index 076840c..93495a4 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -187,6 +187,8 @@ static void update_clock(struct clock *clock, /* Fall through. */ case SERVO_LOCKED: clockadj_set_freq(clock->clkid, -ppb); + if (clock->clkid == CLOCK_REALTIME) + sysclk_set_sync(); break; }