Commit 936cc855 authored by Martin Schwidefsky's avatar Martin Schwidefsky

s390/time: add leap seconds to initial system time

The PTFF instruction can be used to retrieve information about UTC
including the current number of leap seconds. Use this value to
convert the coordinated server time value of the TOD clock to a
proper UTC timestamp to initialize the system time. Without this
correction the system time will be off by the number of leap seonds
until it has been corrected via NTP.
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 40277891
...@@ -56,11 +56,13 @@ void __init ptff_init(void); ...@@ -56,11 +56,13 @@ void __init ptff_init(void);
extern unsigned char ptff_function_mask[16]; extern unsigned char ptff_function_mask[16];
extern unsigned long lpar_offset; extern unsigned long lpar_offset;
extern unsigned long initial_leap_seconds;
/* Function codes for the ptff instruction. */ /* Function codes for the ptff instruction. */
#define PTFF_QAF 0x00 /* query available functions */ #define PTFF_QAF 0x00 /* query available functions */
#define PTFF_QTO 0x01 /* query tod offset */ #define PTFF_QTO 0x01 /* query tod offset */
#define PTFF_QSI 0x02 /* query steering information */ #define PTFF_QSI 0x02 /* query steering information */
#define PTFF_QUI 0x04 /* query UTC information */
#define PTFF_ATO 0x40 /* adjust tod offset */ #define PTFF_ATO 0x40 /* adjust tod offset */
#define PTFF_STO 0x41 /* set tod offset */ #define PTFF_STO 0x41 /* set tod offset */
#define PTFF_SFS 0x42 /* set fine steering rate */ #define PTFF_SFS 0x42 /* set fine steering rate */
...@@ -82,6 +84,22 @@ static inline int ptff_query(unsigned int nr) ...@@ -82,6 +84,22 @@ static inline int ptff_query(unsigned int nr)
return (*ptr & (0x80 >> (nr & 7))) != 0; return (*ptr & (0x80 >> (nr & 7))) != 0;
} }
/* Query UTC information result */
struct ptff_qui {
unsigned int tm : 2;
unsigned int ts : 2;
unsigned int : 28;
unsigned int pad_0x04;
unsigned long leap_event;
short old_leap;
short new_leap;
unsigned int pad_0x14;
unsigned long prt[5];
unsigned long cst[3];
unsigned int skew;
unsigned int pad_0x5c[41];
} __packed;
static inline int ptff(void *ptff_block, size_t len, unsigned int func) static inline int ptff(void *ptff_block, size_t len, unsigned int func)
{ {
typedef struct { char _[len]; } addrtype; typedef struct { char _[len]; } addrtype;
......
...@@ -64,6 +64,7 @@ EXPORT_SYMBOL(s390_epoch_delta_notifier); ...@@ -64,6 +64,7 @@ EXPORT_SYMBOL(s390_epoch_delta_notifier);
unsigned char ptff_function_mask[16]; unsigned char ptff_function_mask[16];
unsigned long lpar_offset; unsigned long lpar_offset;
unsigned long initial_leap_seconds;
/* /*
* Get time offsets with PTFF * Get time offsets with PTFF
...@@ -71,6 +72,7 @@ unsigned long lpar_offset; ...@@ -71,6 +72,7 @@ unsigned long lpar_offset;
void __init ptff_init(void) void __init ptff_init(void)
{ {
struct ptff_qto qto; struct ptff_qto qto;
struct ptff_qui qui;
if (!test_facility(28)) if (!test_facility(28))
return; return;
...@@ -79,6 +81,11 @@ void __init ptff_init(void) ...@@ -79,6 +81,11 @@ void __init ptff_init(void)
/* get LPAR offset */ /* get LPAR offset */
if (ptff_query(PTFF_QTO) && ptff(&qto, sizeof(qto), PTFF_QTO) == 0) if (ptff_query(PTFF_QTO) && ptff(&qto, sizeof(qto), PTFF_QTO) == 0)
lpar_offset = qto.tod_epoch_difference; lpar_offset = qto.tod_epoch_difference;
/* get initial leap seconds */
if (ptff_query(PTFF_QUI) && ptff(&qui, sizeof(qui), PTFF_QUI) == 0)
initial_leap_seconds = (unsigned long)
((long) qui.old_leap * 4096000000L);
} }
/* /*
...@@ -200,12 +207,18 @@ static void stp_reset(void); ...@@ -200,12 +207,18 @@ static void stp_reset(void);
void read_persistent_clock64(struct timespec64 *ts) void read_persistent_clock64(struct timespec64 *ts)
{ {
tod_to_timeval(get_tod_clock() - TOD_UNIX_EPOCH, ts); __u64 clock;
clock = get_tod_clock() - initial_leap_seconds;
tod_to_timeval(clock - TOD_UNIX_EPOCH, ts);
} }
void read_boot_clock64(struct timespec64 *ts) void read_boot_clock64(struct timespec64 *ts)
{ {
tod_to_timeval(sched_clock_base_cc - TOD_UNIX_EPOCH, ts); __u64 clock;
clock = sched_clock_base_cc - initial_leap_seconds;
tod_to_timeval(clock - TOD_UNIX_EPOCH, ts);
} }
static cycle_t read_tod_clock(struct clocksource *cs) static cycle_t read_tod_clock(struct clocksource *cs)
......
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