aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHuacai Chen <chenhc@lemote.com>2013-03-17 07:49:38 -0400
committerRalf Baechle <ralf@linux-mips.org>2013-05-07 19:19:06 -0400
commit8759934e2b6bdb3a08a81fc14a6588f3321719b1 (patch)
tree985985567d0691275692a2f8a4bd4bf64c60c0ce
parent59b435d1ad48ac244058845e18586eb5719f7f99 (diff)
MIPS: Build uasm-generated code only once to avoid CPU Hotplug problem
This and the next patch resolve memory corruption problems while CPU hotplug. Without these patches, memory corruption can triggered easily as below: On a quad-core MIPS platform, use "spawn" of UnixBench-5.1.3 (http:// code.google.com/p/byte-unixbench/) and a CPU hotplug script like this (hotplug.sh): while true; do echo 0 >/sys/devices/system/cpu/cpu1/online echo 0 >/sys/devices/system/cpu/cpu2/online echo 0 >/sys/devices/system/cpu/cpu3/online sleep 1 echo 1 >/sys/devices/system/cpu/cpu1/online echo 1 >/sys/devices/system/cpu/cpu2/online echo 1 >/sys/devices/system/cpu/cpu3/online sleep 1 done Run "hotplug.sh" and then run "spawn 10000", spawn will get segfault after a few minutes. This patch: Currently, clear_page()/copy_page() are generated by Micro-assembler dynamically. But they are unavailable until uasm_resolve_relocs() has finished because jump labels are illegal before that. Since these functions are shared by every CPU, we only call build_clear_page()/ build_copy_page() only once at boot time. Without this patch, programs will get random memory corruption (segmentation fault, bus error, etc.) while CPU Hotplug (e.g. one CPU is using clear_page() while another is generating it in cpu_cache_init()). For similar reasons we modify build_tlb_refill_handler()'s invocation. V2: 1, Rework the code to make CPU#0 can be online/offline. 2, Introduce cpu_has_local_ebase feature since some types of MIPS CPU need a per-CPU tlb_refill_handler(). Signed-off-by: Huacai Chen <chenhc@lemote.com> Signed-off-by: Hongbing Hu <huhb@lemote.com> Acked-by: David Daney <david.daney@cavium.com> Patchwork: http://patchwork.linux-mips.org/patch/4994/ Acked-by: John Crispin <blogic@openwrt.org>
-rw-r--r--arch/mips/include/asm/cpu-features.h3
-rw-r--r--arch/mips/include/asm/mach-loongson/cpu-feature-overrides.h1
-rw-r--r--arch/mips/mm/page.c10
-rw-r--r--arch/mips/mm/tlbex.c10
4 files changed, 22 insertions, 2 deletions
diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h
index 1a57e8b4d092..e5ec8fcd8afa 100644
--- a/arch/mips/include/asm/cpu-features.h
+++ b/arch/mips/include/asm/cpu-features.h
@@ -113,6 +113,9 @@
113#ifndef cpu_has_pindexed_dcache 113#ifndef cpu_has_pindexed_dcache
114#define cpu_has_pindexed_dcache (cpu_data[0].dcache.flags & MIPS_CACHE_PINDEX) 114#define cpu_has_pindexed_dcache (cpu_data[0].dcache.flags & MIPS_CACHE_PINDEX)
115#endif 115#endif
116#ifndef cpu_has_local_ebase
117#define cpu_has_local_ebase 1
118#endif
116 119
117/* 120/*
118 * I-Cache snoops remote store. This only matters on SMP. Some multiprocessors 121 * I-Cache snoops remote store. This only matters on SMP. Some multiprocessors
diff --git a/arch/mips/include/asm/mach-loongson/cpu-feature-overrides.h b/arch/mips/include/asm/mach-loongson/cpu-feature-overrides.h
index 75fd8c0f986e..c0f3ef45c2c1 100644
--- a/arch/mips/include/asm/mach-loongson/cpu-feature-overrides.h
+++ b/arch/mips/include/asm/mach-loongson/cpu-feature-overrides.h
@@ -57,5 +57,6 @@
57#define cpu_has_vint 0 57#define cpu_has_vint 0
58#define cpu_has_vtag_icache 0 58#define cpu_has_vtag_icache 0
59#define cpu_has_watch 1 59#define cpu_has_watch 1
60#define cpu_has_local_ebase 0
60 61
61#endif /* __ASM_MACH_LOONGSON_CPU_FEATURE_OVERRIDES_H */ 62#endif /* __ASM_MACH_LOONGSON_CPU_FEATURE_OVERRIDES_H */
diff --git a/arch/mips/mm/page.c b/arch/mips/mm/page.c
index a29fba55b53e..4eb8dcfaf1ce 100644
--- a/arch/mips/mm/page.c
+++ b/arch/mips/mm/page.c
@@ -247,6 +247,11 @@ void __cpuinit build_clear_page(void)
247 struct uasm_label *l = labels; 247 struct uasm_label *l = labels;
248 struct uasm_reloc *r = relocs; 248 struct uasm_reloc *r = relocs;
249 int i; 249 int i;
250 static atomic_t run_once = ATOMIC_INIT(0);
251
252 if (atomic_xchg(&run_once, 1)) {
253 return;
254 }
250 255
251 memset(labels, 0, sizeof(labels)); 256 memset(labels, 0, sizeof(labels));
252 memset(relocs, 0, sizeof(relocs)); 257 memset(relocs, 0, sizeof(relocs));
@@ -389,6 +394,11 @@ void __cpuinit build_copy_page(void)
389 struct uasm_label *l = labels; 394 struct uasm_label *l = labels;
390 struct uasm_reloc *r = relocs; 395 struct uasm_reloc *r = relocs;
391 int i; 396 int i;
397 static atomic_t run_once = ATOMIC_INIT(0);
398
399 if (atomic_xchg(&run_once, 1)) {
400 return;
401 }
392 402
393 memset(labels, 0, sizeof(labels)); 403 memset(labels, 0, sizeof(labels));
394 memset(relocs, 0, sizeof(relocs)); 404 memset(relocs, 0, sizeof(relocs));
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 820e6612d744..6bc28b4db31d 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -2162,8 +2162,11 @@ void __cpuinit build_tlb_refill_handler(void)
2162 case CPU_TX3922: 2162 case CPU_TX3922:
2163 case CPU_TX3927: 2163 case CPU_TX3927:
2164#ifndef CONFIG_MIPS_PGD_C0_CONTEXT 2164#ifndef CONFIG_MIPS_PGD_C0_CONTEXT
2165 build_r3000_tlb_refill_handler(); 2165 if (cpu_has_local_ebase)
2166 build_r3000_tlb_refill_handler();
2166 if (!run_once) { 2167 if (!run_once) {
2168 if (!cpu_has_local_ebase)
2169 build_r3000_tlb_refill_handler();
2167 build_r3000_tlb_load_handler(); 2170 build_r3000_tlb_load_handler();
2168 build_r3000_tlb_store_handler(); 2171 build_r3000_tlb_store_handler();
2169 build_r3000_tlb_modify_handler(); 2172 build_r3000_tlb_modify_handler();
@@ -2192,9 +2195,12 @@ void __cpuinit build_tlb_refill_handler(void)
2192 build_r4000_tlb_load_handler(); 2195 build_r4000_tlb_load_handler();
2193 build_r4000_tlb_store_handler(); 2196 build_r4000_tlb_store_handler();
2194 build_r4000_tlb_modify_handler(); 2197 build_r4000_tlb_modify_handler();
2198 if (!cpu_has_local_ebase)
2199 build_r4000_tlb_refill_handler();
2195 run_once++; 2200 run_once++;
2196 } 2201 }
2197 build_r4000_tlb_refill_handler(); 2202 if (cpu_has_local_ebase)
2203 build_r4000_tlb_refill_handler();
2198 } 2204 }
2199} 2205}
2200 2206