diff options
author | Paul Mackerras <paulus@samba.org> | 2015-03-27 23:21:06 -0400 |
---|---|---|
committer | Alexander Graf <agraf@suse.de> | 2015-04-21 09:21:32 -0400 |
commit | 5d5b99cd6818bdbea287d23ef055bba1a8a9e648 (patch) | |
tree | 1696dcf7ad7f1e566611093e18a387711c80aab7 /arch | |
parent | 25fedfca94cfbf2461314c6c34ef58e74a31b025 (diff) |
KVM: PPC: Book3S HV: Get rid of vcore nap_count and n_woken
We can tell when a secondary thread has finished running a guest by
the fact that it clears its kvm_hstate.kvm_vcpu pointer, so there
is no real need for the nap_count field in the kvmppc_vcore struct.
This changes kvmppc_wait_for_nap to poll the kvm_hstate.kvm_vcpu
pointers of the secondary threads rather than polling vc->nap_count.
Besides reducing the size of the kvmppc_vcore struct by 8 bytes,
this also means that we can tell which secondary threads have got
stuck and thus print a more informative error message.
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 | 2 | ||||
-rw-r--r-- | arch/powerpc/kernel/asm-offsets.c | 1 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s_hv.c | 47 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s_hv_rmhandlers.S | 19 |
4 files changed, 34 insertions, 35 deletions
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index 83c44257b005..1517faac9b98 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h | |||
@@ -272,8 +272,6 @@ 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_count; |
275 | int n_woken; | ||
276 | int nap_count; | ||
277 | int napping_threads; | 275 | int napping_threads; |
278 | int first_vcpuid; | 276 | int first_vcpuid; |
279 | u16 pcpu; | 277 | u16 pcpu; |
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 92ec3fcb3415..8aa824681d76 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c | |||
@@ -563,7 +563,6 @@ int main(void) | |||
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_count)); |
566 | DEFINE(VCORE_NAP_COUNT, offsetof(struct kvmppc_vcore, nap_count)); | ||
567 | DEFINE(VCORE_IN_GUEST, offsetof(struct kvmppc_vcore, in_guest)); | 566 | DEFINE(VCORE_IN_GUEST, offsetof(struct kvmppc_vcore, in_guest)); |
568 | DEFINE(VCORE_NAPPING_THREADS, offsetof(struct kvmppc_vcore, napping_threads)); | 567 | DEFINE(VCORE_NAPPING_THREADS, offsetof(struct kvmppc_vcore, napping_threads)); |
569 | 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 fb4f16628a51..7c1335dca4a5 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c | |||
@@ -1729,8 +1729,10 @@ static int kvmppc_grab_hwthread(int cpu) | |||
1729 | tpaca = &paca[cpu]; | 1729 | tpaca = &paca[cpu]; |
1730 | 1730 | ||
1731 | /* Ensure the thread won't go into the kernel if it wakes */ | 1731 | /* Ensure the thread won't go into the kernel if it wakes */ |
1732 | tpaca->kvm_hstate.hwthread_req = 1; | ||
1733 | tpaca->kvm_hstate.kvm_vcpu = NULL; | 1732 | tpaca->kvm_hstate.kvm_vcpu = NULL; |
1733 | tpaca->kvm_hstate.napping = 0; | ||
1734 | smp_wmb(); | ||
1735 | tpaca->kvm_hstate.hwthread_req = 1; | ||
1734 | 1736 | ||
1735 | /* | 1737 | /* |
1736 | * If the thread is already executing in the kernel (e.g. handling | 1738 | * If the thread is already executing in the kernel (e.g. handling |
@@ -1773,35 +1775,43 @@ static void kvmppc_start_thread(struct kvm_vcpu *vcpu) | |||
1773 | } | 1775 | } |
1774 | cpu = vc->pcpu + vcpu->arch.ptid; | 1776 | cpu = vc->pcpu + vcpu->arch.ptid; |
1775 | tpaca = &paca[cpu]; | 1777 | tpaca = &paca[cpu]; |
1776 | tpaca->kvm_hstate.kvm_vcpu = vcpu; | ||
1777 | tpaca->kvm_hstate.kvm_vcore = vc; | 1778 | tpaca->kvm_hstate.kvm_vcore = vc; |
1778 | tpaca->kvm_hstate.ptid = vcpu->arch.ptid; | 1779 | tpaca->kvm_hstate.ptid = vcpu->arch.ptid; |
1779 | vcpu->cpu = vc->pcpu; | 1780 | vcpu->cpu = vc->pcpu; |
1781 | /* Order stores to hstate.kvm_vcore etc. before store to kvm_vcpu */ | ||
1780 | smp_wmb(); | 1782 | smp_wmb(); |
1783 | tpaca->kvm_hstate.kvm_vcpu = vcpu; | ||
1781 | #if defined(CONFIG_PPC_ICP_NATIVE) && defined(CONFIG_SMP) | 1784 | #if defined(CONFIG_PPC_ICP_NATIVE) && defined(CONFIG_SMP) |
1782 | if (cpu != smp_processor_id()) { | 1785 | if (cpu != smp_processor_id()) |
1783 | xics_wake_cpu(cpu); | 1786 | xics_wake_cpu(cpu); |
1784 | if (vcpu->arch.ptid) | ||
1785 | ++vc->n_woken; | ||
1786 | } | ||
1787 | #endif | 1787 | #endif |
1788 | } | 1788 | } |
1789 | 1789 | ||
1790 | static void kvmppc_wait_for_nap(struct kvmppc_vcore *vc) | 1790 | static void kvmppc_wait_for_nap(void) |
1791 | { | 1791 | { |
1792 | int i; | 1792 | int cpu = smp_processor_id(); |
1793 | int i, loops; | ||
1793 | 1794 | ||
1794 | HMT_low(); | 1795 | for (loops = 0; loops < 1000000; ++loops) { |
1795 | i = 0; | 1796 | /* |
1796 | while (vc->nap_count < vc->n_woken) { | 1797 | * Check if all threads are finished. |
1797 | if (++i >= 1000000) { | 1798 | * We set the vcpu pointer when starting a thread |
1798 | pr_err("kvmppc_wait_for_nap timeout %d %d\n", | 1799 | * and the thread clears it when finished, so we look |
1799 | vc->nap_count, vc->n_woken); | 1800 | * for any threads that still have a non-NULL vcpu ptr. |
1800 | break; | 1801 | */ |
1802 | for (i = 1; i < threads_per_subcore; ++i) | ||
1803 | if (paca[cpu + i].kvm_hstate.kvm_vcpu) | ||
1804 | break; | ||
1805 | if (i == threads_per_subcore) { | ||
1806 | HMT_medium(); | ||
1807 | return; | ||
1801 | } | 1808 | } |
1802 | cpu_relax(); | 1809 | HMT_low(); |
1803 | } | 1810 | } |
1804 | HMT_medium(); | 1811 | HMT_medium(); |
1812 | for (i = 1; i < threads_per_subcore; ++i) | ||
1813 | if (paca[cpu + i].kvm_hstate.kvm_vcpu) | ||
1814 | pr_err("KVM: CPU %d seems to be stuck\n", cpu + i); | ||
1805 | } | 1815 | } |
1806 | 1816 | ||
1807 | /* | 1817 | /* |
@@ -1942,8 +1952,6 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc) | |||
1942 | /* | 1952 | /* |
1943 | * Initialize *vc. | 1953 | * Initialize *vc. |
1944 | */ | 1954 | */ |
1945 | vc->n_woken = 0; | ||
1946 | vc->nap_count = 0; | ||
1947 | vc->entry_exit_count = 0; | 1955 | vc->entry_exit_count = 0; |
1948 | vc->preempt_tb = TB_NIL; | 1956 | vc->preempt_tb = TB_NIL; |
1949 | vc->in_guest = 0; | 1957 | vc->in_guest = 0; |
@@ -2002,8 +2010,7 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc) | |||
2002 | list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list) | 2010 | list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list) |
2003 | vcpu->cpu = -1; | 2011 | vcpu->cpu = -1; |
2004 | /* wait for secondary threads to finish writing their state to memory */ | 2012 | /* wait for secondary threads to finish writing their state to memory */ |
2005 | if (vc->nap_count < vc->n_woken) | 2013 | kvmppc_wait_for_nap(); |
2006 | kvmppc_wait_for_nap(vc); | ||
2007 | for (i = 0; i < threads_per_subcore; ++i) | 2014 | for (i = 0; i < threads_per_subcore; ++i) |
2008 | kvmppc_release_hwthread(vc->pcpu + i); | 2015 | kvmppc_release_hwthread(vc->pcpu + i); |
2009 | /* prevent other vcpu threads from doing kvmppc_start_thread() now */ | 2016 | /* prevent other vcpu threads from doing kvmppc_start_thread() now */ |
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index f8267e5b3a50..6716db3f1a2b 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S | |||
@@ -292,26 +292,21 @@ kvm_secondary_got_guest: | |||
292 | ld r6, PACA_DSCR(r13) | 292 | ld r6, PACA_DSCR(r13) |
293 | std r6, HSTATE_DSCR(r13) | 293 | std r6, HSTATE_DSCR(r13) |
294 | 294 | ||
295 | /* Order load of vcore, ptid etc. after load of vcpu */ | ||
296 | lwsync | ||
295 | bl kvmppc_hv_entry | 297 | bl kvmppc_hv_entry |
296 | 298 | ||
297 | /* Back from the guest, go back to nap */ | 299 | /* Back from the guest, go back to nap */ |
298 | /* Clear our vcpu pointer so we don't come back in early */ | 300 | /* Clear our vcpu pointer so we don't come back in early */ |
299 | li r0, 0 | 301 | li r0, 0 |
300 | std r0, HSTATE_KVM_VCPU(r13) | ||
301 | /* | 302 | /* |
302 | * Make sure we clear HSTATE_KVM_VCPU(r13) before incrementing | 303 | * Once we clear HSTATE_KVM_VCPU(r13), the code in |
303 | * the nap_count, because once the increment to nap_count is | 304 | * kvmppc_run_core() is going to assume that all our vcpu |
304 | * visible we could be given another vcpu. | 305 | * state is visible in memory. This lwsync makes sure |
306 | * that that is true. | ||
305 | */ | 307 | */ |
306 | lwsync | 308 | lwsync |
307 | 309 | std r0, HSTATE_KVM_VCPU(r13) | |
308 | /* increment the nap count and then go to nap mode */ | ||
309 | ld r4, HSTATE_KVM_VCORE(r13) | ||
310 | addi r4, r4, VCORE_NAP_COUNT | ||
311 | 51: lwarx r3, 0, r4 | ||
312 | addi r3, r3, 1 | ||
313 | stwcx. r3, 0, r4 | ||
314 | bne 51b | ||
315 | 310 | ||
316 | /* | 311 | /* |
317 | * At this point we have finished executing in the guest. | 312 | * At this point we have finished executing in the guest. |