|
@@ -51,8 +51,15 @@
|
|
|
#include <asm/cio.h>
|
|
|
#include "entry.h"
|
|
|
|
|
|
-u64 sched_clock_base_cc = -1; /* Force to data section. */
|
|
|
-EXPORT_SYMBOL_GPL(sched_clock_base_cc);
|
|
|
+unsigned char tod_clock_base[16] __aligned(8) = {
|
|
|
+ /* Force to data section. */
|
|
|
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
|
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
|
|
+};
|
|
|
+EXPORT_SYMBOL_GPL(tod_clock_base);
|
|
|
+
|
|
|
+u64 clock_comparator_max = -1ULL;
|
|
|
+EXPORT_SYMBOL_GPL(clock_comparator_max);
|
|
|
|
|
|
static DEFINE_PER_CPU(struct clock_event_device, comparators);
|
|
|
|
|
@@ -75,7 +82,7 @@ void __init time_early_init(void)
|
|
|
struct ptff_qui qui;
|
|
|
|
|
|
/* Initialize TOD steering parameters */
|
|
|
- tod_steering_end = sched_clock_base_cc;
|
|
|
+ tod_steering_end = *(unsigned long long *) &tod_clock_base[1];
|
|
|
vdso_data->ts_end = tod_steering_end;
|
|
|
|
|
|
if (!test_facility(28))
|
|
@@ -111,22 +118,27 @@ unsigned long long monotonic_clock(void)
|
|
|
}
|
|
|
EXPORT_SYMBOL(monotonic_clock);
|
|
|
|
|
|
-static void tod_to_timeval(__u64 todval, struct timespec64 *xt)
|
|
|
+static void ext_to_timespec64(unsigned char *clk, struct timespec64 *xt)
|
|
|
{
|
|
|
- unsigned long long sec;
|
|
|
+ unsigned long long high, low, rem, sec, nsec;
|
|
|
+
|
|
|
+ /* Split extendnd TOD clock to micro-seconds and sub-micro-seconds */
|
|
|
+ high = (*(unsigned long long *) clk) >> 4;
|
|
|
+ low = (*(unsigned long long *)&clk[7]) << 4;
|
|
|
+ /* Calculate seconds and nano-seconds */
|
|
|
+ sec = high;
|
|
|
+ rem = do_div(sec, 1000000);
|
|
|
+ nsec = (((low >> 32) + (rem << 32)) * 1000) >> 32;
|
|
|
|
|
|
- sec = todval >> 12;
|
|
|
- do_div(sec, 1000000);
|
|
|
xt->tv_sec = sec;
|
|
|
- todval -= (sec * 1000000) << 12;
|
|
|
- xt->tv_nsec = ((todval * 1000) >> 12);
|
|
|
+ xt->tv_nsec = nsec;
|
|
|
}
|
|
|
|
|
|
void clock_comparator_work(void)
|
|
|
{
|
|
|
struct clock_event_device *cd;
|
|
|
|
|
|
- S390_lowcore.clock_comparator = -1ULL;
|
|
|
+ S390_lowcore.clock_comparator = clock_comparator_max;
|
|
|
cd = this_cpu_ptr(&comparators);
|
|
|
cd->event_handler(cd);
|
|
|
}
|
|
@@ -148,7 +160,7 @@ void init_cpu_timer(void)
|
|
|
struct clock_event_device *cd;
|
|
|
int cpu;
|
|
|
|
|
|
- S390_lowcore.clock_comparator = -1ULL;
|
|
|
+ S390_lowcore.clock_comparator = clock_comparator_max;
|
|
|
set_clock_comparator(S390_lowcore.clock_comparator);
|
|
|
|
|
|
cpu = smp_processor_id();
|
|
@@ -179,7 +191,7 @@ static void clock_comparator_interrupt(struct ext_code ext_code,
|
|
|
unsigned long param64)
|
|
|
{
|
|
|
inc_irq_stat(IRQEXT_CLK);
|
|
|
- if (S390_lowcore.clock_comparator == -1ULL)
|
|
|
+ if (S390_lowcore.clock_comparator == clock_comparator_max)
|
|
|
set_clock_comparator(S390_lowcore.clock_comparator);
|
|
|
}
|
|
|
|
|
@@ -197,18 +209,28 @@ static void stp_reset(void);
|
|
|
|
|
|
void read_persistent_clock64(struct timespec64 *ts)
|
|
|
{
|
|
|
- __u64 clock;
|
|
|
+ unsigned char clk[STORE_CLOCK_EXT_SIZE];
|
|
|
+ __u64 delta;
|
|
|
|
|
|
- clock = get_tod_clock() - initial_leap_seconds;
|
|
|
- tod_to_timeval(clock - TOD_UNIX_EPOCH, ts);
|
|
|
+ delta = initial_leap_seconds + TOD_UNIX_EPOCH;
|
|
|
+ get_tod_clock_ext(clk);
|
|
|
+ *(__u64 *) &clk[1] -= delta;
|
|
|
+ if (*(__u64 *) &clk[1] > delta)
|
|
|
+ clk[0]--;
|
|
|
+ ext_to_timespec64(clk, ts);
|
|
|
}
|
|
|
|
|
|
void read_boot_clock64(struct timespec64 *ts)
|
|
|
{
|
|
|
- __u64 clock;
|
|
|
+ unsigned char clk[STORE_CLOCK_EXT_SIZE];
|
|
|
+ __u64 delta;
|
|
|
|
|
|
- clock = sched_clock_base_cc - initial_leap_seconds;
|
|
|
- tod_to_timeval(clock - TOD_UNIX_EPOCH, ts);
|
|
|
+ delta = initial_leap_seconds + TOD_UNIX_EPOCH;
|
|
|
+ memcpy(clk, tod_clock_base, 16);
|
|
|
+ *(__u64 *) &clk[1] -= delta;
|
|
|
+ if (*(__u64 *) &clk[1] > delta)
|
|
|
+ clk[0]--;
|
|
|
+ ext_to_timespec64(clk, ts);
|
|
|
}
|
|
|
|
|
|
static u64 read_tod_clock(struct clocksource *cs)
|
|
@@ -406,7 +428,10 @@ static void clock_sync_global(unsigned long long delta)
|
|
|
struct ptff_qto qto;
|
|
|
|
|
|
/* Fixup the monotonic sched clock. */
|
|
|
- sched_clock_base_cc += delta;
|
|
|
+ *(unsigned long long *) &tod_clock_base[1] += delta;
|
|
|
+ if (*(unsigned long long *) &tod_clock_base[1] < delta)
|
|
|
+ /* Epoch overflow */
|
|
|
+ tod_clock_base[0]++;
|
|
|
/* Adjust TOD steering parameters. */
|
|
|
vdso_data->tb_update_count++;
|
|
|
now = get_tod_clock();
|
|
@@ -437,7 +462,7 @@ static void clock_sync_global(unsigned long long delta)
|
|
|
static void clock_sync_local(unsigned long long delta)
|
|
|
{
|
|
|
/* Add the delta to the clock comparator. */
|
|
|
- if (S390_lowcore.clock_comparator != -1ULL) {
|
|
|
+ if (S390_lowcore.clock_comparator != clock_comparator_max) {
|
|
|
S390_lowcore.clock_comparator += delta;
|
|
|
set_clock_comparator(S390_lowcore.clock_comparator);
|
|
|
}
|