aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/traps.c')
-rw-r--r--arch/mips/kernel/traps.c24
1 files changed, 15 insertions, 9 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 338dfe8ed00..4e00f9bc23e 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -50,6 +50,7 @@
50#include <asm/types.h> 50#include <asm/types.h>
51#include <asm/stacktrace.h> 51#include <asm/stacktrace.h>
52#include <asm/irq.h> 52#include <asm/irq.h>
53#include <asm/uasm.h>
53 54
54extern void check_wait(void); 55extern void check_wait(void);
55extern asmlinkage void r4k_wait(void); 56extern asmlinkage void r4k_wait(void);
@@ -1271,21 +1272,25 @@ unsigned long ebase;
1271unsigned long exception_handlers[32]; 1272unsigned long exception_handlers[32];
1272unsigned long vi_handlers[64]; 1273unsigned long vi_handlers[64];
1273 1274
1274/* 1275void __init *set_except_vector(int n, void *addr)
1275 * As a side effect of the way this is implemented we're limited
1276 * to interrupt handlers in the address range from
1277 * KSEG0 <= x < KSEG0 + 256mb on the Nevada. Oh well ...
1278 */
1279void *set_except_vector(int n, void *addr)
1280{ 1276{
1281 unsigned long handler = (unsigned long) addr; 1277 unsigned long handler = (unsigned long) addr;
1282 unsigned long old_handler = exception_handlers[n]; 1278 unsigned long old_handler = exception_handlers[n];
1283 1279
1284 exception_handlers[n] = handler; 1280 exception_handlers[n] = handler;
1285 if (n == 0 && cpu_has_divec) { 1281 if (n == 0 && cpu_has_divec) {
1286 *(u32 *)(ebase + 0x200) = 0x08000000 | 1282 unsigned long jump_mask = ~((1 << 28) - 1);
1287 (0x03ffffff & (handler >> 2)); 1283 u32 *buf = (u32 *)(ebase + 0x200);
1288 local_flush_icache_range(ebase + 0x200, ebase + 0x204); 1284 unsigned int k0 = 26;
1285 if ((handler & jump_mask) == ((ebase + 0x200) & jump_mask)) {
1286 uasm_i_j(&buf, handler & ~jump_mask);
1287 uasm_i_nop(&buf);
1288 } else {
1289 UASM_i_LA(&buf, k0, handler);
1290 uasm_i_jr(&buf, k0);
1291 uasm_i_nop(&buf);
1292 }
1293 local_flush_icache_range(ebase + 0x200, (unsigned long)buf);
1289 } 1294 }
1290 return (void *)old_handler; 1295 return (void *)old_handler;
1291} 1296}
@@ -1501,6 +1506,7 @@ void __cpuinit per_cpu_trap_init(void)
1501 cp0_perfcount_irq = -1; 1506 cp0_perfcount_irq = -1;
1502 } else { 1507 } else {
1503 cp0_compare_irq = CP0_LEGACY_COMPARE_IRQ; 1508 cp0_compare_irq = CP0_LEGACY_COMPARE_IRQ;
1509 cp0_compare_irq_shift = cp0_compare_irq;
1504 cp0_perfcount_irq = -1; 1510 cp0_perfcount_irq = -1;
1505 } 1511 }
1506 1512