aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2015-03-27 23:21:09 -0400
committerAlexander Graf <agraf@suse.de>2015-04-21 09:21:33 -0400
commit7d6c40da198ac18bd5dd2cd18628d5b4c615d842 (patch)
tree2c2e25ea051d2a569ae8332742fb27f59dff5eb3 /arch
parentfd6d53b12410b4b73e3996629350dee3f4a7994f (diff)
KVM: PPC: Book3S HV: Use bitmap of active threads rather than count
Currently, the entry_exit_count field in the kvmppc_vcore struct contains two 8-bit counts, one of the threads that have started entering the guest, and one of the threads that have started exiting the guest. This changes it to an entry_exit_map field which contains two bitmaps of 8 bits each. The advantage of doing this is that it gives us a bitmap of which threads need to be signalled when exiting the guest. That means that we no longer need to use the trick of setting the HDEC to 0 to pull the other threads out of the guest, which led in some cases to a spurious HDEC interrupt on the next guest entry. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/include/asm/kvm_host.h15
-rw-r--r--arch/powerpc/kernel/asm-offsets.c2
-rw-r--r--arch/powerpc/kvm/book3s_hv.c5
-rw-r--r--arch/powerpc/kvm/book3s_hv_builtin.c10
-rw-r--r--arch/powerpc/kvm/book3s_hv_rmhandlers.S61
5 files changed, 44 insertions, 49 deletions
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 1517faac9b98..d67a83830bd1 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -263,15 +263,15 @@ struct kvm_arch {
263 263
264/* 264/*
265 * Struct for a virtual core. 265 * Struct for a virtual core.
266 * Note: entry_exit_count combines an entry count in the bottom 8 bits 266 * Note: entry_exit_map combines a bitmap of threads that have entered
267 * and an exit count in the next 8 bits. This is so that we can 267 * in the bottom 8 bits and a bitmap of threads that have exited in the
268 * atomically increment the entry count iff the exit count is 0 268 * next 8 bits. This is so that we can atomically set the entry bit
269 * without taking the lock. 269 * iff the exit map is 0 without taking a lock.
270 */ 270 */
271struct kvmppc_vcore { 271struct kvmppc_vcore {
272 int n_runnable; 272 int n_runnable;
273 int num_threads; 273 int num_threads;
274 int entry_exit_count; 274 int entry_exit_map;
275 int napping_threads; 275 int napping_threads;
276 int first_vcpuid; 276 int first_vcpuid;
277 u16 pcpu; 277 u16 pcpu;
@@ -296,8 +296,9 @@ struct kvmppc_vcore {
296 ulong conferring_threads; 296 ulong conferring_threads;
297}; 297};
298 298
299#define VCORE_ENTRY_COUNT(vc) ((vc)->entry_exit_count & 0xff) 299#define VCORE_ENTRY_MAP(vc) ((vc)->entry_exit_map & 0xff)
300#define VCORE_EXIT_COUNT(vc) ((vc)->entry_exit_count >> 8) 300#define VCORE_EXIT_MAP(vc) ((vc)->entry_exit_map >> 8)
301#define VCORE_IS_EXITING(vc) (VCORE_EXIT_MAP(vc) != 0)
301 302
302/* Values for vcore_state */ 303/* Values for vcore_state */
303#define VCORE_INACTIVE 0 304#define VCORE_INACTIVE 0
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 8aa824681d76..0d07efbe3fa7 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -562,7 +562,7 @@ int main(void)
562 DEFINE(VCPU_ACOP, offsetof(struct kvm_vcpu, arch.acop)); 562 DEFINE(VCPU_ACOP, offsetof(struct kvm_vcpu, arch.acop));
563 DEFINE(VCPU_WORT, offsetof(struct kvm_vcpu, arch.wort)); 563 DEFINE(VCPU_WORT, offsetof(struct kvm_vcpu, arch.wort));
564 DEFINE(VCPU_SHADOW_SRR1, offsetof(struct kvm_vcpu, arch.shadow_srr1)); 564 DEFINE(VCPU_SHADOW_SRR1, offsetof(struct kvm_vcpu, arch.shadow_srr1));
565 DEFINE(VCORE_ENTRY_EXIT, offsetof(struct kvmppc_vcore, entry_exit_count)); 565 DEFINE(VCORE_ENTRY_EXIT, offsetof(struct kvmppc_vcore, entry_exit_map));
566 DEFINE(VCORE_IN_GUEST, offsetof(struct kvmppc_vcore, in_guest)); 566 DEFINE(VCORE_IN_GUEST, offsetof(struct kvmppc_vcore, in_guest));
567 DEFINE(VCORE_NAPPING_THREADS, offsetof(struct kvmppc_vcore, napping_threads)); 567 DEFINE(VCORE_NAPPING_THREADS, offsetof(struct kvmppc_vcore, napping_threads));
568 DEFINE(VCORE_KVM, offsetof(struct kvmppc_vcore, kvm)); 568 DEFINE(VCORE_KVM, offsetof(struct kvmppc_vcore, kvm));
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 7c1335dca4a5..ea1600ff52b2 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -1952,7 +1952,7 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc)
1952 /* 1952 /*
1953 * Initialize *vc. 1953 * Initialize *vc.
1954 */ 1954 */
1955 vc->entry_exit_count = 0; 1955 vc->entry_exit_map = 0;
1956 vc->preempt_tb = TB_NIL; 1956 vc->preempt_tb = TB_NIL;
1957 vc->in_guest = 0; 1957 vc->in_guest = 0;
1958 vc->napping_threads = 0; 1958 vc->napping_threads = 0;
@@ -2119,8 +2119,7 @@ static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
2119 * this thread straight away and have it join in. 2119 * this thread straight away and have it join in.
2120 */ 2120 */
2121 if (!signal_pending(current)) { 2121 if (!signal_pending(current)) {
2122 if (vc->vcore_state == VCORE_RUNNING && 2122 if (vc->vcore_state == VCORE_RUNNING && !VCORE_IS_EXITING(vc)) {
2123 VCORE_EXIT_COUNT(vc) == 0) {
2124 kvmppc_create_dtl_entry(vcpu, vc); 2123 kvmppc_create_dtl_entry(vcpu, vc);
2125 kvmppc_start_thread(vcpu); 2124 kvmppc_start_thread(vcpu);
2126 trace_kvm_guest_enter(vcpu); 2125 trace_kvm_guest_enter(vcpu);
diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c
index 1954a1c4b1f9..275425142bb7 100644
--- a/arch/powerpc/kvm/book3s_hv_builtin.c
+++ b/arch/powerpc/kvm/book3s_hv_builtin.c
@@ -115,11 +115,11 @@ long int kvmppc_rm_h_confer(struct kvm_vcpu *vcpu, int target,
115 int rv = H_SUCCESS; /* => don't yield */ 115 int rv = H_SUCCESS; /* => don't yield */
116 116
117 set_bit(vcpu->arch.ptid, &vc->conferring_threads); 117 set_bit(vcpu->arch.ptid, &vc->conferring_threads);
118 while ((get_tb() < stop) && (VCORE_EXIT_COUNT(vc) == 0)) { 118 while ((get_tb() < stop) && !VCORE_IS_EXITING(vc)) {
119 threads_running = VCORE_ENTRY_COUNT(vc); 119 threads_running = VCORE_ENTRY_MAP(vc);
120 threads_ceded = hweight32(vc->napping_threads); 120 threads_ceded = vc->napping_threads;
121 threads_conferring = hweight32(vc->conferring_threads); 121 threads_conferring = vc->conferring_threads;
122 if (threads_ceded + threads_conferring >= threads_running) { 122 if ((threads_ceded | threads_conferring) == threads_running) {
123 rv = H_TOO_HARD; /* => do yield */ 123 rv = H_TOO_HARD; /* => do yield */
124 break; 124 break;
125 } 125 }
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index 16719af88bcc..245f5c972030 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -185,7 +185,7 @@ kvmppc_primary_no_guest:
185 or r3, r3, r0 185 or r3, r3, r0
186 stwcx. r3, 0, r6 186 stwcx. r3, 0, r6
187 bne 1b 187 bne 1b
188 /* order napping_threads update vs testing entry_exit_count */ 188 /* order napping_threads update vs testing entry_exit_map */
189 isync 189 isync
190 li r12, 0 190 li r12, 0
191 lwz r7, VCORE_ENTRY_EXIT(r5) 191 lwz r7, VCORE_ENTRY_EXIT(r5)
@@ -406,19 +406,21 @@ kvmppc_hv_entry:
406 * We don't have to lock against concurrent tlbies, 406 * We don't have to lock against concurrent tlbies,
407 * but we do have to coordinate across hardware threads. 407 * but we do have to coordinate across hardware threads.
408 */ 408 */
409 /* Increment entry count iff exit count is zero. */ 409 /* Set bit in entry map iff exit map is zero. */
410 ld r5,HSTATE_KVM_VCORE(r13) 410 ld r5, HSTATE_KVM_VCORE(r13)
411 addi r9,r5,VCORE_ENTRY_EXIT 411 li r7, 1
41221: lwarx r3,0,r9 412 lbz r6, HSTATE_PTID(r13)
413 cmpwi r3,0x100 /* any threads starting to exit? */ 413 sld r7, r7, r6
414 addi r9, r5, VCORE_ENTRY_EXIT
41521: lwarx r3, 0, r9
416 cmpwi r3, 0x100 /* any threads starting to exit? */
414 bge secondary_too_late /* if so we're too late to the party */ 417 bge secondary_too_late /* if so we're too late to the party */
415 addi r3,r3,1 418 or r3, r3, r7
416 stwcx. r3,0,r9 419 stwcx. r3, 0, r9
417 bne 21b 420 bne 21b
418 421
419 /* Primary thread switches to guest partition. */ 422 /* Primary thread switches to guest partition. */
420 ld r9,VCORE_KVM(r5) /* pointer to struct kvm */ 423 ld r9,VCORE_KVM(r5) /* pointer to struct kvm */
421 lbz r6,HSTATE_PTID(r13)
422 cmpwi r6,0 424 cmpwi r6,0
423 bne 20f 425 bne 20f
424 ld r6,KVM_SDR1(r9) 426 ld r6,KVM_SDR1(r9)
@@ -1477,13 +1479,16 @@ kvmhv_do_exit: /* r12 = trap, r13 = paca */
1477 * We don't have to lock against tlbies but we do 1479 * We don't have to lock against tlbies but we do
1478 * have to coordinate the hardware threads. 1480 * have to coordinate the hardware threads.
1479 */ 1481 */
1480 /* Increment the threads-exiting-guest count in the 0xff00 1482 /* Set our bit in the threads-exiting-guest map in the 0xff00
1481 bits of vcore->entry_exit_count */ 1483 bits of vcore->entry_exit_map */
1482 ld r5,HSTATE_KVM_VCORE(r13) 1484 ld r5, HSTATE_KVM_VCORE(r13)
1483 addi r6,r5,VCORE_ENTRY_EXIT 1485 lbz r4, HSTATE_PTID(r13)
148441: lwarx r3,0,r6 1486 li r7, 0x100
1485 addi r0,r3,0x100 1487 sld r7, r7, r4
1486 stwcx. r0,0,r6 1488 addi r6, r5, VCORE_ENTRY_EXIT
148941: lwarx r3, 0, r6
1490 or r0, r3, r7
1491 stwcx. r0, 0, r6
1487 bne 41b 1492 bne 41b
1488 isync /* order stwcx. vs. reading napping_threads */ 1493 isync /* order stwcx. vs. reading napping_threads */
1489 1494
@@ -1492,9 +1497,9 @@ kvmhv_do_exit: /* r12 = trap, r13 = paca */
1492 * up to the kernel or qemu; we can't handle it in real mode. 1497 * up to the kernel or qemu; we can't handle it in real mode.
1493 * Thus we have to do a partition switch, so we have to 1498 * Thus we have to do a partition switch, so we have to
1494 * collect the other threads, if we are the first thread 1499 * collect the other threads, if we are the first thread
1495 * to take an interrupt. To do this, we set the HDEC to 0, 1500 * to take an interrupt. To do this, we send a message or
1496 * which causes an HDEC interrupt in all threads within 2ns 1501 * IPI to all the threads that have their bit set in the entry
1497 * because the HDEC register is shared between all 4 threads. 1502 * map in vcore->entry_exit_map (other than ourselves).
1498 * However, we don't need to bother if this is an HDEC 1503 * However, we don't need to bother if this is an HDEC
1499 * interrupt, since the other threads will already be on their 1504 * interrupt, since the other threads will already be on their
1500 * way here in that case. 1505 * way here in that case.
@@ -1503,17 +1508,8 @@ kvmhv_do_exit: /* r12 = trap, r13 = paca */
1503 bge 43f 1508 bge 43f
1504 cmpwi r12,BOOK3S_INTERRUPT_HV_DECREMENTER 1509 cmpwi r12,BOOK3S_INTERRUPT_HV_DECREMENTER
1505 beq 43f 1510 beq 43f
1506 li r0,0
1507 mtspr SPRN_HDEC,r0
1508 1511
1509 /* 1512 srwi r0,r7,8
1510 * Send an IPI to any napping threads, since an HDEC interrupt
1511 * doesn't wake CPUs up from nap.
1512 */
1513 lwz r3,VCORE_NAPPING_THREADS(r5)
1514 lbz r4,HSTATE_PTID(r13)
1515 li r0,1
1516 sld r0,r0,r4
1517 andc. r3,r3,r0 /* no sense IPI'ing ourselves */ 1513 andc. r3,r3,r0 /* no sense IPI'ing ourselves */
1518 beq 43f 1514 beq 43f
1519 /* Order entry/exit update vs. IPIs */ 1515 /* Order entry/exit update vs. IPIs */
@@ -2091,12 +2087,11 @@ _GLOBAL(kvmppc_h_cede) /* r3 = vcpu pointer, r11 = msr, r13 = paca */
2091 addi r6,r5,VCORE_NAPPING_THREADS 2087 addi r6,r5,VCORE_NAPPING_THREADS
209231: lwarx r4,0,r6 208831: lwarx r4,0,r6
2093 or r4,r4,r0 2089 or r4,r4,r0
2094 PPC_POPCNTW(R7,R4) 2090 cmpw r4,r8
2095 cmpw r7,r8 2091 beq kvm_cede_exit
2096 bge kvm_cede_exit
2097 stwcx. r4,0,r6 2092 stwcx. r4,0,r6
2098 bne 31b 2093 bne 31b
2099 /* order napping_threads update vs testing entry_exit_count */ 2094 /* order napping_threads update vs testing entry_exit_map */
2100 isync 2095 isync
2101 li r0,NAPPING_CEDE 2096 li r0,NAPPING_CEDE
2102 stb r0,HSTATE_NAPPING(r13) 2097 stb r0,HSTATE_NAPPING(r13)