2 * arch/ubicom32/kernel/time.c
3 * Initialize the timer list and start the appropriate timers.
5 * (C) Copyright 2009, Ubicom, Inc.
6 * Copyright (C) 1991, 1992, 1995 Linus Torvalds
8 * This file is part of the Ubicom32 Linux Kernel Port.
10 * The Ubicom32 Linux Kernel Port is free software: you can redistribute
11 * it and/or modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation, either version 2 of the
13 * License, or (at your option) any later version.
15 * The Ubicom32 Linux Kernel Port is distributed in the hope that it
16 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
17 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
18 * the GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with the Ubicom32 Linux Kernel Port. If not,
22 * see <http://www.gnu.org/licenses/>.
24 * Ubicom32 implementation derived from (with many thanks):
30 #include <linux/profile.h>
31 #include <linux/smp.h>
32 #include <asm/ip5000.h>
33 #include <asm/machdep.h>
36 * A bitmap of the timers on the processor indicates
37 * that the timer is free or in-use.
39 static unsigned int timers
;
43 * Init the specified compare register to go off <n> cycles from now.
45 void timer_set(int timervector
, unsigned int cycles
)
47 int idx
= UBICOM32_VECTOR_TO_TIMER_INDEX(timervector
);
48 UBICOM32_IO_TIMER
->syscom
[idx
] =
49 UBICOM32_IO_TIMER
->sysval
+ cycles
;
50 ldsr_enable_vector(timervector
);
55 * Set/reset the timer to go off again.
57 * Because sysval is a continuous timer, this function is able
58 * to ensure that we do not have clock sku by using the previous
59 * value in syscom to set the next value for syscom.
61 * Returns the number of ticks that transpired since the last event.
63 int timer_reset(int timervector
, unsigned int cycles
)
66 * Reset the timer in the LDSR thread to go off appropriately.
68 * Use the previous value of the timer to calculate the new stop
69 * time. This allows us to account for it taking an
70 * indeterminate amount of time to get here.
72 const int timer_index
= UBICOM32_VECTOR_TO_TIMER_INDEX(timervector
);
73 unsigned int prev
= UBICOM32_IO_TIMER
->syscom
[timer_index
];
74 unsigned int next
= prev
+ cycles
;
80 * If the difference is negative, we have missed at least one
83 * TODO: Decide if we want to "ignore" time (as done below) or
84 * if we want to process time (unevenly) by calling timer_tick()
89 * Set our future time first.
91 UBICOM32_IO_TIMER
->syscom
[timer_index
] = next
;
94 * Then check if we are really set time in the futrue.
96 diff
= (int)next
- (int)UBICOM32_IO_TIMER
->sysval
;
102 * Oops, we are too slow. Playing catch up.
104 * If the debugger is connected the there is a good
105 * chance that we lost time because we were in a
106 * break-point, so in this case we do not print out
109 asm volatile ("move.4 %0, scratchpad3"
110 : "=r" (scratchpad3
));
111 if ((scratchpad3
& 0x1) == 0) {
113 * No debugger attached, print to the console
115 printk(KERN_EMERG
"diff: %d, timer has lost %u "
116 "ticks [rounded up]\n",
118 (unsigned int)((-diff
+ cycles
- 1) / cycles
));
123 diff
= (int)next
- (int)UBICOM32_IO_TIMER
->sysval
;
132 * Returns current time in nano-second units.
135 * 1) This is an override for the weak alias in
136 * kernel/sched_clock.c.
137 * 2) Do not use xtime_lock as this function is
138 * sometimes called with xtime_lock held.
139 * 3) We use a retry algorithm to ensure that
140 * we get a consistent value.
141 * 4) sched_clock must be overwritten if IRQ tracing
142 * is enabled because the default implementation uses
143 * the xtime_lock sequence while holding xtime_lock.
145 unsigned long long sched_clock(void)
147 unsigned long long my_jiffies
;
148 unsigned long jiffies_top
;
149 unsigned long jiffies_bottom
;
152 jiffies_top
= jiffies_64
>> 32;
153 jiffies_bottom
= jiffies_64
& 0xffffffff;
154 } while (unlikely(jiffies_top
!= (unsigned long)(jiffies_64
>> 32)));
156 my_jiffies
= ((unsigned long long)jiffies_top
<< 32) | (jiffies_bottom
);
157 return (my_jiffies
- INITIAL_JIFFIES
) * (NSEC_PER_SEC
/ HZ
);
162 * Free a hardware timer.
164 void timer_free(int interrupt
)
166 unsigned int bit
= interrupt
- TIMER_INT(0);
169 * The timer had not been allocated.
171 BUG_ON(timers
& (1 << bit
));
172 timers
|= (1 << bit
);
177 * Allocate a hardware timer.
179 int timer_alloc(void)
181 unsigned int bit
= find_first_bit((unsigned long *)&timers
, 32);
183 printk(KERN_WARNING
"no more free timers\n");
187 timers
&= ~(1 << bit
);
188 return bit
+ TIMER_INT(0);
193 * Time init function.
198 * Find the processor node and determine what timers are
201 timers
= processor_timers();
203 printk(KERN_WARNING
"no timers are available for Linux\n");
207 #ifdef CONFIG_GENERIC_CLOCKEVENTS