diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2007-10-11 18:46:09 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-10-11 18:46:09 -0400 |
commit | 91a2fcc88634663e9e13dcdfad0e4a860e64aeee (patch) | |
tree | a86b936f1057207d46e5a07ed826052ff640869a /arch/mips/kernel | |
parent | 90b02340dcc6ce00bf22c48f4865915f5989e5e4 (diff) |
[MIPS] Consolidate all variants of MIPS cp0 timer interrupt handlers.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r-- | arch/mips/kernel/smtc.c | 2 | ||||
-rw-r--r-- | arch/mips/kernel/time.c | 93 |
2 files changed, 70 insertions, 25 deletions
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index 137183bba54f..a7afbf2c9710 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c | |||
@@ -867,7 +867,7 @@ void ipi_decode(struct smtc_ipi *pipi) | |||
867 | #ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG | 867 | #ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG |
868 | clock_hang_reported[dest_copy] = 0; | 868 | clock_hang_reported[dest_copy] = 0; |
869 | #endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */ | 869 | #endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */ |
870 | local_timer_interrupt(0, NULL); | 870 | local_timer_interrupt(0); |
871 | irq_exit(); | 871 | irq_exit(); |
872 | break; | 872 | break; |
873 | case LINUX_SMP_IPI: | 873 | case LINUX_SMP_IPI: |
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index c48ebd4b495e..d23e6825e988 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c | |||
@@ -144,7 +144,7 @@ void local_timer_interrupt(int irq, void *dev_id) | |||
144 | * High-level timer interrupt service routines. This function | 144 | * High-level timer interrupt service routines. This function |
145 | * is set as irqaction->handler and is invoked through do_IRQ. | 145 | * is set as irqaction->handler and is invoked through do_IRQ. |
146 | */ | 146 | */ |
147 | irqreturn_t timer_interrupt(int irq, void *dev_id) | 147 | static irqreturn_t timer_interrupt(int irq, void *dev_id) |
148 | { | 148 | { |
149 | write_seqlock(&xtime_lock); | 149 | write_seqlock(&xtime_lock); |
150 | 150 | ||
@@ -174,9 +174,10 @@ int null_perf_irq(void) | |||
174 | return 0; | 174 | return 0; |
175 | } | 175 | } |
176 | 176 | ||
177 | EXPORT_SYMBOL(null_perf_irq); | ||
178 | |||
177 | int (*perf_irq)(void) = null_perf_irq; | 179 | int (*perf_irq)(void) = null_perf_irq; |
178 | 180 | ||
179 | EXPORT_SYMBOL(null_perf_irq); | ||
180 | EXPORT_SYMBOL(perf_irq); | 181 | EXPORT_SYMBOL(perf_irq); |
181 | 182 | ||
182 | /* | 183 | /* |
@@ -208,35 +209,79 @@ static inline int handle_perf_irq (int r2) | |||
208 | !r2; | 209 | !r2; |
209 | } | 210 | } |
210 | 211 | ||
211 | asmlinkage void ll_timer_interrupt(int irq) | 212 | void ll_timer_interrupt(int irq, void *dev_id) |
212 | { | 213 | { |
213 | int r2 = cpu_has_mips_r2; | 214 | int cpu = smp_processor_id(); |
214 | 215 | ||
215 | irq_enter(); | 216 | #ifdef CONFIG_MIPS_MT_SMTC |
216 | kstat_this_cpu.irqs[irq]++; | 217 | /* |
218 | * In an SMTC system, one Count/Compare set exists per VPE. | ||
219 | * Which TC within a VPE gets the interrupt is essentially | ||
220 | * random - we only know that it shouldn't be one with | ||
221 | * IXMT set. Whichever TC gets the interrupt needs to | ||
222 | * send special interprocessor interrupts to the other | ||
223 | * TCs to make sure that they schedule, etc. | ||
224 | * | ||
225 | * That code is specific to the SMTC kernel, not to | ||
226 | * the a particular platform, so it's invoked from | ||
227 | * the general MIPS timer_interrupt routine. | ||
228 | */ | ||
229 | |||
230 | /* | ||
231 | * We could be here due to timer interrupt, | ||
232 | * perf counter overflow, or both. | ||
233 | */ | ||
234 | (void) handle_perf_irq(1); | ||
235 | |||
236 | if (read_c0_cause() & (1 << 30)) { | ||
237 | /* | ||
238 | * There are things we only want to do once per tick | ||
239 | * in an "MP" system. One TC of each VPE will take | ||
240 | * the actual timer interrupt. The others will get | ||
241 | * timer broadcast IPIs. We use whoever it is that takes | ||
242 | * the tick on VPE 0 to run the full timer_interrupt(). | ||
243 | */ | ||
244 | if (cpu_data[cpu].vpe_id == 0) { | ||
245 | timer_interrupt(irq, NULL); | ||
246 | } else { | ||
247 | write_c0_compare(read_c0_count() + | ||
248 | (mips_hpt_frequency/HZ)); | ||
249 | local_timer_interrupt(irq, dev_id); | ||
250 | } | ||
251 | smtc_timer_broadcast(cpu_data[cpu].vpe_id); | ||
252 | } | ||
253 | #else /* CONFIG_MIPS_MT_SMTC */ | ||
254 | int r2 = cpu_has_mips_r2; | ||
217 | 255 | ||
218 | if (handle_perf_irq(r2)) | 256 | if (handle_perf_irq(r2)) |
219 | goto out; | 257 | return; |
220 | 258 | ||
221 | if (r2 && ((read_c0_cause() & (1 << 30)) == 0)) | 259 | if (r2 && ((read_c0_cause() & (1 << 30)) == 0)) |
222 | goto out; | 260 | return; |
223 | |||
224 | timer_interrupt(irq, NULL); | ||
225 | |||
226 | out: | ||
227 | irq_exit(); | ||
228 | } | ||
229 | |||
230 | asmlinkage void ll_local_timer_interrupt(int irq) | ||
231 | { | ||
232 | irq_enter(); | ||
233 | if (smp_processor_id() != 0) | ||
234 | kstat_this_cpu.irqs[irq]++; | ||
235 | |||
236 | /* we keep interrupt disabled all the time */ | ||
237 | local_timer_interrupt(irq, NULL); | ||
238 | 261 | ||
239 | irq_exit(); | 262 | if (cpu == 0) { |
263 | /* | ||
264 | * CPU 0 handles the global timer interrupt job and process | ||
265 | * accounting resets count/compare registers to trigger next | ||
266 | * timer int. | ||
267 | */ | ||
268 | timer_interrupt(irq, NULL); | ||
269 | } else { | ||
270 | /* Everyone else needs to reset the timer int here as | ||
271 | ll_local_timer_interrupt doesn't */ | ||
272 | /* | ||
273 | * FIXME: need to cope with counter underflow. | ||
274 | * More support needs to be added to kernel/time for | ||
275 | * counter/timer interrupts on multiple CPU's | ||
276 | */ | ||
277 | write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ)); | ||
278 | |||
279 | /* | ||
280 | * Other CPUs should do profiling and process accounting | ||
281 | */ | ||
282 | local_timer_interrupt(irq, dev_id); | ||
283 | } | ||
284 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
240 | } | 285 | } |
241 | 286 | ||
242 | /* | 287 | /* |