diff options
author | Anton Blanchard <anton@samba.org> | 2012-07-04 16:37:11 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-07-11 00:18:40 -0400 |
commit | 18ad51dd342a7eb09dbcd059d0b451b616d4dafc (patch) | |
tree | 94809605669eb3b5e4e049501958a2fa93ae2de7 /arch/powerpc | |
parent | e6a74c6ea331b79c86e1898c504790b3dadc591d (diff) |
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')
-rw-r--r-- | arch/powerpc/include/asm/kvm_book3s_asm.h | 1 | ||||
-rw-r--r-- | arch/powerpc/include/asm/reg.h | 5 | ||||
-rw-r--r-- | arch/powerpc/include/asm/vdso.h | 2 | ||||
-rw-r--r-- | arch/powerpc/kernel/asm-offsets.c | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/smp.c | 3 | ||||
-rw-r--r-- | arch/powerpc/kernel/vdso.c | 28 | ||||
-rw-r--r-- | arch/powerpc/kernel/vdso32/Makefile | 4 | ||||
-rw-r--r-- | arch/powerpc/kernel/vdso32/getcpu.S | 45 | ||||
-rw-r--r-- | arch/powerpc/kernel/vdso32/vdso32.lds.S | 3 | ||||
-rw-r--r-- | arch/powerpc/kernel/vdso64/Makefile | 2 | ||||
-rw-r--r-- | arch/powerpc/kernel/vdso64/getcpu.S | 45 | ||||
-rw-r--r-- | arch/powerpc/kernel/vdso64/vdso64.lds.S | 1 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s_hv_rmhandlers.S | 4 |
13 files changed, 140 insertions, 4 deletions
diff --git a/arch/powerpc/include/asm/kvm_book3s_asm.h b/arch/powerpc/include/asm/kvm_book3s_asm.h index 88609b23b775..bfcd00c1485d 100644 --- a/arch/powerpc/include/asm/kvm_book3s_asm.h +++ b/arch/powerpc/include/asm/kvm_book3s_asm.h | |||
@@ -74,6 +74,7 @@ struct kvmppc_host_state { | |||
74 | ulong vmhandler; | 74 | ulong vmhandler; |
75 | ulong scratch0; | 75 | ulong scratch0; |
76 | ulong scratch1; | 76 | ulong scratch1; |
77 | ulong sprg3; | ||
77 | u8 in_guest; | 78 | u8 in_guest; |
78 | u8 restore_hid5; | 79 | u8 restore_hid5; |
79 | u8 napping; | 80 | u8 napping; |
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index f0cb7f461b9d..2baeb7c8764f 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h | |||
@@ -491,6 +491,7 @@ | |||
491 | #define SPRN_SPRG1 0x111 /* Special Purpose Register General 1 */ | 491 | #define SPRN_SPRG1 0x111 /* Special Purpose Register General 1 */ |
492 | #define SPRN_SPRG2 0x112 /* Special Purpose Register General 2 */ | 492 | #define SPRN_SPRG2 0x112 /* Special Purpose Register General 2 */ |
493 | #define SPRN_SPRG3 0x113 /* Special Purpose Register General 3 */ | 493 | #define SPRN_SPRG3 0x113 /* Special Purpose Register General 3 */ |
494 | #define SPRN_USPRG3 0x103 /* SPRG3 userspace read */ | ||
494 | #define SPRN_SPRG4 0x114 /* Special Purpose Register General 4 */ | 495 | #define SPRN_SPRG4 0x114 /* Special Purpose Register General 4 */ |
495 | #define SPRN_SPRG5 0x115 /* Special Purpose Register General 5 */ | 496 | #define SPRN_SPRG5 0x115 /* Special Purpose Register General 5 */ |
496 | #define SPRN_SPRG6 0x116 /* Special Purpose Register General 6 */ | 497 | #define SPRN_SPRG6 0x116 /* Special Purpose Register General 6 */ |
@@ -753,14 +754,14 @@ | |||
753 | * 64-bit server: | 754 | * 64-bit server: |
754 | * - SPRG0 unused (reserved for HV on Power4) | 755 | * - SPRG0 unused (reserved for HV on Power4) |
755 | * - SPRG2 scratch for exception vectors | 756 | * - SPRG2 scratch for exception vectors |
756 | * - SPRG3 unused (user visible) | 757 | * - SPRG3 CPU and NUMA node for VDSO getcpu (user visible) |
757 | * - HSPRG0 stores PACA in HV mode | 758 | * - HSPRG0 stores PACA in HV mode |
758 | * - HSPRG1 scratch for "HV" exceptions | 759 | * - HSPRG1 scratch for "HV" exceptions |
759 | * | 760 | * |
760 | * 64-bit embedded | 761 | * 64-bit embedded |
761 | * - SPRG0 generic exception scratch | 762 | * - SPRG0 generic exception scratch |
762 | * - SPRG2 TLB exception stack | 763 | * - SPRG2 TLB exception stack |
763 | * - SPRG3 unused (user visible) | 764 | * - SPRG3 CPU and NUMA node for VDSO getcpu (user visible) |
764 | * - SPRG4 unused (user visible) | 765 | * - SPRG4 unused (user visible) |
765 | * - SPRG6 TLB miss scratch (user visible, sorry !) | 766 | * - SPRG6 TLB miss scratch (user visible, sorry !) |
766 | * - SPRG7 critical exception scratch | 767 | * - SPRG7 critical exception scratch |
diff --git a/arch/powerpc/include/asm/vdso.h b/arch/powerpc/include/asm/vdso.h index dc0419b66f17..50f261bc3e95 100644 --- a/arch/powerpc/include/asm/vdso.h +++ b/arch/powerpc/include/asm/vdso.h | |||
@@ -22,6 +22,8 @@ extern unsigned long vdso64_rt_sigtramp; | |||
22 | extern unsigned long vdso32_sigtramp; | 22 | extern unsigned long vdso32_sigtramp; |
23 | extern unsigned long vdso32_rt_sigtramp; | 23 | extern unsigned long vdso32_rt_sigtramp; |
24 | 24 | ||
25 | int __cpuinit vdso_getcpu_init(void); | ||
26 | |||
25 | #else /* __ASSEMBLY__ */ | 27 | #else /* __ASSEMBLY__ */ |
26 | 28 | ||
27 | #ifdef __VDSO64__ | 29 | #ifdef __VDSO64__ |
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 52c7ad78242e..85b05c463fae 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c | |||
@@ -533,6 +533,7 @@ int main(void) | |||
533 | HSTATE_FIELD(HSTATE_VMHANDLER, vmhandler); | 533 | HSTATE_FIELD(HSTATE_VMHANDLER, vmhandler); |
534 | HSTATE_FIELD(HSTATE_SCRATCH0, scratch0); | 534 | HSTATE_FIELD(HSTATE_SCRATCH0, scratch0); |
535 | HSTATE_FIELD(HSTATE_SCRATCH1, scratch1); | 535 | HSTATE_FIELD(HSTATE_SCRATCH1, scratch1); |
536 | HSTATE_FIELD(HSTATE_SPRG3, sprg3); | ||
536 | HSTATE_FIELD(HSTATE_IN_GUEST, in_guest); | 537 | HSTATE_FIELD(HSTATE_IN_GUEST, in_guest); |
537 | HSTATE_FIELD(HSTATE_RESTORE_HID5, restore_hid5); | 538 | HSTATE_FIELD(HSTATE_RESTORE_HID5, restore_hid5); |
538 | HSTATE_FIELD(HSTATE_NAPPING, napping); | 539 | HSTATE_FIELD(HSTATE_NAPPING, napping); |
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index e1417c42155c..0321007086f7 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #ifdef CONFIG_PPC64 | 48 | #ifdef CONFIG_PPC64 |
49 | #include <asm/paca.h> | 49 | #include <asm/paca.h> |
50 | #endif | 50 | #endif |
51 | #include <asm/vdso.h> | ||
51 | #include <asm/debug.h> | 52 | #include <asm/debug.h> |
52 | 53 | ||
53 | #ifdef DEBUG | 54 | #ifdef DEBUG |
@@ -570,6 +571,8 @@ void __devinit start_secondary(void *unused) | |||
570 | #ifdef CONFIG_PPC64 | 571 | #ifdef CONFIG_PPC64 |
571 | if (system_state == SYSTEM_RUNNING) | 572 | if (system_state == SYSTEM_RUNNING) |
572 | vdso_data->processorCount++; | 573 | vdso_data->processorCount++; |
574 | |||
575 | vdso_getcpu_init(); | ||
573 | #endif | 576 | #endif |
574 | notify_cpu_starting(cpu); | 577 | notify_cpu_starting(cpu); |
575 | set_cpu_online(cpu, true); | 578 | set_cpu_online(cpu, true); |
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c index 9eb5b9b536a7..b67db22e102d 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) | |||
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 | static int __init vdso_init(void) | 738 | static int __init vdso_init(void) |
711 | { | 739 | { |
diff --git a/arch/powerpc/kernel/vdso32/Makefile b/arch/powerpc/kernel/vdso32/Makefile index 9a7946c41738..53e6c9b979ec 100644 --- a/arch/powerpc/kernel/vdso32/Makefile +++ b/arch/powerpc/kernel/vdso32/Makefile | |||
@@ -1,7 +1,9 @@ | |||
1 | 1 | ||
2 | # List of files in the vdso, has to be asm only for now | 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 | # Build rules | 8 | # Build rules |
7 | 9 | ||
diff --git a/arch/powerpc/kernel/vdso32/getcpu.S b/arch/powerpc/kernel/vdso32/getcpu.S new file mode 100644 index 000000000000..47afd08c90f7 --- /dev/null +++ b/arch/powerpc/kernel/vdso32/getcpu.S | |||
@@ -0,0 +1,45 @@ | |||
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) | ||
diff --git a/arch/powerpc/kernel/vdso32/vdso32.lds.S b/arch/powerpc/kernel/vdso32/vdso32.lds.S index 0546bcd49cd0..43200ba2e570 100644 --- a/arch/powerpc/kernel/vdso32/vdso32.lds.S +++ b/arch/powerpc/kernel/vdso32/vdso32.lds.S | |||
@@ -147,6 +147,9 @@ VERSION | |||
147 | __kernel_sync_dicache_p5; | 147 | __kernel_sync_dicache_p5; |
148 | __kernel_sigtramp32; | 148 | __kernel_sigtramp32; |
149 | __kernel_sigtramp_rt32; | 149 | __kernel_sigtramp_rt32; |
150 | #ifdef CONFIG_PPC64 | ||
151 | __kernel_getcpu; | ||
152 | #endif | ||
150 | 153 | ||
151 | local: *; | 154 | local: *; |
152 | }; | 155 | }; |
diff --git a/arch/powerpc/kernel/vdso64/Makefile b/arch/powerpc/kernel/vdso64/Makefile index 8c500d8622e4..effca9404b17 100644 --- a/arch/powerpc/kernel/vdso64/Makefile +++ b/arch/powerpc/kernel/vdso64/Makefile | |||
@@ -1,6 +1,6 @@ | |||
1 | # List of files in the vdso, has to be asm only for now | 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 | # Build rules | 5 | # Build rules |
6 | 6 | ||
diff --git a/arch/powerpc/kernel/vdso64/getcpu.S b/arch/powerpc/kernel/vdso64/getcpu.S new file mode 100644 index 000000000000..47afd08c90f7 --- /dev/null +++ b/arch/powerpc/kernel/vdso64/getcpu.S | |||
@@ -0,0 +1,45 @@ | |||
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) | ||
diff --git a/arch/powerpc/kernel/vdso64/vdso64.lds.S b/arch/powerpc/kernel/vdso64/vdso64.lds.S index 0e615404e247..e6c1758f3588 100644 --- a/arch/powerpc/kernel/vdso64/vdso64.lds.S +++ b/arch/powerpc/kernel/vdso64/vdso64.lds.S | |||
@@ -146,6 +146,7 @@ VERSION | |||
146 | __kernel_sync_dicache; | 146 | __kernel_sync_dicache; |
147 | __kernel_sync_dicache_p5; | 147 | __kernel_sync_dicache_p5; |
148 | __kernel_sigtramp_rt64; | 148 | __kernel_sigtramp_rt64; |
149 | __kernel_getcpu; | ||
149 | 150 | ||
150 | local: *; | 151 | local: *; |
151 | }; | 152 | }; |
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index e764e2361d47..5a84c8d3d040 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S | |||
@@ -1064,6 +1064,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) | |||
1064 | mtspr SPRN_DABR,r5 | 1064 | mtspr SPRN_DABR,r5 |
1065 | mtspr SPRN_DABRX,r6 | 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 | * Reload DEC. HDEC interrupts were disabled when | 1072 | * Reload DEC. HDEC interrupts were disabled when |
1069 | * we reloaded the host's LPCR value. | 1073 | * we reloaded the host's LPCR value. |