summaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/traps.c
diff options
context:
space:
mode:
authorFlorian Fainelli <florian@openwrt.org>2010-01-28 15:22:37 +0100
committerRalf Baechle <ralf@linux-mips.org>2010-02-27 12:53:19 +0100
commit92bbe1b988d3d6fa6348e3e376ff6d27e0712147 (patch)
tree71ab0d2cad91210a98b4c4b1a72598125ec0d100 /arch/mips/kernel/traps.c
parent2d1b6e95515d63030b6e002125799f2aa52a9d27 (diff)
downloadlinux-92bbe1b988d3d6fa6348e3e376ff6d27e0712147.tar.gz
linux-92bbe1b988d3d6fa6348e3e376ff6d27e0712147.tar.xz
linux-92bbe1b988d3d6fa6348e3e376ff6d27e0712147.zip
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>
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 @@
#include <asm/types.h>
#include <asm/stacktrace.h>
#include <asm/irq.h>
+#include <asm/uasm.h>
extern void check_wait(void);
extern asmlinkage void r4k_wait(void);
@@ -1271,11 +1272,6 @@ unsigned long ebase;
unsigned long exception_handlers[32];
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)
{
unsigned long handler = (unsigned long) addr;
@@ -1283,9 +1279,18 @@ void __init *set_except_vector(int n, void *addr)
exception_handlers[n] = handler;
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;
}