diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2007-10-18 08:34:12 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-10-18 13:11:47 -0400 |
commit | e887b24592c5ddf46d37e592b2ee6bd2188257e1 (patch) | |
tree | 802956f841441d87dc472240c9eee87f6a574f46 /arch | |
parent | 832348ff0bf1538e026ff862f91ab6db06e73499 (diff) |
[MIPS] IP27: Convert to clock_event_device.
This separates the tick timer stuff from the generic MIPS time.c.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/mips/sgi-ip27/ip27-irq.c | 5 | ||||
-rw-r--r-- | arch/mips/sgi-ip27/ip27-timer.c | 155 |
2 files changed, 94 insertions, 66 deletions
diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c index 856649cf9f1e..1bb692a3b319 100644 --- a/arch/mips/sgi-ip27/ip27-irq.c +++ b/arch/mips/sgi-ip27/ip27-irq.c | |||
@@ -374,14 +374,13 @@ int __devinit request_bridge_irq(struct bridge_controller *bc) | |||
374 | return irq; | 374 | return irq; |
375 | } | 375 | } |
376 | 376 | ||
377 | extern void ip27_rt_timer_interrupt(void); | ||
378 | |||
379 | asmlinkage void plat_irq_dispatch(void) | 377 | asmlinkage void plat_irq_dispatch(void) |
380 | { | 378 | { |
381 | unsigned long pending = read_c0_cause() & read_c0_status(); | 379 | unsigned long pending = read_c0_cause() & read_c0_status(); |
380 | extern unsigned int rt_timer_irq; | ||
382 | 381 | ||
383 | if (pending & CAUSEF_IP4) | 382 | if (pending & CAUSEF_IP4) |
384 | ip27_rt_timer_interrupt(); | 383 | do_IRQ(rt_timer_irq); |
385 | else if (pending & CAUSEF_IP2) /* PI_INT_PEND_0 or CC_PEND_{A|B} */ | 384 | else if (pending & CAUSEF_IP2) /* PI_INT_PEND_0 or CC_PEND_{A|B} */ |
386 | ip27_do_irq_mask0(); | 385 | ip27_do_irq_mask0(); |
387 | else if (pending & CAUSEF_IP3) /* PI_INT_PEND_1 */ | 386 | else if (pending & CAUSEF_IP3) /* PI_INT_PEND_1 */ |
diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index b7b3479b6bce..d467bf4f6c3f 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c | |||
@@ -3,6 +3,7 @@ | |||
3 | * Copytight (C) 1999, 2000 Silicon Graphics, Inc. | 3 | * Copytight (C) 1999, 2000 Silicon Graphics, Inc. |
4 | */ | 4 | */ |
5 | #include <linux/bcd.h> | 5 | #include <linux/bcd.h> |
6 | #include <linux/clockchips.h> | ||
6 | #include <linux/init.h> | 7 | #include <linux/init.h> |
7 | #include <linux/kernel.h> | 8 | #include <linux/kernel.h> |
8 | #include <linux/sched.h> | 9 | #include <linux/sched.h> |
@@ -25,22 +26,8 @@ | |||
25 | #include <asm/sn/sn0/ip27.h> | 26 | #include <asm/sn/sn0/ip27.h> |
26 | #include <asm/sn/sn0/hub.h> | 27 | #include <asm/sn/sn0/hub.h> |
27 | 28 | ||
28 | /* | ||
29 | * This is a hack; we really need to figure these values out dynamically | ||
30 | * | ||
31 | * Since 800 ns works very well with various HUB frequencies, such as | ||
32 | * 360, 380, 390 and 400 MHZ, we use 800 ns rtc cycle time. | ||
33 | * | ||
34 | * Ralf: which clock rate is used to feed the counter? | ||
35 | */ | ||
36 | #define NSEC_PER_CYCLE 800 | ||
37 | #define CYCLES_PER_SEC (NSEC_PER_SEC/NSEC_PER_CYCLE) | ||
38 | #define CYCLES_PER_JIFFY (CYCLES_PER_SEC/HZ) | ||
39 | |||
40 | #define TICK_SIZE (tick_nsec / 1000) | 29 | #define TICK_SIZE (tick_nsec / 1000) |
41 | 30 | ||
42 | static unsigned long ct_cur[NR_CPUS]; /* What counter should be at next timer irq */ | ||
43 | |||
44 | #if 0 | 31 | #if 0 |
45 | static int set_rtc_mmss(unsigned long nowtime) | 32 | static int set_rtc_mmss(unsigned long nowtime) |
46 | { | 33 | { |
@@ -86,36 +73,6 @@ static int set_rtc_mmss(unsigned long nowtime) | |||
86 | } | 73 | } |
87 | #endif | 74 | #endif |
88 | 75 | ||
89 | static unsigned int rt_timer_irq; | ||
90 | |||
91 | void ip27_rt_timer_interrupt(void) | ||
92 | { | ||
93 | int cpu = smp_processor_id(); | ||
94 | int cpuA = cputoslice(cpu) == 0; | ||
95 | unsigned int irq = rt_timer_irq; | ||
96 | |||
97 | irq_enter(); | ||
98 | write_seqlock(&xtime_lock); | ||
99 | |||
100 | again: | ||
101 | LOCAL_HUB_S(cpuA ? PI_RT_PEND_A : PI_RT_PEND_B, 0); /* Ack */ | ||
102 | ct_cur[cpu] += CYCLES_PER_JIFFY; | ||
103 | LOCAL_HUB_S(cpuA ? PI_RT_COMPARE_A : PI_RT_COMPARE_B, ct_cur[cpu]); | ||
104 | |||
105 | if (LOCAL_HUB_L(PI_RT_COUNT) >= ct_cur[cpu]) | ||
106 | goto again; | ||
107 | |||
108 | kstat_this_cpu.irqs[irq]++; /* kstat only for bootcpu? */ | ||
109 | |||
110 | if (cpu == 0) | ||
111 | do_timer(1); | ||
112 | |||
113 | update_process_times(user_mode(get_irq_regs())); | ||
114 | |||
115 | write_sequnlock(&xtime_lock); | ||
116 | irq_exit(); | ||
117 | } | ||
118 | |||
119 | /* Includes for ioc3_init(). */ | 76 | /* Includes for ioc3_init(). */ |
120 | #include <asm/sn/types.h> | 77 | #include <asm/sn/types.h> |
121 | #include <asm/sn/sn0/addrs.h> | 78 | #include <asm/sn/sn0/addrs.h> |
@@ -154,6 +111,46 @@ unsigned long read_persistent_clock(void) | |||
154 | return mktime(year, month, date, hour, min, sec); | 111 | return mktime(year, month, date, hour, min, sec); |
155 | } | 112 | } |
156 | 113 | ||
114 | static int rt_set_next_event(unsigned long delta, | ||
115 | struct clock_event_device *evt) | ||
116 | { | ||
117 | unsigned int cpu = smp_processor_id(); | ||
118 | int slice = cputoslice(cpu) == 0; | ||
119 | unsigned long cnt; | ||
120 | |||
121 | cnt = LOCAL_HUB_L(PI_RT_COUNT); | ||
122 | cnt += delta; | ||
123 | LOCAL_HUB_S(slice ? PI_RT_COMPARE_A : PI_RT_COMPARE_B, cnt); | ||
124 | |||
125 | return LOCAL_HUB_L(PI_RT_COUNT) >= cnt ? -ETIME : 0; | ||
126 | } | ||
127 | |||
128 | static void rt_set_mode(enum clock_event_mode mode, | ||
129 | struct clock_event_device *evt) | ||
130 | { | ||
131 | switch (mode) { | ||
132 | case CLOCK_EVT_MODE_PERIODIC: | ||
133 | /* The only mode supported */ | ||
134 | break; | ||
135 | |||
136 | case CLOCK_EVT_MODE_UNUSED: | ||
137 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
138 | case CLOCK_EVT_MODE_ONESHOT: | ||
139 | case CLOCK_EVT_MODE_RESUME: | ||
140 | /* Nothing to do */ | ||
141 | break; | ||
142 | } | ||
143 | } | ||
144 | |||
145 | struct clock_event_device rt_clock_event_device = { | ||
146 | .name = "HUB-RT", | ||
147 | .features = CLOCK_EVT_FEAT_ONESHOT, | ||
148 | |||
149 | .rating = 300, | ||
150 | .set_next_event = rt_set_next_event, | ||
151 | .set_mode = rt_set_mode, | ||
152 | }; | ||
153 | |||
157 | static void enable_rt_irq(unsigned int irq) | 154 | static void enable_rt_irq(unsigned int irq) |
158 | { | 155 | { |
159 | } | 156 | } |
@@ -171,6 +168,20 @@ static struct irq_chip rt_irq_type = { | |||
171 | .eoi = enable_rt_irq, | 168 | .eoi = enable_rt_irq, |
172 | }; | 169 | }; |
173 | 170 | ||
171 | unsigned int rt_timer_irq; | ||
172 | |||
173 | static irqreturn_t ip27_rt_timer_interrupt(int irq, void *dev_id) | ||
174 | { | ||
175 | struct clock_event_device *cd = &rt_clock_event_device; | ||
176 | unsigned int cpu = smp_processor_id(); | ||
177 | int slice = cputoslice(cpu) == 0; | ||
178 | |||
179 | LOCAL_HUB_S(slice ? PI_RT_PEND_A : PI_RT_PEND_B, 0); /* Ack */ | ||
180 | cd->event_handler(cd); | ||
181 | |||
182 | return IRQ_HANDLED; | ||
183 | } | ||
184 | |||
174 | static struct irqaction rt_irqaction = { | 185 | static struct irqaction rt_irqaction = { |
175 | .handler = (irq_handler_t) ip27_rt_timer_interrupt, | 186 | .handler = (irq_handler_t) ip27_rt_timer_interrupt, |
176 | .flags = IRQF_DISABLED, | 187 | .flags = IRQF_DISABLED, |
@@ -178,26 +189,43 @@ static struct irqaction rt_irqaction = { | |||
178 | .name = "timer" | 189 | .name = "timer" |
179 | }; | 190 | }; |
180 | 191 | ||
181 | void __init plat_timer_setup(struct irqaction *irq) | 192 | /* |
193 | * This is a hack; we really need to figure these values out dynamically | ||
194 | * | ||
195 | * Since 800 ns works very well with various HUB frequencies, such as | ||
196 | * 360, 380, 390 and 400 MHZ, we use 800 ns rtc cycle time. | ||
197 | * | ||
198 | * Ralf: which clock rate is used to feed the counter? | ||
199 | */ | ||
200 | #define NSEC_PER_CYCLE 800 | ||
201 | #define CYCLES_PER_SEC (NSEC_PER_SEC / NSEC_PER_CYCLE) | ||
202 | |||
203 | static void __init ip27_rt_clock_event_init(void) | ||
182 | { | 204 | { |
183 | int irqno = allocate_irqno(); | 205 | struct clock_event_device *cd = &rt_clock_event_device; |
206 | unsigned int cpu = smp_processor_id(); | ||
207 | int irq = allocate_irqno(); | ||
184 | 208 | ||
185 | if (irqno < 0) | 209 | if (irq < 0) |
186 | panic("Can't allocate interrupt number for timer interrupt"); | 210 | panic("Can't allocate interrupt number for timer interrupt"); |
187 | 211 | ||
188 | set_irq_chip_and_handler(irqno, &rt_irq_type, handle_percpu_irq); | 212 | rt_timer_irq = irq; |
189 | 213 | ||
190 | /* over-write the handler, we use our own way */ | 214 | cd->irq = irq, |
191 | irq->handler = no_action; | 215 | cd->cpumask = cpumask_of_cpu(cpu), |
192 | 216 | ||
193 | /* setup irqaction */ | ||
194 | irq_desc[irqno].status |= IRQ_PER_CPU; | ||
195 | |||
196 | rt_timer_irq = irqno; | ||
197 | /* | 217 | /* |
198 | * Only needed to get /proc/interrupt to display timer irq stats | 218 | * Calculate the min / max delta |
199 | */ | 219 | */ |
200 | setup_irq(irqno, &rt_irqaction); | 220 | cd->mult = |
221 | div_sc((unsigned long) CYCLES_PER_SEC, NSEC_PER_SEC, 32); | ||
222 | cd->shift = 32; | ||
223 | cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); | ||
224 | cd->min_delta_ns = clockevent_delta2ns(0x300, cd); | ||
225 | clockevents_register_device(cd); | ||
226 | |||
227 | set_irq_chip_and_handler(irq, &rt_irq_type, handle_percpu_irq); | ||
228 | setup_irq(irq, &rt_irqaction); | ||
201 | } | 229 | } |
202 | 230 | ||
203 | static cycle_t hub_rt_read(void) | 231 | static cycle_t hub_rt_read(void) |
@@ -206,7 +234,7 @@ static cycle_t hub_rt_read(void) | |||
206 | } | 234 | } |
207 | 235 | ||
208 | struct clocksource ht_rt_clocksource = { | 236 | struct clocksource ht_rt_clocksource = { |
209 | .name = "HUB", | 237 | .name = "HUB-RT", |
210 | .rating = 200, | 238 | .rating = 200, |
211 | .read = hub_rt_read, | 239 | .read = hub_rt_read, |
212 | .mask = CLOCKSOURCE_MASK(52), | 240 | .mask = CLOCKSOURCE_MASK(52), |
@@ -214,11 +242,17 @@ struct clocksource ht_rt_clocksource = { | |||
214 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | 242 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
215 | }; | 243 | }; |
216 | 244 | ||
217 | void __init plat_time_init(void) | 245 | static void __init ip27_rt_clocksource_init(void) |
218 | { | 246 | { |
219 | clocksource_register(&ht_rt_clocksource); | 247 | clocksource_register(&ht_rt_clocksource); |
220 | } | 248 | } |
221 | 249 | ||
250 | void __init plat_time_init(void) | ||
251 | { | ||
252 | ip27_rt_clock_event_init(); | ||
253 | ip27_rt_clocksource_init(); | ||
254 | } | ||
255 | |||
222 | void __init cpu_time_init(void) | 256 | void __init cpu_time_init(void) |
223 | { | 257 | { |
224 | lboard_t *board; | 258 | lboard_t *board; |
@@ -248,17 +282,12 @@ void __init hub_rtc_init(cnodeid_t cnode) | |||
248 | * node and timeouts will not happen there. | 282 | * node and timeouts will not happen there. |
249 | */ | 283 | */ |
250 | if (get_compact_nodeid() == cnode) { | 284 | if (get_compact_nodeid() == cnode) { |
251 | int cpu = smp_processor_id(); | ||
252 | LOCAL_HUB_S(PI_RT_EN_A, 1); | 285 | LOCAL_HUB_S(PI_RT_EN_A, 1); |
253 | LOCAL_HUB_S(PI_RT_EN_B, 1); | 286 | LOCAL_HUB_S(PI_RT_EN_B, 1); |
254 | LOCAL_HUB_S(PI_PROF_EN_A, 0); | 287 | LOCAL_HUB_S(PI_PROF_EN_A, 0); |
255 | LOCAL_HUB_S(PI_PROF_EN_B, 0); | 288 | LOCAL_HUB_S(PI_PROF_EN_B, 0); |
256 | ct_cur[cpu] = CYCLES_PER_JIFFY; | ||
257 | LOCAL_HUB_S(PI_RT_COMPARE_A, ct_cur[cpu]); | ||
258 | LOCAL_HUB_S(PI_RT_COUNT, 0); | 289 | LOCAL_HUB_S(PI_RT_COUNT, 0); |
259 | LOCAL_HUB_S(PI_RT_PEND_A, 0); | 290 | LOCAL_HUB_S(PI_RT_PEND_A, 0); |
260 | LOCAL_HUB_S(PI_RT_COMPARE_B, ct_cur[cpu]); | ||
261 | LOCAL_HUB_S(PI_RT_COUNT, 0); | ||
262 | LOCAL_HUB_S(PI_RT_PEND_B, 0); | 291 | LOCAL_HUB_S(PI_RT_PEND_B, 0); |
263 | } | 292 | } |
264 | } | 293 | } |