diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2007-11-21 11:39:44 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-11-26 12:26:14 -0500 |
commit | 5aa85c9fc49a6ce44dc10a42e2011bbde9dc445a (patch) | |
tree | 14b8d1a014349568be39753f879c152e1e3f2b41 /arch/mips/kernel/cevt-r4k.c | |
parent | 0f67e90e1caea4a0a14d2c60102547bce29f7f08 (diff) |
[MIPS] Handle R4000/R4400 mfc0 from count register.
The R4000 and R4400 have an errata where if the cp0 count register is read
in the exact moment when it matches the compare register no interrupt will
be generated.
This bug may be triggered if the cp0 count register is being used as
clocksource and the compare interrupt as clockevent. So a simple
workaround is to avoid using the compare for both facilities on the
affected CPUs.
This is different from the workaround suggested in the old errata documents;
at some opportunity probably the official version should be implemented
and tested. Another thing to find out is which processor versions
exactly are affected. I only have errata documents upto R4400 V3.0
available so for the moment the code treats all R4000 and R4400 as broken.
This is potencially a problem for some machines that have no other decent
clocksource available; this workaround will cause them to fall back to
another clocksource, worst case the "jiffies" source.
Diffstat (limited to 'arch/mips/kernel/cevt-r4k.c')
-rw-r--r-- | arch/mips/kernel/cevt-r4k.c | 12 |
1 files changed, 7 insertions, 5 deletions
diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c index 076f52b9bb7..24a2d907aa0 100644 --- a/arch/mips/kernel/cevt-r4k.c +++ b/arch/mips/kernel/cevt-r4k.c | |||
@@ -219,7 +219,7 @@ static int c0_compare_int_usable(void) | |||
219 | return 1; | 219 | return 1; |
220 | } | 220 | } |
221 | 221 | ||
222 | void __cpuinit mips_clockevent_init(void) | 222 | int __cpuinit mips_clockevent_init(void) |
223 | { | 223 | { |
224 | uint64_t mips_freq = mips_hpt_frequency; | 224 | uint64_t mips_freq = mips_hpt_frequency; |
225 | unsigned int cpu = smp_processor_id(); | 225 | unsigned int cpu = smp_processor_id(); |
@@ -227,7 +227,7 @@ void __cpuinit mips_clockevent_init(void) | |||
227 | unsigned int irq; | 227 | unsigned int irq; |
228 | 228 | ||
229 | if (!cpu_has_counter || !mips_hpt_frequency) | 229 | if (!cpu_has_counter || !mips_hpt_frequency) |
230 | return; | 230 | return -ENXIO; |
231 | 231 | ||
232 | #ifdef CONFIG_MIPS_MT_SMTC | 232 | #ifdef CONFIG_MIPS_MT_SMTC |
233 | setup_smtc_dummy_clockevent_device(); | 233 | setup_smtc_dummy_clockevent_device(); |
@@ -237,11 +237,11 @@ void __cpuinit mips_clockevent_init(void) | |||
237 | * device. | 237 | * device. |
238 | */ | 238 | */ |
239 | if (cpu) | 239 | if (cpu) |
240 | return; | 240 | return 0; |
241 | #endif | 241 | #endif |
242 | 242 | ||
243 | if (!c0_compare_int_usable()) | 243 | if (!c0_compare_int_usable()) |
244 | return; | 244 | return -ENXIO; |
245 | 245 | ||
246 | /* | 246 | /* |
247 | * With vectored interrupts things are getting platform specific. | 247 | * With vectored interrupts things are getting platform specific. |
@@ -277,7 +277,7 @@ void __cpuinit mips_clockevent_init(void) | |||
277 | clockevents_register_device(cd); | 277 | clockevents_register_device(cd); |
278 | 278 | ||
279 | if (cp0_timer_irq_installed) | 279 | if (cp0_timer_irq_installed) |
280 | return; | 280 | return 0; |
281 | 281 | ||
282 | cp0_timer_irq_installed = 1; | 282 | cp0_timer_irq_installed = 1; |
283 | 283 | ||
@@ -287,4 +287,6 @@ void __cpuinit mips_clockevent_init(void) | |||
287 | #else | 287 | #else |
288 | setup_irq(irq, &c0_compare_irqaction); | 288 | setup_irq(irq, &c0_compare_irqaction); |
289 | #endif | 289 | #endif |
290 | |||
291 | return 0; | ||
290 | } | 292 | } |