diff options
author | Paul Mackerras <paulus@samba.org> | 2015-03-27 23:21:09 -0400 |
---|---|---|
committer | Alexander Graf <agraf@suse.de> | 2015-04-21 09:21:33 -0400 |
commit | 7d6c40da198ac18bd5dd2cd18628d5b4c615d842 (patch) | |
tree | 2c2e25ea051d2a569ae8332742fb27f59dff5eb3 /arch | |
parent | fd6d53b12410b4b73e3996629350dee3f4a7994f (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.h | 15 | ||||
-rw-r--r-- | arch/powerpc/kernel/asm-offsets.c | 2 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s_hv.c | 5 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s_hv_builtin.c | 10 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s_hv_rmhandlers.S | 61 |
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 | */ |
271 | struct kvmppc_vcore { | 271 | struct 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 |
412 | 21: 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 | ||
415 | 21: 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) |
1484 | 41: 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 |
1489 | 41: 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 |
2092 | 31: lwarx r4,0,r6 | 2088 | 31: 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) |