vserver 1.9.5.x5
[linux-2.6.git] / arch / arm / mach-iop3xx / iop321-time.c
index 64a1e7c..9b7dd64 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Author: Deepak Saxena <dsaxena@mvista.com>
  *
- * Copyright 2002 MontaVista Software Inc.
+ * Copyright 2002-2003 MontaVista Software Inc.
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
 #include <asm/uaccess.h>
 #include <asm/mach-types.h>
 #include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+
+#define IOP321_TIME_SYNC 0
+
+static inline unsigned long get_elapsed(void)
+{
+       return LATCH - *IOP321_TU_TCR0;
+}
 
 static unsigned long iop321_gettimeoffset(void)
 {
        unsigned long elapsed, usec;
+       u32 tisr1, tisr2;
 
        /*
-        * FIXME: Implement what is described in this comment.
-        *
         * If an interrupt was pending before we read the timer,
         * we've already wrapped.  Factor this into the time.
         * If an interrupt was pending after we read the timer,
@@ -41,12 +48,19 @@ static unsigned long iop321_gettimeoffset(void)
         * be sure its value is after the wrap.
         */
 
-       elapsed = *IOP321_TU_TCR0;
+       asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr1));
+       elapsed = get_elapsed();
+       asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr2));
+
+       if(tisr1 & 1)
+               elapsed += LATCH;
+       else if (tisr2 & 1)
+               elapsed = LATCH + get_elapsed();
 
        /*
         * Now convert them to usec.
         */
-       usec = (unsigned long)((LATCH - elapsed) * (tick_nsec / 1000)) / LATCH;
+       usec = (unsigned long)(elapsed * (tick_nsec / 1000)) / LATCH;
 
        return usec;
 }
@@ -56,33 +70,30 @@ iop321_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        u32 tisr;
 
-       asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr));
+       write_seqlock(&xtime_lock);
 
+       asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr));
        tisr |= 1;
-
        asm volatile("mcr p6, 0, %0, c6, c1, 0" : : "r" (tisr));
 
-       do_timer(regs);
+       timer_tick(regs);
+
+       write_sequnlock(&xtime_lock);
 
        return IRQ_HANDLED;
 }
 
-extern unsigned long (*gettimeoffset)(void);
-
-static struct irqaction timer_irq = {
-       .name           = "timer",
+static struct irqaction iop321_timer_irq = {
+       .name           = "IOP321 Timer Tick",
        .handler        = iop321_timer_interrupt,
+       .flags          = SA_INTERRUPT
 };
 
-extern int setup_arm_irq(int, struct irqaction*);
-
-void __init time_init(void)
+static void __init iop321_timer_init(void)
 {
        u32 timer_ctl;
-       u32 latch = LATCH;
 
-       gettimeoffset = iop321_gettimeoffset;
-       setup_irq(IRQ_IOP321_TIMER0, &timer_irq);
+       setup_irq(IRQ_IOP321_TIMER0, &iop321_timer_irq);
 
        timer_ctl = IOP321_TMR_EN | IOP321_TMR_PRIVILEGED | IOP321_TMR_RELOAD |
                        IOP321_TMR_RATIO_1_1;
@@ -92,4 +103,7 @@ void __init time_init(void)
        asm volatile("mcr p6, 0, %0, c0, c1, 0" : : "r" (timer_ctl));
 }
 
-
+struct sys_timer iop321_timer = {
+       .init           = &iop321_timer_init,
+       .offset         = iop321_gettimeoffset,
+};