Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=d968014b7280e2c447b20363e576999040ac72ef
Commit:     d968014b7280e2c447b20363e576999040ac72ef
Parent:     87a72f9e171e558a0288aa83ef1dc6ae4af32224
Author:     Paul Mackerras <[EMAIL PROTECTED]>
AuthorDate: Tue Oct 9 09:59:17 2007 +1000
Committer:  Paul Mackerras <[EMAIL PROTECTED]>
CommitDate: Thu Oct 11 21:39:31 2007 +1000

    [POWERPC] Prevent decrementer clockevents from firing early
    
    On old powermacs, we sometimes set the decrementer to 1 in order to
    trigger a decrementer interrupt, which we use to handle an interrupt
    that was pending at the time when it was re-enabled.  This was causing
    the decrementer clock event device to call the event function for the
    next event early, which was causing problems when high-res timers were
    not enabled.
    
    This fixes the problem by recording the timebase value at which the
    next event should occur, and checking the current timebase against the
    recorded value in timer_interrupt.  If it isn't time for the next
    event, it just reprograms the decrementer and returns.
    
    This also subtracts 1 from the value stored into the decrementer,
    which is appropriate because the decrementer interrupts on the
    transition from 0 to -1, not when the decrementer reaches 0.
    
    Signed-off-by: Paul Mackerras <[EMAIL PROTECTED]>
---
 arch/powerpc/kernel/time.c |   14 ++++++++++++++
 1 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index d20947c..64b503c 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -118,6 +118,7 @@ static struct clock_event_device decrementer_clockevent = {
 
 static DEFINE_PER_CPU(struct clock_event_device, decrementers);
 void init_decrementer_clockevent(void);
+static DEFINE_PER_CPU(u64, decrementer_next_tb);
 
 #ifdef CONFIG_PPC_ISERIES
 static unsigned long __initdata iSeries_recal_titan;
@@ -541,6 +542,7 @@ void timer_interrupt(struct pt_regs * regs)
        struct pt_regs *old_regs;
        int cpu = smp_processor_id();
        struct clock_event_device *evt = &per_cpu(decrementers, cpu);
+       u64 now;
 
        /* Ensure a positive value is written to the decrementer, or else
         * some CPUs will continuue to take decrementer exceptions */
@@ -551,6 +553,14 @@ void timer_interrupt(struct pt_regs * regs)
                do_IRQ(regs);
 #endif
 
+       now = get_tb_or_rtc();
+       if (now < per_cpu(decrementer_next_tb, cpu)) {
+               /* not time for this event yet */
+               now = per_cpu(decrementer_next_tb, cpu) - now;
+               if (now <= DECREMENTER_MAX)
+                       set_dec((unsigned int)now - 1);
+               return;
+       }
        old_regs = set_irq_regs(regs);
        irq_enter();
 
@@ -797,6 +807,10 @@ void __init clocksource_init(void)
 static int decrementer_set_next_event(unsigned long evt,
                                      struct clock_event_device *dev)
 {
+       __get_cpu_var(decrementer_next_tb) = get_tb_or_rtc() + evt;
+       /* The decrementer interrupts on the 0 -> -1 transition */
+       if (evt)
+               --evt;
        set_dec(evt);
        return 0;
 }
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to