summaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel/setup_32.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2012-05-13 23:09:04 -0700
committerDavid S. Miller <davem@davemloft.net>2012-05-14 13:31:38 -0700
commitc68e5d39a502d01421cbc70d25c377e9215facef (patch)
tree9135a68681381d94a929b57a28a1878df0134ff7 /arch/sparc/kernel/setup_32.c
parent5d83d66635bb1642f3c6a3690c28ff4afdf1ae5f (diff)
downloadlinux-c68e5d39a502d01421cbc70d25c377e9215facef.tar.bz2
sparc32: Implement hard_smp_processor_id() via instruction patching.
This is the last non-trivial user of btfixup. Like sparc64, use a special patch section to resolve the various implementations of how to read the current CPU's ID when we don't have current_thread_info()->cpu necessarily available. Signed-off-by: David S. Miller <davem@davemloft.net> Tested-by: Sam Ravnborg <sam@ravnborg.org>
Diffstat (limited to 'arch/sparc/kernel/setup_32.c')
-rw-r--r--arch/sparc/kernel/setup_32.c51
1 files changed, 51 insertions, 0 deletions
diff --git a/arch/sparc/kernel/setup_32.c b/arch/sparc/kernel/setup_32.c
index 6f294f371d68..2f7cfb5f7569 100644
--- a/arch/sparc/kernel/setup_32.c
+++ b/arch/sparc/kernel/setup_32.c
@@ -192,6 +192,52 @@ extern int root_mountflags;
char reboot_command[COMMAND_LINE_SIZE];
+struct cpuid_patch_entry {
+ unsigned int addr;
+ unsigned int sun4d[3];
+ unsigned int leon[3];
+};
+extern struct cpuid_patch_entry __cpuid_patch, __cpuid_patch_end;
+
+static void __init per_cpu_patch(void)
+{
+ struct cpuid_patch_entry *p;
+
+ if (sparc_cpu_model == sun4m) {
+ /* Nothing to do, this is what the unpatched code
+ * targets.
+ */
+ return;
+ }
+
+ p = &__cpuid_patch;
+ while (p < &__cpuid_patch_end) {
+ unsigned long addr = p->addr;
+ unsigned int *insns;
+
+ switch (sparc_cpu_model) {
+ case sun4d:
+ insns = &p->sun4d[0];
+ break;
+
+ case sparc_leon:
+ insns = &p->leon[0];
+ break;
+ default:
+ prom_printf("Unknown cpu type, halting.\n");
+ prom_halt();
+ }
+ *(unsigned int *) (addr + 0) = insns[0];
+ *(unsigned int *) (addr + 4) = insns[1];
+ *(unsigned int *) (addr + 8) = insns[2];
+ }
+#ifdef CONFIG_SMP
+ local_ops->cache_all();
+#else
+ sparc32_cachetlb_ops->cache_all();
+#endif
+}
+
enum sparc_cpu sparc_cpu_model;
EXPORT_SYMBOL(sparc_cpu_model);
@@ -295,6 +341,11 @@ void __init setup_arch(char **cmdline_p)
paging_init();
+ /* Now that we have the cache ops hooked up, we can patch
+ * instructions.
+ */
+ per_cpu_patch();
+
smp_setup_cpu_possible_map();
}