aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2015-03-27 23:21:12 -0400
committerAlexander Graf <agraf@suse.de>2015-04-21 09:21:34 -0400
commit66feed61cdf6ee65fd551d3460b1efba6bee55b8 (patch)
tree9c1f268dcf1f7431b451cbb21d99c09eacdf8ec7
parenteddb60fb1443f85c5728f1b1cd4be608c6832a79 (diff)
KVM: PPC: Book3S HV: Use msgsnd for signalling threads on POWER8
This uses msgsnd where possible for signalling other threads within the same core on POWER8 systems, rather than IPIs through the XICS interrupt controller. This includes waking secondary threads to run the guest, the interrupts generated by the virtual XICS, and the interrupts to bring the other threads out of the guest when exiting. Aggregated statistics from debugfs across vcpus for a guest with 32 vcpus, 8 threads/vcore, running on a POWER8, show this before the change: rm_entry: 3387.6ns (228 - 86600, 1008969 samples) rm_exit: 4561.5ns (12 - 3477452, 1009402 samples) rm_intr: 1660.0ns (12 - 553050, 3600051 samples) and this after the change: rm_entry: 3060.1ns (212 - 65138, 953873 samples) rm_exit: 4244.1ns (12 - 9693408, 954331 samples) rm_intr: 1342.3ns (12 - 1104718, 3405326 samples) for a test of booting Fedora 20 big-endian to the login prompt. The time taken for a H_PROD hcall (which is handled in the host kernel) went down from about 35 microseconds to about 16 microseconds with this change. The noinline added to kvmppc_run_core turned out to be necessary for good performance, at least with gcc 4.9.2 as packaged with Fedora 21 and a little-endian POWER8 host. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Alexander Graf <agraf@suse.de>
-rw-r--r--arch/powerpc/kernel/asm-offsets.c3
-rw-r--r--arch/powerpc/kvm/book3s_hv.c51
-rw-r--r--arch/powerpc/kvm/book3s_hv_builtin.c16
-rw-r--r--arch/powerpc/kvm/book3s_hv_rmhandlers.S22
4 files changed, 70 insertions, 22 deletions
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 0d07efbe3fa7..0034b6b3556a 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -37,6 +37,7 @@
37#include <asm/thread_info.h> 37#include <asm/thread_info.h>
38#include <asm/rtas.h> 38#include <asm/rtas.h>
39#include <asm/vdso_datapage.h> 39#include <asm/vdso_datapage.h>
40#include <asm/dbell.h>
40#ifdef CONFIG_PPC64 41#ifdef CONFIG_PPC64
41#include <asm/paca.h> 42#include <asm/paca.h>
42#include <asm/lppaca.h> 43#include <asm/lppaca.h>
@@ -759,5 +760,7 @@ int main(void)
759 offsetof(struct paca_struct, subcore_sibling_mask)); 760 offsetof(struct paca_struct, subcore_sibling_mask));
760#endif 761#endif
761 762
763 DEFINE(PPC_DBELL_SERVER, PPC_DBELL_SERVER);
764
762 return 0; 765 return 0;
763} 766}
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index ea1600ff52b2..48d3c5d2ecc9 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -51,6 +51,7 @@
51#include <asm/hvcall.h> 51#include <asm/hvcall.h>
52#include <asm/switch_to.h> 52#include <asm/switch_to.h>
53#include <asm/smp.h> 53#include <asm/smp.h>
54#include <asm/dbell.h>
54#include <linux/gfp.h> 55#include <linux/gfp.h>
55#include <linux/vmalloc.h> 56#include <linux/vmalloc.h>
56#include <linux/highmem.h> 57#include <linux/highmem.h>
@@ -84,9 +85,35 @@ static DECLARE_BITMAP(default_enabled_hcalls, MAX_HCALL_OPCODE/4 + 1);
84static void kvmppc_end_cede(struct kvm_vcpu *vcpu); 85static void kvmppc_end_cede(struct kvm_vcpu *vcpu);
85static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu); 86static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu);
86 87
88static bool kvmppc_ipi_thread(int cpu)
89{
90 /* On POWER8 for IPIs to threads in the same core, use msgsnd */
91 if (cpu_has_feature(CPU_FTR_ARCH_207S)) {
92 preempt_disable();
93 if (cpu_first_thread_sibling(cpu) ==
94 cpu_first_thread_sibling(smp_processor_id())) {
95 unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER);
96 msg |= cpu_thread_in_core(cpu);
97 smp_mb();
98 __asm__ __volatile__ (PPC_MSGSND(%0) : : "r" (msg));
99 preempt_enable();
100 return true;
101 }
102 preempt_enable();
103 }
104
105#if defined(CONFIG_PPC_ICP_NATIVE) && defined(CONFIG_SMP)
106 if (cpu >= 0 && cpu < nr_cpu_ids && paca[cpu].kvm_hstate.xics_phys) {
107 xics_wake_cpu(cpu);
108 return true;
109 }
110#endif
111
112 return false;
113}
114
87static void kvmppc_fast_vcpu_kick_hv(struct kvm_vcpu *vcpu) 115static void kvmppc_fast_vcpu_kick_hv(struct kvm_vcpu *vcpu)
88{ 116{
89 int me;
90 int cpu = vcpu->cpu; 117 int cpu = vcpu->cpu;
91 wait_queue_head_t *wqp; 118 wait_queue_head_t *wqp;
92 119
@@ -96,20 +123,12 @@ static void kvmppc_fast_vcpu_kick_hv(struct kvm_vcpu *vcpu)
96 ++vcpu->stat.halt_wakeup; 123 ++vcpu->stat.halt_wakeup;
97 } 124 }
98 125
99 me = get_cpu(); 126 if (kvmppc_ipi_thread(cpu + vcpu->arch.ptid))
127 return;
100 128
101 /* CPU points to the first thread of the core */ 129 /* CPU points to the first thread of the core */
102 if (cpu != me && cpu >= 0 && cpu < nr_cpu_ids) { 130 if (cpu >= 0 && cpu < nr_cpu_ids && cpu_online(cpu))
103#ifdef CONFIG_PPC_ICP_NATIVE 131 smp_send_reschedule(cpu);
104 int real_cpu = cpu + vcpu->arch.ptid;
105 if (paca[real_cpu].kvm_hstate.xics_phys)
106 xics_wake_cpu(real_cpu);
107 else
108#endif
109 if (cpu_online(cpu))
110 smp_send_reschedule(cpu);
111 }
112 put_cpu();
113} 132}
114 133
115/* 134/*
@@ -1781,10 +1800,8 @@ static void kvmppc_start_thread(struct kvm_vcpu *vcpu)
1781 /* Order stores to hstate.kvm_vcore etc. before store to kvm_vcpu */ 1800 /* Order stores to hstate.kvm_vcore etc. before store to kvm_vcpu */
1782 smp_wmb(); 1801 smp_wmb();
1783 tpaca->kvm_hstate.kvm_vcpu = vcpu; 1802 tpaca->kvm_hstate.kvm_vcpu = vcpu;
1784#if defined(CONFIG_PPC_ICP_NATIVE) && defined(CONFIG_SMP)
1785 if (cpu != smp_processor_id()) 1803 if (cpu != smp_processor_id())
1786 xics_wake_cpu(cpu); 1804 kvmppc_ipi_thread(cpu);
1787#endif
1788} 1805}
1789 1806
1790static void kvmppc_wait_for_nap(void) 1807static void kvmppc_wait_for_nap(void)
@@ -1933,7 +1950,7 @@ static void post_guest_process(struct kvmppc_vcore *vc)
1933 * Run a set of guest threads on a physical core. 1950 * Run a set of guest threads on a physical core.
1934 * Called with vc->lock held. 1951 * Called with vc->lock held.
1935 */ 1952 */
1936static void kvmppc_run_core(struct kvmppc_vcore *vc) 1953static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
1937{ 1954{
1938 struct kvm_vcpu *vcpu; 1955 struct kvm_vcpu *vcpu;
1939 int i; 1956 int i;
diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c
index c42aa55b885f..ed2589d4593f 100644
--- a/arch/powerpc/kvm/book3s_hv_builtin.c
+++ b/arch/powerpc/kvm/book3s_hv_builtin.c
@@ -23,6 +23,8 @@
23#include <asm/kvm_book3s.h> 23#include <asm/kvm_book3s.h>
24#include <asm/archrandom.h> 24#include <asm/archrandom.h>
25#include <asm/xics.h> 25#include <asm/xics.h>
26#include <asm/dbell.h>
27#include <asm/cputhreads.h>
26 28
27#define KVM_CMA_CHUNK_ORDER 18 29#define KVM_CMA_CHUNK_ORDER 18
28 30
@@ -193,7 +195,7 @@ static inline void rm_writeb(unsigned long paddr, u8 val)
193} 195}
194 196
195/* 197/*
196 * Send an interrupt to another CPU. 198 * Send an interrupt or message to another CPU.
197 * This can only be called in real mode. 199 * This can only be called in real mode.
198 * The caller needs to include any barrier needed to order writes 200 * The caller needs to include any barrier needed to order writes
199 * to memory vs. the IPI/message. 201 * to memory vs. the IPI/message.
@@ -202,7 +204,17 @@ void kvmhv_rm_send_ipi(int cpu)
202{ 204{
203 unsigned long xics_phys; 205 unsigned long xics_phys;
204 206
205 /* Poke the target */ 207 /* On POWER8 for IPIs to threads in the same core, use msgsnd */
208 if (cpu_has_feature(CPU_FTR_ARCH_207S) &&
209 cpu_first_thread_sibling(cpu) ==
210 cpu_first_thread_sibling(raw_smp_processor_id())) {
211 unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER);
212 msg |= cpu_thread_in_core(cpu);
213 __asm__ __volatile__ (PPC_MSGSND(%0) : : "r" (msg));
214 return;
215 }
216
217 /* Else poke the target with an IPI */
206 xics_phys = paca[cpu].kvm_hstate.xics_phys; 218 xics_phys = paca[cpu].kvm_hstate.xics_phys;
207 rm_writeb(xics_phys + XICS_MFRR, IPI_PRIORITY); 219 rm_writeb(xics_phys + XICS_MFRR, IPI_PRIORITY);
208} 220}
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index fcf3a617cc8a..4d70df26c402 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -1123,6 +1123,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
1123 cmpwi r12,BOOK3S_INTERRUPT_SYSCALL 1123 cmpwi r12,BOOK3S_INTERRUPT_SYSCALL
1124 beq hcall_try_real_mode 1124 beq hcall_try_real_mode
1125 1125
1126 /* Hypervisor doorbell - exit only if host IPI flag set */
1127 cmpwi r12, BOOK3S_INTERRUPT_H_DOORBELL
1128 bne 3f
1129 lbz r0, HSTATE_HOST_IPI(r13)
1130 beq 4f
1131 b guest_exit_cont
11323:
1126 /* External interrupt ? */ 1133 /* External interrupt ? */
1127 cmpwi r12, BOOK3S_INTERRUPT_EXTERNAL 1134 cmpwi r12, BOOK3S_INTERRUPT_EXTERNAL
1128 bne+ guest_exit_cont 1135 bne+ guest_exit_cont
@@ -1135,7 +1142,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
1135 bgt guest_exit_cont 1142 bgt guest_exit_cont
1136 1143
1137 /* Check if any CPU is heading out to the host, if so head out too */ 1144 /* Check if any CPU is heading out to the host, if so head out too */
1138 ld r5, HSTATE_KVM_VCORE(r13) 11454: ld r5, HSTATE_KVM_VCORE(r13)
1139 lwz r0, VCORE_ENTRY_EXIT(r5) 1146 lwz r0, VCORE_ENTRY_EXIT(r5)
1140 cmpwi r0, 0x100 1147 cmpwi r0, 0x100
1141 mr r4, r9 1148 mr r4, r9
@@ -2148,7 +2155,7 @@ _GLOBAL(kvmppc_h_cede) /* r3 = vcpu pointer, r11 = msr, r13 = paca */
2148 /* 2155 /*
2149 * Take a nap until a decrementer or external or doobell interrupt 2156 * Take a nap until a decrementer or external or doobell interrupt
2150 * occurs, with PECE1 and PECE0 set in LPCR. 2157 * occurs, with PECE1 and PECE0 set in LPCR.
2151 * On POWER8, if we are ceding, also set PECEDP. 2158 * On POWER8, set PECEDH, and if we are ceding, also set PECEDP.
2152 * Also clear the runlatch bit before napping. 2159 * Also clear the runlatch bit before napping.
2153 */ 2160 */
2154kvm_do_nap: 2161kvm_do_nap:
@@ -2161,6 +2168,7 @@ kvm_do_nap:
2161 mfspr r5,SPRN_LPCR 2168 mfspr r5,SPRN_LPCR
2162 ori r5,r5,LPCR_PECE0 | LPCR_PECE1 2169 ori r5,r5,LPCR_PECE0 | LPCR_PECE1
2163BEGIN_FTR_SECTION 2170BEGIN_FTR_SECTION
2171 ori r5, r5, LPCR_PECEDH
2164 rlwimi r5, r3, 0, LPCR_PECEDP 2172 rlwimi r5, r3, 0, LPCR_PECEDP
2165END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) 2173END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
2166 mtspr SPRN_LPCR,r5 2174 mtspr SPRN_LPCR,r5
@@ -2299,7 +2307,7 @@ machine_check_realmode:
2299 * Returns (in r3): 2307 * Returns (in r3):
2300 * 0 if nothing needs to be done 2308 * 0 if nothing needs to be done
2301 * 1 if something happened that needs to be handled by the host 2309 * 1 if something happened that needs to be handled by the host
2302 * -1 if there was a guest wakeup (IPI) 2310 * -1 if there was a guest wakeup (IPI or msgsnd)
2303 * 2311 *
2304 * Also sets r12 to the interrupt vector for any interrupt that needs 2312 * Also sets r12 to the interrupt vector for any interrupt that needs
2305 * to be handled now by the host (0x500 for external interrupt), or zero. 2313 * to be handled now by the host (0x500 for external interrupt), or zero.
@@ -2330,7 +2338,15 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
2330 2338
2331 /* hypervisor doorbell */ 2339 /* hypervisor doorbell */
23323: li r12, BOOK3S_INTERRUPT_H_DOORBELL 23403: li r12, BOOK3S_INTERRUPT_H_DOORBELL
2341 /* see if it's a host IPI */
2333 li r3, 1 2342 li r3, 1
2343 lbz r0, HSTATE_HOST_IPI(r13)
2344 cmpwi r0, 0
2345 bnelr
2346 /* if not, clear it and return -1 */
2347 lis r6, (PPC_DBELL_SERVER << (63-36))@h
2348 PPC_MSGCLR(6)
2349 li r3, -1
2334 blr 2350 blr
2335 2351
2336/* 2352/*