diff options
author | Helge Deller <deller@gmx.de> | 2007-01-02 23:54:16 +0100 |
---|---|---|
committer | Kyle McMartin <kyle@athena.road.mcmartin.ca> | 2007-02-17 01:02:29 -0500 |
commit | 12df29b64c782133afea8cacc6acdad68a6b7d17 (patch) | |
tree | 8a41bfedfcb8cc543d2eec948cf7d003f1a183b9 | |
parent | df47b4386a473eba87095e6dea8046762434817d (diff) |
[PARISC] GENERIC_TIME patchset for parisc
Signed-off-by: Helge Deller <deller@gmx.de>
Signed-off-by: Kyle McMartin <kyle@parisc-linux.org>
-rw-r--r-- | arch/parisc/Kconfig | 4 | ||||
-rw-r--r-- | arch/parisc/kernel/time.c | 134 |
2 files changed, 28 insertions, 110 deletions
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index 848a67a024b..e18eeecae85 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -50,6 +50,10 @@ config GENERIC_CALIBRATE_DELAY bool default y +config GENERIC_TIME + bool + default y + config TIME_LOW_RES bool depends on SMP diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index bad7d1eb62b..e47e27cea42 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -22,6 +22,7 @@ #include <linux/init.h> #include <linux/smp.h> #include <linux/profile.h> +#include <linux/clocksource.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -172,121 +173,23 @@ unsigned long profile_pc(struct pt_regs *regs) EXPORT_SYMBOL(profile_pc); -/* - * Return the number of micro-seconds that elapsed since the last - * update to wall time (aka xtime). The xtime_lock - * must be at least read-locked when calling this routine. - */ -static inline unsigned long gettimeoffset (void) -{ -#ifndef CONFIG_SMP - /* - * FIXME: This won't work on smp because jiffies are updated by cpu 0. - * Once parisc-linux learns the cr16 difference between processors, - * this could be made to work. - */ - unsigned long now; - unsigned long prev_tick; - unsigned long next_tick; - unsigned long elapsed_cycles; - unsigned long usec; - unsigned long cpuid = smp_processor_id(); - unsigned long cpt = clocktick; +/* clock source code */ - next_tick = cpu_data[cpuid].it_value; - now = mfctl(16); /* Read the hardware interval timer. */ - - prev_tick = next_tick - cpt; - - /* Assume Scenario 1: "now" is later than prev_tick. */ - elapsed_cycles = now - prev_tick; - -/* aproximate HZ with shifts. Intended math is "(elapsed/clocktick) > HZ" */ -#if HZ == 1000 - if (elapsed_cycles > (cpt << 10) ) -#elif HZ == 250 - if (elapsed_cycles > (cpt << 8) ) -#elif HZ == 100 - if (elapsed_cycles > (cpt << 7) ) -#else -#warn WTF is HZ set to anyway? - if (elapsed_cycles > (HZ * cpt) ) -#endif - { - /* Scenario 3: clock ticks are missing. */ - printk (KERN_CRIT "gettimeoffset(CPU %ld): missing %ld ticks!" - " cycles %lX prev/now/next %lX/%lX/%lX clock %lX\n", - cpuid, elapsed_cycles / cpt, - elapsed_cycles, prev_tick, now, next_tick, cpt); - } - - /* FIXME: Can we improve the precision? Not with PAGE0. */ - usec = (elapsed_cycles * 10000) / PAGE0->mem_10msec; - return usec; -#else - return 0; -#endif -} - -void -do_gettimeofday (struct timeval *tv) +static cycle_t read_cr16(void) { - unsigned long flags, seq, usec, sec; - - /* Hold xtime_lock and adjust timeval. */ - do { - seq = read_seqbegin_irqsave(&xtime_lock, flags); - usec = gettimeoffset(); - sec = xtime.tv_sec; - usec += (xtime.tv_nsec / 1000); - } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); - - /* Move adjusted usec's into sec's. */ - while (usec >= USEC_PER_SEC) { - usec -= USEC_PER_SEC; - ++sec; - } - - /* Return adjusted result. */ - tv->tv_sec = sec; - tv->tv_usec = usec; + return get_cycles(); } -EXPORT_SYMBOL(do_gettimeofday); - -int -do_settimeofday (struct timespec *tv) -{ - time_t wtm_sec, sec = tv->tv_sec; - long wtm_nsec, nsec = tv->tv_nsec; - - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) - return -EINVAL; - - write_seqlock_irq(&xtime_lock); - { - /* - * This is revolting. We need to set "xtime" - * correctly. However, the value in this location is - * the value at the most recent update of wall time. - * Discover what correction gettimeofday would have - * done, and then undo it! - */ - nsec -= gettimeoffset() * 1000; +static struct clocksource clocksource_cr16 = { + .name = "cr16", + .rating = 300, + .read = read_cr16, + .mask = CLOCKSOURCE_MASK(BITS_PER_LONG), + .mult = 0, /* to be set */ + .shift = 22, + .is_continuous = 1, +}; - wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); - wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); - - set_normalized_timespec(&xtime, sec, nsec); - set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); - - ntp_clear(); - } - write_sequnlock_irq(&xtime_lock); - clock_was_set(); - return 0; -} -EXPORT_SYMBOL(do_settimeofday); /* * XXX: We can do better than this. @@ -312,11 +215,22 @@ void __init start_cpu_itimer(void) void __init time_init(void) { static struct pdc_tod tod_data; + unsigned long current_cr16_khz; clocktick = (100 * PAGE0->mem_10msec) / HZ; start_cpu_itimer(); /* get CPU 0 started */ + /* register at clocksource framework */ + current_cr16_khz = PAGE0->mem_10msec/10; /* kHz */ + clocksource_cr16.mult = clocksource_khz2mult(current_cr16_khz, + clocksource_cr16.shift); + /* lower the rating if we already know its unstable: */ + if (num_online_cpus()>1) + clocksource_cr16.rating = 200; + + clocksource_register(&clocksource_cr16); + if (pdc_tod_read(&tod_data) == 0) { unsigned long flags; |