X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Farm26%2Fkernel%2Ftime.c;h=1206469b2b86249574f0dd111a83d457b960c7a8;hb=refs%2Fheads%2Fvserver;hp=af2905a1f48bb46a996ebaecbaa0ecc2b2a68fd0;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/arch/arm26/kernel/time.c b/arch/arm26/kernel/time.c index af2905a1f..1206469b2 100644 --- a/arch/arm26/kernel/time.c +++ b/arch/arm26/kernel/time.c @@ -18,7 +18,6 @@ * "A Kernel Model for Precision Timekeeping" by Dave Mills */ -#include #include #include #include @@ -32,16 +31,10 @@ #include #include #include -#include - -u64 jiffies_64 = INITIAL_JIFFIES; - -EXPORT_SYMBOL(jiffies_64); - -extern unsigned long wall_jiffies; +#include /* this needs a better home */ -spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; +DEFINE_SPINLOCK(rtc_lock); /* change this if you have some constant time drift */ #define USECS_PER_JIFFY (1000000/HZ) @@ -56,37 +49,52 @@ static int dummy_set_rtc(void) */ int (*set_rtc)(void) = dummy_set_rtc; -static unsigned long dummy_gettimeoffset(void) -{ - return 0; -} - /* - * hook for getting the time offset. Note that it is - * always called with interrupts disabled. + * Get time offset based on IOCs timer. + * FIXME - if this is called with interrutps off, why the shennanigans + * below ? */ -unsigned long (*gettimeoffset)(void) = dummy_gettimeoffset; +static unsigned long gettimeoffset(void) +{ + unsigned int count1, count2, status; + long offset; + + ioc_writeb (0, IOC_T0LATCH); + barrier (); + count1 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8); + barrier (); + status = ioc_readb(IOC_IRQREQA); + barrier (); + ioc_writeb (0, IOC_T0LATCH); + barrier (); + count2 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8); + + offset = count2; + if (count2 < count1) { + /* + * We have not had an interrupt between reading count1 + * and count2. + */ + if (status & (1 << 5)) + offset -= LATCH; + } else if (count2 > count1) { + /* + * We have just had another interrupt between reading + * count1 and count2. + */ + offset -= LATCH; + } + + offset = (LATCH - offset) * (tick_nsec / 1000); + return (offset + LATCH/2) / LATCH; +} /* - * Handle kernel profile stuff... + * Scheduler clock - returns current time in nanosec units. */ -static inline void do_profile(struct pt_regs *regs) +unsigned long long sched_clock(void) { - if (!user_mode(regs) && - prof_buffer && - current->pid) { - unsigned long pc = instruction_pointer(regs); - extern int _stext; - - pc -= (unsigned long)&_stext; - - pc >>= prof_shift; - - if (pc >= prof_len) - pc = prof_len - 1; - - prof_buffer[pc] += 1; - } + return (unsigned long long)jiffies * (1000000000 / HZ); } static unsigned long next_rtc_update; @@ -99,7 +107,7 @@ static unsigned long next_rtc_update; */ static inline void do_set_rtc(void) { - if (time_status & STA_UNSYNC || set_rtc == NULL) + if (!ntp_synced() || set_rtc == NULL) return; //FIXME - timespec.tv_sec is a time_t not unsigned long @@ -126,16 +134,11 @@ void do_gettimeofday(struct timeval *tv) { unsigned long flags; unsigned long seq; - unsigned long usec, sec, lost; + unsigned long usec, sec; do { seq = read_seqbegin_irqsave(&xtime_lock, flags); usec = gettimeoffset(); - - lost = jiffies - wall_jiffies; - if (lost) - usec += lost * USECS_PER_JIFFY; - sec = xtime.tv_sec; usec += xtime.tv_nsec / 1000; } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); @@ -164,8 +167,7 @@ int do_settimeofday(struct timespec *tv) * wall time. Discover what correction gettimeofday() would have * done, and then undo it! */ - tv->tv_nsec -= 1000 * (gettimeoffset() + - (jiffies - wall_jiffies) * USECS_PER_JIFFY); + tv->tv_nsec -= 1000 * gettimeoffset(); while (tv->tv_nsec < 0) { tv->tv_nsec += NSEC_PER_SEC; @@ -174,10 +176,7 @@ int do_settimeofday(struct timespec *tv) xtime.tv_sec = tv->tv_sec; xtime.tv_nsec = tv->tv_nsec; - time_adjust = 0; /* stop active adjtime() */ - time_status |= STA_UNSYNC; - time_maxerror = NTP_PHASE_LIMIT; - time_esterror = NTP_PHASE_LIMIT; + ntp_clear(); write_sequnlock_irq(&xtime_lock); clock_was_set(); return 0; @@ -187,15 +186,18 @@ EXPORT_SYMBOL(do_settimeofday); static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - do_timer(regs); + do_timer(1); +#ifndef CONFIG_SMP + update_process_times(user_mode(regs)); +#endif do_set_rtc(); //FIME - EVERY timer IRQ? - do_profile(regs); + profile_tick(CPU_PROFILING, regs); return IRQ_HANDLED; //FIXME - is this right? } static struct irqaction timer_irq = { .name = "timer", - .flags = SA_INTERRUPT, + .flags = IRQF_DISABLED, .handler = timer_interrupt, }; @@ -206,7 +208,10 @@ extern void ioctime_init(void); */ void __init time_init(void) { - ioctime_init(); + ioc_writeb(LATCH & 255, IOC_T0LTCHL); + ioc_writeb(LATCH >> 8, IOC_T0LTCHH); + ioc_writeb(0, IOC_T0GO); + setup_irq(IRQ_TIMER, &timer_irq); }