summaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorJonas Gorski <jogo@openwrt.org>2013-06-21 17:48:48 +0000
committerRalf Baechle <ralf@linux-mips.org>2013-06-25 17:48:06 +0200
commita3d9086bb121a6459c9ed0452e3c58891a504785 (patch)
tree99f9d81a1781e4a563dd4a20277ec4a99a49668f /arch/mips
parent6a72015d3c3602dd969e79510486807c481a0e1b (diff)
MIPS: Flush TLB handlers directly after writing them
When having enabled MIPS_PGD_C0_CONTEXT, trap_init() might call the generated tlbmiss_handler_setup_pgd before it was committed to memory, causing boot failures: trap_init() |- per_cpu_trap_init() | |- TLBMISS_HANDLER_SETUP() | |- tlbmiss_handler_setup_pgd() |- flush_tlb_handlers() To avoid this, move flush_tlb_handlers() into build_tlb_refill_handler() right after they were generated. We can do this as the cache handling is initialized just before creating the tlb handlers. This issue was introduced in 3d8bfdd0307223de678962f1c1907a7cec549136 ("MIPS: Use C0_KScratch (if present) to hold PGD pointer."). Signed-off-by: Jonas Gorski <jogo@openwrt.org> Cc: linux-mips@linux-mips.org Cc: Steven J. Hill <Steven.Hill@imgtec.com> Cc: Jayachandran C <jchandra@broadcom.com> Cc: David Daney <david.daney@cavium.com> Patchwork: https://patchwork.linux-mips.org/patch/5539/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/kernel/traps.c2
-rw-r--r--arch/mips/mm/tlbex.c30
2 files changed, 16 insertions, 16 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index a75ae40184a..8ef484c6b9d 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -1627,7 +1627,6 @@ void *set_vi_handler(int n, vi_handler_t addr)
}
extern void tlb_init(void);
-extern void flush_tlb_handlers(void);
/*
* Timer interrupt
@@ -1956,7 +1955,6 @@ void __init trap_init(void)
set_handler(0x080, &except_vec3_generic, 0x80);
local_flush_icache_range(ebase, ebase + 0x400);
- flush_tlb_handlers();
sort_extable(__start___dbe_table, __stop___dbe_table);
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index f0f4dc44f39..7f6cd461dac 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -2181,6 +2181,20 @@ static void __cpuinit build_r4000_tlb_modify_handler(void)
dump_handler("r4000_tlb_modify", handle_tlbm, ARRAY_SIZE(handle_tlbm));
}
+static void __cpuinit flush_tlb_handlers(void)
+{
+ local_flush_icache_range((unsigned long)handle_tlbl,
+ (unsigned long)handle_tlbl + sizeof(handle_tlbl));
+ local_flush_icache_range((unsigned long)handle_tlbs,
+ (unsigned long)handle_tlbs + sizeof(handle_tlbs));
+ local_flush_icache_range((unsigned long)handle_tlbm,
+ (unsigned long)handle_tlbm + sizeof(handle_tlbm));
+#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
+ local_flush_icache_range((unsigned long)tlbmiss_handler_setup_pgd_array,
+ (unsigned long)tlbmiss_handler_setup_pgd_array + sizeof(handle_tlbm));
+#endif
+}
+
void __cpuinit build_tlb_refill_handler(void)
{
/*
@@ -2213,6 +2227,7 @@ void __cpuinit build_tlb_refill_handler(void)
build_r3000_tlb_load_handler();
build_r3000_tlb_store_handler();
build_r3000_tlb_modify_handler();
+ flush_tlb_handlers();
run_once++;
}
#else
@@ -2240,23 +2255,10 @@ void __cpuinit build_tlb_refill_handler(void)
build_r4000_tlb_modify_handler();
if (!cpu_has_local_ebase)
build_r4000_tlb_refill_handler();
+ flush_tlb_handlers();
run_once++;
}
if (cpu_has_local_ebase)
build_r4000_tlb_refill_handler();
}
}
-
-void __cpuinit flush_tlb_handlers(void)
-{
- local_flush_icache_range((unsigned long)handle_tlbl,
- (unsigned long)handle_tlbl + sizeof(handle_tlbl));
- local_flush_icache_range((unsigned long)handle_tlbs,
- (unsigned long)handle_tlbs + sizeof(handle_tlbs));
- local_flush_icache_range((unsigned long)handle_tlbm,
- (unsigned long)handle_tlbm + sizeof(handle_tlbm));
-#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
- local_flush_icache_range((unsigned long)tlbmiss_handler_setup_pgd_array,
- (unsigned long)tlbmiss_handler_setup_pgd_array + sizeof(handle_tlbm));
-#endif
-}