diff options
author | Jesper Nilsson <jesper.nilsson@axis.com> | 2007-12-04 11:25:45 -0500 |
---|---|---|
committer | Jesper Nilsson <jesper.nilsson@axis.com> | 2008-02-08 05:06:28 -0500 |
commit | fbdb5f865b570e34d6e0d17f327f8d9bc2c4ccc6 (patch) | |
tree | f73d1344e299dac0c8e214368c5d1774a759a244 /arch/cris/arch-v32/kernel | |
parent | bd1c8c54b9a0a60fde31322bcae9d308ba069f12 (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.
Diffstat (limited to 'arch/cris/arch-v32/kernel')
-rw-r--r-- | arch/cris/arch-v32/kernel/time.c | 237 |
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 | ||
34 | unsigned long timer_regs[NR_CPUS] = | 39 | unsigned 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); | |||
44 | extern int setup_irq(int, struct irqaction *); | 49 | extern int setup_irq(int, struct irqaction *); |
45 | extern int have_rtc; | 50 | extern int have_rtc; |
46 | 51 | ||
52 | #ifdef CONFIG_CPU_FREQ | ||
53 | static int | ||
54 | cris_time_freq_notifier(struct notifier_block *nb, unsigned long val, | ||
55 | void *data); | ||
56 | |||
57 | static struct notifier_block cris_time_freq_notifier_block = { | ||
58 | .notifier_call = cris_time_freq_notifier, | ||
59 | }; | ||
60 | #endif | ||
61 | |||
47 | unsigned long get_ns_in_jiffie(void) | 62 | unsigned 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) |
113 | static short int watchdog_key = 42; /* arbitrary 7 bit number */ | 124 | static 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 | ||
122 | void | 131 | void |
@@ -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. */ |
182 | static long last_rtc_update = 0; | 203 | static 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 | |||
191 | extern void cris_do_profile(struct pt_regs *regs); | 209 | extern void cris_do_profile(struct pt_regs *regs); |
192 | 210 | ||
193 | static inline irqreturn_t | 211 | static inline irqreturn_t |
194 | timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 212 | timer_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 | 267 | static struct irqaction irq_timer = { | |
248 | static 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 | |||
256 | cris_timer_init(void) | 275 | cris_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 | ||
282 | void __init | 301 | void __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 | ||
369 | static int | ||
370 | cris_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 | ||