diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/s390/include/asm/timex.h | 18 | ||||
-rw-r--r-- | arch/s390/kernel/time.c | 17 |
2 files changed, 33 insertions, 2 deletions
diff --git a/arch/s390/include/asm/timex.h b/arch/s390/include/asm/timex.h index 0f34db4..0bb08f3 100644 --- a/arch/s390/include/asm/timex.h +++ b/arch/s390/include/asm/timex.h @@ -56,11 +56,13 @@ void __init ptff_init(void); extern unsigned char ptff_function_mask[16]; extern unsigned long lpar_offset; +extern unsigned long initial_leap_seconds; /* Function codes for the ptff instruction. */ #define PTFF_QAF 0x00 /* query available functions */ #define PTFF_QTO 0x01 /* query tod offset */ #define PTFF_QSI 0x02 /* query steering information */ +#define PTFF_QUI 0x04 /* query UTC information */ #define PTFF_ATO 0x40 /* adjust tod offset */ #define PTFF_STO 0x41 /* set tod offset */ #define PTFF_SFS 0x42 /* set fine steering rate */ @@ -82,6 +84,22 @@ static inline int ptff_query(unsigned int nr) 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) { typedef struct { char _[len]; } addrtype; diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index d716236..1a27d4d 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -64,6 +64,7 @@ EXPORT_SYMBOL(s390_epoch_delta_notifier); unsigned char ptff_function_mask[16]; unsigned long lpar_offset; +unsigned long initial_leap_seconds; /* * Get time offsets with PTFF @@ -71,6 +72,7 @@ unsigned long lpar_offset; void __init ptff_init(void) { struct ptff_qto qto; + struct ptff_qui qui; if (!test_facility(28)) return; @@ -79,6 +81,11 @@ void __init ptff_init(void) /* get LPAR offset */ if (ptff_query(PTFF_QTO) && ptff(&qto, sizeof(qto), PTFF_QTO) == 0) 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); 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) { - 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) |