aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesper Nilsson <jesper.nilsson@axis.com>2007-12-04 11:25:45 -0500
committerJesper Nilsson <jesper.nilsson@axis.com>2008-02-08 05:06:28 -0500
commitfbdb5f865b570e34d6e0d17f327f8d9bc2c4ccc6 (patch)
treef73d1344e299dac0c8e214368c5d1774a759a244
parentbd1c8c54b9a0a60fde31322bcae9d308ba069f12 (diff)
CRIS v32: Update and improve kernel/time.c
- Shorten include paths to machine dependent header files. - Register name for first timer is now regi_timer0. - Remove raw_printk hack, use oops_in_progress instead. - Add handling of CPU frequency scaling for CRIS. - Remove regs parameter to timer_interrupt, get them from get_irq_regs instead. - Whitespace and formatting changes.
-rw-r--r--arch/cris/arch-v32/kernel/time.c237
1 files changed, 139 insertions, 98 deletions
diff --git a/arch/cris/arch-v32/kernel/time.c b/arch/cris/arch-v32/kernel/time.c
index 2f7e8e200f2c..3a13dd6e0a9a 100644
--- a/arch/cris/arch-v32/kernel/time.c
+++ b/arch/cris/arch-v32/kernel/time.c
@@ -1,8 +1,7 @@
1/* $Id: time.c,v 1.19 2005/04/29 05:40:09 starvik Exp $ 1/*
2 *
3 * linux/arch/cris/arch-v32/kernel/time.c 2 * linux/arch/cris/arch-v32/kernel/time.c
4 * 3 *
5 * Copyright (C) 2003 Axis Communications AB 4 * Copyright (C) 2003-2007 Axis Communications AB
6 * 5 *
7 */ 6 */
8 7
@@ -14,28 +13,34 @@
14#include <linux/sched.h> 13#include <linux/sched.h>
15#include <linux/init.h> 14#include <linux/init.h>
16#include <linux/threads.h> 15#include <linux/threads.h>
16#include <linux/cpufreq.h>
17#include <asm/types.h> 17#include <asm/types.h>
18#include <asm/signal.h> 18#include <asm/signal.h>
19#include <asm/io.h> 19#include <asm/io.h>
20#include <asm/delay.h> 20#include <asm/delay.h>
21#include <asm/rtc.h> 21#include <asm/rtc.h>
22#include <asm/irq.h> 22#include <asm/irq.h>
23 23#include <asm/irq_regs.h>
24#include <asm/arch/hwregs/reg_map.h> 24
25#include <asm/arch/hwregs/reg_rdwr.h> 25#include <hwregs/reg_map.h>
26#include <asm/arch/hwregs/timer_defs.h> 26#include <hwregs/reg_rdwr.h>
27#include <asm/arch/hwregs/intr_vect_defs.h> 27#include <hwregs/timer_defs.h>
28#include <hwregs/intr_vect_defs.h>
29#ifdef CONFIG_CRIS_MACH_ARTPEC3
30#include <hwregs/clkgen_defs.h>
31#endif
28 32
29/* Watchdog defines */ 33/* Watchdog defines */
30#define ETRAX_WD_KEY_MASK 0x7F /* key is 7 bit */ 34#define ETRAX_WD_KEY_MASK 0x7F /* key is 7 bit */
31#define ETRAX_WD_HZ 763 /* watchdog counts at 763 Hz */ 35#define ETRAX_WD_HZ 763 /* watchdog counts at 763 Hz */
32#define ETRAX_WD_CNT ((2*ETRAX_WD_HZ)/HZ + 1) /* Number of 763 counts before watchdog bites */ 36/* Number of 763 counts before watchdog bites */
37#define ETRAX_WD_CNT ((2*ETRAX_WD_HZ)/HZ + 1)
33 38
34unsigned long timer_regs[NR_CPUS] = 39unsigned long timer_regs[NR_CPUS] =
35{ 40{
36 regi_timer, 41 regi_timer0,
37#ifdef CONFIG_SMP 42#ifdef CONFIG_SMP
38 regi_timer2 43 regi_timer2
39#endif 44#endif
40}; 45};
41 46
@@ -44,12 +49,22 @@ extern int set_rtc_mmss(unsigned long nowtime);
44extern int setup_irq(int, struct irqaction *); 49extern int setup_irq(int, struct irqaction *);
45extern int have_rtc; 50extern int have_rtc;
46 51
52#ifdef CONFIG_CPU_FREQ
53static int
54cris_time_freq_notifier(struct notifier_block *nb, unsigned long val,
55 void *data);
56
57static struct notifier_block cris_time_freq_notifier_block = {
58 .notifier_call = cris_time_freq_notifier,
59};
60#endif
61
47unsigned long get_ns_in_jiffie(void) 62unsigned long get_ns_in_jiffie(void)
48{ 63{
49 reg_timer_r_tmr0_data data; 64 reg_timer_r_tmr0_data data;
50 unsigned long ns; 65 unsigned long ns;
51 66
52 data = REG_RD(timer, regi_timer, r_tmr0_data); 67 data = REG_RD(timer, regi_timer0, r_tmr0_data);
53 ns = (TIMER0_DIV - data) * 10; 68 ns = (TIMER0_DIV - data) * 10;
54 return ns; 69 return ns;
55} 70}
@@ -59,31 +74,27 @@ unsigned long do_slow_gettimeoffset(void)
59 unsigned long count; 74 unsigned long count;
60 unsigned long usec_count = 0; 75 unsigned long usec_count = 0;
61 76
62 static unsigned long count_p = TIMER0_DIV;/* for the first call after boot */ 77 /* For the first call after boot */
78 static unsigned long count_p = TIMER0_DIV;
63 static unsigned long jiffies_p = 0; 79 static unsigned long jiffies_p = 0;
64 80
65 /* 81 /* Cache volatile jiffies temporarily; we have IRQs turned off. */
66 * cache volatile jiffies temporarily; we have IRQs turned off.
67 */
68 unsigned long jiffies_t; 82 unsigned long jiffies_t;
69 83
70 /* The timer interrupt comes from Etrax timer 0. In order to get 84 /* The timer interrupt comes from Etrax timer 0. In order to get
71 * better precision, we check the current value. It might have 85 * better precision, we check the current value. It might have
72 * underflowed already though. 86 * underflowed already though. */
73 */ 87 count = REG_RD(timer, regi_timer0, r_tmr0_data);
88 jiffies_t = jiffies;
74 89
75 count = REG_RD(timer, regi_timer, r_tmr0_data); 90 /* Avoiding timer inconsistencies (they are rare, but they happen)
76 jiffies_t = jiffies; 91 * There is one problem that must be avoided here:
77 92 * 1. the timer counter underflows
78 /*
79 * avoiding timer inconsistencies (they are rare, but they happen)...
80 * there are one problem that must be avoided here:
81 * 1. the timer counter underflows
82 */ 93 */
83 if( jiffies_t == jiffies_p ) { 94 if( jiffies_t == jiffies_p ) {
84 if( count > count_p ) { 95 if( count > count_p ) {
85 /* Timer wrapped, use new count and prescale 96 /* Timer wrapped, use new count and prescale.
86 * increase the time corresponding to one jiffie 97 * Increase the time corresponding to one jiffy.
87 */ 98 */
88 usec_count = 1000000/HZ; 99 usec_count = 1000000/HZ;
89 } 100 }
@@ -106,17 +117,15 @@ unsigned long do_slow_gettimeoffset(void)
106 */ 117 */
107/* This gives us 1.3 ms to do something useful when the NMI comes */ 118/* This gives us 1.3 ms to do something useful when the NMI comes */
108 119
109/* right now, starting the watchdog is the same as resetting it */ 120/* Right now, starting the watchdog is the same as resetting it */
110#define start_watchdog reset_watchdog 121#define start_watchdog reset_watchdog
111 122
112#if defined(CONFIG_ETRAX_WATCHDOG) 123#if defined(CONFIG_ETRAX_WATCHDOG)
113static short int watchdog_key = 42; /* arbitrary 7 bit number */ 124static short int watchdog_key = 42; /* arbitrary 7 bit number */
114#endif 125#endif
115 126
116/* number of pages to consider "out of memory". it is normal that the memory 127/* Number of pages to consider "out of memory". It is normal that the memory
117 * is used though, so put this really low. 128 * is used though, so set this really low. */
118 */
119
120#define WATCHDOG_MIN_FREE_PAGES 8 129#define WATCHDOG_MIN_FREE_PAGES 8
121 130
122void 131void
@@ -125,14 +134,15 @@ reset_watchdog(void)
125#if defined(CONFIG_ETRAX_WATCHDOG) 134#if defined(CONFIG_ETRAX_WATCHDOG)
126 reg_timer_rw_wd_ctrl wd_ctrl = { 0 }; 135 reg_timer_rw_wd_ctrl wd_ctrl = { 0 };
127 136
128 /* only keep watchdog happy as long as we have memory left! */ 137 /* Only keep watchdog happy as long as we have memory left! */
129 if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) { 138 if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) {
130 /* reset the watchdog with the inverse of the old key */ 139 /* Reset the watchdog with the inverse of the old key */
131 watchdog_key ^= ETRAX_WD_KEY_MASK; /* invert key, which is 7 bits */ 140 /* Invert key, which is 7 bits */
141 watchdog_key ^= ETRAX_WD_KEY_MASK;
132 wd_ctrl.cnt = ETRAX_WD_CNT; 142 wd_ctrl.cnt = ETRAX_WD_CNT;
133 wd_ctrl.cmd = regk_timer_start; 143 wd_ctrl.cmd = regk_timer_start;
134 wd_ctrl.key = watchdog_key; 144 wd_ctrl.key = watchdog_key;
135 REG_WR(timer, regi_timer, rw_wd_ctrl, wd_ctrl); 145 REG_WR(timer, regi_timer0, rw_wd_ctrl, wd_ctrl);
136 } 146 }
137#endif 147#endif
138} 148}
@@ -148,7 +158,7 @@ stop_watchdog(void)
148 wd_ctrl.cnt = ETRAX_WD_CNT; 158 wd_ctrl.cnt = ETRAX_WD_CNT;
149 wd_ctrl.cmd = regk_timer_stop; 159 wd_ctrl.cmd = regk_timer_stop;
150 wd_ctrl.key = watchdog_key; 160 wd_ctrl.key = watchdog_key;
151 REG_WR(timer, regi_timer, rw_wd_ctrl, wd_ctrl); 161 REG_WR(timer, regi_timer0, rw_wd_ctrl, wd_ctrl);
152#endif 162#endif
153} 163}
154 164
@@ -160,17 +170,28 @@ handle_watchdog_bite(struct pt_regs* regs)
160#if defined(CONFIG_ETRAX_WATCHDOG) 170#if defined(CONFIG_ETRAX_WATCHDOG)
161 extern int cause_of_death; 171 extern int cause_of_death;
162 172
163 raw_printk("Watchdog bite\n"); 173 oops_in_progress = 1;
174 printk(KERN_WARNING "Watchdog bite\n");
164 175
165 /* Check if forced restart or unexpected watchdog */ 176 /* Check if forced restart or unexpected watchdog */
166 if (cause_of_death == 0xbedead) { 177 if (cause_of_death == 0xbedead) {
178#ifdef CONFIG_CRIS_MACH_ARTPEC3
179 /* There is a bug in Artpec-3 (voodoo TR 78) that requires
180 * us to go to lower frequency for the reset to be reliable
181 */
182 reg_clkgen_rw_clk_ctrl ctrl =
183 REG_RD(clkgen, regi_clkgen, rw_clk_ctrl);
184 ctrl.pll = 0;
185 REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, ctrl);
186#endif
167 while(1); 187 while(1);
168 } 188 }
169 189
170 /* Unexpected watchdog, stop the watchdog and dump registers*/ 190 /* Unexpected watchdog, stop the watchdog and dump registers. */
171 stop_watchdog(); 191 stop_watchdog();
172 raw_printk("Oops: bitten by watchdog\n"); 192 printk(KERN_WARNING "Oops: bitten by watchdog\n");
173 show_registers(regs); 193 show_registers(regs);
194 oops_in_progress = 0;
174#ifndef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY 195#ifndef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
175 reset_watchdog(); 196 reset_watchdog();
176#endif 197#endif
@@ -178,21 +199,19 @@ handle_watchdog_bite(struct pt_regs* regs)
178#endif 199#endif
179} 200}
180 201
181/* last time the cmos clock got updated */ 202/* Last time the cmos clock got updated. */
182static long last_rtc_update = 0; 203static long last_rtc_update = 0;
183 204
184/* 205/*
185 * timer_interrupt() needs to keep up the real-time clock, 206 * timer_interrupt() needs to keep up the real-time clock,
186 * as well as call the "do_timer()" routine every clocktick 207 * as well as call the "do_timer()" routine every clocktick.
187 */ 208 */
188
189//static unsigned short myjiff; /* used by our debug routine print_timestamp */
190
191extern void cris_do_profile(struct pt_regs *regs); 209extern void cris_do_profile(struct pt_regs *regs);
192 210
193static inline irqreturn_t 211static inline irqreturn_t
194timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) 212timer_interrupt(int irq, void *dev_id)
195{ 213{
214 struct pt_regs *regs = get_irq_regs();
196 int cpu = smp_processor_id(); 215 int cpu = smp_processor_id();
197 reg_timer_r_masked_intr masked_intr; 216 reg_timer_r_masked_intr masked_intr;
198 reg_timer_rw_ack_intr ack_intr = { 0 }; 217 reg_timer_rw_ack_intr ack_intr = { 0 };
@@ -202,11 +221,11 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
202 if (!masked_intr.tmr0) 221 if (!masked_intr.tmr0)
203 return IRQ_NONE; 222 return IRQ_NONE;
204 223
205 /* acknowledge the timer irq */ 224 /* Acknowledge the timer irq. */
206 ack_intr.tmr0 = 1; 225 ack_intr.tmr0 = 1;
207 REG_WR(timer, timer_regs[cpu], rw_ack_intr, ack_intr); 226 REG_WR(timer, timer_regs[cpu], rw_ack_intr, ack_intr);
208 227
209 /* reset watchdog otherwise it resets us! */ 228 /* Reset watchdog otherwise it resets us! */
210 reset_watchdog(); 229 reset_watchdog();
211 230
212 /* Update statistics. */ 231 /* Update statistics. */
@@ -218,7 +237,7 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
218 if (cpu != 0) 237 if (cpu != 0)
219 return IRQ_HANDLED; 238 return IRQ_HANDLED;
220 239
221 /* call the real timer interrupt handler */ 240 /* Call the real timer interrupt handler */
222 do_timer(1); 241 do_timer(1);
223 242
224 /* 243 /*
@@ -236,17 +255,17 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
236 if (set_rtc_mmss(xtime.tv_sec) == 0) 255 if (set_rtc_mmss(xtime.tv_sec) == 0)
237 last_rtc_update = xtime.tv_sec; 256 last_rtc_update = xtime.tv_sec;
238 else 257 else
239 last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ 258 /* Do it again in 60 s */
259 last_rtc_update = xtime.tv_sec - 600;
240 } 260 }
241 return IRQ_HANDLED; 261 return IRQ_HANDLED;
242} 262}
243 263
244/* timer is IRQF_SHARED so drivers can add stuff to the timer irq chain 264/* Timer is IRQF_SHARED so drivers can add stuff to the timer irq chain.
245 * it needs to be IRQF_DISABLED to make the jiffies update work properly 265 * It needs to be IRQF_DISABLED to make the jiffies update work properly.
246 */ 266 */
247 267static struct irqaction irq_timer = {
248static struct irqaction irq_timer = { 268 .handler = timer_interrupt,
249 .mask = timer_interrupt,
250 .flags = IRQF_SHARED | IRQF_DISABLED, 269 .flags = IRQF_SHARED | IRQF_DISABLED,
251 .mask = CPU_MASK_NONE, 270 .mask = CPU_MASK_NONE,
252 .name = "timer" 271 .name = "timer"
@@ -256,27 +275,27 @@ void __init
256cris_timer_init(void) 275cris_timer_init(void)
257{ 276{
258 int cpu = smp_processor_id(); 277 int cpu = smp_processor_id();
259 reg_timer_rw_tmr0_ctrl tmr0_ctrl = { 0 }; 278 reg_timer_rw_tmr0_ctrl tmr0_ctrl = { 0 };
260 reg_timer_rw_tmr0_div tmr0_div = TIMER0_DIV; 279 reg_timer_rw_tmr0_div tmr0_div = TIMER0_DIV;
261 reg_timer_rw_intr_mask timer_intr_mask; 280 reg_timer_rw_intr_mask timer_intr_mask;
262 281
263 /* Setup the etrax timers 282 /* Setup the etrax timers.
264 * Base frequency is 100MHz, divider 1000000 -> 100 HZ 283 * Base frequency is 100MHz, divider 1000000 -> 100 HZ
265 * We use timer0, so timer1 is free. 284 * We use timer0, so timer1 is free.
266 * The trig timer is used by the fasttimer API if enabled. 285 * The trig timer is used by the fasttimer API if enabled.
267 */ 286 */
268 287
269 tmr0_ctrl.op = regk_timer_ld; 288 tmr0_ctrl.op = regk_timer_ld;
270 tmr0_ctrl.freq = regk_timer_f100; 289 tmr0_ctrl.freq = regk_timer_f100;
271 REG_WR(timer, timer_regs[cpu], rw_tmr0_div, tmr0_div); 290 REG_WR(timer, timer_regs[cpu], rw_tmr0_div, tmr0_div);
272 REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Load */ 291 REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Load */
273 tmr0_ctrl.op = regk_timer_run; 292 tmr0_ctrl.op = regk_timer_run;
274 REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Start */ 293 REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Start */
275 294
276 /* enable the timer irq */ 295 /* Enable the timer irq. */
277 timer_intr_mask = REG_RD(timer, timer_regs[cpu], rw_intr_mask); 296 timer_intr_mask = REG_RD(timer, timer_regs[cpu], rw_intr_mask);
278 timer_intr_mask.tmr0 = 1; 297 timer_intr_mask.tmr0 = 1;
279 REG_WR(timer, timer_regs[cpu], rw_intr_mask, timer_intr_mask); 298 REG_WR(timer, timer_regs[cpu], rw_intr_mask, timer_intr_mask);
280} 299}
281 300
282void __init 301void __init
@@ -284,7 +303,7 @@ time_init(void)
284{ 303{
285 reg_intr_vect_rw_mask intr_mask; 304 reg_intr_vect_rw_mask intr_mask;
286 305
287 /* probe for the RTC and read it if it exists 306 /* Probe for the RTC and read it if it exists.
288 * Before the RTC can be probed the loops_per_usec variable needs 307 * Before the RTC can be probed the loops_per_usec variable needs
289 * to be initialized to make usleep work. A better value for 308 * to be initialized to make usleep work. A better value for
290 * loops_per_usec is calculated by the kernel later once the 309 * loops_per_usec is calculated by the kernel later once the
@@ -293,52 +312,74 @@ time_init(void)
293 loops_per_usec = 50; 312 loops_per_usec = 50;
294 313
295 if(RTC_INIT() < 0) { 314 if(RTC_INIT() < 0) {
296 /* no RTC, start at 1980 */ 315 /* No RTC, start at 1980 */
297 xtime.tv_sec = 0; 316 xtime.tv_sec = 0;
298 xtime.tv_nsec = 0; 317 xtime.tv_nsec = 0;
299 have_rtc = 0; 318 have_rtc = 0;
300 } else { 319 } else {
301 /* get the current time */ 320 /* Get the current time */
302 have_rtc = 1; 321 have_rtc = 1;
303 update_xtime_from_cmos(); 322 update_xtime_from_cmos();
304 } 323 }
305 324
306 /* 325 /*
307 * Initialize wall_to_monotonic such that adding it to xtime will yield zero, the 326 * Initialize wall_to_monotonic such that adding it to
308 * tv_nsec field must be normalized (i.e., 0 <= nsec < NSEC_PER_SEC). 327 * xtime will yield zero, the tv_nsec field must be normalized
328 * (i.e., 0 <= nsec < NSEC_PER_SEC).
309 */ 329 */
310 set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec); 330 set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec);
311 331
312 /* Start CPU local timer */ 332 /* Start CPU local timer. */
313 cris_timer_init(); 333 cris_timer_init();
314 334
315 /* enable the timer irq in global config */ 335 /* Enable the timer irq in global config. */
316 intr_mask = REG_RD(intr_vect, regi_irq, rw_mask); 336 intr_mask = REG_RD_VECT(intr_vect, regi_irq, rw_mask, 1);
317 intr_mask.timer = 1; 337 intr_mask.timer0 = 1;
318 REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); 338 REG_WR_VECT(intr_vect, regi_irq, rw_mask, 1, intr_mask);
319
320 /* now actually register the timer irq handler that calls timer_interrupt() */
321 339
322 setup_irq(TIMER_INTR_VECT, &irq_timer); 340 /* Now actually register the timer irq handler that calls
341 * timer_interrupt(). */
342 setup_irq(TIMER0_INTR_VECT, &irq_timer);
323 343
324 /* enable watchdog if we should use one */ 344 /* Enable watchdog if we should use one. */
325 345
326#if defined(CONFIG_ETRAX_WATCHDOG) 346#if defined(CONFIG_ETRAX_WATCHDOG)
327 printk("Enabling watchdog...\n"); 347 printk(KERN_INFO "Enabling watchdog...\n");
328 start_watchdog(); 348 start_watchdog();
329 349
330 /* If we use the hardware watchdog, we want to trap it as an NMI 350 /* If we use the hardware watchdog, we want to trap it as an NMI
331 and dump registers before it resets us. For this to happen, we 351 * and dump registers before it resets us. For this to happen, we
332 must set the "m" NMI enable flag (which once set, is unset only 352 * must set the "m" NMI enable flag (which once set, is unset only
333 when an NMI is taken). 353 * when an NMI is taken). */
334 354 {
335 The same goes for the external NMI, but that doesn't have any 355 unsigned long flags;
336 driver or infrastructure support yet. */ 356 local_save_flags(flags);
337 { 357 flags |= (1<<30); /* NMI M flag is at bit 30 */
338 unsigned long flags; 358 local_irq_restore(flags);
339 local_save_flags(flags); 359 }
340 flags |= (1<<30); /* NMI M flag is at bit 30 */ 360#endif
341 local_irq_restore(flags); 361
342 } 362#ifdef CONFIG_CPU_FREQ
363 cpufreq_register_notifier(&cris_time_freq_notifier_block,
364 CPUFREQ_TRANSITION_NOTIFIER);
343#endif 365#endif
344} 366}
367
368#ifdef CONFIG_CPU_FREQ
369static int
370cris_time_freq_notifier(struct notifier_block *nb, unsigned long val,
371 void *data)
372{
373 struct cpufreq_freqs *freqs = data;
374 if (val == CPUFREQ_POSTCHANGE) {
375 reg_timer_r_tmr0_data data;
376 reg_timer_rw_tmr0_div div = (freqs->new * 500) / HZ;
377 do {
378 data = REG_RD(timer, timer_regs[freqs->cpu],
379 r_tmr0_data);
380 } while (data > 20);
381 REG_WR(timer, timer_regs[freqs->cpu], rw_tmr0_div, div);
382 }
383 return 0;
384}
385#endif