aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/time.c
diff options
context:
space:
mode:
authorAnton Blanchard <anton@samba.org>2009-05-10 09:37:36 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2009-05-21 01:44:24 -0400
commit8d165db10772f238103c3e8f955c54145e5c07f3 (patch)
tree54f287e003df92f2d7b237a2382e4f68db9821cd /arch/powerpc/kernel/time.c
parent9aa4e7b1699d0fa197778da96de7e03fa2374f0a (diff)
powerpc: Improve decrementer accuracy
I have been looking at sources of OS jitter and notice that after a long NO_HZ idle period we wakeup too early: relative time (us) event timer irq exit 999946.405 timer irq entry 4.835 timer irq exit 21.685 timer irq entry 3.540 timer (tick_sched_timer) entry Here we slept for just under a second then took a timer interrupt that did nothing. 21.685 us later we wake up again and do the work. We set a rather low shift value of 16 for the decrementer clockevent, which I think is causing this issue. On this box we have a 207MHz decrementer and see: clockevent: decrementer mult[3501] shift[16] cpu[0] For calculations of large intervals this mult/shift combination could be off by a significant amount. I notice the sparc code has a loop that iterates to find a mult/shift combination that maximises the shift value while keeping mult under 32bit. With the patch below we get: clockevent: decrementer mult[35015c20] shift[32] cpu[15] And we no longer see the spurious wakeups. Signed-off-by: Anton Blanchard <anton@samba.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/time.c')
-rw-r--r--arch/powerpc/kernel/time.c21
1 files changed, 18 insertions, 3 deletions
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 48571ac56fb7..bee1443da763 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -109,7 +109,7 @@ static void decrementer_set_mode(enum clock_event_mode mode,
109static struct clock_event_device decrementer_clockevent = { 109static struct clock_event_device decrementer_clockevent = {
110 .name = "decrementer", 110 .name = "decrementer",
111 .rating = 200, 111 .rating = 200,
112 .shift = 16, 112 .shift = 0, /* To be filled in */
113 .mult = 0, /* To be filled in */ 113 .mult = 0, /* To be filled in */
114 .irq = 0, 114 .irq = 0,
115 .set_next_event = decrementer_set_next_event, 115 .set_next_event = decrementer_set_next_event,
@@ -843,6 +843,22 @@ static void decrementer_set_mode(enum clock_event_mode mode,
843 decrementer_set_next_event(DECREMENTER_MAX, dev); 843 decrementer_set_next_event(DECREMENTER_MAX, dev);
844} 844}
845 845
846static void __init setup_clockevent_multiplier(unsigned long hz)
847{
848 u64 mult, shift = 32;
849
850 while (1) {
851 mult = div_sc(hz, NSEC_PER_SEC, shift);
852 if (mult && (mult >> 32UL) == 0UL)
853 break;
854
855 shift--;
856 }
857
858 decrementer_clockevent.shift = shift;
859 decrementer_clockevent.mult = mult;
860}
861
846static void register_decrementer_clockevent(int cpu) 862static void register_decrementer_clockevent(int cpu)
847{ 863{
848 struct clock_event_device *dec = &per_cpu(decrementers, cpu).event; 864 struct clock_event_device *dec = &per_cpu(decrementers, cpu).event;
@@ -860,8 +876,7 @@ static void __init init_decrementer_clockevent(void)
860{ 876{
861 int cpu = smp_processor_id(); 877 int cpu = smp_processor_id();
862 878
863 decrementer_clockevent.mult = div_sc(ppc_tb_freq, NSEC_PER_SEC, 879 setup_clockevent_multiplier(ppc_tb_freq);
864 decrementer_clockevent.shift);
865 decrementer_clockevent.max_delta_ns = 880 decrementer_clockevent.max_delta_ns =
866 clockevent_delta2ns(DECREMENTER_MAX, &decrementer_clockevent); 881 clockevent_delta2ns(DECREMENTER_MAX, &decrementer_clockevent);
867 decrementer_clockevent.min_delta_ns = 882 decrementer_clockevent.min_delta_ns =