--- zzzz-none-000/linux-2.4.17/arch/mips/ite-boards/generic/time.c 2001-09-09 17:43:01.000000000 +0000 +++ sangam-fb-322/linux-2.4.17/arch/mips/ite-boards/generic/time.c 2004-11-24 13:22:38.000000000 +0000 @@ -28,135 +28,20 @@ #include #include #include +#include #include #include #include +#include #include #include -extern void enable_cpu_timer(void); -extern volatile unsigned long wall_jiffies; -extern rwlock_t xtime_lock; - -unsigned long missed_heart_beats = 0; -static long last_rtc_update = 0; static unsigned long r4k_offset; /* Amount to increment compare reg each time */ static unsigned long r4k_cur; /* What counter should be at next timer irq */ -static unsigned int timer_tick_count=0; - -static inline void ack_r4ktimer(unsigned long newval) -{ - write_32bit_cp0_register(CP0_COMPARE, newval); -} - - -/* - * In order to set the CMOS clock precisely, set_rtc_mmss has to be - * called 500 ms after the second nowtime has started, because when - * nowtime is written into the registers of the CMOS clock, it will - * jump to the next second precisely 500 ms later. Check the Motorola - * MC146818A or Dallas DS12887 data sheet for details. - * - * BUG: This routine does not handle hour overflow properly; it just - * sets the minutes. Usually you won't notice until after reboot! - */ -static int set_rtc_mmss(unsigned long nowtime) -{ - int retval = 0; - int real_seconds, real_minutes, cmos_minutes; - unsigned char save_control, save_freq_select; - - save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ - CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); - - save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ - CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); - - cmos_minutes = CMOS_READ(RTC_MINUTES); - - /* - * since we're only adjusting minutes and seconds, - * don't interfere with hour overflow. This avoids - * messing with unknown time zones but requires your - * RTC not to be off by more than 15 minutes - */ - real_seconds = nowtime % 60; - real_minutes = nowtime / 60; - if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) - real_minutes += 30; /* correct for half hour time zone */ - real_minutes %= 60; - - if (abs(real_minutes - cmos_minutes) < 30) { - CMOS_WRITE(real_seconds,RTC_SECONDS); - CMOS_WRITE(real_minutes,RTC_MINUTES); - } else { - printk(KERN_WARNING - "set_rtc_mmss: can't update from %d to %d\n", - cmos_minutes, real_minutes); - retval = -1; - } - - /* The following flags have to be released exactly in this order, - * otherwise the DS12887 (popular MC146818A clone with integrated - * battery and quartz) will not reset the oscillator and will not - * update precisely 500 ms later. You won't find this mentioned in - * the Dallas Semiconductor data sheets, but who believes data - * sheets anyway ... -- Markus Kuhn - */ - CMOS_WRITE(save_control, RTC_CONTROL); - CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); - - return retval; -} - - -/* - * There are a lot of conceptually broken versions of the MIPS timer interrupt - * handler floating around. This one is rather different, but the algorithm - * is provably more robust. - */ -void mips_timer_interrupt(struct pt_regs *regs) -{ - if (r4k_offset == 0) - goto null; - - do { - kstat.irqs[0][MIPS_CPU_TIMER_IRQ]++; - do_timer(regs); - - /* Historical comment/code: - * RTC time of day s updated approx. every 11 - * minutes. Because of how the numbers work out - * we need to make absolutely sure we do this update - * within 500ms before the * next second starts, - * thus the following code. - */ - read_lock(&xtime_lock); - if ((time_status & STA_UNSYNC) == 0 - && xtime.tv_sec > last_rtc_update + 660 - && xtime.tv_usec >= 500000 - (tick >> 1) - && xtime.tv_usec <= 500000 + (tick >> 1)) - if (set_rtc_mmss(xtime.tv_sec) == 0) - last_rtc_update = xtime.tv_sec; - else { - /* do it again in 60 s */ - last_rtc_update = xtime.tv_sec - 600; - } - read_unlock(&xtime_lock); - - r4k_cur += r4k_offset; - ack_r4ktimer(r4k_cur); - - } while (((unsigned long)read_32bit_cp0_register(CP0_COUNT) - - r4k_cur) < 0x7fffffff); - - return; - -null: - ack_r4ktimer(0); -} +extern unsigned int mips_counter_frequency; +extern asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs); /* * Figure out the r4k offset, the amount to increment the compare @@ -165,7 +50,6 @@ */ static unsigned long __init cal_r4koff(void) { - unsigned long count; unsigned int flags; __save_and_cli(flags); @@ -181,15 +65,15 @@ while (CMOS_READ(RTC_REG_A) & RTC_UIP); while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); - count = read_32bit_cp0_register(CP0_COUNT); + mips_counter_frequency = read_32bit_cp0_register(CP0_COUNT); /* restore interrupts */ __restore_flags(flags); - return (count / HZ); + return (mips_counter_frequency / HZ); } -static unsigned long __init get_mips_time(void) +unsigned long it8172_rtc_get_time(void) { unsigned int year, mon, day, hour, min, sec; unsigned char save_control; @@ -224,10 +108,11 @@ return mktime(year, mon, day, hour, min, sec); } -void __init time_init(void) +void __init it8172_time_init(void) { unsigned int est_freq, flags; + __save_and_cli(flags); /* Set Data mode - binary. */ CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL); @@ -240,140 +125,22 @@ est_freq -= est_freq%10000; printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, (est_freq%1000000)*100/1000000); - r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset); - - write_32bit_cp0_register(CP0_COMPARE, r4k_cur); - - enable_cpu_timer(); - - /* Read time from the RTC chipset. */ - write_lock_irqsave (&xtime_lock, flags); - xtime.tv_sec = get_mips_time(); - xtime.tv_usec = 0; - write_unlock_irqrestore(&xtime_lock, flags); -} - -/* This is for machines which generate the exact clock. */ -#define USECS_PER_JIFFY (1000000/HZ) - -/* Cycle counter value at the previous timer interrupt.. */ - -static unsigned int timerhi = 0, timerlo = 0; - -/* - * FIXME: Does playing with the RP bit in c0_status interfere with this code? - */ -static unsigned long do_fast_gettimeoffset(void) -{ - u32 count; - unsigned long res, tmp; - - /* Last jiffy when do_fast_gettimeoffset() was called. */ - static unsigned long last_jiffies=0; - unsigned long quotient; - - /* - * Cached "1/(clocks per usec)*2^32" value. - * It has to be recalculated once each jiffy. - */ - static unsigned long cached_quotient=0; - - tmp = jiffies; - - quotient = cached_quotient; - - if (tmp && last_jiffies != tmp) { - last_jiffies = tmp; - __asm__(".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "lwu\t%0,%2\n\t" - "dsll32\t$1,%1,0\n\t" - "or\t$1,$1,%0\n\t" - "ddivu\t$0,$1,%3\n\t" - "mflo\t$1\n\t" - "dsll32\t%0,%4,0\n\t" - "nop\n\t" - "ddivu\t$0,%0,$1\n\t" - "mflo\t%0\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=&r" (quotient) - :"r" (timerhi), - "m" (timerlo), - "r" (tmp), - "r" (USECS_PER_JIFFY) - :"$1"); - cached_quotient = quotient; - } - - /* Get last timer tick in absolute kernel time */ - count = read_32bit_cp0_register(CP0_COUNT); - - /* .. relative to previous jiffy (32 bits is enough) */ - count -= timerlo; - - __asm__("multu\t%1,%2\n\t" - "mfhi\t%0" - :"=r" (res) - :"r" (count), - "r" (quotient)); - - /* - * Due to possible jiffies inconsistencies, we need to check - * the result so that we'll get a timer that is monotonic. - */ - if (res >= USECS_PER_JIFFY) - res = USECS_PER_JIFFY-1; - - return res; + __restore_flags(flags); } -void do_gettimeofday(struct timeval *tv) +#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) +void __init it8172_timer_setup(struct irqaction *irq) { - unsigned int flags; + /* we are using the cpu counter for timer interrupts */ + setup_irq(MIPS_CPU_TIMER_IRQ, irq); - read_lock_irqsave (&xtime_lock, flags); - *tv = xtime; - tv->tv_usec += do_fast_gettimeoffset(); - - /* - * xtime is atomically updated in timer_bh. jiffies - wall_jiffies - * is nonzero if the timer bottom half hasnt executed yet. - */ - if (jiffies - wall_jiffies) - tv->tv_usec += USECS_PER_JIFFY; - - read_unlock_irqrestore (&xtime_lock, flags); - - if (tv->tv_usec >= 1000000) { - tv->tv_usec -= 1000000; - tv->tv_sec++; - } + /* to generate the first timer interrupt */ + r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset); + write_32bit_cp0_register(CP0_COMPARE, r4k_cur); + set_cp0_status(ALLINTS); } -void do_settimeofday(struct timeval *tv) +void local_timer_interrupt(struct pt_regs *regs) { - write_lock_irq (&xtime_lock); - - /* This is revolting. We need to set the xtime.tv_usec correctly. - * However, the value in this location is is value at the last tick. - * Discover what correction gettimeofday would have done, and then - * undo it! - */ - tv->tv_usec -= do_fast_gettimeoffset(); - - if (tv->tv_usec < 0) { - tv->tv_usec += 1000000; - tv->tv_sec--; - } - - xtime = *tv; - time_adjust = 0; /* stop active adjtime() */ - time_status |= STA_UNSYNC; - time_maxerror = NTP_PHASE_LIMIT; - time_esterror = NTP_PHASE_LIMIT; - - write_unlock_irq (&xtime_lock); + do_IRQ(MIPS_CPU_TIMER_IRQ, regs); }