X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fsparc64%2Fkernel%2Ftime.c;h=5c341ece0ce48903ad5595ea832b99be703aaaa7;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=57ebd69e5c79d464a8397b8d3d9571ccd1edb6af;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 57ebd69e5..5c341ece0 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -45,8 +46,8 @@ #include #include -spinlock_t mostek_lock = SPIN_LOCK_UNLOCKED; -spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; +DEFINE_SPINLOCK(mostek_lock); +DEFINE_SPINLOCK(rtc_lock); unsigned long mstk48t02_regs = 0UL; #ifdef CONFIG_PCI unsigned long ds1287_regs = 0UL; @@ -63,10 +64,31 @@ static unsigned long mstk48t59_regs = 0UL; static int set_rtc_mmss(unsigned long); -struct sparc64_tick_ops *tick_ops; +static __init unsigned long dummy_get_tick(void) +{ + return 0; +} + +static __initdata struct sparc64_tick_ops dummy_tick_ops = { + .get_tick = dummy_get_tick, +}; + +struct sparc64_tick_ops *tick_ops = &dummy_tick_ops; #define TICK_PRIV_BIT (1UL << 63) +#ifdef CONFIG_SMP +unsigned long profile_pc(struct pt_regs *regs) +{ + unsigned long pc = instruction_pointer(regs); + + if (in_lock_functions(pc)) + return regs->u_regs[UREG_RETPC]; + return pc; +} +EXPORT_SYMBOL(profile_pc); +#endif + static void tick_disable_protection(void) { /* Set things up so user can access tick register for profiling @@ -418,12 +440,11 @@ static struct sparc64_tick_ops hbtick_operations = { unsigned long timer_tick_offset; unsigned long timer_tick_compare; -static unsigned long timer_ticks_per_usec_quotient; static unsigned long timer_ticks_per_nsec_quotient; #define TICK_SIZE (tick_nsec / 1000) -static __inline__ void timer_check_rtc(void) +static inline void timer_check_rtc(void) { /* last time the cmos clock got updated */ static long last_rtc_update; @@ -441,47 +462,6 @@ static __inline__ void timer_check_rtc(void) } } -void sparc64_do_profile(struct pt_regs *regs) -{ - unsigned long pc = regs->tpc; - unsigned long o7 = regs->u_regs[UREG_RETPC]; - - profile_hook(regs); - - if (user_mode(regs)) - return; - - if (!prof_buffer) - return; - - { - extern int rwlock_impl_begin, rwlock_impl_end; - extern int atomic_impl_begin, atomic_impl_end; - extern int __memcpy_begin, __memcpy_end; - extern int __bzero_begin, __bzero_end; - extern int __bitops_begin, __bitops_end; - - if ((pc >= (unsigned long) &atomic_impl_begin && - pc < (unsigned long) &atomic_impl_end) || - (pc >= (unsigned long) &rwlock_impl_begin && - pc < (unsigned long) &rwlock_impl_end) || - (pc >= (unsigned long) &__memcpy_begin && - pc < (unsigned long) &__memcpy_end) || - (pc >= (unsigned long) &__bzero_begin && - pc < (unsigned long) &__bzero_end) || - (pc >= (unsigned long) &__bitops_begin && - pc < (unsigned long) &__bitops_end)) - pc = o7; - - pc -= (unsigned long) _stext; - pc >>= prof_shift; - - if(pc >= prof_len) - pc = prof_len - 1; - atomic_inc((atomic_t *)&prof_buffer[pc]); - } -} - static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) { unsigned long ticks, pstate; @@ -490,7 +470,8 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) do { #ifndef CONFIG_SMP - sparc64_do_profile(regs); + profile_tick(CPU_PROFILING, regs); + update_process_times(user_mode(regs)); #endif do_timer(regs); @@ -939,10 +920,10 @@ try_isa_clock: } /* This is gets the master TICK_INT timer going. */ -static unsigned long sparc64_init_timers(irqreturn_t (*cfunc)(int, void *, struct pt_regs *)) +static unsigned long sparc64_init_timers(void) { - unsigned long pstate, clock; - int node, err; + unsigned long clock; + int node; #ifdef CONFIG_SMP extern void smp_tick_init(void); #endif @@ -975,6 +956,14 @@ static unsigned long sparc64_init_timers(irqreturn_t (*cfunc)(int, void *, struc smp_tick_init(); #endif + return clock; +} + +static void sparc64_start_timers(irqreturn_t (*cfunc)(int, void *, struct pt_regs *)) +{ + unsigned long pstate; + int err; + /* Register IRQ handler. */ err = request_irq(build_irq(0, 0, 0UL, 0UL), cfunc, SA_STATIC_ALLOC, "timer", NULL); @@ -1000,8 +989,6 @@ static unsigned long sparc64_init_timers(irqreturn_t (*cfunc)(int, void *, struc : "r" (pstate)); local_irq_enable(); - - return clock; } struct freq_table { @@ -1035,7 +1022,8 @@ static int sparc64_cpufreq_notifier(struct notifier_block *nb, unsigned long val ft->clock_tick_ref = cpu_data(cpu).clock_tick; } if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || - (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) { + (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) || + (val == CPUFREQ_RESUMECHANGE)) { cpu_data(cpu).udelay_val = cpufreq_scale(ft->udelay_val_ref, ft->ref_freq, @@ -1052,18 +1040,28 @@ static int sparc64_cpufreq_notifier(struct notifier_block *nb, unsigned long val static struct notifier_block sparc64_cpufreq_notifier_block = { .notifier_call = sparc64_cpufreq_notifier }; -#endif + +#endif /* CONFIG_CPU_FREQ */ + +static struct time_interpolator sparc64_cpu_interpolator = { + .source = TIME_SOURCE_CPU, + .shift = 16, + .mask = 0xffffffffffffffffLL +}; /* The quotient formula is taken from the IA64 port. */ -#define SPARC64_USEC_PER_CYC_SHIFT 30UL #define SPARC64_NSEC_PER_CYC_SHIFT 30UL void __init time_init(void) { - unsigned long clock = sparc64_init_timers(timer_interrupt); + unsigned long clock = sparc64_init_timers(); - timer_ticks_per_usec_quotient = - (((1000000UL << SPARC64_USEC_PER_CYC_SHIFT) + - (clock / 2)) / clock); + sparc64_cpu_interpolator.frequency = clock; + register_time_interpolator(&sparc64_cpu_interpolator); + + /* Now that the interpolator is registered, it is + * safe to start the timer ticking. + */ + sparc64_start_timers(timer_interrupt); timer_ticks_per_nsec_quotient = (((NSEC_PER_SEC << SPARC64_NSEC_PER_CYC_SHIFT) + @@ -1075,17 +1073,6 @@ void __init time_init(void) #endif } -static __inline__ unsigned long do_gettimeoffset(void) -{ - unsigned long ticks = tick_ops->get_tick(); - - ticks += timer_tick_offset; - ticks -= timer_tick_compare; - - return (ticks * timer_ticks_per_usec_quotient) - >> SPARC64_USEC_PER_CYC_SHIFT; -} - unsigned long long sched_clock(void) { unsigned long ticks = tick_ops->get_tick(); @@ -1094,91 +1081,6 @@ unsigned long long sched_clock(void) >> SPARC64_NSEC_PER_CYC_SHIFT; } -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; - - if (this_is_starfire) - return 0; - - 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 - * made, and then undo it! - */ - nsec -= do_gettimeoffset() * 1000; - nsec -= (jiffies - wall_jiffies) * (NSEC_PER_SEC / HZ); - - 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); - - time_adjust = 0; /* stop active adjtime() */ - time_status |= STA_UNSYNC; - time_maxerror = NTP_PHASE_LIMIT; - time_esterror = NTP_PHASE_LIMIT; - write_sequnlock_irq(&xtime_lock); - clock_was_set(); - return 0; -} - -EXPORT_SYMBOL(do_settimeofday); - -/* Ok, my cute asm atomicity trick doesn't work anymore. - * There are just too many variables that need to be protected - * now (both members of xtime, wall_jiffies, et al.) - */ -void do_gettimeofday(struct timeval *tv) -{ - unsigned long flags; - unsigned long seq; - unsigned long usec, sec; - unsigned long max_ntp_tick = tick_usec - tickadj; - - do { - unsigned long lost; - - seq = read_seqbegin_irqsave(&xtime_lock, flags); - usec = do_gettimeoffset(); - lost = jiffies - wall_jiffies; - - /* - * If time_adjust is negative then NTP is slowing the clock - * so make sure not to go into next possible interval. - * Better to lose some accuracy than have time go backwards.. - */ - if (unlikely(time_adjust < 0)) { - usec = min(usec, max_ntp_tick); - - if (lost) - usec += lost * max_ntp_tick; - } - else if (unlikely(lost)) - usec += lost * tick_usec; - - sec = xtime.tv_sec; - usec += (xtime.tv_nsec / 1000); - } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); - - while (usec >= 1000000) { - usec -= 1000000; - sec++; - } - - tv->tv_sec = sec; - tv->tv_usec = usec; -} - -EXPORT_SYMBOL(do_gettimeofday); - static int set_rtc_mmss(unsigned long nowtime) { int real_seconds, real_minutes, chip_minutes;