powerpc: Add VDSO version of getcpu
authorAnton Blanchard <anton@samba.org>
Wed, 4 Jul 2012 20:37:11 +0000 (20:37 +0000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Wed, 11 Jul 2012 04:18:40 +0000 (14:18 +1000)
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>
13 files changed:
arch/powerpc/include/asm/kvm_book3s_asm.h
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/vdso.h
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/vdso.c
arch/powerpc/kernel/vdso32/Makefile
arch/powerpc/kernel/vdso32/getcpu.S [new file with mode: 0644]
arch/powerpc/kernel/vdso32/vdso32.lds.S
arch/powerpc/kernel/vdso64/Makefile
arch/powerpc/kernel/vdso64/getcpu.S [new file with mode: 0644]
arch/powerpc/kernel/vdso64/vdso64.lds.S
arch/powerpc/kvm/book3s_hv_rmhandlers.S

index 88609b23b775460c96a4d9d805feaf49fecf94a3..bfcd00c1485d04474c00461d4f7b9097bd624fb4 100644 (file)
@@ -74,6 +74,7 @@ struct kvmppc_host_state {
        ulong vmhandler;
        ulong scratch0;
        ulong scratch1;
+       ulong sprg3;
        u8 in_guest;
        u8 restore_hid5;
        u8 napping;
index f0cb7f461b9d5470c2cd61e7428d44e9f10f4238..2baeb7c8764f15647e7f9533f7cd1ac416a7c45e 100644 (file)
 #define SPRN_SPRG1     0x111   /* Special Purpose Register General 1 */
 #define SPRN_SPRG2     0x112   /* Special Purpose Register General 2 */
 #define SPRN_SPRG3     0x113   /* Special Purpose Register General 3 */
+#define SPRN_USPRG3    0x103   /* SPRG3 userspace read */
 #define SPRN_SPRG4     0x114   /* Special Purpose Register General 4 */
 #define SPRN_SPRG5     0x115   /* Special Purpose Register General 5 */
 #define SPRN_SPRG6     0x116   /* Special Purpose Register General 6 */
  * 64-bit server:
  *     - SPRG0 unused (reserved for HV on Power4)
  *     - SPRG2 scratch for exception vectors
- *     - SPRG3 unused (user visible)
+ *     - SPRG3 CPU and NUMA node for VDSO getcpu (user visible)
  *      - HSPRG0 stores PACA in HV mode
  *      - HSPRG1 scratch for "HV" exceptions
  *
  * 64-bit embedded
  *     - SPRG0 generic exception scratch
  *     - SPRG2 TLB exception stack
- *     - SPRG3 unused (user visible)
+ *     - SPRG3 CPU and NUMA node for VDSO getcpu (user visible)
  *     - SPRG4 unused (user visible)
  *     - SPRG6 TLB miss scratch (user visible, sorry !)
  *     - SPRG7 critical exception scratch
index dc0419b66f17ac1f676bf247f8706b0a1a08b9f2..50f261bc3e9595a1ad972a63af1f14073710c105 100644 (file)
@@ -22,6 +22,8 @@ extern unsigned long vdso64_rt_sigtramp;
 extern unsigned long vdso32_sigtramp;
 extern unsigned long vdso32_rt_sigtramp;
 
+int __cpuinit vdso_getcpu_init(void);
+
 #else /* __ASSEMBLY__ */
 
 #ifdef __VDSO64__
index 52c7ad78242ebd95c16d950424552d6a4741018e..85b05c463fae9077b4490bacfa80c31050a617fa 100644 (file)
@@ -533,6 +533,7 @@ int main(void)
        HSTATE_FIELD(HSTATE_VMHANDLER, vmhandler);
        HSTATE_FIELD(HSTATE_SCRATCH0, scratch0);
        HSTATE_FIELD(HSTATE_SCRATCH1, scratch1);
+       HSTATE_FIELD(HSTATE_SPRG3, sprg3);
        HSTATE_FIELD(HSTATE_IN_GUEST, in_guest);
        HSTATE_FIELD(HSTATE_RESTORE_HID5, restore_hid5);
        HSTATE_FIELD(HSTATE_NAPPING, napping);
index e1417c42155cd66dfe3532dfd8d7e4d3cd426233..0321007086f7c499771ad0f71bc1f63969faff7a 100644 (file)
@@ -48,6 +48,7 @@
 #ifdef CONFIG_PPC64
 #include <asm/paca.h>
 #endif
+#include <asm/vdso.h>
 #include <asm/debug.h>
 
 #ifdef DEBUG
@@ -570,6 +571,8 @@ void __devinit start_secondary(void *unused)
 #ifdef CONFIG_PPC64
        if (system_state == SYSTEM_RUNNING)
                vdso_data->processorCount++;
+
+       vdso_getcpu_init();
 #endif
        notify_cpu_starting(cpu);
        set_cpu_online(cpu, true);
index 9eb5b9b536a71b704b62a6cc6b38660f80d426b4..b67db22e102dd93dc11ec131ac7e942cf6de3d5c 100644 (file)
@@ -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)
 {
index 9a7946c417387fdd0c56b4c3dd1010c4b642312f..53e6c9b979ec6bd44d4892f62b281e5a4c0906b3 100644 (file)
@@ -1,7 +1,9 @@
 
 # List of files in the vdso, has to be asm only for now
 
-obj-vdso32 = sigtramp.o gettimeofday.o datapage.o cacheflush.o note.o
+obj-vdso32-$(CONFIG_PPC64) = getcpu.o
+obj-vdso32 = sigtramp.o gettimeofday.o datapage.o cacheflush.o note.o \
+               $(obj-vdso32-y)
 
 # Build rules
 
diff --git a/arch/powerpc/kernel/vdso32/getcpu.S b/arch/powerpc/kernel/vdso32/getcpu.S
new file mode 100644 (file)
index 0000000..47afd08
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2012
+ *
+ * Author: Anton Blanchard <anton@au.ibm.com>
+ */
+#include <asm/ppc_asm.h>
+#include <asm/vdso.h>
+
+       .text
+/*
+ * Exact prototype of getcpu
+ *
+ * int __kernel_getcpu(unsigned *cpu, unsigned *node);
+ *
+ */
+V_FUNCTION_BEGIN(__kernel_getcpu)
+  .cfi_startproc
+       mfspr   r5,SPRN_USPRG3
+       cmpdi   cr0,r3,0
+       cmpdi   cr1,r4,0
+       clrlwi  r6,r5,16
+       rlwinm  r7,r5,16,31-15,31-0
+       beq     cr0,1f
+       stw     r6,0(r3)
+1:     beq     cr1,2f
+       stw     r7,0(r4)
+2:     crclr   cr0*4+so
+       li      r3,0                    /* always success */
+       blr
+  .cfi_endproc
+V_FUNCTION_END(__kernel_getcpu)
index 0546bcd49cd0363c317424e25359c7e08176b832..43200ba2e57004f74e3f990d427d729c789e07c9 100644 (file)
@@ -147,6 +147,9 @@ VERSION
                __kernel_sync_dicache_p5;
                __kernel_sigtramp32;
                __kernel_sigtramp_rt32;
+#ifdef CONFIG_PPC64
+               __kernel_getcpu;
+#endif
 
        local: *;
        };
index 8c500d8622e4d8d7696099b684b0ad519c63a8a4..effca9404b1763c077ff0dcde9e2910ded4c0423 100644 (file)
@@ -1,6 +1,6 @@
 # List of files in the vdso, has to be asm only for now
 
-obj-vdso64 = sigtramp.o gettimeofday.o datapage.o cacheflush.o note.o
+obj-vdso64 = sigtramp.o gettimeofday.o datapage.o cacheflush.o note.o getcpu.o
 
 # Build rules
 
diff --git a/arch/powerpc/kernel/vdso64/getcpu.S b/arch/powerpc/kernel/vdso64/getcpu.S
new file mode 100644 (file)
index 0000000..47afd08
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2012
+ *
+ * Author: Anton Blanchard <anton@au.ibm.com>
+ */
+#include <asm/ppc_asm.h>
+#include <asm/vdso.h>
+
+       .text
+/*
+ * Exact prototype of getcpu
+ *
+ * int __kernel_getcpu(unsigned *cpu, unsigned *node);
+ *
+ */
+V_FUNCTION_BEGIN(__kernel_getcpu)
+  .cfi_startproc
+       mfspr   r5,SPRN_USPRG3
+       cmpdi   cr0,r3,0
+       cmpdi   cr1,r4,0
+       clrlwi  r6,r5,16
+       rlwinm  r7,r5,16,31-15,31-0
+       beq     cr0,1f
+       stw     r6,0(r3)
+1:     beq     cr1,2f
+       stw     r7,0(r4)
+2:     crclr   cr0*4+so
+       li      r3,0                    /* always success */
+       blr
+  .cfi_endproc
+V_FUNCTION_END(__kernel_getcpu)
index 0e615404e247353cd9a696bb086d03486013403e..e6c1758f3588c4c2d4e5f314e489a8c4c8b65a36 100644 (file)
@@ -146,6 +146,7 @@ VERSION
                __kernel_sync_dicache;
                __kernel_sync_dicache_p5;
                __kernel_sigtramp_rt64;
+               __kernel_getcpu;
 
        local: *;
        };
index e764e2361d47eb52dd415efe2558f868696dbab6..5a84c8d3d04050b98ab818c9d83cedeb74b8f235 100644 (file)
@@ -1064,6 +1064,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
        mtspr   SPRN_DABR,r5
        mtspr   SPRN_DABRX,r6
 
+       /* Restore SPRG3 */
+       ld      r3,HSTATE_SPRG3(r13)
+       mtspr   SPRN_SPRG3,r3
+
        /*
         * Reload DEC.  HDEC interrupts were disabled when
         * we reloaded the host's LPCR value.