summaryrefslogtreecommitdiff
path: root/arch/powerpc/kernel/vdso.c
diff options
context:
space:
mode:
authorAnton Blanchard <anton@samba.org>2012-07-04 20:37:11 (GMT)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-07-11 04:18:40 (GMT)
commit18ad51dd342a7eb09dbcd059d0b451b616d4dafc (patch)
tree94809605669eb3b5e4e049501958a2fa93ae2de7 /arch/powerpc/kernel/vdso.c
parente6a74c6ea331b79c86e1898c504790b3dadc591d (diff)
downloadlinux-18ad51dd342a7eb09dbcd059d0b451b616d4dafc.tar.xz
powerpc: Add VDSO version of getcpu
We have a request for a fast method of getting CPU and NUMA node IDs from userspace. This patch implements a getcpu VDSO function, similar to x86. Ben suggested we use SPRG3 which is userspace readable. SPRG3 can be modified by a KVM guest, so we save the SPRG3 value in the paca and restore it when transitioning from the guest to the host. I have a glibc patch that implements sched_getcpu on top of this. Testing on a POWER7: baseline: 538 cycles vdso: 30 cycles Signed-off-by: Anton Blanchard <anton@samba.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/vdso.c')
-rw-r--r--arch/powerpc/kernel/vdso.c28
1 files changed, 28 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index 9eb5b9b..b67db22 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -706,6 +706,34 @@ static void __init vdso_setup_syscall_map(void)
}
}
+#ifdef CONFIG_PPC64
+int __cpuinit vdso_getcpu_init(void)
+{
+ unsigned long cpu, node, val;
+
+ /*
+ * SPRG3 contains the CPU in the bottom 16 bits and the NUMA node in
+ * the next 16 bits. The VDSO uses this to implement getcpu().
+ */
+ cpu = get_cpu();
+ WARN_ON_ONCE(cpu > 0xffff);
+
+ node = cpu_to_node(cpu);
+ WARN_ON_ONCE(node > 0xffff);
+
+ val = (cpu & 0xfff) | ((node & 0xffff) << 16);
+ mtspr(SPRN_SPRG3, val);
+#ifdef CONFIG_KVM_BOOK3S_HANDLER
+ get_paca()->kvm_hstate.sprg3 = val;
+#endif
+
+ put_cpu();
+
+ return 0;
+}
+/* We need to call this before SMP init */
+early_initcall(vdso_getcpu_init);
+#endif
static int __init vdso_init(void)
{