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.c21
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
54extern void check_wait(void); 55extern void check_wait(void);
55extern asmlinkage void r4k_wait(void); 56extern asmlinkage void r4k_wait(void);
@@ -1271,11 +1272,6 @@ 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/*
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 __init *set_except_vector(int n, void *addr) 1275void __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}