diff options
Diffstat (limited to 'arch/mips/kernel/traps.c')
-rw-r--r-- | arch/mips/kernel/traps.c | 21 |
1 files changed, 13 insertions, 8 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index b417e2727050..4e00f9bc23ee 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 | ||
54 | extern void check_wait(void); | 55 | extern void check_wait(void); |
55 | extern asmlinkage void r4k_wait(void); | 56 | extern asmlinkage void r4k_wait(void); |
@@ -1271,11 +1272,6 @@ unsigned long ebase; | |||
1271 | unsigned long exception_handlers[32]; | 1272 | unsigned long exception_handlers[32]; |
1272 | unsigned long vi_handlers[64]; | 1273 | unsigned long vi_handlers[64]; |
1273 | 1274 | ||
1274 | /* | ||
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 | */ | ||
1279 | void __init *set_except_vector(int n, void *addr) | 1275 | void __init *set_except_vector(int n, void *addr) |
1280 | { | 1276 | { |
1281 | unsigned long handler = (unsigned long) addr; | 1277 | unsigned long handler = (unsigned long) addr; |
@@ -1283,9 +1279,18 @@ void __init *set_except_vector(int n, void *addr) | |||
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 | } |