Commit b2f4280d authored by Sven Meier's avatar Sven Meier

utc&leap: fixed kernel issue with leap second handling

kernel has two bugs regarding leap second handling: it need to have the
leap second flags cleared twice before setting them and it doesn't clear the leap second flags after the leap second happened. A workaround was implemented
accordingly.
parent c0c600ec
......@@ -170,6 +170,18 @@ void bmc_s1(struct pp_instance *ppi,
(seconds >= (60 - (2 * (1 << ppi->portDS->logAnnounceInterval))))) {
pp_diag(ppi, bmc, 2,
"Approaching midnight, not updating leap flags\n");
ret = ppi->t_ops->get_utc_offset(ppi, &offset, &leap59, &leap61);
if (ret) {
pp_diag(ppi, bmc, 1,
"Could not get UTC offset from system\n");
} else {
pp_diag(ppi, bmc, 3,
"Current UTC flags, "
"offset: %i, "
"leap59: %i, "
"leap61: %i\n",
offset, leap59, leap61);
}
} else {
ret = ppi->t_ops->get_utc_offset(ppi, &offset, &leap59, &leap61);
if (ret) {
......@@ -180,6 +192,12 @@ void bmc_s1(struct pp_instance *ppi,
prop->currentUtcOffset = frgn_master->currentUtcOffset;
} else {
pp_diag(ppi, bmc, 3,
"Current UTC flags, "
"offset: %i, "
"leap59: %i, "
"leap61: %i\n",
offset, leap59, leap61);
if (((leap59 != 0) != ((frgn_master->flagField[1] & FFB_LI59) != 0)) ||
((leap61 != 0) != ((frgn_master->flagField[1] & FFB_LI61) != 0)) ||
......@@ -201,7 +219,7 @@ void bmc_s1(struct pp_instance *ppi,
offset = prop->currentUtcOffset;
pp_diag(ppi, bmc, 1,
"UTC flags changed,"
"UTC flags changed, "
"offset: %i, "
"leap59: %i, "
"leap61: %i\n",
......@@ -227,6 +245,12 @@ void bmc_s1(struct pp_instance *ppi,
pp_diag(ppi, bmc, 1,
"Could not get UTC offset from system\n");
} else {
pp_diag(ppi, bmc, 3,
"Current UTC flags, "
"offset: %i, "
"leap59: %i, "
"leap61: %i\n",
offset, leap59, leap61);
prop->currentUtcOffset = offset;
}
prop->leap59 = FALSE;
......
......@@ -23,6 +23,32 @@ static void clock_fatal_error(char *context)
exit(1);
}
static void unix_time_clear_utc_flags(void)
{
struct timex t;
/*
* We have to call adjtime twice here, as kernels
* prior to 6b1859dba01c7 (included in 3.5 and
* -stable), had an issue with the state machine
* and wouldn't clear the STA_INS/DEL flag directly.
*/
t.modes = ADJ_STATUS;
t.status = STA_PLL;
adjtimex(&t);
/* Clear maxerror, as it can cause UNSYNC to be set */
t.modes = ADJ_MAXERROR;
t.maxerror = 0;
adjtimex(&t);
/* Clear the status */
t.modes = ADJ_STATUS;
t.status = 0;
adjtimex(&t);
}
static int unix_time_get_utc_time(struct pp_instance *ppi, int *hours, int *minutes, int *seconds)
{
int ret;
......@@ -35,8 +61,8 @@ static int unix_time_get_utc_time(struct pp_instance *ppi, int *hours, int *minu
ret = adjtimex(&t);
if (ret >= 0) {
now = t.time.tv_sec;
/* use localtime for correct leap handling */
date = localtime(&now);
/* use gmtime for correct leap handling */
date = gmtime(&now);
*hours = date->tm_hour;
*minutes = date->tm_min;
*seconds = date->tm_sec;
......@@ -55,22 +81,32 @@ static int unix_time_get_utc_offset(struct pp_instance *ppi, int *offset, int *l
{
int ret;
struct timex t;
int hours, minutes, seconds;
unix_time_get_utc_time(ppi, &hours, &minutes, &seconds);
/*
* Get the UTC/TAI difference
*/
memset(&t, 0, sizeof(t));
ret = adjtimex(&t);
if (ret >= 0) {
if ((t.status & STA_INS) == STA_INS) {
*leap59 = 0;
*leap61 = 1;
} else if ((t.status & STA_DEL) == STA_DEL) {
*leap59 = 1;
*leap61 = 0;
if (hours >= 12) {
if ((t.status & STA_INS) == STA_INS) {
*leap59 = 0;
*leap61 = 1;
} else if ((t.status & STA_DEL) == STA_DEL) {
*leap59 = 1;
*leap61 = 0;
} else {
*leap59 = 0;
*leap61 = 0;
}
} else {
unix_time_clear_utc_flags();
*leap59 = 0;
*leap61 = 0;
}
}
/*
* Our WRS kernel has tai support, but our compiler does not.
* We are 32-bit only, and we know for sure that tai is
......@@ -89,8 +125,10 @@ static int unix_time_get_utc_offset(struct pp_instance *ppi, int *offset, int *l
static int unix_time_set_utc_offset(struct pp_instance *ppi, int offset, int leap59, int leap61)
{
struct timex t;
int ret;
int ret;
unix_time_clear_utc_flags();
/* get the current flags first */
memset(&t, 0, sizeof(t));
ret = adjtimex(&t);
......
......@@ -265,7 +265,6 @@ static int wrs_time_set(struct pp_instance *ppi, const struct pp_time *t)
{
struct pp_time diff, now;
struct timex tx;
int tai_offset = 0;
int msec;
/*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment