aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/time.c
diff options
context:
space:
mode:
authorDavid Hildenbrand <dahi@linux.vnet.ibm.com>2016-07-14 07:09:57 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2016-08-29 05:04:52 -0400
commit41ad022039522485456802f09d8eccebc24aac3e (patch)
treea685ba9aa893138539e05e54e6cbb8c47d02a7b3 /arch/s390/kernel/time.c
parent88bf46bfde1eaa5f27bc5df75912b1ab7c7baf7e (diff)
s390/time: simplify stp time syncs
The way we call do_adjtimex() today is broken. It has 0 effect, as ADJ_OFFSET_SINGLESHOT (0x0001) in the kernel maps to !ADJ_ADJTIME (in contrast to user space where it maps to ADJ_OFFSET_SINGLESHOT | ADJ_ADJTIME - 0x8001). !ADJ_ADJTIME will silently ignore all adjustments without STA_PLL being active. We could switch to ADJ_ADJTIME or turn STA_PLL on, but still we would run into some problems: - Even when switching to nanoseconds, we lose accuracy. - Successive calls to do_adjtimex() will simply overwrite any leftovers from the previous call (if not fully handled) - Anything that NTP does using the sysctl heavily interferes with our use. - !ADJ_ADJTIME will silently round stuff > or < than 0.5 seconds Reusing do_adjtimex() here just feels wrong. The whole STP synchronization works right now *somehow* only, as do_adjtimex() does nothing and our TOD clock jumps in time, although it shouldn't. This is especially bad as the clock could jump backwards in time. We will have to find another way to fix this up. As leap seconds are also not properly handled yet, let's just get rid of all this complex logic altogether and use the correct clock_delta for fixing up the clock comparator and keeping the sched_clock monotonic. This change should have 0 effect on the current STP mechanism. Once we know how to best handle sync events and leap second updates, we'll start with a fresh implementation. Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/time.c')
-rw-r--r--arch/s390/kernel/time.c50
1 files changed, 4 insertions, 46 deletions
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index 4e9949800562..c95e98d49b38 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -50,10 +50,6 @@
50#include <asm/cio.h> 50#include <asm/cio.h>
51#include "entry.h" 51#include "entry.h"
52 52
53/* change this if you have some constant time drift */
54#define USECS_PER_JIFFY ((unsigned long) 1000000/HZ)
55#define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12)
56
57u64 sched_clock_base_cc = -1; /* Force to data section. */ 53u64 sched_clock_base_cc = -1; /* Force to data section. */
58EXPORT_SYMBOL_GPL(sched_clock_base_cc); 54EXPORT_SYMBOL_GPL(sched_clock_base_cc);
59 55
@@ -318,43 +314,6 @@ void __init time_init(void)
318 vtime_init(); 314 vtime_init();
319} 315}
320 316
321/*
322 * The time is "clock". old is what we think the time is.
323 * Adjust the value by a multiple of jiffies and add the delta to ntp.
324 * "delay" is an approximation how long the synchronization took. If
325 * the time correction is positive, then "delay" is subtracted from
326 * the time difference and only the remaining part is passed to ntp.
327 */
328static unsigned long long adjust_time(unsigned long long old,
329 unsigned long long clock,
330 unsigned long long delay)
331{
332 unsigned long long delta, ticks;
333 struct timex adjust;
334
335 if (clock > old) {
336 /* It is later than we thought. */
337 delta = ticks = clock - old;
338 delta = ticks = (delta < delay) ? 0 : delta - delay;
339 delta -= do_div(ticks, CLK_TICKS_PER_JIFFY);
340 adjust.offset = ticks * (1000000 / HZ);
341 } else {
342 /* It is earlier than we thought. */
343 delta = ticks = old - clock;
344 delta -= do_div(ticks, CLK_TICKS_PER_JIFFY);
345 delta = -delta;
346 adjust.offset = -ticks * (1000000 / HZ);
347 }
348 sched_clock_base_cc += delta;
349 if (adjust.offset != 0) {
350 pr_notice("The ETR interface has adjusted the clock "
351 "by %li microseconds\n", adjust.offset);
352 adjust.modes = ADJ_OFFSET_SINGLESHOT;
353 do_adjtimex(&adjust);
354 }
355 return delta;
356}
357
358static DEFINE_PER_CPU(atomic_t, clock_sync_word); 317static DEFINE_PER_CPU(atomic_t, clock_sync_word);
359static DEFINE_MUTEX(clock_sync_mutex); 318static DEFINE_MUTEX(clock_sync_mutex);
360static unsigned long clock_sync_flags; 319static unsigned long clock_sync_flags;
@@ -582,7 +541,7 @@ void stp_queue_work(void)
582static int stp_sync_clock(void *data) 541static int stp_sync_clock(void *data)
583{ 542{
584 static int first; 543 static int first;
585 unsigned long long old_clock, delta, new_clock, clock_delta; 544 unsigned long long clock_delta;
586 struct clock_sync_data *stp_sync; 545 struct clock_sync_data *stp_sync;
587 struct ptff_qto qto; 546 struct ptff_qto qto;
588 int rc; 547 int rc;
@@ -605,18 +564,17 @@ static int stp_sync_clock(void *data)
605 if (stp_info.todoff[0] || stp_info.todoff[1] || 564 if (stp_info.todoff[0] || stp_info.todoff[1] ||
606 stp_info.todoff[2] || stp_info.todoff[3] || 565 stp_info.todoff[2] || stp_info.todoff[3] ||
607 stp_info.tmd != 2) { 566 stp_info.tmd != 2) {
608 old_clock = get_tod_clock();
609 rc = chsc_sstpc(stp_page, STP_OP_SYNC, 0, &clock_delta); 567 rc = chsc_sstpc(stp_page, STP_OP_SYNC, 0, &clock_delta);
610 if (rc == 0) { 568 if (rc == 0) {
611 new_clock = old_clock + clock_delta; 569 /* fixup the monotonic sched clock */
612 delta = adjust_time(old_clock, new_clock, 0); 570 sched_clock_base_cc += clock_delta;
613 if (ptff_query(PTFF_QTO) && 571 if (ptff_query(PTFF_QTO) &&
614 ptff(&qto, sizeof(qto), PTFF_QTO) == 0) 572 ptff(&qto, sizeof(qto), PTFF_QTO) == 0)
615 /* Update LPAR offset */ 573 /* Update LPAR offset */
616 lpar_offset = qto.tod_epoch_difference; 574 lpar_offset = qto.tod_epoch_difference;
617 atomic_notifier_call_chain(&s390_epoch_delta_notifier, 575 atomic_notifier_call_chain(&s390_epoch_delta_notifier,
618 0, &clock_delta); 576 0, &clock_delta);
619 fixup_clock_comparator(delta); 577 fixup_clock_comparator(clock_delta);
620 rc = chsc_sstpi(stp_page, &stp_info, 578 rc = chsc_sstpi(stp_page, &stp_info,
621 sizeof(struct stp_sstpi)); 579 sizeof(struct stp_sstpi));
622 if (rc == 0 && stp_info.tmd != 2) 580 if (rc == 0 && stp_info.tmd != 2)