瀏覽代碼

MIPS: Deal with larger physical offsets

AR7 has a larger physical offset than other MIPS based systems and therefore
needs to setup its handlers beyond the usual KSEG0 range. When running the
kernel in mapped mode this modification is also required. Remove function
comment which is now incorrect.

Signed-off-by: David Daney <ddaney@caviumnetworks.com>
Signed-off-by: Eugene Konev <ejka@imfi.kspu.ru>
Signed-off-by: Florian Fainelli <florian@openwrt.org>
To: linux-mips@linux-mips.org
To: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Cc: linux-mips@linux-mips.org
Patchwork: http://patchwork.linux-mips.org/patch/889/
Patchwork: http://patchwork.linux-mips.org/patch/932/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Florian Fainelli 15 年之前
父節點
當前提交
92bbe1b988
共有 1 個文件被更改,包括 13 次插入8 次删除
  1. 13 8
      arch/mips/kernel/traps.c

+ 13 - 8
arch/mips/kernel/traps.c

@@ -50,6 +50,7 @@
 #include <asm/types.h>
 #include <asm/types.h>
 #include <asm/stacktrace.h>
 #include <asm/stacktrace.h>
 #include <asm/irq.h>
 #include <asm/irq.h>
+#include <asm/uasm.h>
 
 
 extern void check_wait(void);
 extern void check_wait(void);
 extern asmlinkage void r4k_wait(void);
 extern asmlinkage void r4k_wait(void);
@@ -1271,11 +1272,6 @@ unsigned long ebase;
 unsigned long exception_handlers[32];
 unsigned long exception_handlers[32];
 unsigned long vi_handlers[64];
 unsigned long vi_handlers[64];
 
 
-/*
- * As a side effect of the way this is implemented we're limited
- * to interrupt handlers in the address range from
- * KSEG0 <= x < KSEG0 + 256mb on the Nevada.  Oh well ...
- */
 void __init *set_except_vector(int n, void *addr)
 void __init *set_except_vector(int n, void *addr)
 {
 {
 	unsigned long handler = (unsigned long) addr;
 	unsigned long handler = (unsigned long) addr;
@@ -1283,9 +1279,18 @@ void __init *set_except_vector(int n, void *addr)
 
 
 	exception_handlers[n] = handler;
 	exception_handlers[n] = handler;
 	if (n == 0 && cpu_has_divec) {
 	if (n == 0 && cpu_has_divec) {
-		*(u32 *)(ebase + 0x200) = 0x08000000 |
-					  (0x03ffffff & (handler >> 2));
-		local_flush_icache_range(ebase + 0x200, ebase + 0x204);
+		unsigned long jump_mask = ~((1 << 28) - 1);
+		u32 *buf = (u32 *)(ebase + 0x200);
+		unsigned int k0 = 26;
+		if ((handler & jump_mask) == ((ebase + 0x200) & jump_mask)) {
+			uasm_i_j(&buf, handler & ~jump_mask);
+			uasm_i_nop(&buf);
+		} else {
+			UASM_i_LA(&buf, k0, handler);
+			uasm_i_jr(&buf, k0);
+			uasm_i_nop(&buf);
+		}
+		local_flush_icache_range(ebase + 0x200, (unsigned long)buf);
 	}
 	}
 	return (void *)old_handler;
 	return (void *)old_handler;
 }
 }