Merge branch 'tmpreg' into devel
[safe/jmp/linux-2.6] / arch / powerpc / kernel / time.c
index edb1edb..6c6093d 100644 (file)
@@ -53,7 +53,8 @@
 #include <linux/posix-timers.h>
 #include <linux/irq.h>
 #include <linux/delay.h>
-#include <linux/perf_counter.h>
+#include <linux/perf_event.h>
+#include <asm/trace.h>
 
 #include <asm/io.h>
 #include <asm/processor.h>
@@ -193,6 +194,8 @@ EXPORT_SYMBOL(__cputime_clockt_factor);
 DEFINE_PER_CPU(unsigned long, cputime_last_delta);
 DEFINE_PER_CPU(unsigned long, cputime_scaled_last_delta);
 
+cputime_t cputime_one_jiffy;
+
 static void calc_cputime_factors(void)
 {
        struct div_result res;
@@ -266,6 +269,7 @@ void account_system_vtime(struct task_struct *tsk)
        per_cpu(cputime_scaled_last_delta, smp_processor_id()) = deltascaled;
        local_irq_restore(flags);
 }
+EXPORT_SYMBOL_GPL(account_system_vtime);
 
 /*
  * Transfer the user and system times accumulated in the paca
@@ -501,6 +505,7 @@ static int __init iSeries_tb_recal(void)
                                tb_to_xs = divres.result_low;
                                vdso_data->tb_ticks_per_sec = tb_ticks_per_sec;
                                vdso_data->tb_to_xs = tb_to_xs;
+                               setup_cputime_one_jiffy();
                        }
                        else {
                                printk( "Titan recalibrate: FAILED (difference > 4 percent)\n"
@@ -527,25 +532,25 @@ void __init iSeries_time_init_early(void)
 }
 #endif /* CONFIG_PPC_ISERIES */
 
-#if defined(CONFIG_PERF_COUNTERS) && defined(CONFIG_PPC32)
-DEFINE_PER_CPU(u8, perf_counter_pending);
+#if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_PPC32)
+DEFINE_PER_CPU(u8, perf_event_pending);
 
-void set_perf_counter_pending(void)
+void set_perf_event_pending(void)
 {
-       get_cpu_var(perf_counter_pending) = 1;
+       get_cpu_var(perf_event_pending) = 1;
        set_dec(1);
-       put_cpu_var(perf_counter_pending);
+       put_cpu_var(perf_event_pending);
 }
 
-#define test_perf_counter_pending()    __get_cpu_var(perf_counter_pending)
-#define clear_perf_counter_pending()   __get_cpu_var(perf_counter_pending) = 0
+#define test_perf_event_pending()      __get_cpu_var(perf_event_pending)
+#define clear_perf_event_pending()     __get_cpu_var(perf_event_pending) = 0
 
-#else  /* CONFIG_PERF_COUNTERS && CONFIG_PPC32 */
+#else  /* CONFIG_PERF_EVENTS && CONFIG_PPC32 */
 
-#define test_perf_counter_pending()    0
-#define clear_perf_counter_pending()
+#define test_perf_event_pending()      0
+#define clear_perf_event_pending()
 
-#endif /* CONFIG_PERF_COUNTERS && CONFIG_PPC32 */
+#endif /* CONFIG_PERF_EVENTS && CONFIG_PPC32 */
 
 /*
  * For iSeries shared processors, we have to let the hypervisor
@@ -568,14 +573,16 @@ void timer_interrupt(struct pt_regs * regs)
        struct clock_event_device *evt = &decrementer->event;
        u64 now;
 
+       trace_timer_interrupt_entry(regs);
+
        /* Ensure a positive value is written to the decrementer, or else
         * some CPUs will continuue to take decrementer exceptions */
        set_dec(DECREMENTER_MAX);
 
 #ifdef CONFIG_PPC32
-       if (test_perf_counter_pending()) {
-               clear_perf_counter_pending();
-               perf_counter_do_pending();
+       if (test_perf_event_pending()) {
+               clear_perf_event_pending();
+               perf_event_do_pending();
        }
        if (atomic_read(&ppc_n_lost_interrupts) != 0)
                do_IRQ(regs);
@@ -587,6 +594,7 @@ void timer_interrupt(struct pt_regs * regs)
                now = decrementer->next_tb - now;
                if (now <= DECREMENTER_MAX)
                        set_dec((int)now);
+               trace_timer_interrupt_exit(regs);
                return;
        }
        old_regs = set_irq_regs(regs);
@@ -617,6 +625,8 @@ void timer_interrupt(struct pt_regs * regs)
 
        irq_exit();
        set_irq_regs(old_regs);
+
+       trace_timer_interrupt_exit(regs);
 }
 
 void wakeup_decrementer(void)
@@ -727,6 +737,18 @@ static int __init get_freq(char *name, int cells, unsigned long *val)
        return found;
 }
 
+/* should become __cpuinit when secondary_cpu_time_init also is */
+void start_cpu_decrementer(void)
+{
+#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
+       /* Clear any pending timer interrupts */
+       mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
+
+       /* Enable decrementer interrupt */
+       mtspr(SPRN_TCR, TCR_DIE);
+#endif /* defined(CONFIG_BOOKE) || defined(CONFIG_40x) */
+}
+
 void __init generic_calibrate_decr(void)
 {
        ppc_tb_freq = DEFAULT_TB_FREQ;          /* hardcoded default */
@@ -746,14 +768,6 @@ void __init generic_calibrate_decr(void)
                printk(KERN_ERR "WARNING: Estimating processor frequency "
                                "(not found)\n");
        }
-
-#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
-       /* Clear any pending timer interrupts */
-       mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
-
-       /* Enable decrementer interrupt */
-       mtspr(SPRN_TCR, TCR_DIE);
-#endif
 }
 
 int update_persistent_clock(struct timespec now)
@@ -770,11 +784,12 @@ int update_persistent_clock(struct timespec now)
        return ppc_md.set_rtc_time(&tm);
 }
 
-unsigned long read_persistent_clock(void)
+static void __read_persistent_clock(struct timespec *ts)
 {
        struct rtc_time tm;
        static int first = 1;
 
+       ts->tv_nsec = 0;
        /* XXX this is a litle fragile but will work okay in the short term */
        if (first) {
                first = 0;
@@ -782,14 +797,31 @@ unsigned long read_persistent_clock(void)
                        timezone_offset = ppc_md.time_init();
 
                /* get_boot_time() isn't guaranteed to be safe to call late */
-               if (ppc_md.get_boot_time)
-                       return ppc_md.get_boot_time() -timezone_offset;
+               if (ppc_md.get_boot_time) {
+                       ts->tv_sec = ppc_md.get_boot_time() - timezone_offset;
+                       return;
+               }
+       }
+       if (!ppc_md.get_rtc_time) {
+               ts->tv_sec = 0;
+               return;
        }
-       if (!ppc_md.get_rtc_time)
-               return 0;
        ppc_md.get_rtc_time(&tm);
-       return mktime(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
-                     tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+       ts->tv_sec = mktime(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
+                           tm.tm_hour, tm.tm_min, tm.tm_sec);
+}
+
+void read_persistent_clock(struct timespec *ts)
+{
+       __read_persistent_clock(ts);
+
+       /* Sanitize it in case real time clock is set below EPOCH */
+       if (ts->tv_sec < 0) {
+               ts->tv_sec = 0;
+               ts->tv_nsec = 0;
+       }
+               
 }
 
 /* clocksource code */
@@ -803,7 +835,8 @@ static cycle_t timebase_read(struct clocksource *cs)
        return (cycle_t)get_tb();
 }
 
-void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
+void update_vsyscall(struct timespec *wall_time, struct clocksource *clock,
+                    u32 mult)
 {
        u64 t2x, stamp_xsec;
 
@@ -816,7 +849,7 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
 
        /* XXX this assumes clock->shift == 22 */
        /* 4611686018 ~= 2^(20+64-22) / 1e9 */
-       t2x = (u64) clock->mult * 4611686018ULL;
+       t2x = (u64) mult * 4611686018ULL;
        stamp_xsec = (u64) xtime.tv_nsec * XSEC_PER_SEC;
        do_div(stamp_xsec, 1000000000);
        stamp_xsec += (u64) xtime.tv_sec * XSEC_PER_SEC;
@@ -870,12 +903,21 @@ static void decrementer_set_mode(enum clock_event_mode mode,
                decrementer_set_next_event(DECREMENTER_MAX, dev);
 }
 
+static inline uint64_t div_sc64(unsigned long ticks, unsigned long nsec,
+                               int shift)
+{
+       uint64_t tmp = ((uint64_t)ticks) << shift;
+
+       do_div(tmp, nsec);
+       return tmp;
+}
+
 static void __init setup_clockevent_multiplier(unsigned long hz)
 {
        u64 mult, shift = 32;
 
        while (1) {
-               mult = div_sc(hz, NSEC_PER_SEC, shift);
+               mult = div_sc64(hz, NSEC_PER_SEC, shift);
                if (mult && (mult >> 32UL) == 0UL)
                        break;
 
@@ -893,7 +935,7 @@ static void register_decrementer_clockevent(int cpu)
        *dec = decrementer_clockevent;
        dec->cpumask = cpumask_of(cpu);
 
-       printk(KERN_DEBUG "clockevent: %s mult[%lx] shift[%d] cpu[%d]\n",
+       printk(KERN_DEBUG "clockevent: %s mult[%x] shift[%d] cpu[%d]\n",
               dec->name, dec->mult, dec->shift, cpu);
 
        clockevents_register_device(dec);
@@ -914,6 +956,11 @@ static void __init init_decrementer_clockevent(void)
 
 void secondary_cpu_time_init(void)
 {
+       /* Start the decrementer on CPUs that have manual control
+        * such as BookE
+        */
+       start_cpu_decrementer();
+
        /* FIME: Should make unrelatred change to move snapshot_timebase
         * call here ! */
        register_decrementer_clockevent(smp_processor_id());
@@ -946,6 +993,7 @@ void __init time_init(void)
        tb_ticks_per_usec = ppc_tb_freq / 1000000;
        tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000);
        calc_cputime_factors();
+       setup_cputime_one_jiffy();
 
        /*
         * Calculate the length of each tick in ns.  It will not be
@@ -1017,6 +1065,11 @@ void __init time_init(void)
 
        write_sequnlock_irqrestore(&xtime_lock, flags);
 
+       /* Start the decrementer on CPUs that have manual control
+        * such as BookE
+        */
+       start_cpu_decrementer();
+
        /* Register the clocksource, if we're not running on iSeries */
        if (!firmware_has_feature(FW_FEATURE_ISERIES))
                clocksource_init();