Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Anton Blanchard and committed by
Benjamin Herrenschmidt
18ad51dd e6a74c6e

+140 -4
+1
arch/powerpc/include/asm/kvm_book3s_asm.h
··· 74 74 ulong vmhandler; 75 75 ulong scratch0; 76 76 ulong scratch1; 77 + ulong sprg3; 77 78 u8 in_guest; 78 79 u8 restore_hid5; 79 80 u8 napping;
+3 -2
arch/powerpc/include/asm/reg.h
··· 491 491 #define SPRN_SPRG1 0x111 /* Special Purpose Register General 1 */ 492 492 #define SPRN_SPRG2 0x112 /* Special Purpose Register General 2 */ 493 493 #define SPRN_SPRG3 0x113 /* Special Purpose Register General 3 */ 494 + #define SPRN_USPRG3 0x103 /* SPRG3 userspace read */ 494 495 #define SPRN_SPRG4 0x114 /* Special Purpose Register General 4 */ 495 496 #define SPRN_SPRG5 0x115 /* Special Purpose Register General 5 */ 496 497 #define SPRN_SPRG6 0x116 /* Special Purpose Register General 6 */ ··· 754 753 * 64-bit server: 755 754 * - SPRG0 unused (reserved for HV on Power4) 756 755 * - SPRG2 scratch for exception vectors 757 - * - SPRG3 unused (user visible) 756 + * - SPRG3 CPU and NUMA node for VDSO getcpu (user visible) 758 757 * - HSPRG0 stores PACA in HV mode 759 758 * - HSPRG1 scratch for "HV" exceptions 760 759 * 761 760 * 64-bit embedded 762 761 * - SPRG0 generic exception scratch 763 762 * - SPRG2 TLB exception stack 764 - * - SPRG3 unused (user visible) 763 + * - SPRG3 CPU and NUMA node for VDSO getcpu (user visible) 765 764 * - SPRG4 unused (user visible) 766 765 * - SPRG6 TLB miss scratch (user visible, sorry !) 767 766 * - SPRG7 critical exception scratch
+2
arch/powerpc/include/asm/vdso.h
··· 22 22 extern unsigned long vdso32_sigtramp; 23 23 extern unsigned long vdso32_rt_sigtramp; 24 24 25 + int __cpuinit vdso_getcpu_init(void); 26 + 25 27 #else /* __ASSEMBLY__ */ 26 28 27 29 #ifdef __VDSO64__
+1
arch/powerpc/kernel/asm-offsets.c
··· 533 533 HSTATE_FIELD(HSTATE_VMHANDLER, vmhandler); 534 534 HSTATE_FIELD(HSTATE_SCRATCH0, scratch0); 535 535 HSTATE_FIELD(HSTATE_SCRATCH1, scratch1); 536 + HSTATE_FIELD(HSTATE_SPRG3, sprg3); 536 537 HSTATE_FIELD(HSTATE_IN_GUEST, in_guest); 537 538 HSTATE_FIELD(HSTATE_RESTORE_HID5, restore_hid5); 538 539 HSTATE_FIELD(HSTATE_NAPPING, napping);
+3
arch/powerpc/kernel/smp.c
··· 48 48 #ifdef CONFIG_PPC64 49 49 #include <asm/paca.h> 50 50 #endif 51 + #include <asm/vdso.h> 51 52 #include <asm/debug.h> 52 53 53 54 #ifdef DEBUG ··· 571 570 #ifdef CONFIG_PPC64 572 571 if (system_state == SYSTEM_RUNNING) 573 572 vdso_data->processorCount++; 573 + 574 + vdso_getcpu_init(); 574 575 #endif 575 576 notify_cpu_starting(cpu); 576 577 set_cpu_online(cpu, true);
+28
arch/powerpc/kernel/vdso.c
··· 706 706 } 707 707 } 708 708 709 + #ifdef CONFIG_PPC64 710 + int __cpuinit vdso_getcpu_init(void) 711 + { 712 + unsigned long cpu, node, val; 713 + 714 + /* 715 + * SPRG3 contains the CPU in the bottom 16 bits and the NUMA node in 716 + * the next 16 bits. The VDSO uses this to implement getcpu(). 717 + */ 718 + cpu = get_cpu(); 719 + WARN_ON_ONCE(cpu > 0xffff); 720 + 721 + node = cpu_to_node(cpu); 722 + WARN_ON_ONCE(node > 0xffff); 723 + 724 + val = (cpu & 0xfff) | ((node & 0xffff) << 16); 725 + mtspr(SPRN_SPRG3, val); 726 + #ifdef CONFIG_KVM_BOOK3S_HANDLER 727 + get_paca()->kvm_hstate.sprg3 = val; 728 + #endif 729 + 730 + put_cpu(); 731 + 732 + return 0; 733 + } 734 + /* We need to call this before SMP init */ 735 + early_initcall(vdso_getcpu_init); 736 + #endif 709 737 710 738 static int __init vdso_init(void) 711 739 {
+3 -1
arch/powerpc/kernel/vdso32/Makefile
··· 1 1 2 2 # List of files in the vdso, has to be asm only for now 3 3 4 - obj-vdso32 = sigtramp.o gettimeofday.o datapage.o cacheflush.o note.o 4 + obj-vdso32-$(CONFIG_PPC64) = getcpu.o 5 + obj-vdso32 = sigtramp.o gettimeofday.o datapage.o cacheflush.o note.o \ 6 + $(obj-vdso32-y) 5 7 6 8 # Build rules 7 9
+45
arch/powerpc/kernel/vdso32/getcpu.S
··· 1 + /* 2 + * This program is free software; you can redistribute it and/or modify 3 + * it under the terms of the GNU General Public License as published by 4 + * the Free Software Foundation; either version 2 of the License, or 5 + * (at your option) any later version. 6 + * 7 + * This program is distributed in the hope that it will be useful, 8 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 + * GNU General Public License for more details. 11 + * 12 + * You should have received a copy of the GNU General Public License 13 + * along with this program; if not, write to the Free Software 14 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 15 + * 16 + * Copyright (C) IBM Corporation, 2012 17 + * 18 + * Author: Anton Blanchard <anton@au.ibm.com> 19 + */ 20 + #include <asm/ppc_asm.h> 21 + #include <asm/vdso.h> 22 + 23 + .text 24 + /* 25 + * Exact prototype of getcpu 26 + * 27 + * int __kernel_getcpu(unsigned *cpu, unsigned *node); 28 + * 29 + */ 30 + V_FUNCTION_BEGIN(__kernel_getcpu) 31 + .cfi_startproc 32 + mfspr r5,SPRN_USPRG3 33 + cmpdi cr0,r3,0 34 + cmpdi cr1,r4,0 35 + clrlwi r6,r5,16 36 + rlwinm r7,r5,16,31-15,31-0 37 + beq cr0,1f 38 + stw r6,0(r3) 39 + 1: beq cr1,2f 40 + stw r7,0(r4) 41 + 2: crclr cr0*4+so 42 + li r3,0 /* always success */ 43 + blr 44 + .cfi_endproc 45 + V_FUNCTION_END(__kernel_getcpu)
+3
arch/powerpc/kernel/vdso32/vdso32.lds.S
··· 147 147 __kernel_sync_dicache_p5; 148 148 __kernel_sigtramp32; 149 149 __kernel_sigtramp_rt32; 150 + #ifdef CONFIG_PPC64 151 + __kernel_getcpu; 152 + #endif 150 153 151 154 local: *; 152 155 };
+1 -1
arch/powerpc/kernel/vdso64/Makefile
··· 1 1 # List of files in the vdso, has to be asm only for now 2 2 3 - obj-vdso64 = sigtramp.o gettimeofday.o datapage.o cacheflush.o note.o 3 + obj-vdso64 = sigtramp.o gettimeofday.o datapage.o cacheflush.o note.o getcpu.o 4 4 5 5 # Build rules 6 6
+45
arch/powerpc/kernel/vdso64/getcpu.S
··· 1 + /* 2 + * This program is free software; you can redistribute it and/or modify 3 + * it under the terms of the GNU General Public License as published by 4 + * the Free Software Foundation; either version 2 of the License, or 5 + * (at your option) any later version. 6 + * 7 + * This program is distributed in the hope that it will be useful, 8 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 + * GNU General Public License for more details. 11 + * 12 + * You should have received a copy of the GNU General Public License 13 + * along with this program; if not, write to the Free Software 14 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 15 + * 16 + * Copyright (C) IBM Corporation, 2012 17 + * 18 + * Author: Anton Blanchard <anton@au.ibm.com> 19 + */ 20 + #include <asm/ppc_asm.h> 21 + #include <asm/vdso.h> 22 + 23 + .text 24 + /* 25 + * Exact prototype of getcpu 26 + * 27 + * int __kernel_getcpu(unsigned *cpu, unsigned *node); 28 + * 29 + */ 30 + V_FUNCTION_BEGIN(__kernel_getcpu) 31 + .cfi_startproc 32 + mfspr r5,SPRN_USPRG3 33 + cmpdi cr0,r3,0 34 + cmpdi cr1,r4,0 35 + clrlwi r6,r5,16 36 + rlwinm r7,r5,16,31-15,31-0 37 + beq cr0,1f 38 + stw r6,0(r3) 39 + 1: beq cr1,2f 40 + stw r7,0(r4) 41 + 2: crclr cr0*4+so 42 + li r3,0 /* always success */ 43 + blr 44 + .cfi_endproc 45 + V_FUNCTION_END(__kernel_getcpu)
+1
arch/powerpc/kernel/vdso64/vdso64.lds.S
··· 146 146 __kernel_sync_dicache; 147 147 __kernel_sync_dicache_p5; 148 148 __kernel_sigtramp_rt64; 149 + __kernel_getcpu; 149 150 150 151 local: *; 151 152 };
+4
arch/powerpc/kvm/book3s_hv_rmhandlers.S
··· 1064 1064 mtspr SPRN_DABR,r5 1065 1065 mtspr SPRN_DABRX,r6 1066 1066 1067 + /* Restore SPRG3 */ 1068 + ld r3,HSTATE_SPRG3(r13) 1069 + mtspr SPRN_SPRG3,r3 1070 + 1067 1071 /* 1068 1072 * Reload DEC. HDEC interrupts were disabled when 1069 1073 * we reloaded the host's LPCR value.