KVM: PPC: Book3S HV P9: entry/exit optimisations
Subsystems (3)
Nicholas Piggin
reviewerv4 cover KVM: PPC: Book3S HV P9: entry/exit optimisations
This reduces radix guest full entry/exit latency on POWER9 and POWER10 by 2x.
Nested HV guests should see smaller improvements in their L1 entry/exit, but this is also combined with most L0 speedups also applying to nested entry. nginx localhost throughput test in a SMP nested guest is improved about 10% (in a direct guest it doesn't change much because it uses XIVE for IPIs) when L0 and L1 are patched.
It does this in several main ways:
- Rearrange code to optimise SPR accesses. Mainly, avoid scoreboard stalls.
- Test SPR values to avoid mtSPRs where possible. mtSPRs are expensive.
- Reduce mftb. mftb is expensive.
- Demand fault certain facilities to avoid saving and/or restoring them (at the cost of fault when they are used, but this is mitigated over a number of entries, like the facilities when context switching processes). PM, TM, and EBB so far.
- Defer some sequences that are made just in case a guest is interrupted in the middle of a critical section to the case where the guest is scheduled on a different CPU, rather than every time (at the cost of an extra IPI in this case). Namely the tlbsync sequence for radix with GTSE, which is very expensive.
- Reduce locking, barriers, atomics related to the vcpus-per-vcore > 1 handling that the P9 path does not require.
Changes since v3:
- Fix a possible bug in "Avoid tlbsync sequence on radix guest exit" where the TLB flushing optimisation (1 thread TLBIEL flushes TLB for entire core) might break because 'ptesync' was no longer guaranteed to be executed on all threads (via regular exit path). Now the TLB flush keeps track of all threads and whether they need to do a TLBIEL or a PTESYNC. Fixing this requires a new patch "Split P8 from P9 path guest vCPU TLB flushing".
Changes since v2:
- Rebased, several patches from the series were merged in the previous merge window.
- Fixed some compile errors noticed by kernel test robot.
- Added RB from Athira for the PMU stuff (thanks!)
- Split TIDR ftr check (patch 2) out into its own patch.
- Added a missed license tag on new file.
Changes since v1:
- Verified DPDES changes still work with msgsndp SMT emulation.
- Fixed HMI handling bug.
- Split softpatch handling fixes into smaller pieces.
- Rebased with Fabiano's latest HV sanitising patches.
- Fix TM demand faulting bug causing nested guest TM tests to TM Bad Thing the host in rare cases.
- Re-name new "pmu=" command line option to "pmu_override=" and update documentation wording.
- Add default=y config option rather than unconditionally removing the L0 nested PMU workaround.
- Remove unnecessary MSR[RI] updates in entry/exit. Down to about 4700 cycles now.
- Another bugfix from Alexey's testing.
Changes since RFC:
- Rebased with Fabiano's HV sanitising patches at the front.
- Several demand faulting bug fixes mostly relating to nested guests.
- Removed facility demand-faulting from L0 nested entry/exit handler. Demand faulting is still done in the L1, but not the L0. The reason is to reduce complexity (although it's only a small amount of complexity), reduce demand faulting overhead that may require several
Thanks,
Nick
Nicholas Piggin (53):
powerpc/64s: Remove WORT SPR from POWER9/10 (take 2) powerpc/64s: guard optional TIDR SPR with CPU ftr test
KMV: PPC: Book3S HV P9: Use set_dec to set decrementer to host
KVM: PPC: Book3S HV P9: Use host timer accounting to avoid decrementer
read
KVM: PPC: Book3S HV P9: Use large decrementer for HDEC
KVM: PPC: Book3S HV P9: Reduce mftb per guest entry/exit powerpc/time: add API for KVM to re-arm the host timer/decrementer
KVM: PPC: Book3S HV: POWER10 enable HAIL when running radix guests powerpc/64s: Keep AMOR SPR a constant ~0 at runtime
KVM: PPC: Book3S HV: Don't always save PMU for guest capable of
nesting
powerpc/64s: Always set PMU control registers to frozen/disabled when
not in use
powerpc/64s: Implement PMU override command line option
KVM: PPC: Book3S HV P9: Implement PMU save/restore in C
KVM: PPC: Book3S HV P9: Factor PMU save/load into context switch
functions
KVM: PPC: Book3S HV P9: Demand fault PMU SPRs when marked not inuse
KVM: PPC: Book3S HV P9: Factor out yield_count increment
KVM: PPC: Book3S HV: CTRL SPR does not require read-modify-write
KVM: PPC: Book3S HV P9: Move SPRG restore to restore_p9_host_os_sprs
KVM: PPC: Book3S HV P9: Reduce mtmsrd instructions required to save
host SPRs
KVM: PPC: Book3S HV P9: Improve mtmsrd scheduling by delaying MSR[EE]
disable
KVM: PPC: Book3S HV P9: Add kvmppc_stop_thread to match
kvmppc_start_thread
KVM: PPC: Book3S HV: Change dec_expires to be relative to guest
timebase
KVM: PPC: Book3S HV P9: Move TB updates
KVM: PPC: Book3S HV P9: Optimise timebase reads
KVM: PPC: Book3S HV P9: Avoid SPR scoreboard stalls
KVM: PPC: Book3S HV P9: Only execute mtSPR if the value changed
KVM: PPC: Book3S HV P9: Juggle SPR switching around
KVM: PPC: Book3S HV P9: Move vcpu register save/restore into functions
KVM: PPC: Book3S HV P9: Move host OS save/restore functions to
built-in
KVM: PPC: Book3S HV P9: Move nested guest entry into its own function
KVM: PPC: Book3S HV P9: Move remaining SPR and MSR access into low
level entry
KVM: PPC: Book3S HV P9: Implement TM fastpath for guest entry/exit
KVM: PPC: Book3S HV P9: Switch PMU to guest as late as possible
KVM: PPC: Book3S HV P9: Restrict DSISR canary workaround to processors
that require it
KVM: PPC: Book3S HV P9: More SPR speed improvements
KVM: PPC: Book3S HV P9: Demand fault EBB facility registers
KVM: PPC: Book3S HV P9: Demand fault TM facility registers
KVM: PPC: Book3S HV P9: Use Linux SPR save/restore to manage some host
SPRs
KVM: PPC: Book3S HV P9: Comment and fix MMU context switching code
KVM: PPC: Book3S HV P9: Test dawr_enabled() before saving host DAWR
SPRs
KVM: PPC: Book3S HV P9: Don't restore PSSCR if not needed
KVM: PPC: Book3S HV: Split P8 from P9 path guest vCPU TLB flushing
KVM: PPC: Book3S HV P9: Avoid tlbsync sequence on radix guest exit
KVM: PPC: Book3S HV Nested: Avoid extra mftb() in nested entry
KVM: PPC: Book3S HV P9: Improve mfmsr performance on entry
KVM: PPC: Book3S HV P9: Optimise hash guest SLB saving
KVM: PPC: Book3S HV P9: Avoid changing MSR[RI] in entry and exit
KVM: PPC: Book3S HV P9: Add unlikely annotation for !mmu_ready
KVM: PPC: Book3S HV P9: Avoid cpu_in_guest atomics on entry and exit
KVM: PPC: Book3S HV P9: Remove most of the vcore logic
KVM: PPC: Book3S HV P9: Tidy kvmppc_create_dtl_entry
KVM: PPC: Book3S HV P9: Stop using vc->dpdes
KVM: PPC: Book3S HV P9: Remove subcore HMI handling
.../admin-guide/kernel-parameters.txt | 8 + arch/powerpc/include/asm/asm-prototypes.h | 5 - arch/powerpc/include/asm/kvm_asm.h | 1 + arch/powerpc/include/asm/kvm_book3s.h | 6 + arch/powerpc/include/asm/kvm_book3s_64.h | 5 +- arch/powerpc/include/asm/kvm_host.h | 7 +- arch/powerpc/include/asm/kvm_ppc.h | 4 +- arch/powerpc/include/asm/switch_to.h | 3 + arch/powerpc/include/asm/time.h | 19 +- arch/powerpc/kernel/cpu_setup_power.c | 12 +- arch/powerpc/kernel/dt_cpu_ftrs.c | 8 +- arch/powerpc/kernel/process.c | 34 + arch/powerpc/kernel/time.c | 54 +- arch/powerpc/kvm/Kconfig | 15 + arch/powerpc/kvm/book3s_64_entry.S | 11 +- arch/powerpc/kvm/book3s_64_mmu_radix.c | 4 + arch/powerpc/kvm/book3s_hv.c | 851 +++++++++-------- arch/powerpc/kvm/book3s_hv.h | 42 + arch/powerpc/kvm/book3s_hv_builtin.c | 55 +- arch/powerpc/kvm/book3s_hv_hmi.c | 7 +- arch/powerpc/kvm/book3s_hv_interrupts.S | 13 +- arch/powerpc/kvm/book3s_hv_nested.c | 8 +- arch/powerpc/kvm/book3s_hv_p9_entry.c | 898 +++++++++++++++--- arch/powerpc/kvm/book3s_hv_ras.c | 54 ++ arch/powerpc/kvm/book3s_hv_rm_mmu.c | 6 - arch/powerpc/kvm/book3s_hv_rmhandlers.S | 73 +- arch/powerpc/mm/book3s64/radix_pgtable.c | 15 - arch/powerpc/perf/core-book3s.c | 35 + arch/powerpc/platforms/powernv/idle.c | 9 +- arch/powerpc/xmon/xmon.c | 10 +- 30 files changed, 1555 insertions(+), 717 deletions(-) create mode 100644 arch/powerpc/kvm/book3s_hv.h
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 1/53 powerpc/64s: Remove WORT SPR from POWER9/10 (take 2)
This removes a missed remnant of the WORT SPR.
--- arch/powerpc/platforms/powernv/idle.c | 1 - 1 file changed, 1 deletion(-)
arch/powerpc/platforms/powernv/idle.c +0 -1
@@ -589,7 +589,6 @@ struct p9_sprs {u64 purr;u64 spurr;u64 dscr; -u64 wort;u64 ciabr;u64 mmcra;
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 2/53 powerpc/64s: guard optional TIDR SPR with CPU ftr test
In reply to Nicholas PigginThe TIDR SPR only exists on POWER9. Avoid accessing it when the feature bit for it is not set.
--- arch/powerpc/kvm/book3s_hv.c | 12 ++++++++---- arch/powerpc/xmon/xmon.c | 10 ++++++++-- 2 files changed, 16 insertions(+), 6 deletions(-)
arch/powerpc/kvm/book3s_hv.c +8 -4
@@ -3780,7 +3780,8 @@ static void load_spr_state(struct kvm_vcpu *vcpu)mtspr (SPRN_EBBHR , vcpu->arch.ebbhr);mtspr (SPRN_EBBRR , vcpu->arch.ebbrr);mtspr (SPRN_BESCR , vcpu->arch.bescr); -mtspr (SPRN_TIDR , vcpu->arch.tid); +if (cpu_has_feature (CPU_FTR_P9_TIDR )) +mtspr (SPRN_TIDR , vcpu->arch.tid);mtspr (SPRN_AMR , vcpu->arch.amr);mtspr (SPRN_UAMOR , vcpu->arch.uamor);
@@ -3806,7 +3807,8 @@ static void store_spr_state(struct kvm_vcpu *vcpu) vcpu->arch.ebbhr =mfspr (SPRN_EBBHR ); vcpu->arch.ebbrr =mfspr (SPRN_EBBRR ); vcpu->arch.bescr =mfspr (SPRN_BESCR ); - vcpu->arch.tid =mfspr (SPRN_TIDR ); +if (cpu_has_feature (CPU_FTR_P9_TIDR )) + vcpu->arch.tid =mfspr (SPRN_TIDR ); vcpu->arch.amr =mfspr (SPRN_AMR ); vcpu->arch.uamor =mfspr (SPRN_UAMOR ); vcpu->arch.dscr =mfspr (SPRN_DSCR );
@@ -3826,7 +3828,8 @@ struct p9_host_os_sprs {static void save_p9_host_os_sprs (struct p9_host_os_sprs *host_os_sprs) { host_os_sprs->dscr =mfspr (SPRN_DSCR ); - host_os_sprs->tidr =mfspr (SPRN_TIDR ); +if (cpu_has_feature (CPU_FTR_P9_TIDR )) + host_os_sprs->tidr =mfspr (SPRN_TIDR ); host_os_sprs->iamr =mfspr (SPRN_IAMR ); host_os_sprs->amr =mfspr (SPRN_AMR ); host_os_sprs->fscr =mfspr (SPRN_FSCR );
@@ -3840,7 +3843,8 @@ static void restore_p9_host_os_sprs(struct kvm_vcpu *vcpu,mtspr (SPRN_UAMOR ,0 );mtspr (SPRN_DSCR , host_os_sprs->dscr); -mtspr (SPRN_TIDR , host_os_sprs->tidr); +if (cpu_has_feature (CPU_FTR_P9_TIDR )) +mtspr (SPRN_TIDR , host_os_sprs->tidr);mtspr (SPRN_IAMR , host_os_sprs->iamr);if (host_os_sprs->amr != vcpu->arch.amr)
arch/powerpc/xmon/xmon.c +8 -2
@@ -2107,8 +2107,14 @@ static void dump_300_sprs(void)if (!cpu_has_feature (CPU_FTR_ARCH_300 ))return ; -printf ("pidr = %.16lx tidr = %.16lx\n" , -mfspr (SPRN_PID ),mfspr (SPRN_TIDR )); +if (cpu_has_feature (CPU_FTR_P9_TIDR )) { +printf ("pidr = %.16lx tidr = %.16lx\n" , +mfspr (SPRN_PID ),mfspr (SPRN_TIDR )); + }else { +printf ("pidr = %.16lx\n" , +mfspr (SPRN_PID )); + } +printf ("psscr = %.16lx\n" , hv ?mfspr (SPRN_PSSCR ) :mfspr (SPRN_PSSCR_PR ));
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 3/53 KMV: PPC: Book3S HV P9: Use set_dec to set decrementer to host
In reply to Nicholas PigginThe host Linux timer code arms the decrementer with the value 'decrementers_next_tb - current_tb' using set_dec(), which stores val - 1 on Book3S-64, which is not quite the same as what KVM does to re-arm the host decrementer when exiting the guest.
This shouldn't be a significant change, but it makes the logic match and avoids this small extra change being brought into the next patch.
--- arch/powerpc/kvm/book3s_hv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/powerpc/kvm/book3s_hv.c +1 -1
@@ -4063,7 +4063,7 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, vc->entry_exit_map =0x101 ; vc->in_guest =0 ; -mtspr (SPRN_DEC , local_paca->kvm_hstate.dec_expires -mftb ()); +set_dec (local_paca->kvm_hstate.dec_expires -mftb ());/* We may have raced with new irq work */ if (test_irq_work_pending ())set_dec (1 );
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 4/53 KVM: PPC: Book3S HV P9: Use host timer accounting to avoid decrementer read
In reply to Nicholas PigginThere is no need to save away the host DEC value, as it is derived from the host timer subsystem which maintains the next timer time, so it can be restored from there.
--- arch/powerpc/include/asm/time.h | 5 +++++ arch/powerpc/kernel/time.c | 1 + arch/powerpc/kvm/book3s_hv.c | 14 +++++++------- 3 files changed, 13 insertions(+), 7 deletions(-)
arch/powerpc/include/asm/time.h +5 -0
@@ -111,6 +111,11 @@ static inline unsigned long test_irq_work_pending(void)DECLARE_PER_CPU (u64, decrementers_next_tb); +static inline u64 timer_get_next_tb (void ) +{ +return __this_cpu_read (decrementers_next_tb); +} +/* Convert timebase ticks to nanoseconds */ unsigned long long tb_to_ns (unsigned long long tb_ticks);
arch/powerpc/kernel/time.c +1 -0
@@ -107,6 +107,7 @@ struct clock_event_device decrementer_clockevent = {EXPORT_SYMBOL (decrementer_clockevent);DEFINE_PER_CPU (u64, decrementers_next_tb); +EXPORT_SYMBOL_GPL (decrementers_next_tb); static DEFINE_PER_CPU(struct clock_event_device, decrementers);#define XSEC_PER_SEC (1024*1024)
arch/powerpc/kvm/book3s_hv.c +7 -7
@@ -3873,18 +3873,17 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,struct kvmppc_vcore *vc = vcpu->arch.vcore;struct p9_host_os_sprs host_os_sprs;s64 dec; -u64 tb; +u64 tb, next_timer;int trap, save_pmu;WARN_ON_ONCE (vcpu->arch.ceded); - dec =mfspr (SPRN_DEC ); tb =mftb (); -if (dec <0 ) + next_timer =timer_get_next_tb (); +if (tb >= next_timer)return BOOK3S_INTERRUPT_HV_DECREMENTER ; - local_paca->kvm_hstate.dec_expires = dec + tb; -if (local_paca->kvm_hstate.dec_expires < time_limit) - time_limit = local_paca->kvm_hstate.dec_expires; +if (next_timer < time_limit) + time_limit = next_timer;save_p9_host_os_sprs (&host_os_sprs);
@@ -4063,7 +4062,8 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, vc->entry_exit_map =0x101 ; vc->in_guest =0 ; -set_dec (local_paca->kvm_hstate.dec_expires -mftb ()); + next_timer =timer_get_next_tb (); +set_dec (next_timer -mftb ());/* We may have raced with new irq work */ if (test_irq_work_pending ())set_dec (1 );
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 5/53 KVM: PPC: Book3S HV P9: Use large decrementer for HDEC
In reply to Nicholas PigginOn processors that don't suppress the HDEC exceptions when LPCR[HDICE]=0, this could help reduce needless guest exits due to leftover exceptions on entering the guest.
--- arch/powerpc/include/asm/time.h | 2 ++ arch/powerpc/kernel/time.c | 1 + arch/powerpc/kvm/book3s_hv_p9_entry.c | 3 ++- 3 files changed, 5 insertions(+), 1 deletion(-)
arch/powerpc/include/asm/time.h +2 -0
@@ -18,6 +18,8 @@#include <asm/vdso/timebase.h> /* time.c */ +extern u64 decrementer_max; +extern unsigned long tb_ticks_per_jiffy;extern unsigned long tb_ticks_per_usec;extern unsigned long tb_ticks_per_sec;
arch/powerpc/kernel/time.c +1 -0
@@ -88,6 +88,7 @@ static struct clocksource clocksource_timebase = {#define DECREMENTER_DEFAULT_MAX 0x7FFFFFFFu64 decrementer_max =DECREMENTER_DEFAULT_MAX ; +EXPORT_SYMBOL_GPL (decrementer_max);/* for KVM HDEC */ static int decrementer_set_next_event (unsigned long evt,struct clock_event_device *dev);
arch/powerpc/kvm/book3s_hv_p9_entry.c +2 -1
@@ -504,7 +504,8 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc vc->tb_offset_applied =0 ; } -mtspr (SPRN_HDEC ,0x7fffffff ); +/* HDEC must be at least as large as DEC, so decrementer_max fits */ +mtspr (SPRN_HDEC , decrementer_max);save_clear_guest_mmu (kvm, vcpu);switch_mmu_to_host (kvm, host_pidr);
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 6/53 KVM: PPC: Book3S HV P9: Reduce mftb per guest entry/exit
In reply to Nicholas Pigginmftb is serialising (dispatch next-to-complete) so it is heavy weight for a mfspr. Avoid reading it multiple times in the entry or exit paths. A small number of cycles delay to timers is tolerable.
--- arch/powerpc/kvm/book3s_hv.c | 4 ++-- arch/powerpc/kvm/book3s_hv_p9_entry.c | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-)
arch/powerpc/kvm/book3s_hv.c +2 -2
@@ -3940,7 +3940,7 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,* * XXX: Another day's problem. */ -mtspr (SPRN_DEC , vcpu->arch.dec_expires -mftb ()); +mtspr (SPRN_DEC , vcpu->arch.dec_expires - tb);if (kvmhv_on_pseries ()) {/*
@@ -4063,7 +4063,7 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, vc->in_guest =0 ; next_timer =timer_get_next_tb (); -set_dec (next_timer -mftb ()); +set_dec (next_timer - tb);/* We may have raced with new irq work */ if (test_irq_work_pending ())set_dec (1 );
arch/powerpc/kvm/book3s_hv_p9_entry.c +3 -2
@@ -203,7 +203,8 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcunsigned long host_dawr1;unsigned long host_dawrx1; - hdec = time_limit -mftb (); + tb =mftb (); + hdec = time_limit - tb;if (hdec <0 )return BOOK3S_INTERRUPT_HV_DECREMENTER ;
@@ -215,7 +216,7 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc vcpu->arch.ceded =0 ;if (vc->tb_offset) { -u64 new_tb =mftb () + vc->tb_offset; +u64 new_tb = tb + vc->tb_offset;mtspr (SPRN_TBU40 , new_tb); tb =mftb ();if ((tb &0xffffff ) < (new_tb &0xffffff ))
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 7/53 powerpc/time: add API for KVM to re-arm the host timer/decrementer
In reply to Nicholas PigginRather than have KVM look up the host timer and fiddle with the irq-work internal details, have the powerpc/time.c code provide a function for KVM to re-arm the Linux timer code when exiting a guest.
This is implementation has an improvement over existing code of marking a decrementer interrupt as soft-pending if a timer has expired, rather than setting DEC to a -ve value, which tended to cause host timers to take two interrupts (first hdec to exit the guest, then the immediate dec).
--- arch/powerpc/include/asm/time.h | 16 +++------- arch/powerpc/kernel/time.c | 52 +++++++++++++++++++++++++++------ arch/powerpc/kvm/book3s_hv.c | 7 ++--- 3 files changed, 49 insertions(+), 26 deletions(-)
arch/powerpc/include/asm/time.h +4 -12
@@ -99,18 +99,6 @@ extern void div128_by_32(u64 dividend_high, u64 dividend_low,extern void secondary_cpu_time_init (void );extern void __init time_init (void ); -#ifdef CONFIG_PPC64 -static inline unsigned long test_irq_work_pending (void ) -{ -unsigned long x; - - asmvolatile ("lbz %0,%1(13)" - :"=r" (x) - :"i" (offsetof(struct paca_struct , irq_work_pending))); -return x; -} -#endif -DECLARE_PER_CPU (u64, decrementers_next_tb);static inline u64 timer_get_next_tb (void )
@@ -118,6 +106,10 @@ static inline u64 timer_get_next_tb(void)return __this_cpu_read (decrementers_next_tb); } +#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE +void timer_rearm_host_dec (u64 now); +#endif +/* Convert timebase ticks to nanoseconds */ unsigned long long tb_to_ns (unsigned long long tb_ticks);
arch/powerpc/kernel/time.c +43 -9
83 lines not on this page · raw message
arch/powerpc/kvm/book3s_hv.c +2 -5
@@ -4062,11 +4062,8 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, vc->entry_exit_map =0x101 ; vc->in_guest =0 ; - next_timer =timer_get_next_tb (); -set_dec (next_timer - tb); -/* We may have raced with new irq work */ -if (test_irq_work_pending ()) -set_dec (1 ); +timer_rearm_host_dec (tb); +mtspr (SPRN_SPRG_VDSO_WRITE , local_paca->sprg_vdso);kvmhv_load_host_pmu ();
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 8/53 KVM: PPC: Book3S HV: POWER10 enable HAIL when running radix guests
In reply to Nicholas PigginHV interrupts may be taken with the MMU enabled when radix guests are running. Enable LPCR[HAIL] on ISA v3.1 processors for radix guests. Make this depend on the host LPCR[HAIL] being enabled. Currently that is always enabled, but having this test means any issue that might require LPCR[HAIL] to be disabled in the host will not have to be duplicated in KVM.
This optimisation takes 1380 cycles off a NULL hcall entry+exit micro benchmark on a POWER10.
--- arch/powerpc/kvm/book3s_hv.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-)
arch/powerpc/kvm/book3s_hv.c +25 -4
@@ -5073,6 +5073,8 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu)*/ int kvmppc_switch_mmu_to_hpt (struct kvm *kvm) { +unsigned long lpcr, lpcr_mask; +if (nesting_enabled (kvm))kvmhv_release_all_nested (kvm);kvmppc_rmap_reset (kvm);
@@ -5082,8 +5084,13 @@ int kvmppc_switch_mmu_to_hpt(struct kvm *kvm) kvm->arch.radix =0 ;spin_unlock (&kvm->mmu_lock);kvmppc_free_radix (kvm); -kvmppc_update_lpcr (kvm,LPCR_VPM1 , -LPCR_VPM1 |LPCR_UPRT |LPCR_GTSE |LPCR_HR ); + + lpcr =LPCR_VPM1 ; + lpcr_mask =LPCR_VPM1 |LPCR_UPRT |LPCR_GTSE |LPCR_HR ; +if (cpu_has_feature (CPU_FTR_ARCH_31 )) + lpcr_mask |=LPCR_HAIL ; +kvmppc_update_lpcr (kvm, lpcr, lpcr_mask); +return 0 ; }
@@ -5093,6 +5100,7 @@ int kvmppc_switch_mmu_to_hpt(struct kvm *kvm)*/ int kvmppc_switch_mmu_to_radix (struct kvm *kvm) { +unsigned long lpcr, lpcr_mask;int err; err =kvmppc_init_vm_radix (kvm);
@@ -5104,8 +5112,17 @@ int kvmppc_switch_mmu_to_radix(struct kvm *kvm) kvm->arch.radix =1 ;spin_unlock (&kvm->mmu_lock);kvmppc_free_hpt (&kvm->arch.hpt); -kvmppc_update_lpcr (kvm,LPCR_UPRT |LPCR_GTSE |LPCR_HR , -LPCR_VPM1 |LPCR_UPRT |LPCR_GTSE |LPCR_HR ); + + lpcr =LPCR_UPRT |LPCR_GTSE |LPCR_HR ; + lpcr_mask =LPCR_VPM1 |LPCR_UPRT |LPCR_GTSE |LPCR_HR ; +if (cpu_has_feature (CPU_FTR_ARCH_31 )) { + lpcr_mask |=LPCR_HAIL ; +if (cpu_has_feature (CPU_FTR_HVMODE ) && + (kvm->arch.host_lpcr &LPCR_HAIL )) + lpcr |=LPCR_HAIL ; + } +kvmppc_update_lpcr (kvm, lpcr, lpcr_mask); +return 0 ; }
@@ -5269,6 +5286,10 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm) kvm->arch.mmu_ready =1 ; lpcr &= ~LPCR_VPM1 ; lpcr |=LPCR_UPRT |LPCR_GTSE |LPCR_HR ; +if (cpu_has_feature (CPU_FTR_HVMODE ) && +cpu_has_feature (CPU_FTR_ARCH_31 ) && + (kvm->arch.host_lpcr &LPCR_HAIL )) + lpcr |=LPCR_HAIL ; ret =kvmppc_init_vm_radix (kvm);if (ret) {kvmppc_free_lpid (kvm->arch.lpid);
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 9/53 powerpc/64s: Keep AMOR SPR a constant ~0 at runtime
In reply to Nicholas PigginThis register controls supervisor SPR modifications, and as such is only relevant for KVM. KVM always sets AMOR to ~0 on guest entry, and never restores it coming back out to the host, so it can be kept constant and avoid the mtSPR in KVM guest entry.
--- arch/powerpc/kernel/cpu_setup_power.c | 8 ++++++++ arch/powerpc/kernel/dt_cpu_ftrs.c | 2 ++ arch/powerpc/kvm/book3s_hv_p9_entry.c | 2 -- arch/powerpc/kvm/book3s_hv_rmhandlers.S | 2 -- arch/powerpc/mm/book3s64/radix_pgtable.c | 15 --------------- arch/powerpc/platforms/powernv/idle.c | 8 +++----- 6 files changed, 13 insertions(+), 24 deletions(-)
arch/powerpc/kernel/cpu_setup_power.c +8 -0
@@ -137,6 +137,7 @@ void __setup_cpu_power7(unsigned long offset, struct cpu_spec *t)return ;mtspr (SPRN_LPID ,0 ); +mtspr (SPRN_AMOR , ~0 );mtspr (SPRN_PCR ,PCR_MASK );init_LPCR_ISA206 (mfspr (SPRN_LPCR ),LPCR_LPES1 >>LPCR_LPES_SH ); }
@@ -150,6 +151,7 @@ void __restore_cpu_power7(void)return ;mtspr (SPRN_LPID ,0 ); +mtspr (SPRN_AMOR , ~0 );mtspr (SPRN_PCR ,PCR_MASK );init_LPCR_ISA206 (mfspr (SPRN_LPCR ),LPCR_LPES1 >>LPCR_LPES_SH ); }
@@ -164,6 +166,7 @@ void __setup_cpu_power8(unsigned long offset, struct cpu_spec *t)return ;mtspr (SPRN_LPID ,0 ); +mtspr (SPRN_AMOR , ~0 );mtspr (SPRN_PCR ,PCR_MASK );init_LPCR_ISA206 (mfspr (SPRN_LPCR ) |LPCR_PECEDH ,0 );/* LPES = 0 */ init_HFSCR ();
@@ -184,6 +187,7 @@ void __restore_cpu_power8(void)return ;mtspr (SPRN_LPID ,0 ); +mtspr (SPRN_AMOR , ~0 );mtspr (SPRN_PCR ,PCR_MASK );init_LPCR_ISA206 (mfspr (SPRN_LPCR ) |LPCR_PECEDH ,0 );/* LPES = 0 */ init_HFSCR ();
@@ -202,6 +206,7 @@ void __setup_cpu_power9(unsigned long offset, struct cpu_spec *t)mtspr (SPRN_PSSCR ,0 );mtspr (SPRN_LPID ,0 );mtspr (SPRN_PID ,0 ); +mtspr (SPRN_AMOR , ~0 );mtspr (SPRN_PCR ,PCR_MASK );init_LPCR_ISA300 ((mfspr (SPRN_LPCR ) |LPCR_PECEDH |LPCR_PECE_HVEE |\LPCR_HVICE |LPCR_HEIC ) & ~(LPCR_UPRT |LPCR_HR ),0 );
@@ -223,6 +228,7 @@ void __restore_cpu_power9(void)mtspr (SPRN_PSSCR ,0 );mtspr (SPRN_LPID ,0 );mtspr (SPRN_PID ,0 ); +mtspr (SPRN_AMOR , ~0 );mtspr (SPRN_PCR ,PCR_MASK );init_LPCR_ISA300 ((mfspr (SPRN_LPCR ) |LPCR_PECEDH |LPCR_PECE_HVEE |\LPCR_HVICE |LPCR_HEIC ) & ~(LPCR_UPRT |LPCR_HR ),0 );
@@ -242,6 +248,7 @@ void __setup_cpu_power10(unsigned long offset, struct cpu_spec *t)mtspr (SPRN_PSSCR ,0 );mtspr (SPRN_LPID ,0 );mtspr (SPRN_PID ,0 ); +mtspr (SPRN_AMOR , ~0 );mtspr (SPRN_PCR ,PCR_MASK );init_LPCR_ISA300 ((mfspr (SPRN_LPCR ) |LPCR_PECEDH |LPCR_PECE_HVEE |\LPCR_HVICE |LPCR_HEIC ) & ~(LPCR_UPRT |LPCR_HR ),0 );
@@ -264,6 +271,7 @@ void __restore_cpu_power10(void)mtspr (SPRN_PSSCR ,0 );mtspr (SPRN_LPID ,0 );mtspr (SPRN_PID ,0 ); +mtspr (SPRN_AMOR , ~0 );mtspr (SPRN_PCR ,PCR_MASK );init_LPCR_ISA300 ((mfspr (SPRN_LPCR ) |LPCR_PECEDH |LPCR_PECE_HVEE |\LPCR_HVICE |LPCR_HEIC ) & ~(LPCR_UPRT |LPCR_HR ),0 );
arch/powerpc/kernel/dt_cpu_ftrs.c +2 -0
@@ -80,6 +80,7 @@ static void __restore_cpu_cpufeatures(void)mtspr (SPRN_LPCR , system_registers.lpcr);if (hv_mode) {mtspr (SPRN_LPID ,0 ); +mtspr (SPRN_AMOR , ~0 );mtspr (SPRN_HFSCR , system_registers.hfscr);mtspr (SPRN_PCR , system_registers.pcr); }
@@ -216,6 +217,7 @@ static int __init feat_enable_hv(struct dt_cpu_feature *f) }mtspr (SPRN_LPID ,0 ); +mtspr (SPRN_AMOR , ~0 ); lpcr =mfspr (SPRN_LPCR ); lpcr &= ~LPCR_LPES0 ;/* HV external interrupts */
arch/powerpc/kvm/book3s_hv_p9_entry.c +0 -2
@@ -286,8 +286,6 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcmtspr (SPRN_SPRG2 , vcpu->arch.shregs.sprg2);mtspr (SPRN_SPRG3 , vcpu->arch.shregs.sprg3); -mtspr (SPRN_AMOR , ~0UL ); - local_paca->kvm_hstate.in_guest =KVM_GUEST_MODE_HV_P9 ;/*
arch/powerpc/kvm/book3s_hv_rmhandlers.S +0 -2
@@ -778,10 +778,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S) /* Restore AMR and UAMOR, set AMOR to all 1s */ ld r5,VCPU_AMR(r4) ld r6,VCPU_UAMOR(r4) - li r7,-1 mtspr SPRN_AMR,r5 mtspr SPRN_UAMOR,r6 - mtspr SPRN_AMOR,r7 /* Restore state of CTRL run bit; assume 1 on entry */ lwz r5,VCPU_CTRL(r4)
arch/powerpc/mm/book3s64/radix_pgtable.c +0 -15
@@ -572,18 +572,6 @@ void __init radix__early_init_devtree(void)return ; } -static void radix_init_amor (void ) -{ -/* -* In HV mode, we init AMOR (Authority Mask Override Register) so that -* the hypervisor and guest can setup IAMR (Instruction Authority Mask -* Register), enable key 0 and set it to 1. -* -* AMOR = 0b1100 .... 0000 (Mask for key 0 is 11) -*/ -mtspr (SPRN_AMOR , (3ul <<62 )); -} -void __init radix__early_init_mmu (void ) {unsigned long lpcr;
@@ -644,7 +632,6 @@ void __init radix__early_init_mmu(void) lpcr =mfspr (SPRN_LPCR );mtspr (SPRN_LPCR , lpcr |LPCR_UPRT |LPCR_HR );radix_init_partition_table (); -radix_init_amor (); }else {radix_init_pseries (); }
@@ -668,8 +655,6 @@ void radix__early_init_mmu_secondary(void)set_ptcr_when_no_uv (__pa (partition_tb) | (PATB_SIZE_SHIFT -12 )); - -radix_init_amor (); }radix__switch_mmu_context (NULL , &init_mm);
arch/powerpc/platforms/powernv/idle.c +3 -5
@@ -306,8 +306,8 @@ struct p7_sprs {/* per thread SPRs that get lost in shallow states */ u64 amr;u64 iamr; -u64 amor;u64 uamor; +/* amor is restored to constant ~0 */ };static unsigned long power7_idle_insn (unsigned long type)
@@ -378,7 +378,6 @@ static unsigned long power7_idle_insn(unsigned long type)if (cpu_has_feature (CPU_FTR_ARCH_207S )) { sprs.amr =mfspr (SPRN_AMR ); sprs.iamr =mfspr (SPRN_IAMR ); - sprs.amor =mfspr (SPRN_AMOR ); sprs.uamor =mfspr (SPRN_UAMOR ); }
@@ -397,7 +396,7 @@ static unsigned long power7_idle_insn(unsigned long type)*/ mtspr (SPRN_AMR , sprs.amr);mtspr (SPRN_IAMR , sprs.iamr); -mtspr (SPRN_AMOR , sprs.amor); +mtspr (SPRN_AMOR , ~0 );mtspr (SPRN_UAMOR , sprs.uamor); } }
@@ -686,7 +685,6 @@ static unsigned long power9_idle_stop(unsigned long psscr) sprs.amr =mfspr (SPRN_AMR ); sprs.iamr =mfspr (SPRN_IAMR ); - sprs.amor =mfspr (SPRN_AMOR ); sprs.uamor =mfspr (SPRN_UAMOR ); srr1 =isa300_idle_stop_mayloss (psscr);/* go idle */
@@ -707,7 +705,7 @@ static unsigned long power9_idle_stop(unsigned long psscr)*/ mtspr (SPRN_AMR , sprs.amr);mtspr (SPRN_IAMR , sprs.iamr); -mtspr (SPRN_AMOR , sprs.amor); +mtspr (SPRN_AMOR , ~0 );mtspr (SPRN_UAMOR , sprs.uamor);/*
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 10/53 KVM: PPC: Book3S HV: Don't always save PMU for guest capable of nesting
In reply to Nicholas PigginProvide a config option that controls the workaround added by commit 63279eeb7f93 ("KVM: PPC: Book3S HV: Always save guest pmu for guest capable of nesting"). The option defaults to y for now, but is expected to go away within a few releases.
Nested capable guests running with the earlier commit 178266389794 ("KVM: PPC: Book3S HV Nested: Reflect guest PMU in-use to L0 when guest SPRs are live") will now indicate the PMU in-use status of their guests, which means the parent does not need to unconditionally save the PMU for nested capable guests.
After this latest round of performance optimisations, this option costs about 540 cycles or 10% entry/exit performance on a POWER9 nested-capable guest.
References: 178266389794 ("KVM: PPC: Book3S HV Nested: Reflect guest PMU in-use to L0 when guest SPRs are live")
--- arch/powerpc/kvm/Kconfig | 15 +++++++++++++++ arch/powerpc/kvm/book3s_hv.c | 10 ++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-)
arch/powerpc/kvm/Kconfig +15 -0
@@ -130,6 +130,21 @@ config KVM_BOOK3S_HV_EXIT_TIMING If unsure, say N. +config KVM_BOOK3S_HV_NESTED_PMU_WORKAROUND + bool "Nested L0 host workaround for L1 KVM host PMU handling bug" if EXPERT + depends on KVM_BOOK3S_HV_POSSIBLE + default !EXPERT + help + Old nested HV capable Linux guests have a bug where they don't + reflect the PMU in-use status of their L2 guest to the L0 host + while the L2 PMU registers are live. This can result in loss + of L2 PMU register state, causing perf to not work correctly in + L2 guests. + + Selecting this option for the L0 host implements a workaround for + those buggy L1s which saves the L2 state, at the cost of performance + in all nested-capable guest entry/exit. + config KVM_BOOKE_HV bool
arch/powerpc/kvm/book3s_hv.c +8 -2
@@ -4047,8 +4047,14 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, vcpu->arch.vpa.dirty =1 ; save_pmu = lp->pmcregs_in_use; } -/* Must save pmu if this guest is capable of running nested guests */ - save_pmu |=nesting_enabled (vcpu->kvm); +if (IS_ENABLED (CONFIG_KVM_BOOK3S_HV_NESTED_PMU_WORKAROUND )) { +/* +* Save pmu if this guest is capable of running nested guests. +* This is option is for old L1s that do not set their +* lppaca->pmcregs_in_use properly when entering their L2. +*/ + save_pmu |=nesting_enabled (vcpu->kvm); + }kvmhv_save_guest_pmu (vcpu, save_pmu);#ifdef CONFIG_PPC_PSERIES
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 11/53 powerpc/64s: Always set PMU control registers to frozen/disabled when not in use
In reply to Nicholas PigginKVM PMU management code looks for particular frozen/disabled bits in the PMU registers so it knows whether it must clear them when coming out of a guest or not. Setting this up helps KVM make these optimisations without getting confused. Longer term the better approach might be to move guest/host PMU switching to the perf subsystem.
--- arch/powerpc/kernel/cpu_setup_power.c | 4 ++-- arch/powerpc/kernel/dt_cpu_ftrs.c | 6 +++--- arch/powerpc/kvm/book3s_hv.c | 5 +++++ 3 files changed, 10 insertions(+), 5 deletions(-)
arch/powerpc/kernel/cpu_setup_power.c +2 -2
@@ -109,7 +109,7 @@ static void init_PMU_HV_ISA207(void)static void init_PMU (void ) {mtspr (SPRN_MMCRA ,0 ); -mtspr (SPRN_MMCR0 ,0 ); +mtspr (SPRN_MMCR0 ,MMCR0_FC );mtspr (SPRN_MMCR1 ,0 );mtspr (SPRN_MMCR2 ,0 ); }
@@ -123,7 +123,7 @@ static void init_PMU_ISA31(void) {mtspr (SPRN_MMCR3 ,0 );mtspr (SPRN_MMCRA ,MMCRA_BHRB_DISABLE ); -mtspr (SPRN_MMCR0 ,MMCR0_PMCCEXT ); +mtspr (SPRN_MMCR0 ,MMCR0_FC |MMCR0_PMCCEXT ); }/*
arch/powerpc/kernel/dt_cpu_ftrs.c +3 -3
@@ -353,7 +353,7 @@ static void init_pmu_power8(void) }mtspr (SPRN_MMCRA ,0 ); -mtspr (SPRN_MMCR0 ,0 ); +mtspr (SPRN_MMCR0 ,MMCR0_FC );mtspr (SPRN_MMCR1 ,0 );mtspr (SPRN_MMCR2 ,0 );mtspr (SPRN_MMCRS ,0 );
@@ -392,7 +392,7 @@ static void init_pmu_power9(void)mtspr (SPRN_MMCRC ,0 );mtspr (SPRN_MMCRA ,0 ); -mtspr (SPRN_MMCR0 ,0 ); +mtspr (SPRN_MMCR0 ,MMCR0_FC );mtspr (SPRN_MMCR1 ,0 );mtspr (SPRN_MMCR2 ,0 ); }
@@ -428,7 +428,7 @@ static void init_pmu_power10(void)mtspr (SPRN_MMCR3 ,0 );mtspr (SPRN_MMCRA ,MMCRA_BHRB_DISABLE ); -mtspr (SPRN_MMCR0 ,MMCR0_PMCCEXT ); +mtspr (SPRN_MMCR0 ,MMCR0_FC |MMCR0_PMCCEXT ); }static int __init feat_enable_pmu_power10 (struct dt_cpu_feature *f)
arch/powerpc/kvm/book3s_hv.c +5 -0
@@ -2715,6 +2715,11 @@ static int kvmppc_core_vcpu_create_hv(struct kvm_vcpu *vcpu)#endif #endif vcpu->arch.mmcr[0 ] =MMCR0_FC ; +if (cpu_has_feature (CPU_FTR_ARCH_31 )) { + vcpu->arch.mmcr[0 ] |=MMCR0_PMCCEXT ; + vcpu->arch.mmcra =MMCRA_BHRB_DISABLE ; + } + vcpu->arch.ctrl =CTRL_RUNLATCH ;/* default to host PVR, since we can't spoof it */ kvmppc_set_pvr_hv (vcpu,mfspr (SPRN_PVR ));
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 12/53 powerpc/64s: Implement PMU override command line option
In reply to Nicholas PigginIt can be useful in simulators (with very constrained environments) to allow some PMCs to run from boot so they can be sampled directly by a test harness, rather than having to run perf.
A previous change freezes counters at boot by default, so provide a boot time option to un-freeze (plus a bit more flexibility).
--- .../admin-guide/kernel-parameters.txt | 8 +++++ arch/powerpc/perf/core-book3s.c | 35 +++++++++++++++++++ 2 files changed, 43 insertions(+)
Documentation/admin-guide/kernel-parameters.txt +8 -0
@@ -4144,6 +4144,14 @@ Override pmtimer IOPort with a hex value. e.g. pmtmr=0x508 + pmu_override= [PPC] Override the PMU. + This option takes over the PMU facility, so it is no + longer usable by perf. Setting this option starts the + PMU counters by setting MMCR0 to 0 (the FC bit is + cleared). If a number is given, then MMCR1 is set to + that number, otherwise (e.g., 'pmu_override=on'), MMCR1 + remains 0. + pm_debug_messages [SUSPEND,KNL] Enable suspend/resume debug messages during boot up.
arch/powerpc/perf/core-book3s.c +35 -0
@@ -2419,8 +2419,24 @@ int register_power_pmu(struct power_pmu *pmu) }#ifdef CONFIG_PPC64 +static bool pmu_override = false; +static unsigned long pmu_override_val; +static void do_pmu_override (void *data) +{ +ppc_set_pmu_inuse (1 ); +if (pmu_override_val) +mtspr (SPRN_MMCR1 , pmu_override_val); +mtspr (SPRN_MMCR0 ,mfspr (SPRN_MMCR0 ) & ~MMCR0_FC ); +} +static int __init init_ppc64_pmu (void ) { +if (cpu_has_feature (CPU_FTR_HVMODE ) && pmu_override) { +pr_warn ("disabling perf due to pmu_override= command line option.\n" ); +on_each_cpu (do_pmu_override,NULL ,1 ); +return 0 ; + } +/* run through all the pmu drivers one at a time */ if (!init_power5_pmu ())return 0 ;
@@ -2442,4 +2458,23 @@ static int __init init_ppc64_pmu(void) return init_generic_compat_pmu(); }early_initcall (init_ppc64_pmu); + +static int __init pmu_setup (char *str) +{ +unsigned long val; + +if (!early_cpu_has_feature (CPU_FTR_HVMODE )) +return 0 ; + + pmu_override = true; + +if (kstrtoul (str,0 , &val)) + val =0 ; + + pmu_override_val = val; + +return 1 ; +} +__setup ("pmu_override=" , pmu_setup); +#endif
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 13/53 KVM: PPC: Book3S HV P9: Implement PMU save/restore in C
In reply to Nicholas PigginImplement the P9 path PMU save/restore code in C, and remove the POWER9/10 code from the P7/8 path assembly.
--- arch/powerpc/include/asm/asm-prototypes.h | 5 - arch/powerpc/kvm/book3s_hv.c | 221 +++++++++++++++++++--- arch/powerpc/kvm/book3s_hv_interrupts.S | 13 +- arch/powerpc/kvm/book3s_hv_rmhandlers.S | 43 +---- 4 files changed, 208 insertions(+), 74 deletions(-)
arch/powerpc/include/asm/asm-prototypes.h +0 -5
@@ -141,11 +141,6 @@ static inline void kvmppc_restore_tm_hv(struct kvm_vcpu *vcpu, u64 msr, bool preserve_nv) { }#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ -void kvmhv_save_host_pmu (void ); -void kvmhv_load_host_pmu (void ); -void kvmhv_save_guest_pmu (struct kvm_vcpu *vcpu,bool pmu_in_use); -void kvmhv_load_guest_pmu (struct kvm_vcpu *vcpu); -void kvmppc_p9_enter_guest (struct kvm_vcpu *vcpu);long kvmppc_h_set_dabr (struct kvm_vcpu *vcpu,unsigned long dabr);
arch/powerpc/kvm/book3s_hv.c +195 -26
270 lines not on this page · raw message
arch/powerpc/kvm/book3s_hv_interrupts.S +4 -9
@@ -104,7 +104,10 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S) mtlr r0 blr -_GLOBAL(kvmhv_save_host_pmu) +/* + * void kvmhv_save_host_pmu(void) + */ +kvmhv_save_host_pmu: BEGIN_FTR_SECTION /* Work around P8 PMAE bug */ li r3, -1
@@ -138,14 +141,6 @@ BEGIN_FTR_SECTION std r8, HSTATE_MMCR2(r13) std r9, HSTATE_SIER(r13) END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) -BEGIN_FTR_SECTION - mfspr r5, SPRN_MMCR3 - mfspr r6, SPRN_SIER2 - mfspr r7, SPRN_SIER3 - std r5, HSTATE_MMCR3(r13) - std r6, HSTATE_SIER2(r13) - std r7, HSTATE_SIER3(r13) -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_31) mfspr r3, SPRN_PMC1 mfspr r5, SPRN_PMC2 mfspr r6, SPRN_PMC3
arch/powerpc/kvm/book3s_hv_rmhandlers.S +9 -34
109 lines not on this page · raw message
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 14/53 KVM: PPC: Book3S HV P9: Factor PMU save/load into context switch functions
In reply to Nicholas PigginRather than guest/host save/retsore functions, implement context switch functions that take care of details like the VPA update for nested.
The reason to split these kind of helpers into explicit save/load functions is mainly to schedule SPR access nicely, but PMU is a special case where the load requires mtSPR (to stop counters) and other difficulties, so there's less possibility to schedule those nicely. The SPR accesses also have side-effects if the PMU is running, and in later changes we keep the host PMU running as long as possible so this code can be better profiled, which also complicates scheduling.
--- arch/powerpc/kvm/book3s_hv.c | 61 +++++++++++++++++------------------- 1 file changed, 28 insertions(+), 33 deletions(-)
arch/powerpc/kvm/book3s_hv.c +28 -33
@@ -3830,7 +3830,8 @@ static void freeze_pmu(unsigned long mmcr0, unsigned long mmcra)isync (); } -static void save_p9_host_pmu (struct p9_host_os_sprs *host_os_sprs) +static void switch_pmu_to_guest (struct kvm_vcpu *vcpu, +struct p9_host_os_sprs *host_os_sprs) {if (ppc_get_pmu_inuse ()) {/*
@@ -3864,10 +3865,21 @@ static void save_p9_host_pmu(struct p9_host_os_sprs *host_os_sprs) host_os_sprs->sier3 =mfspr (SPRN_SIER3 ); } } -} -static void load_p9_guest_pmu (struct kvm_vcpu *vcpu) -{ +#ifdef CONFIG_PPC_PSERIES +if (kvmhv_on_pseries ()) { +barrier (); +if (vcpu->arch.vpa.pinned_addr) { +struct lppaca *lp = vcpu->arch.vpa.pinned_addr; +get_lppaca ()->pmcregs_in_use = lp->pmcregs_in_use; + }else { +get_lppaca ()->pmcregs_in_use =1 ; + } +barrier (); + } +#endif + +/* load guest */ mtspr (SPRN_PMC1 , vcpu->arch.pmc[0 ]);mtspr (SPRN_PMC2 , vcpu->arch.pmc[1 ]);mtspr (SPRN_PMC3 , vcpu->arch.pmc[2 ]);
@@ -3892,7 +3904,8 @@ static void load_p9_guest_pmu(struct kvm_vcpu *vcpu)/* No isync necessary because we're starting counters */ } -static void save_p9_guest_pmu (struct kvm_vcpu *vcpu) +static void switch_pmu_to_host (struct kvm_vcpu *vcpu, +struct p9_host_os_sprs *host_os_sprs) {struct lppaca *lp;int save_pmu =1 ;
@@ -3935,10 +3948,15 @@ static void save_p9_guest_pmu(struct kvm_vcpu *vcpu) }else {freeze_pmu (mfspr (SPRN_MMCR0 ),mfspr (SPRN_MMCRA )); } -} -static void load_p9_host_pmu (struct p9_host_os_sprs *host_os_sprs) -{ +#ifdef CONFIG_PPC_PSERIES +if (kvmhv_on_pseries ()) { +barrier (); +get_lppaca ()->pmcregs_in_use =ppc_get_pmu_inuse (); +barrier (); + } +#endif +if (ppc_get_pmu_inuse ()) {mtspr (SPRN_PMC1 , host_os_sprs->pmc1);mtspr (SPRN_PMC2 , host_os_sprs->pmc2);
@@ -4071,8 +4089,6 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,save_p9_host_os_sprs (&host_os_sprs); -save_p9_host_pmu (&host_os_sprs); -kvmppc_subcore_enter_guest (); vc->entry_exit_map =1 ;
@@ -4089,19 +4105,7 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST))kvmppc_restore_tm_hv (vcpu, vcpu->arch.shregs.msr, true); -#ifdef CONFIG_PPC_PSERIES -if (kvmhv_on_pseries ()) { -barrier (); -if (vcpu->arch.vpa.pinned_addr) { -struct lppaca *lp = vcpu->arch.vpa.pinned_addr; -get_lppaca ()->pmcregs_in_use = lp->pmcregs_in_use; - }else { -get_lppaca ()->pmcregs_in_use =1 ; - } -barrier (); - } -#endif -load_p9_guest_pmu (vcpu); +switch_pmu_to_guest (vcpu, &host_os_sprs);msr_check_and_set (MSR_FP |MSR_VEC |MSR_VSX );load_fp_state (&vcpu->arch.fp);
@@ -4230,14 +4234,7 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, vcpu->arch.vpa.dirty =1 ; } -save_p9_guest_pmu (vcpu); -#ifdef CONFIG_PPC_PSERIES -if (kvmhv_on_pseries ()) { -barrier (); -get_lppaca ()->pmcregs_in_use =ppc_get_pmu_inuse (); -barrier (); - } -#endif +switch_pmu_to_host (vcpu, &host_os_sprs); vc->entry_exit_map =0x101 ; vc->in_guest =0 ;
@@ -4246,8 +4243,6 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,mtspr (SPRN_SPRG_VDSO_WRITE , local_paca->sprg_vdso); -load_p9_host_pmu (&host_os_sprs); -kvmppc_subcore_exit_guest ();return trap;
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 15/53 KVM: PPC: Book3S HV P9: Demand fault PMU SPRs when marked not inuse
In reply to Nicholas PigginThe pmcregs_in_use field in the guest VPA can not be trusted to reflect what the guest is doing with PMU SPRs, so the PMU must always be managed (stopped) when exiting the guest, and SPR values set when entering the guest to ensure it can't cause a covert channel or otherwise cause other guests or the host to misbehave.
So prevent guest access to the PMU with HFSCR[PM] if pmcregs_in_use is clear, and avoid the PMU SPR access on every partition switch. Guests that set pmcregs_in_use incorrectly or when first setting it and using the PMU will take a hypervisor facility unavailable interrupt that will bring in the PMU SPRs.
--- arch/powerpc/kvm/book3s_hv.c | 131 ++++++++++++++++++++++++++--------- 1 file changed, 98 insertions(+), 33 deletions(-)
arch/powerpc/kvm/book3s_hv.c +98 -33
@@ -1421,6 +1421,23 @@ static int kvmppc_emulate_doorbell_instr(struct kvm_vcpu *vcpu)return RESUME_GUEST ; } +/* +* If the lppaca had pmcregs_in_use clear when we exited the guest, then +* HFSCR_PM is cleared for next entry. If the guest then tries to access +* the PMU SPRs, we get this facility unavailable interrupt. Putting HFSCR_PM +* back in the guest HFSCR will cause the next entry to load the PMU SPRs and +* allow the guest access to continue. +*/ +static int kvmppc_pmu_unavailable (struct kvm_vcpu *vcpu) +{ +if (!(vcpu->arch.hfscr_permitted &HFSCR_PM )) +return EMULATE_FAIL ; + + vcpu->arch.hfscr |=HFSCR_PM ; + +return RESUME_GUEST ; +} +static int kvmppc_handle_exit_hv (struct kvm_vcpu *vcpu,struct task_struct *tsk) {
@@ -1702,16 +1719,22 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu,* to emulate. * Otherwise, we just generate a program interrupt to the guest. */ -case BOOK3S_INTERRUPT_H_FAC_UNAVAIL : +case BOOK3S_INTERRUPT_H_FAC_UNAVAIL : { +u64 cause = vcpu->arch.hfscr >>56 ; + r =EMULATE_FAIL ; -if (((vcpu->arch.hfscr >>56 ) ==FSCR_MSGP_LG ) && -cpu_has_feature (CPU_FTR_ARCH_300 )) - r =kvmppc_emulate_doorbell_instr (vcpu); +if (cpu_has_feature (CPU_FTR_ARCH_300 )) { +if (cause ==FSCR_MSGP_LG ) + r =kvmppc_emulate_doorbell_instr (vcpu); +if (cause ==FSCR_PM_LG ) + r =kvmppc_pmu_unavailable (vcpu); + }if (r ==EMULATE_FAIL ) {kvmppc_core_queue_program (vcpu,SRR1_PROGILL ); r =RESUME_GUEST ; }break ; + }case BOOK3S_INTERRUPT_HV_RM_HARD : r =RESUME_PASSTHROUGH ;
@@ -2750,6 +2773,11 @@ static int kvmppc_core_vcpu_create_hv(struct kvm_vcpu *vcpu) vcpu->arch.hfscr_permitted = vcpu->arch.hfscr; +/* +* PM is demand-faulted so start with it clear. +*/ + vcpu->arch.hfscr &= ~HFSCR_PM ; +kvmppc_mmu_book3s_hv_init (vcpu); vcpu->arch.state =KVMPPC_VCPU_NOTREADY ;
@@ -3833,6 +3861,14 @@ static void freeze_pmu(unsigned long mmcr0, unsigned long mmcra)static void switch_pmu_to_guest (struct kvm_vcpu *vcpu,struct p9_host_os_sprs *host_os_sprs) { +struct lppaca *lp; +int load_pmu =1 ; + + lp = vcpu->arch.vpa.pinned_addr; +if (lp) + load_pmu = lp->pmcregs_in_use; + +/* Save host */ if (ppc_get_pmu_inuse ()) {/* * It might be better to put PMU handling (at least for the
@@ -3867,41 +3903,47 @@ static void switch_pmu_to_guest(struct kvm_vcpu *vcpu, }#ifdef CONFIG_PPC_PSERIES +/* After saving PMU, before loading guest PMU, flip pmcregs_in_use */ if (kvmhv_on_pseries ()) {barrier (); -if (vcpu->arch.vpa.pinned_addr) { -struct lppaca *lp = vcpu->arch.vpa.pinned_addr; -get_lppaca ()->pmcregs_in_use = lp->pmcregs_in_use; - }else { -get_lppaca ()->pmcregs_in_use =1 ; - } +get_lppaca ()->pmcregs_in_use = load_pmu;barrier (); }#endif -/* load guest */ -mtspr (SPRN_PMC1 , vcpu->arch.pmc[0 ]); -mtspr (SPRN_PMC2 , vcpu->arch.pmc[1 ]); -mtspr (SPRN_PMC3 , vcpu->arch.pmc[2 ]); -mtspr (SPRN_PMC4 , vcpu->arch.pmc[3 ]); -mtspr (SPRN_PMC5 , vcpu->arch.pmc[4 ]); -mtspr (SPRN_PMC6 , vcpu->arch.pmc[5 ]); -mtspr (SPRN_MMCR1 , vcpu->arch.mmcr[1 ]); -mtspr (SPRN_MMCR2 , vcpu->arch.mmcr[2 ]); -mtspr (SPRN_SDAR , vcpu->arch.sdar); -mtspr (SPRN_SIAR , vcpu->arch.siar); -mtspr (SPRN_SIER , vcpu->arch.sier[0 ]); +/* +* Load guest. If the VPA said the PMCs are not in use but the guest +* tried to access them anyway, HFSCR[PM] will be set by the HFAC +* fault so we can make forward progress. +*/ +if (load_pmu || (vcpu->arch.hfscr &HFSCR_PM )) { +mtspr (SPRN_PMC1 , vcpu->arch.pmc[0 ]); +mtspr (SPRN_PMC2 , vcpu->arch.pmc[1 ]); +mtspr (SPRN_PMC3 , vcpu->arch.pmc[2 ]); +mtspr (SPRN_PMC4 , vcpu->arch.pmc[3 ]); +mtspr (SPRN_PMC5 , vcpu->arch.pmc[4 ]); +mtspr (SPRN_PMC6 , vcpu->arch.pmc[5 ]); +mtspr (SPRN_MMCR1 , vcpu->arch.mmcr[1 ]); +mtspr (SPRN_MMCR2 , vcpu->arch.mmcr[2 ]); +mtspr (SPRN_SDAR , vcpu->arch.sdar); +mtspr (SPRN_SIAR , vcpu->arch.siar); +mtspr (SPRN_SIER , vcpu->arch.sier[0 ]); + +if (cpu_has_feature (CPU_FTR_ARCH_31 )) { +mtspr (SPRN_MMCR3 , vcpu->arch.mmcr[3 ]); +mtspr (SPRN_SIER2 , vcpu->arch.sier[1 ]); +mtspr (SPRN_SIER3 , vcpu->arch.sier[2 ]); + } -if (cpu_has_feature (CPU_FTR_ARCH_31 )) { -mtspr (SPRN_MMCR3 , vcpu->arch.mmcr[3 ]); -mtspr (SPRN_SIER2 , vcpu->arch.sier[1 ]); -mtspr (SPRN_SIER3 , vcpu->arch.sier[2 ]); - } +/* Set MMCRA then MMCR0 last */ +mtspr (SPRN_MMCRA , vcpu->arch.mmcra); +mtspr (SPRN_MMCR0 , vcpu->arch.mmcr[0 ]); +/* No isync necessary because we're starting counters */ -/* Set MMCRA then MMCR0 last */ -mtspr (SPRN_MMCRA , vcpu->arch.mmcra); -mtspr (SPRN_MMCR0 , vcpu->arch.mmcr[0 ]); -/* No isync necessary because we're starting counters */ +if (!vcpu->arch.nested && + (vcpu->arch.hfscr_permitted &HFSCR_PM )) + vcpu->arch.hfscr |=HFSCR_PM ; + } } static void switch_pmu_to_host(struct kvm_vcpu *vcpu,
@@ -3945,9 +3987,32 @@ static void switch_pmu_to_host(struct kvm_vcpu *vcpu, vcpu->arch.sier[1 ] =mfspr (SPRN_SIER2 ); vcpu->arch.sier[2 ] =mfspr (SPRN_SIER3 ); } - }else { + + }else if (vcpu->arch.hfscr &HFSCR_PM ) { +/* +* The guest accessed PMC SPRs without specifying they should +* be preserved, or it cleared pmcregs_in_use after the last +* access. Just ensure they are frozen. +*/ freeze_pmu (mfspr (SPRN_MMCR0 ),mfspr (SPRN_MMCRA )); - } + +/* +* Demand-fault PMU register access in the guest. +* +* This is used to grab the guest's VPA pmcregs_in_use value +* and reflect it into the host's VPA in the case of a nested +* hypervisor. +* +* It also avoids having to zero-out SPRs after each guest +* exit to avoid side-channels when. +* +* This is cleared here when we exit the guest, so later HFSCR +* interrupt handling can add it back to run the guest with +* PM enabled next time. +*/ +if (!vcpu->arch.nested) + vcpu->arch.hfscr &= ~HFSCR_PM ; + }/* otherwise the PMU should still be frozen */ #ifdef CONFIG_PPC_PSERIES if (kvmhv_on_pseries ()) {
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 16/53 KVM: PPC: Book3S HV P9: Factor out yield_count increment
In reply to Nicholas PigginFactor duplicated code into a helper function.
--- arch/powerpc/kvm/book3s_hv.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-)
arch/powerpc/kvm/book3s_hv.c +12 -12
@@ -4131,6 +4131,16 @@ static inline bool hcall_is_xics(unsigned long req) req ==H_IPOLL || req ==H_XIRR || req ==H_XIRR_X ; } +static void vcpu_vpa_increment_dispatch (struct kvm_vcpu *vcpu) +{ +struct lppaca *lp = vcpu->arch.vpa.pinned_addr; +if (lp) { +u32 yield_count =be32_to_cpu (lp->yield_count) +1 ; + lp->yield_count =cpu_to_be32 (yield_count); + vcpu->arch.vpa.dirty =1 ; + } +} +/* * Guest entry for POWER9 and later CPUs. */
@@ -4159,12 +4169,7 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, vc->entry_exit_map =1 ; vc->in_guest =1 ; -if (vcpu->arch.vpa.pinned_addr) { -struct lppaca *lp = vcpu->arch.vpa.pinned_addr; -u32 yield_count =be32_to_cpu (lp->yield_count) +1 ; - lp->yield_count =cpu_to_be32 (yield_count); - vcpu->arch.vpa.dirty =1 ; - } +vcpu_vpa_increment_dispatch (vcpu);if (cpu_has_feature (CPU_FTR_TM ) ||cpu_has_feature (CPU_FTR_P9_TM_HV_ASSIST ))
@@ -4292,12 +4297,7 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST))kvmppc_save_tm_hv (vcpu, vcpu->arch.shregs.msr, true); -if (vcpu->arch.vpa.pinned_addr) { -struct lppaca *lp = vcpu->arch.vpa.pinned_addr; -u32 yield_count =be32_to_cpu (lp->yield_count) +1 ; - lp->yield_count =cpu_to_be32 (yield_count); - vcpu->arch.vpa.dirty =1 ; - } +vcpu_vpa_increment_dispatch (vcpu);switch_pmu_to_host (vcpu, &host_os_sprs);
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 17/53 KVM: PPC: Book3S HV: CTRL SPR does not require read-modify-write
In reply to Nicholas PigginProcessors that support KVM HV do not require read-modify-write of the CTRL SPR to set/clear their thread's runlatch. Just write 1 or 0 to it.
--- arch/powerpc/kvm/book3s_hv.c | 2 +- arch/powerpc/kvm/book3s_hv_rmhandlers.S | 15 ++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-)
arch/powerpc/kvm/book3s_hv.c +1 -1
@@ -4071,7 +4071,7 @@ static void load_spr_state(struct kvm_vcpu *vcpu)*/ if (!(vcpu->arch.ctrl &1 )) -mtspr (SPRN_CTRLT ,mfspr (SPRN_CTRLF ) & ~1 ); +mtspr (SPRN_CTRLT ,0 ); }static void store_spr_state (struct kvm_vcpu *vcpu)
arch/powerpc/kvm/book3s_hv_rmhandlers.S +6 -9
@@ -781,12 +781,11 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S) mtspr SPRN_AMR,r5 mtspr SPRN_UAMOR,r6 - /* Restore state of CTRL run bit; assume 1 on entry */ + /* Restore state of CTRL run bit; the host currently has it set to 1 */ lwz r5,VCPU_CTRL(r4) andi. r5,r5,1 bne 4f - mfspr r6,SPRN_CTRLF - clrrdi r6,r6,1 + li r6,0 mtspr SPRN_CTRLT,r6 4: /* Secondary threads wait for primary to have done partition switch */
@@ -1209,12 +1208,12 @@ guest_bypass: stw r0, VCPU_CPU(r9) stw r0, VCPU_THREAD_CPU(r9) - /* Save guest CTRL register, set runlatch to 1 */ + /* Save guest CTRL register, set runlatch to 1 if it was clear */ mfspr r6,SPRN_CTRLF stw r6,VCPU_CTRL(r9) andi. r0,r6,1 bne 4f - ori r6,r6,1 + li r6,1 mtspr SPRN_CTRLT,r6 4: /*
@@ -2184,8 +2183,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_TM) * Also clear the runlatch bit before napping. */ kvm_do_nap: - mfspr r0, SPRN_CTRLF - clrrdi r0, r0, 1 + li r0,0 mtspr SPRN_CTRLT, r0 li r0,1
@@ -2204,8 +2202,7 @@ kvm_nap_sequence: /* desired LPCR value in r5 */ bl isa206_idle_insn_mayloss - mfspr r0, SPRN_CTRLF - ori r0, r0, 1 + li r0,1 mtspr SPRN_CTRLT, r0 mtspr SPRN_SRR1, r3
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 18/53 KVM: PPC: Book3S HV P9: Move SPRG restore to restore_p9_host_os_sprs
In reply to Nicholas PigginMove the SPR update into its relevant helper function. This will help with SPR scheduling improvements in later changes.
--- arch/powerpc/kvm/book3s_hv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/powerpc/kvm/book3s_hv.c +2 -2
@@ -4106,6 +4106,8 @@ static void save_p9_host_os_sprs(struct p9_host_os_sprs *host_os_sprs)static void restore_p9_host_os_sprs (struct kvm_vcpu *vcpu,struct p9_host_os_sprs *host_os_sprs) { +mtspr (SPRN_SPRG_VDSO_WRITE , local_paca->sprg_vdso); +mtspr (SPRN_PSPB ,0 );mtspr (SPRN_UAMOR ,0 );
@@ -4306,8 +4308,6 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,timer_rearm_host_dec (tb); -mtspr (SPRN_SPRG_VDSO_WRITE , local_paca->sprg_vdso); -kvmppc_subcore_exit_guest ();return trap;
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 19/53 KVM: PPC: Book3S HV P9: Reduce mtmsrd instructions required to save host SPRs
In reply to Nicholas PigginThis reduces the number of mtmsrd required to enable facility bits when saving/restoring registers, by having the KVM code set all bits up front rather than using individual facility functions that set their particular MSR bits.
--- arch/powerpc/include/asm/switch_to.h | 2 + arch/powerpc/kernel/process.c | 28 +++++++++++++ arch/powerpc/kvm/book3s_hv.c | 59 ++++++++++++++++++--------- arch/powerpc/kvm/book3s_hv_p9_entry.c | 1 + 4 files changed, 71 insertions(+), 19 deletions(-)
arch/powerpc/include/asm/switch_to.h +2 -0
@@ -112,6 +112,8 @@ static inline void clear_task_ebb(struct task_struct *t) #endif } +void kvmppc_save_user_regs (void ); +extern int set_thread_tidr (struct task_struct *t);#endif /* _ASM_POWERPC_SWITCH_TO_H */
arch/powerpc/kernel/process.c +28 -0
@@ -1156,6 +1156,34 @@ static inline void save_sprs(struct thread_struct *t)#endif } +#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE +void kvmppc_save_user_regs (void ) +{ +unsigned long usermsr; + +if (!current->thread.regs) +return ; + + usermsr = current->thread.regs->msr; + +if (usermsr &MSR_FP ) +save_fpu (current); + +if (usermsr &MSR_VEC ) +save_altivec (current); + +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +if (usermsr &MSR_TM ) { + current->thread.tm_tfhar =mfspr (SPRN_TFHAR ); + current->thread.tm_tfiar =mfspr (SPRN_TFIAR ); + current->thread.tm_texasr =mfspr (SPRN_TEXASR ); + current->thread.regs->msr &= ~MSR_TM ; + } +#endif +} +EXPORT_SYMBOL_GPL (kvmppc_save_user_regs); +#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */ +static inline void restore_sprs (struct thread_struct *old_thread,struct thread_struct *new_thread) {
arch/powerpc/kvm/book3s_hv.c +40 -19
122 lines not on this page · raw message
arch/powerpc/kvm/book3s_hv_p9_entry.c +1 -0
@@ -224,6 +224,7 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc vc->tb_offset_applied = vc->tb_offset; } +/* Could avoid mfmsr by passing around, but probably no big deal */ msr =mfmsr (); host_hfscr =mfspr (SPRN_HFSCR );
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 20/53 KVM: PPC: Book3S HV P9: Improve mtmsrd scheduling by delaying MSR[EE] disable
In reply to Nicholas PigginMoving the mtmsrd after the host SPRs are saved and before the guest SPRs start to be loaded can prevent an SPR scoreboard stall (because the mtmsrd is L=1 type which does not cause context synchronisation.
This is also now more convenient to combined with the mtmsrd L=0 instruction to enable facilities just below, but that is not done yet.
--- arch/powerpc/kvm/book3s_hv.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-)
arch/powerpc/kvm/book3s_hv.c +18 -5
@@ -4169,6 +4169,18 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,save_p9_host_os_sprs (&host_os_sprs); +/* +* This could be combined with MSR[RI] clearing, but that expands +* the unrecoverable window. It would be better to cover unrecoverable +* with KVM bad interrupt handling rather than use MSR[RI] at all. +* +* Much more difficult and less worthwhile to combine with IR/DR +* disable. +*/ +hard_irq_disable (); +if (lazy_irq_pending ()) +return 0 ; +/* MSR bits may have been cleared by context switch */ msr =0 ;if (IS_ENABLED (CONFIG_PPC_FPU ))
@@ -4680,6 +4692,7 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit,struct kvmppc_vcore *vc;struct kvm *kvm = vcpu->kvm;struct kvm_nested_guest *nested = vcpu->arch.nested; +unsigned long flags;trace_kvmppc_run_vcpu_enter (vcpu);
@@ -4723,11 +4736,11 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit,if (kvm_is_radix (kvm))kvmppc_prepare_radix_vcpu (vcpu, pcpu); -local_irq_disable (); -hard_irq_disable (); +/* flags save not required, but irq_pmu has no disable/enable API */ +powerpc_local_irq_pmu_save (flags);if (signal_pending (current)) goto sigpend; -if (lazy_irq_pending () ||need_resched () || !kvm->arch.mmu_ready) +if (need_resched () || !kvm->arch.mmu_ready) goto out;if (!nested) {
@@ -4795,7 +4808,7 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit, }vtime_account_guest_exit (); -local_irq_enable (); +powerpc_local_irq_pmu_restore (flags);cpumask_clear_cpu (pcpu, &kvm->arch.cpu_in_guest);
@@ -4853,7 +4866,7 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit, run->exit_reason =KVM_EXIT_INTR ; vcpu->arch.ret = -EINTR ; out: -local_irq_enable (); +powerpc_local_irq_pmu_restore (flags);preempt_enable (); goto done; }
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 21/53 KVM: PPC: Book3S HV P9: Add kvmppc_stop_thread to match kvmppc_start_thread
In reply to Nicholas PigginSmall cleanup makes it a bit easier to match up entry and exit operations.
--- arch/powerpc/kvm/book3s_hv.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
arch/powerpc/kvm/book3s_hv.c +9 -2
@@ -3070,6 +3070,13 @@ static void kvmppc_start_thread(struct kvm_vcpu *vcpu, struct kvmppc_vcore *vc)kvmppc_ipi_thread (cpu); } +/* Old path does this in asm */ +static void kvmppc_stop_thread (struct kvm_vcpu *vcpu) +{ + vcpu->cpu =-1 ; + vcpu->arch.thread_cpu =-1 ; +} +static void kvmppc_wait_for_nap (int n_threads) {int cpu =smp_processor_id ();
@@ -4310,8 +4317,6 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, dec = (s32 ) dec; tb =mftb (); vcpu->arch.dec_expires = dec + tb; - vcpu->cpu =-1 ; - vcpu->arch.thread_cpu =-1 ;store_spr_state (vcpu);
@@ -4808,6 +4813,8 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit, }vtime_account_guest_exit (); +kvmppc_stop_thread (vcpu); +powerpc_local_irq_pmu_restore (flags);cpumask_clear_cpu (pcpu, &kvm->arch.cpu_in_guest);
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 22/53 KVM: PPC: Book3S HV: Change dec_expires to be relative to guest timebase
In reply to Nicholas PigginChange dec_expires to be relative to the guest timebase, and allow it to be moved into low level P9 guest entry functions, to improve SPR access scheduling.
--- arch/powerpc/include/asm/kvm_book3s.h | 6 +++ arch/powerpc/include/asm/kvm_host.h | 2 +- arch/powerpc/kvm/book3s_hv.c | 58 +++++++++++++------------ arch/powerpc/kvm/book3s_hv_nested.c | 3 ++ arch/powerpc/kvm/book3s_hv_p9_entry.c | 10 ++++- arch/powerpc/kvm/book3s_hv_rmhandlers.S | 13 ------ 6 files changed, 49 insertions(+), 43 deletions(-)
arch/powerpc/include/asm/kvm_book3s.h +6 -0
@@ -406,6 +406,12 @@ static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu)return vcpu->arch.fault_dar; } +/* Expiry time of vcpu DEC relative to host TB */ +static inline u64 kvmppc_dec_expires_host_tb (struct kvm_vcpu *vcpu) +{ +return vcpu->arch.dec_expires - vcpu->arch.vcore->tb_offset; +} +static inline bool is_kvmppc_resume_guest (int r) {return (r ==RESUME_GUEST || r ==RESUME_GUEST_NV );
arch/powerpc/include/asm/kvm_host.h +1 -1
@@ -741,7 +741,7 @@ struct kvm_vcpu_arch {struct hrtimer dec_timer;u64 dec_jiffies; -u64 dec_expires; +u64 dec_expires;/* Relative to guest timebase. */ unsigned long pending_exceptions;u8 ceded;u8 prodded;
arch/powerpc/kvm/book3s_hv.c +30 -28
123 lines not on this page · raw message
arch/powerpc/kvm/book3s_hv_nested.c +3 -0
@@ -358,6 +358,7 @@ long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu)/* convert TB values/offsets to host (L0) values */ hdec_exp = l2_hv.hdec_expiry - vc->tb_offset; vc->tb_offset += l2_hv.tb_offset; + vcpu->arch.dec_expires += l2_hv.tb_offset;/* set L1 state to L2 state */ vcpu->arch.nested = l2;
@@ -399,6 +400,8 @@ long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu)if (l2_regs.msr &MSR_TS_MASK ) vcpu->arch.shregs.msr |=MSR_TS_S ; vc->tb_offset = saved_l1_hv.tb_offset; +/* XXX: is this always the same delta as saved_l1_hv.tb_offset? */ + vcpu->arch.dec_expires -= l2_hv.tb_offset;restore_hv_regs (vcpu, &saved_l1_hv); vcpu->arch.purr += delta_purr; vcpu->arch.spurr += delta_spurr;
arch/powerpc/kvm/book3s_hv_p9_entry.c +9 -1
@@ -188,7 +188,7 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcstruct kvm *kvm = vcpu->kvm;struct kvm_nested_guest *nested = vcpu->arch.nested;struct kvmppc_vcore *vc = vcpu->arch.vcore; -s64 hdec; +s64 hdec, dec;u64 tb, purr, spurr;u64 *exsave;bool ri_set;
@@ -317,6 +317,8 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc*/ mtspr (SPRN_HDEC , hdec); +mtspr (SPRN_DEC , vcpu->arch.dec_expires - tb); +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM tm_return_to_guest:#endif
@@ -461,6 +463,12 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc vcpu->arch.shregs.sprg2 =mfspr (SPRN_SPRG2 ); vcpu->arch.shregs.sprg3 =mfspr (SPRN_SPRG3 ); + dec =mfspr (SPRN_DEC ); +if (!(lpcr &LPCR_LD ))/* Sign extend if not using large decrementer */ + dec = (s32 ) dec; + tb =mftb (); + vcpu->arch.dec_expires = dec + tb; +/* Preserve PSSCR[FAKE_SUSPEND] until we've called kvmppc_save_tm_hv */ mtspr (SPRN_PSSCR , host_psscr | (local_paca->kvm_hstate.fake_suspend <<PSSCR_FAKE_SUSPEND_LG ));
arch/powerpc/kvm/book3s_hv_rmhandlers.S +0 -13
@@ -814,10 +814,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S) * Set the decrementer to the guest decrementer. */ ld r8,VCPU_DEC_EXPIRES(r4) - /* r8 is a host timebase value here, convert to guest TB */ - ld r5,HSTATE_KVM_VCORE(r13) - ld r6,VCORE_TB_OFFSET_APPL(r5) - add r8,r8,r6 mftb r7 subf r3,r7,r8 mtspr SPRN_DEC,r3
@@ -1192,9 +1188,6 @@ guest_bypass: mftb r6 extsw r5,r5 16: add r5,r5,r6 - /* r5 is a guest timebase value here, convert to host TB */ - ld r4,VCORE_TB_OFFSET_APPL(r3) - subf r5,r4,r5 std r5,VCPU_DEC_EXPIRES(r9) /* Increment exit count, poke other threads to exit */
@@ -2160,9 +2153,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_TM) /* save expiry time of guest decrementer */ add r3, r3, r5 ld r4, HSTATE_KVM_VCPU(r13) - ld r5, HSTATE_KVM_VCORE(r13) - ld r6, VCORE_TB_OFFSET_APPL(r5) - subf r3, r6, r3 /* convert to host TB value */ std r3, VCPU_DEC_EXPIRES(r4) #ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
@@ -2259,9 +2249,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_TM) /* Restore guest decrementer */ ld r3, VCPU_DEC_EXPIRES(r4) - ld r5, HSTATE_KVM_VCORE(r13) - ld r6, VCORE_TB_OFFSET_APPL(r5) - add r3, r3, r6 /* convert host TB to guest TB value */ mftb r7 subf r3, r7, r3 mtspr SPRN_DEC, r3
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 23/53 KVM: PPC: Book3S HV P9: Move TB updates
In reply to Nicholas PigginMove the TB updates between saving and loading guest and host SPRs, to improve scheduling by keeping issue-NTC operations together as much as possible.
--- arch/powerpc/kvm/book3s_hv_p9_entry.c | 36 +++++++++++++-------------- 1 file changed, 18 insertions(+), 18 deletions(-)
arch/powerpc/kvm/book3s_hv_p9_entry.c +18 -18
@@ -215,15 +215,6 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc vcpu->arch.ceded =0 ; -if (vc->tb_offset) { -u64 new_tb = tb + vc->tb_offset; -mtspr (SPRN_TBU40 , new_tb); - tb =mftb (); -if ((tb &0xffffff ) < (new_tb &0xffffff )) -mtspr (SPRN_TBU40 , new_tb +0x1000000 ); - vc->tb_offset_applied = vc->tb_offset; - } -/* Could avoid mfmsr by passing around, but probably no big deal */ msr =mfmsr ();
@@ -238,6 +229,15 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc host_dawrx1 =mfspr (SPRN_DAWRX1 ); } +if (vc->tb_offset) { +u64 new_tb = tb + vc->tb_offset; +mtspr (SPRN_TBU40 , new_tb); + tb =mftb (); +if ((tb &0xffffff ) < (new_tb &0xffffff )) +mtspr (SPRN_TBU40 , new_tb +0x1000000 ); + vc->tb_offset_applied = vc->tb_offset; + } +if (vc->pcr)mtspr (SPRN_PCR , vc->pcr |PCR_MASK );mtspr (SPRN_DPDES , vc->dpdes);
@@ -469,6 +469,15 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc tb =mftb (); vcpu->arch.dec_expires = dec + tb; +if (vc->tb_offset_applied) { +u64 new_tb = tb - vc->tb_offset_applied; +mtspr (SPRN_TBU40 , new_tb); + tb =mftb (); +if ((tb &0xffffff ) < (new_tb &0xffffff )) +mtspr (SPRN_TBU40 , new_tb +0x1000000 ); + vc->tb_offset_applied =0 ; + } +/* Preserve PSSCR[FAKE_SUSPEND] until we've called kvmppc_save_tm_hv */ mtspr (SPRN_PSSCR , host_psscr | (local_paca->kvm_hstate.fake_suspend <<PSSCR_FAKE_SUSPEND_LG ));
@@ -503,15 +512,6 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcif (vc->pcr)mtspr (SPRN_PCR ,PCR_MASK ); -if (vc->tb_offset_applied) { -u64 new_tb =mftb () - vc->tb_offset_applied; -mtspr (SPRN_TBU40 , new_tb); - tb =mftb (); -if ((tb &0xffffff ) < (new_tb &0xffffff )) -mtspr (SPRN_TBU40 , new_tb +0x1000000 ); - vc->tb_offset_applied =0 ; - } -/* HDEC must be at least as large as DEC, so decrementer_max fits */ mtspr (SPRN_HDEC , decrementer_max);
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 24/53 KVM: PPC: Book3S HV P9: Optimise timebase reads
In reply to Nicholas PigginReduce the number of mfTB executed by passing the current timebase around entry and exit code rather than read it multiple times.
--- arch/powerpc/include/asm/kvm_book3s_64.h | 2 +- arch/powerpc/kvm/book3s_hv.c | 88 +++++++++++++----------- arch/powerpc/kvm/book3s_hv_p9_entry.c | 33 +++++---- 3 files changed, 65 insertions(+), 58 deletions(-)
arch/powerpc/include/asm/kvm_book3s_64.h +1 -1
@@ -154,7 +154,7 @@ static inline bool kvmhv_vcpu_is_radix(struct kvm_vcpu *vcpu) return radix; } -int kvmhv_vcpu_entry_p9 (struct kvm_vcpu *vcpu,u64 time_limit,unsigned long lpcr); +int kvmhv_vcpu_entry_p9 (struct kvm_vcpu *vcpu,u64 time_limit,unsigned long lpcr,u64 *tb);#define KVM_DEFAULT_HPT_ORDER 24/* 16MB HPT by default */ #endif
arch/powerpc/kvm/book3s_hv.c +46 -42
326 lines not on this page · raw message
arch/powerpc/kvm/book3s_hv_p9_entry.c +18 -15
@@ -183,13 +183,13 @@ static void save_clear_guest_mmu(struct kvm *kvm, struct kvm_vcpu *vcpu) } } -int kvmhv_vcpu_entry_p9 (struct kvm_vcpu *vcpu,u64 time_limit,unsigned long lpcr) +int kvmhv_vcpu_entry_p9 (struct kvm_vcpu *vcpu,u64 time_limit,unsigned long lpcr,u64 *tb) {struct kvm *kvm = vcpu->kvm;struct kvm_nested_guest *nested = vcpu->arch.nested;struct kvmppc_vcore *vc = vcpu->arch.vcore;s64 hdec, dec; -u64 tb, purr, spurr; +u64 purr, spurr;u64 *exsave;bool ri_set;int trap;
@@ -203,8 +203,7 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcunsigned long host_dawr1;unsigned long host_dawrx1; - tb =mftb (); - hdec = time_limit - tb; + hdec = time_limit - *tb;if (hdec <0 )return BOOK3S_INTERRUPT_HV_DECREMENTER ;
@@ -230,11 +229,13 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc }if (vc->tb_offset) { -u64 new_tb = tb + vc->tb_offset; +u64 new_tb = *tb + vc->tb_offset;mtspr (SPRN_TBU40 , new_tb); - tb =mftb (); -if ((tb &0xffffff ) < (new_tb &0xffffff )) -mtspr (SPRN_TBU40 , new_tb +0x1000000 ); +if ((mftb () &0xffffff ) < (new_tb &0xffffff )) { + new_tb +=0x1000000 ; +mtspr (SPRN_TBU40 , new_tb); + } + *tb = new_tb; vc->tb_offset_applied = vc->tb_offset; }
@@ -317,7 +318,7 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc*/ mtspr (SPRN_HDEC , hdec); -mtspr (SPRN_DEC , vcpu->arch.dec_expires - tb); +mtspr (SPRN_DEC , vcpu->arch.dec_expires - *tb);#ifdef CONFIG_PPC_TRANSACTIONAL_MEM tm_return_to_guest:
@@ -466,15 +467,17 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc dec =mfspr (SPRN_DEC );if (!(lpcr &LPCR_LD ))/* Sign extend if not using large decrementer */ dec = (s32 ) dec; - tb =mftb (); - vcpu->arch.dec_expires = dec + tb; + *tb =mftb (); + vcpu->arch.dec_expires = dec + *tb;if (vc->tb_offset_applied) { -u64 new_tb = tb - vc->tb_offset_applied; +u64 new_tb = *tb - vc->tb_offset_applied;mtspr (SPRN_TBU40 , new_tb); - tb =mftb (); -if ((tb &0xffffff ) < (new_tb &0xffffff )) -mtspr (SPRN_TBU40 , new_tb +0x1000000 ); +if ((mftb () &0xffffff ) < (new_tb &0xffffff )) { + new_tb +=0x1000000 ; +mtspr (SPRN_TBU40 , new_tb); + } + *tb = new_tb; vc->tb_offset_applied =0 ; }
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 25/53 KVM: PPC: Book3S HV P9: Avoid SPR scoreboard stalls
In reply to Nicholas PigginAvoid interleaving mfSPR and mtSPR to reduce SPR scoreboard stalls.
--- arch/powerpc/kvm/book3s_hv.c | 8 ++++---- arch/powerpc/kvm/book3s_hv_p9_entry.c | 19 +++++++++++-------- 2 files changed, 15 insertions(+), 12 deletions(-)
arch/powerpc/kvm/book3s_hv.c +4 -4
@@ -4321,10 +4321,6 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,store_spr_state (vcpu); -timer_rearm_host_dec (*tb); - -restore_p9_host_os_sprs (vcpu, &host_os_sprs); -store_fp_state (&vcpu->arch.fp);#ifdef CONFIG_ALTIVEC store_vr_state (&vcpu->arch.vr);
@@ -4339,6 +4335,10 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,switch_pmu_to_host (vcpu, &host_os_sprs); +timer_rearm_host_dec (*tb); + +restore_p9_host_os_sprs (vcpu, &host_os_sprs); + vc->entry_exit_map =0x101 ; vc->in_guest =0 ;
arch/powerpc/kvm/book3s_hv_p9_entry.c +11 -8
@@ -228,6 +228,9 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc host_dawrx1 =mfspr (SPRN_DAWRX1 ); } + local_paca->kvm_hstate.host_purr =mfspr (SPRN_PURR ); + local_paca->kvm_hstate.host_spurr =mfspr (SPRN_SPURR ); +if (vc->tb_offset) {u64 new_tb = *tb + vc->tb_offset;mtspr (SPRN_TBU40 , new_tb);
@@ -244,8 +247,6 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcmtspr (SPRN_DPDES , vc->dpdes);mtspr (SPRN_VTB , vc->vtb); - local_paca->kvm_hstate.host_purr =mfspr (SPRN_PURR ); - local_paca->kvm_hstate.host_spurr =mfspr (SPRN_SPURR );mtspr (SPRN_PURR , vcpu->arch.purr);mtspr (SPRN_SPURR , vcpu->arch.spurr);
@@ -448,10 +449,8 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc/* Advance host PURR/SPURR by the amount used by guest */ purr =mfspr (SPRN_PURR ); spurr =mfspr (SPRN_SPURR ); -mtspr (SPRN_PURR , local_paca->kvm_hstate.host_purr + - purr - vcpu->arch.purr); -mtspr (SPRN_SPURR , local_paca->kvm_hstate.host_spurr + - spurr - vcpu->arch.spurr); + local_paca->kvm_hstate.host_purr += purr - vcpu->arch.purr; + local_paca->kvm_hstate.host_spurr += spurr - vcpu->arch.spurr; vcpu->arch.purr = purr; vcpu->arch.spurr = spurr;
@@ -464,6 +463,9 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc vcpu->arch.shregs.sprg2 =mfspr (SPRN_SPRG2 ); vcpu->arch.shregs.sprg3 =mfspr (SPRN_SPRG3 ); + vc->dpdes =mfspr (SPRN_DPDES ); + vc->vtb =mfspr (SPRN_VTB ); + dec =mfspr (SPRN_DEC );if (!(lpcr &LPCR_LD ))/* Sign extend if not using large decrementer */ dec = (s32 ) dec;
@@ -481,6 +483,9 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc vc->tb_offset_applied =0 ; } +mtspr (SPRN_PURR , local_paca->kvm_hstate.host_purr); +mtspr (SPRN_SPURR , local_paca->kvm_hstate.host_spurr); +/* Preserve PSSCR[FAKE_SUSPEND] until we've called kvmppc_save_tm_hv */ mtspr (SPRN_PSSCR , host_psscr | (local_paca->kvm_hstate.fake_suspend <<PSSCR_FAKE_SUSPEND_LG ));
@@ -509,8 +514,6 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcif (cpu_has_feature (CPU_FTR_ARCH_31 )) asm volatile(PPC_CP_ABORT); - vc->dpdes =mfspr (SPRN_DPDES ); - vc->vtb =mfspr (SPRN_VTB );mtspr (SPRN_DPDES ,0 );if (vc->pcr)mtspr (SPRN_PCR ,PCR_MASK );
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 26/53 KVM: PPC: Book3S HV P9: Only execute mtSPR if the value changed
In reply to Nicholas PigginKeep better track of the current SPR value in places where they are to be loaded with a new context, to reduce expensive mtSPR operations.
--- arch/powerpc/kvm/book3s_hv.c | 51 ++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 20 deletions(-)
arch/powerpc/kvm/book3s_hv.c +31 -20
@@ -4055,20 +4055,28 @@ static void switch_pmu_to_host(struct kvm_vcpu *vcpu, } } -static void load_spr_state (struct kvm_vcpu *vcpu) +static void load_spr_state (struct kvm_vcpu *vcpu, +struct p9_host_os_sprs *host_os_sprs) { -mtspr (SPRN_DSCR , vcpu->arch.dscr); -mtspr (SPRN_IAMR , vcpu->arch.iamr); -mtspr (SPRN_PSPB , vcpu->arch.pspb); -mtspr (SPRN_FSCR , vcpu->arch.fscr);mtspr (SPRN_TAR , vcpu->arch.tar);mtspr (SPRN_EBBHR , vcpu->arch.ebbhr);mtspr (SPRN_EBBRR , vcpu->arch.ebbrr);mtspr (SPRN_BESCR , vcpu->arch.bescr); +if (cpu_has_feature (CPU_FTR_P9_TIDR ))mtspr (SPRN_TIDR , vcpu->arch.tid); -mtspr (SPRN_AMR , vcpu->arch.amr); -mtspr (SPRN_UAMOR , vcpu->arch.uamor); +if (host_os_sprs->iamr != vcpu->arch.iamr) +mtspr (SPRN_IAMR , vcpu->arch.iamr); +if (host_os_sprs->amr != vcpu->arch.amr) +mtspr (SPRN_AMR , vcpu->arch.amr); +if (vcpu->arch.uamor !=0 ) +mtspr (SPRN_UAMOR , vcpu->arch.uamor); +if (host_os_sprs->fscr != vcpu->arch.fscr) +mtspr (SPRN_FSCR , vcpu->arch.fscr); +if (host_os_sprs->dscr != vcpu->arch.dscr) +mtspr (SPRN_DSCR , vcpu->arch.dscr); +if (vcpu->arch.pspb !=0 ) +mtspr (SPRN_PSPB , vcpu->arch.pspb);/* * DAR, DSISR, and for nested HV, SPRGs must be set with MSR[RI]
@@ -4083,20 +4091,21 @@ static void load_spr_state(struct kvm_vcpu *vcpu)static void store_spr_state (struct kvm_vcpu *vcpu) { - vcpu->arch.ctrl =mfspr (SPRN_CTRLF ); - - vcpu->arch.iamr =mfspr (SPRN_IAMR ); - vcpu->arch.pspb =mfspr (SPRN_PSPB ); - vcpu->arch.fscr =mfspr (SPRN_FSCR ); vcpu->arch.tar =mfspr (SPRN_TAR ); vcpu->arch.ebbhr =mfspr (SPRN_EBBHR ); vcpu->arch.ebbrr =mfspr (SPRN_EBBRR ); vcpu->arch.bescr =mfspr (SPRN_BESCR ); +if (cpu_has_feature (CPU_FTR_P9_TIDR )) vcpu->arch.tid =mfspr (SPRN_TIDR ); + vcpu->arch.iamr =mfspr (SPRN_IAMR ); vcpu->arch.amr =mfspr (SPRN_AMR ); vcpu->arch.uamor =mfspr (SPRN_UAMOR ); + vcpu->arch.fscr =mfspr (SPRN_FSCR ); vcpu->arch.dscr =mfspr (SPRN_DSCR ); + vcpu->arch.pspb =mfspr (SPRN_PSPB ); + + vcpu->arch.ctrl =mfspr (SPRN_CTRLF ); }static void save_p9_host_os_sprs (struct p9_host_os_sprs *host_os_sprs)
@@ -4107,6 +4116,7 @@ static void save_p9_host_os_sprs(struct p9_host_os_sprs *host_os_sprs) host_os_sprs->iamr =mfspr (SPRN_IAMR ); host_os_sprs->amr =mfspr (SPRN_AMR ); host_os_sprs->fscr =mfspr (SPRN_FSCR ); + host_os_sprs->dscr =mfspr (SPRN_DSCR ); }/* vcpu guest regs must already be saved */
@@ -4115,19 +4125,20 @@ static void restore_p9_host_os_sprs(struct kvm_vcpu *vcpu, {mtspr (SPRN_SPRG_VDSO_WRITE , local_paca->sprg_vdso); -mtspr (SPRN_PSPB ,0 ); -mtspr (SPRN_UAMOR ,0 ); - -mtspr (SPRN_DSCR , host_os_sprs->dscr);if (cpu_has_feature (CPU_FTR_P9_TIDR ))mtspr (SPRN_TIDR , host_os_sprs->tidr); -mtspr (SPRN_IAMR , host_os_sprs->iamr); - +if (host_os_sprs->iamr != vcpu->arch.iamr) +mtspr (SPRN_IAMR , host_os_sprs->iamr); +if (vcpu->arch.uamor !=0 ) +mtspr (SPRN_UAMOR ,0 );if (host_os_sprs->amr != vcpu->arch.amr)mtspr (SPRN_AMR , host_os_sprs->amr); -if (host_os_sprs->fscr != vcpu->arch.fscr)mtspr (SPRN_FSCR , host_os_sprs->fscr); +if (host_os_sprs->dscr != vcpu->arch.dscr) +mtspr (SPRN_DSCR , host_os_sprs->dscr); +if (vcpu->arch.pspb !=0 ) +mtspr (SPRN_PSPB ,0 );/* Save guest CTRL register, set runlatch to 1 */ if (!(vcpu->arch.ctrl &1 ))
@@ -4219,7 +4230,7 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,#endif mtspr (SPRN_VRSAVE , vcpu->arch.vrsave); -load_spr_state (vcpu); +load_spr_state (vcpu, &host_os_sprs);if (kvmhv_on_pseries ()) {/*
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 27/53 KVM: PPC: Book3S HV P9: Juggle SPR switching around
In reply to Nicholas PigginThis juggles SPR switching on the entry and exit sides to be more symmetric, which makes the next refactoring patch possible with no functional change.
--- arch/powerpc/kvm/book3s_hv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
arch/powerpc/kvm/book3s_hv.c +4 -4
@@ -4222,7 +4222,7 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, msr =mfmsr ();/* TM restore can update msr */ } -switch_pmu_to_guest (vcpu, &host_os_sprs); +load_spr_state (vcpu, &host_os_sprs);load_fp_state (&vcpu->arch.fp);#ifdef CONFIG_ALTIVEC
@@ -4230,7 +4230,7 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,#endif mtspr (SPRN_VRSAVE , vcpu->arch.vrsave); -load_spr_state (vcpu, &host_os_sprs); +switch_pmu_to_guest (vcpu, &host_os_sprs);if (kvmhv_on_pseries ()) {/*
@@ -4330,6 +4330,8 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, vcpu->arch.slb_max =0 ; } +switch_pmu_to_host (vcpu, &host_os_sprs); +store_spr_state (vcpu);store_fp_state (&vcpu->arch.fp);
@@ -4344,8 +4346,6 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,vcpu_vpa_increment_dispatch (vcpu); -switch_pmu_to_host (vcpu, &host_os_sprs); -timer_rearm_host_dec (*tb);restore_p9_host_os_sprs (vcpu, &host_os_sprs);
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 28/53 KVM: PPC: Book3S HV P9: Move vcpu register save/restore into functions
In reply to Nicholas PigginThis should be no functional difference but makes the caller easier to read.
--- arch/powerpc/kvm/book3s_hv.c | 65 +++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 24 deletions(-)
arch/powerpc/kvm/book3s_hv.c +41 -24
@@ -4108,6 +4108,44 @@ static void store_spr_state(struct kvm_vcpu *vcpu) vcpu->arch.ctrl =mfspr (SPRN_CTRLF ); } +/* Returns true if current MSR and/or guest MSR may have changed */ +static bool load_vcpu_state (struct kvm_vcpu *vcpu, +struct p9_host_os_sprs *host_os_sprs) +{ +bool ret = false; + +if (cpu_has_feature (CPU_FTR_TM ) || +cpu_has_feature (CPU_FTR_P9_TM_HV_ASSIST )) { +kvmppc_restore_tm_hv (vcpu, vcpu->arch.shregs.msr, true); + ret = true; + } + +load_spr_state (vcpu, host_os_sprs); + +load_fp_state (&vcpu->arch.fp); +#ifdef CONFIG_ALTIVEC +load_vr_state (&vcpu->arch.vr); +#endif +mtspr (SPRN_VRSAVE , vcpu->arch.vrsave); + +return ret; +} + +static void store_vcpu_state (struct kvm_vcpu *vcpu) +{ +store_spr_state (vcpu); + +store_fp_state (&vcpu->arch.fp); +#ifdef CONFIG_ALTIVEC +store_vr_state (&vcpu->arch.vr); +#endif + vcpu->arch.vrsave =mfspr (SPRN_VRSAVE ); + +if (cpu_has_feature (CPU_FTR_TM ) || +cpu_has_feature (CPU_FTR_P9_TM_HV_ASSIST )) +kvmppc_save_tm_hv (vcpu, vcpu->arch.shregs.msr, true); +} +static void save_p9_host_os_sprs (struct p9_host_os_sprs *host_os_sprs) { host_os_sprs->dscr =mfspr (SPRN_DSCR );
@@ -4216,19 +4254,8 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,vcpu_vpa_increment_dispatch (vcpu); -if (cpu_has_feature (CPU_FTR_TM ) || -cpu_has_feature (CPU_FTR_P9_TM_HV_ASSIST )) { -kvmppc_restore_tm_hv (vcpu, vcpu->arch.shregs.msr, true); - msr =mfmsr ();/* TM restore can update msr */ - } - -load_spr_state (vcpu, &host_os_sprs); - -load_fp_state (&vcpu->arch.fp); -#ifdef CONFIG_ALTIVEC -load_vr_state (&vcpu->arch.vr); -#endif -mtspr (SPRN_VRSAVE , vcpu->arch.vrsave); +if (unlikely (load_vcpu_state (vcpu, &host_os_sprs))) + msr =mfmsr ();/* MSR may have been updated */ switch_pmu_to_guest (vcpu, &host_os_sprs);
@@ -4332,17 +4359,7 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,switch_pmu_to_host (vcpu, &host_os_sprs); -store_spr_state (vcpu); - -store_fp_state (&vcpu->arch.fp); -#ifdef CONFIG_ALTIVEC -store_vr_state (&vcpu->arch.vr); -#endif - vcpu->arch.vrsave =mfspr (SPRN_VRSAVE ); - -if (cpu_has_feature (CPU_FTR_TM ) || -cpu_has_feature (CPU_FTR_P9_TM_HV_ASSIST )) -kvmppc_save_tm_hv (vcpu, vcpu->arch.shregs.msr, true); +store_vcpu_state (vcpu);vcpu_vpa_increment_dispatch (vcpu);
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 29/53 KVM: PPC: Book3S HV P9: Move host OS save/restore functions to built-in
In reply to Nicholas PigginMove the P9 guest/host register switching functions to the built-in P9 entry code, and export it for nested to use as well.
This allows more flexibility in scheduling these supervisor privileged SPR accesses with the HV privileged and PR SPR accesses in the low level entry code.
--- arch/powerpc/kvm/book3s_hv.c | 379 +------------------------- arch/powerpc/kvm/book3s_hv.h | 45 +++ arch/powerpc/kvm/book3s_hv_p9_entry.c | 353 ++++++++++++++++++++++++ 3 files changed, 399 insertions(+), 378 deletions(-) create mode 100644 arch/powerpc/kvm/book3s_hv.h
arch/powerpc/kvm/book3s_hv.c +1 -378
@@ -80,6 +80,7 @@#include <asm/plpar_wrappers.h> #include "book3s.h" +#include "book3s_hv.h" #define CREATE_TRACE_POINTS #include "trace_hv.h"
@@ -127,11 +128,6 @@ static bool nested = true;module_param (nested, bool,S_IRUGO |S_IWUSR );MODULE_PARM_DESC (nested,"Enable nested virtualization (only on POWER9)" ); -static inline bool nesting_enabled (struct kvm *kvm) -{ -return kvm->arch.nested_enable &&kvm_is_radix (kvm); -} -static int kvmppc_hv_setup_htab_rma (struct kvm_vcpu *vcpu);/*
@@ -3810,379 +3806,6 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)trace_kvmppc_run_core (vc,1 ); } -/* -* Privileged (non-hypervisor) host registers to save. -*/ -struct p9_host_os_sprs { -unsigned long dscr; -unsigned long tidr; -unsigned long iamr; -unsigned long amr; -unsigned long fscr; - -unsigned int pmc1; -unsigned int pmc2; -unsigned int pmc3; -unsigned int pmc4; -unsigned int pmc5; -unsigned int pmc6; -unsigned long mmcr0; -unsigned long mmcr1; -unsigned long mmcr2; -unsigned long mmcr3; -unsigned long mmcra; -unsigned long siar; -unsigned long sier1; -unsigned long sier2; -unsigned long sier3; -unsigned long sdar; -}; - -static void freeze_pmu (unsigned long mmcr0,unsigned long mmcra) -{ -if (!(mmcr0 &MMCR0_FC )) - goto do_freeze; -if (mmcra &MMCRA_SAMPLE_ENABLE ) - goto do_freeze; -if (cpu_has_feature (CPU_FTR_ARCH_31 )) { -if (!(mmcr0 &MMCR0_PMCCEXT )) - goto do_freeze; -if (!(mmcra &MMCRA_BHRB_DISABLE )) - goto do_freeze; - } -return ; - -do_freeze: - mmcr0 =MMCR0_FC ; - mmcra =0 ; -if (cpu_has_feature (CPU_FTR_ARCH_31 )) { - mmcr0 |=MMCR0_PMCCEXT ; - mmcra =MMCRA_BHRB_DISABLE ; - } - -mtspr (SPRN_MMCR0 , mmcr0); -mtspr (SPRN_MMCRA , mmcra); -isync (); -} - -static void switch_pmu_to_guest (struct kvm_vcpu *vcpu, -struct p9_host_os_sprs *host_os_sprs) -{ -struct lppaca *lp; -int load_pmu =1 ; - - lp = vcpu->arch.vpa.pinned_addr; -if (lp) - load_pmu = lp->pmcregs_in_use; - -/* Save host */ -if (ppc_get_pmu_inuse ()) { -/* -* It might be better to put PMU handling (at least for the -* host) in the perf subsystem because it knows more about what -* is being used. -*/ - -/* POWER9, POWER10 do not implement HPMC or SPMC */ - - host_os_sprs->mmcr0 =mfspr (SPRN_MMCR0 ); - host_os_sprs->mmcra =mfspr (SPRN_MMCRA ); - -freeze_pmu (host_os_sprs->mmcr0, host_os_sprs->mmcra); - - host_os_sprs->pmc1 =mfspr (SPRN_PMC1 ); - host_os_sprs->pmc2 =mfspr (SPRN_PMC2 ); - host_os_sprs->pmc3 =mfspr (SPRN_PMC3 ); - host_os_sprs->pmc4 =mfspr (SPRN_PMC4 ); - host_os_sprs->pmc5 =mfspr (SPRN_PMC5 ); - host_os_sprs->pmc6 =mfspr (SPRN_PMC6 ); - host_os_sprs->mmcr1 =mfspr (SPRN_MMCR1 ); - host_os_sprs->mmcr2 =mfspr (SPRN_MMCR2 ); - host_os_sprs->sdar =mfspr (SPRN_SDAR ); - host_os_sprs->siar =mfspr (SPRN_SIAR ); - host_os_sprs->sier1 =mfspr (SPRN_SIER ); - -if (cpu_has_feature (CPU_FTR_ARCH_31 )) { - host_os_sprs->mmcr3 =mfspr (SPRN_MMCR3 ); - host_os_sprs->sier2 =mfspr (SPRN_SIER2 ); - host_os_sprs->sier3 =mfspr (SPRN_SIER3 ); - } - } - -#ifdef CONFIG_PPC_PSERIES -/* After saving PMU, before loading guest PMU, flip pmcregs_in_use */ -if (kvmhv_on_pseries ()) { -barrier (); -get_lppaca ()->pmcregs_in_use = load_pmu; -barrier (); - } -#endif - -/* -* Load guest. If the VPA said the PMCs are not in use but the guest -* tried to access them anyway, HFSCR[PM] will be set by the HFAC -* fault so we can make forward progress. -*/ -if (load_pmu || (vcpu->arch.hfscr &HFSCR_PM )) { -mtspr (SPRN_PMC1 , vcpu->arch.pmc[0 ]); -mtspr (SPRN_PMC2 , vcpu->arch.pmc[1 ]); -mtspr (SPRN_PMC3 , vcpu->arch.pmc[2 ]); -mtspr (SPRN_PMC4 , vcpu->arch.pmc[3 ]); -mtspr (SPRN_PMC5 , vcpu->arch.pmc[4 ]); -mtspr (SPRN_PMC6 , vcpu->arch.pmc[5 ]); -mtspr (SPRN_MMCR1 , vcpu->arch.mmcr[1 ]); -mtspr (SPRN_MMCR2 , vcpu->arch.mmcr[2 ]); -mtspr (SPRN_SDAR , vcpu->arch.sdar); -mtspr (SPRN_SIAR , vcpu->arch.siar); -mtspr (SPRN_SIER , vcpu->arch.sier[0 ]); - -if (cpu_has_feature (CPU_FTR_ARCH_31 )) { -mtspr (SPRN_MMCR3 , vcpu->arch.mmcr[3 ]); -mtspr (SPRN_SIER2 , vcpu->arch.sier[1 ]); -mtspr (SPRN_SIER3 , vcpu->arch.sier[2 ]); - } - -/* Set MMCRA then MMCR0 last */ -mtspr (SPRN_MMCRA , vcpu->arch.mmcra); -mtspr (SPRN_MMCR0 , vcpu->arch.mmcr[0 ]); -/* No isync necessary because we're starting counters */ - -if (!vcpu->arch.nested && - (vcpu->arch.hfscr_permitted &HFSCR_PM )) - vcpu->arch.hfscr |=HFSCR_PM ; - } -} - -static void switch_pmu_to_host (struct kvm_vcpu *vcpu, -struct p9_host_os_sprs *host_os_sprs) -{ -struct lppaca *lp; -int save_pmu =1 ; - - lp = vcpu->arch.vpa.pinned_addr; -if (lp) - save_pmu = lp->pmcregs_in_use; -if (IS_ENABLED (CONFIG_KVM_BOOK3S_HV_NESTED_PMU_WORKAROUND )) { -/* -* Save pmu if this guest is capable of running nested guests. -* This is option is for old L1s that do not set their -* lppaca->pmcregs_in_use properly when entering their L2. -*/ - save_pmu |=nesting_enabled (vcpu->kvm); - } - -if (save_pmu) { - vcpu->arch.mmcr[0 ] =mfspr (SPRN_MMCR0 ); - vcpu->arch.mmcra =mfspr (SPRN_MMCRA ); - -freeze_pmu (vcpu->arch.mmcr[0 ], vcpu->arch.mmcra); - - vcpu->arch.pmc[0 ] =mfspr (SPRN_PMC1 ); - vcpu->arch.pmc[1 ] =mfspr (SPRN_PMC2 ); - vcpu->arch.pmc[2 ] =mfspr (SPRN_PMC3 ); - vcpu->arch.pmc[3 ] =mfspr (SPRN_PMC4 ); - vcpu->arch.pmc[4 ] =mfspr (SPRN_PMC5 ); - vcpu->arch.pmc[5 ] =mfspr (SPRN_PMC6 ); - vcpu->arch.mmcr[1 ] =mfspr (SPRN_MMCR1 ); - vcpu->arch.mmcr[2 ] =mfspr (SPRN_MMCR2 ); - vcpu->arch.sdar =mfspr (SPRN_SDAR ); - vcpu->arch.siar =mfspr (SPRN_SIAR ); - vcpu->arch.sier[0 ] =mfspr (SPRN_SIER ); - -if (cpu_has_feature (CPU_FTR_ARCH_31 )) { - vcpu->arch.mmcr[3 ] =mfspr (SPRN_MMCR3 ); - vcpu->arch.sier[1 ] =mfspr (SPRN_SIER2 ); - vcpu->arch.sier[2 ] =mfspr (SPRN_SIER3 ); - } - - }else if (vcpu->arch.hfscr &HFSCR_PM ) { -/* -* The guest accessed PMC SPRs without specifying they should -* be preserved, or it cleared pmcregs_in_use after the last -* access. Just ensure they are frozen. -*/ -freeze_pmu (mfspr (SPRN_MMCR0 ),mfspr (SPRN_MMCRA )); - -/* -* Demand-fault PMU register access in the guest. -* -* This is used to grab the guest's VPA pmcregs_in_use value -* and reflect it into the host's VPA in the case of a nested -* hypervisor. -* -* It also avoids having to zero-out SPRs after each guest -* exit to avoid side-channels when. -* -* This is cleared here when we exit the guest, so later HFSCR -* interrupt handling can add it back to run the guest with -* PM enabled next time. -*/ -if (!vcpu->arch.nested) - vcpu->arch.hfscr &= ~HFSCR_PM ; - }/* otherwise the PMU should still be frozen */ - -#ifdef CONFIG_PPC_PSERIES -if (kvmhv_on_pseries ()) { -barrier (); -get_lppaca ()->pmcregs_in_use =ppc_get_pmu_inuse (); -barrier (); - } -#endif - -if (ppc_get_pmu_inuse ()) { -mtspr (SPRN_PMC1 , host_os_sprs->pmc1); -mtspr (SPRN_PMC2 , host_os_sprs->pmc2); -mtspr (SPRN_PMC3 , host_os_sprs->pmc3); -mtspr (SPRN_PMC4 , host_os_sprs->pmc4); -mtspr (SPRN_PMC5 , host_os_sprs->pmc5); -mtspr (SPRN_PMC6 , host_os_sprs->pmc6); -mtspr (SPRN_MMCR1 , host_os_sprs->mmcr1); -mtspr (SPRN_MMCR2 , host_os_sprs->mmcr2); -mtspr (SPRN_SDAR , host_os_sprs->sdar); -mtspr (SPRN_SIAR , host_os_sprs->siar); -mtspr (SPRN_SIER , host_os_sprs->sier1); - -if (cpu_has_feature (CPU_FTR_ARCH_31 )) { -mtspr (SPRN_MMCR3 , host_os_sprs->mmcr3); -mtspr (SPRN_SIER2 , host_os_sprs->sier2); -mtspr (SPRN_SIER3 , host_os_sprs->sier3); - } - -/* Set MMCRA then MMCR0 last */ -mtspr (SPRN_MMCRA , host_os_sprs->mmcra); -mtspr (SPRN_MMCR0 , host_os_sprs->mmcr0); -isync (); - } -} - -static void load_spr_state (struct kvm_vcpu *vcpu, -struct p9_host_os_sprs *host_os_sprs) -{ -mtspr (SPRN_TAR , vcpu->arch.tar); -mtspr (SPRN_EBBHR , vcpu->arch.ebbhr); -mtspr (SPRN_EBBRR , vcpu->arch.ebbrr); -mtspr (SPRN_BESCR , vcpu->arch.bescr); - -if (cpu_has_feature (CPU_FTR_P9_TIDR )) -mtspr (SPRN_TIDR , vcpu->arch.tid); -if (host_os_sprs->iamr != vcpu->arch.iamr) -mtspr (SPRN_IAMR , vcpu->arch.iamr); -if (host_os_sprs->amr != vcpu->arch.amr) -mtspr (SPRN_AMR , vcpu->arch.amr); -if (vcpu->arch.uamor !=0 ) -mtspr (SPRN_UAMOR , vcpu->arch.uamor); -if (host_os_sprs->fscr != vcpu->arch.fscr) -mtspr (SPRN_FSCR , vcpu->arch.fscr); -if (host_os_sprs->dscr != vcpu->arch.dscr) -mtspr (SPRN_DSCR , vcpu->arch.dscr); -if (vcpu->arch.pspb !=0 ) -mtspr (SPRN_PSPB , vcpu->arch.pspb); - -/* -* DAR, DSISR, and for nested HV, SPRGs must be set with MSR[RI] -* clear (or hstate set appropriately to catch those registers -* being clobbered if we take a MCE or SRESET), so those are done -* later. -*/ - -if (!(vcpu->arch.ctrl &1 )) -mtspr (SPRN_CTRLT ,0 ); -} - -static void store_spr_state (struct kvm_vcpu *vcpu) -{ - vcpu->arch.tar =mfspr (SPRN_TAR ); - vcpu->arch.ebbhr =mfspr (SPRN_EBBHR ); - vcpu->arch.ebbrr =mfspr (SPRN_EBBRR ); - vcpu->arch.bescr =mfspr (SPRN_BESCR ); - -if (cpu_has_feature (CPU_FTR_P9_TIDR )) - vcpu->arch.tid =mfspr (SPRN_TIDR ); - vcpu->arch.iamr =mfspr (SPRN_IAMR ); - vcpu->arch.amr =mfspr (SPRN_AMR ); - vcpu->arch.uamor =mfspr (SPRN_UAMOR ); - vcpu->arch.fscr =mfspr (SPRN_FSCR ); - vcpu->arch.dscr =mfspr (SPRN_DSCR ); - vcpu->arch.pspb =mfspr (SPRN_PSPB ); - - vcpu->arch.ctrl =mfspr (SPRN_CTRLF ); -} - -/* Returns true if current MSR and/or guest MSR may have changed */ -static bool load_vcpu_state (struct kvm_vcpu *vcpu, -struct p9_host_os_sprs *host_os_sprs) -{ -bool ret = false; - -if (cpu_has_feature (CPU_FTR_TM ) || -cpu_has_feature (CPU_FTR_P9_TM_HV_ASSIST )) { -kvmppc_restore_tm_hv (vcpu, vcpu->arch.shregs.msr, true); - ret = true; - } - -load_spr_state (vcpu, host_os_sprs); - -load_fp_state (&vcpu->arch.fp); -#ifdef CONFIG_ALTIVEC -load_vr_state (&vcpu->arch.vr); -#endif -mtspr (SPRN_VRSAVE , vcpu->arch.vrsave); - -return ret; -} - -static void store_vcpu_state (struct kvm_vcpu *vcpu) -{ -store_spr_state (vcpu); - -store_fp_state (&vcpu->arch.fp); -#ifdef CONFIG_ALTIVEC -store_vr_state (&vcpu->arch.vr); -#endif - vcpu->arch.vrsave =mfspr (SPRN_VRSAVE ); - -if (cpu_has_feature (CPU_FTR_TM ) || -cpu_has_feature (CPU_FTR_P9_TM_HV_ASSIST )) -kvmppc_save_tm_hv (vcpu, vcpu->arch.shregs.msr, true); -} - -static void save_p9_host_os_sprs (struct p9_host_os_sprs *host_os_sprs) -{ - host_os_sprs->dscr =mfspr (SPRN_DSCR ); -if (cpu_has_feature (CPU_FTR_P9_TIDR )) - host_os_sprs->tidr =mfspr (SPRN_TIDR ); - host_os_sprs->iamr =mfspr (SPRN_IAMR ); - host_os_sprs->amr =mfspr (SPRN_AMR ); - host_os_sprs->fscr =mfspr (SPRN_FSCR ); - host_os_sprs->dscr =mfspr (SPRN_DSCR ); -} - -/* vcpu guest regs must already be saved */ -static void restore_p9_host_os_sprs (struct kvm_vcpu *vcpu, -struct p9_host_os_sprs *host_os_sprs) -{ -mtspr (SPRN_SPRG_VDSO_WRITE , local_paca->sprg_vdso); - -if (cpu_has_feature (CPU_FTR_P9_TIDR )) -mtspr (SPRN_TIDR , host_os_sprs->tidr); -if (host_os_sprs->iamr != vcpu->arch.iamr) -mtspr (SPRN_IAMR , host_os_sprs->iamr); -if (vcpu->arch.uamor !=0 ) -mtspr (SPRN_UAMOR ,0 ); -if (host_os_sprs->amr != vcpu->arch.amr) -mtspr (SPRN_AMR , host_os_sprs->amr); -if (host_os_sprs->fscr != vcpu->arch.fscr) -mtspr (SPRN_FSCR , host_os_sprs->fscr); -if (host_os_sprs->dscr != vcpu->arch.dscr) -mtspr (SPRN_DSCR , host_os_sprs->dscr); -if (vcpu->arch.pspb !=0 ) -mtspr (SPRN_PSPB ,0 ); - -/* Save guest CTRL register, set runlatch to 1 */ -if (!(vcpu->arch.ctrl &1 )) -mtspr (SPRN_CTRLT ,1 ); -} -static inline bool hcall_is_xics (unsigned long req) { return req == H_EOI || req == H_CPPR || req == H_IPI ||
arch/powerpc/kvm/book3s_hv.h new file +45 -0
45 lines not on this page · raw message
arch/powerpc/kvm/book3s_hv_p9_entry.c +353 -0
361 lines not on this page · raw message
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 30/53 KVM: PPC: Book3S HV P9: Move nested guest entry into its own function
In reply to Nicholas PigginMove the part of the guest entry which is specific to nested HV into its own function. This is just refactoring.
--- arch/powerpc/kvm/book3s_hv.c | 125 +++++++++++++++++++---------------- 1 file changed, 67 insertions(+), 58 deletions(-)
arch/powerpc/kvm/book3s_hv.c +67 -58
@@ -3822,6 +3822,72 @@ static void vcpu_vpa_increment_dispatch(struct kvm_vcpu *vcpu) } } +/* call our hypervisor to load up HV regs and go */ +static int kvmhv_vcpu_entry_p9_nested (struct kvm_vcpu *vcpu,u64 time_limit,unsigned long lpcr,u64 *tb) +{ +struct kvmppc_vcore *vc = vcpu->arch.vcore; +unsigned long host_psscr; +struct hv_guest_state hvregs; +int trap; +s64 dec; + +/* +* We need to save and restore the guest visible part of the +* psscr (i.e. using SPRN_PSSCR_PR) since the hypervisor +* doesn't do this for us. Note only required if pseries since +* this is done in kvmhv_vcpu_entry_p9() below otherwise. +*/ + host_psscr =mfspr (SPRN_PSSCR_PR ); +mtspr (SPRN_PSSCR_PR , vcpu->arch.psscr); +kvmhv_save_hv_regs (vcpu, &hvregs); + hvregs.lpcr = lpcr; + vcpu->arch.regs.msr = vcpu->arch.shregs.msr; + hvregs.version =HV_GUEST_STATE_VERSION ; +if (vcpu->arch.nested) { + hvregs.lpid = vcpu->arch.nested->shadow_lpid; + hvregs.vcpu_token = vcpu->arch.nested_vcpu_id; + }else { + hvregs.lpid = vcpu->kvm->arch.lpid; + hvregs.vcpu_token = vcpu->vcpu_id; + } + hvregs.hdec_expiry = time_limit; + +/* +* When setting DEC, we must always deal with irq_work_raise +* via NMI vs setting DEC. The problem occurs right as we +* switch into guest mode if a NMI hits and sets pending work +* and sets DEC, then that will apply to the guest and not +* bring us back to the host. +* +* irq_work_raise could check a flag (or possibly LPCR[HDICE] +* for example) and set HDEC to 1? That wouldn't solve the +* nested hv case which needs to abort the hcall or zero the +* time limit. +* +* XXX: Another day's problem. +*/ +mtspr (SPRN_DEC ,kvmppc_dec_expires_host_tb (vcpu) - *tb); + +mtspr (SPRN_DAR , vcpu->arch.shregs.dar); +mtspr (SPRN_DSISR , vcpu->arch.shregs.dsisr); + trap =plpar_hcall_norets (H_ENTER_NESTED ,__pa (&hvregs), +__pa (&vcpu->arch.regs)); +kvmhv_restore_hv_return_state (vcpu, &hvregs); + vcpu->arch.shregs.msr = vcpu->arch.regs.msr; + vcpu->arch.shregs.dar =mfspr (SPRN_DAR ); + vcpu->arch.shregs.dsisr =mfspr (SPRN_DSISR ); + vcpu->arch.psscr =mfspr (SPRN_PSSCR_PR ); +mtspr (SPRN_PSSCR_PR , host_psscr); + + dec =mfspr (SPRN_DEC ); +if (!(lpcr &LPCR_LD ))/* Sign extend if not using large decrementer */ + dec = (s32 ) dec; + *tb =mftb (); + vcpu->arch.dec_expires = dec + (*tb + vc->tb_offset); + +return trap; +} +/* * Guest entry for POWER9 and later CPUs. */
@@ -3830,7 +3896,6 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, {struct kvmppc_vcore *vc = vcpu->arch.vcore;struct p9_host_os_sprs host_os_sprs; -s64 dec;u64 next_timer;unsigned long msr;int trap;
@@ -3883,63 +3948,7 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,switch_pmu_to_guest (vcpu, &host_os_sprs);if (kvmhv_on_pseries ()) { -/* -* We need to save and restore the guest visible part of the -* psscr (i.e. using SPRN_PSSCR_PR) since the hypervisor -* doesn't do this for us. Note only required if pseries since -* this is done in kvmhv_vcpu_entry_p9() below otherwise. -*/ -unsigned long host_psscr; -/* call our hypervisor to load up HV regs and go */ -struct hv_guest_state hvregs; - - host_psscr =mfspr (SPRN_PSSCR_PR ); -mtspr (SPRN_PSSCR_PR , vcpu->arch.psscr); -kvmhv_save_hv_regs (vcpu, &hvregs); - hvregs.lpcr = lpcr; - vcpu->arch.regs.msr = vcpu->arch.shregs.msr; - hvregs.version =HV_GUEST_STATE_VERSION ; -if (vcpu->arch.nested) { - hvregs.lpid = vcpu->arch.nested->shadow_lpid; - hvregs.vcpu_token = vcpu->arch.nested_vcpu_id; - }else { - hvregs.lpid = vcpu->kvm->arch.lpid; - hvregs.vcpu_token = vcpu->vcpu_id; - } - hvregs.hdec_expiry = time_limit; - -/* -* When setting DEC, we must always deal with irq_work_raise -* via NMI vs setting DEC. The problem occurs right as we -* switch into guest mode if a NMI hits and sets pending work -* and sets DEC, then that will apply to the guest and not -* bring us back to the host. -* -* irq_work_raise could check a flag (or possibly LPCR[HDICE] -* for example) and set HDEC to 1? That wouldn't solve the -* nested hv case which needs to abort the hcall or zero the -* time limit. -* -* XXX: Another day's problem. -*/ -mtspr (SPRN_DEC ,kvmppc_dec_expires_host_tb (vcpu) - *tb); - -mtspr (SPRN_DAR , vcpu->arch.shregs.dar); -mtspr (SPRN_DSISR , vcpu->arch.shregs.dsisr); - trap =plpar_hcall_norets (H_ENTER_NESTED ,__pa (&hvregs), -__pa (&vcpu->arch.regs)); -kvmhv_restore_hv_return_state (vcpu, &hvregs); - vcpu->arch.shregs.msr = vcpu->arch.regs.msr; - vcpu->arch.shregs.dar =mfspr (SPRN_DAR ); - vcpu->arch.shregs.dsisr =mfspr (SPRN_DSISR ); - vcpu->arch.psscr =mfspr (SPRN_PSSCR_PR ); -mtspr (SPRN_PSSCR_PR , host_psscr); - - dec =mfspr (SPRN_DEC ); -if (!(lpcr &LPCR_LD ))/* Sign extend if not using large decrementer */ - dec = (s32 ) dec; - *tb =mftb (); - vcpu->arch.dec_expires = dec + (*tb + vc->tb_offset); + trap =kvmhv_vcpu_entry_p9_nested (vcpu, time_limit, lpcr, tb);/* H_CEDE has to be handled now, not later */ if (trap == BOOK3S_INTERRUPT_SYSCALL && !vcpu->arch.nested &&
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 31/53 KVM: PPC: Book3S HV P9: Move remaining SPR and MSR access into low level entry
In reply to Nicholas PigginMove register saving and loading from kvmhv_p9_guest_entry() into the HV and nested entry handlers.
Accesses are scheduled to reduce mtSPR / mfSPR interleaving which reduces SPR scoreboard stalls.
--- arch/powerpc/kvm/book3s_hv.c | 79 ++++++++++------------ arch/powerpc/kvm/book3s_hv_p9_entry.c | 96 ++++++++++++++++++++------- 2 files changed, 109 insertions(+), 66 deletions(-)
arch/powerpc/kvm/book3s_hv.c +36 -43
@@ -3827,9 +3827,15 @@ static int kvmhv_vcpu_entry_p9_nested(struct kvm_vcpu *vcpu, u64 time_limit, uns {struct kvmppc_vcore *vc = vcpu->arch.vcore;unsigned long host_psscr; +unsigned long msr;struct hv_guest_state hvregs; -int trap; +struct p9_host_os_sprs host_os_sprs;s64 dec; +int trap; + +switch_pmu_to_guest (vcpu, &host_os_sprs); + +save_p9_host_os_sprs (&host_os_sprs);/* * We need to save and restore the guest visible part of the
@@ -3838,6 +3844,27 @@ static int kvmhv_vcpu_entry_p9_nested(struct kvm_vcpu *vcpu, u64 time_limit, uns* this is done in kvmhv_vcpu_entry_p9() below otherwise. */ host_psscr =mfspr (SPRN_PSSCR_PR ); + +hard_irq_disable (); +if (lazy_irq_pending ()) +return 0 ; + +/* MSR bits may have been cleared by context switch */ + msr =0 ; +if (IS_ENABLED (CONFIG_PPC_FPU )) + msr |=MSR_FP ; +if (cpu_has_feature (CPU_FTR_ALTIVEC )) + msr |=MSR_VEC ; +if (cpu_has_feature (CPU_FTR_VSX )) + msr |=MSR_VSX ; +if (cpu_has_feature (CPU_FTR_TM ) || +cpu_has_feature (CPU_FTR_P9_TM_HV_ASSIST )) + msr |=MSR_TM ; + msr =msr_check_and_set (msr); + +if (unlikely (load_vcpu_state (vcpu, &host_os_sprs))) + msr =mfmsr ();/* TM restore can update msr */ +mtspr (SPRN_PSSCR_PR , vcpu->arch.psscr);kvmhv_save_hv_regs (vcpu, &hvregs); hvregs.lpcr = lpcr;
@@ -3879,12 +3906,20 @@ static int kvmhv_vcpu_entry_p9_nested(struct kvm_vcpu *vcpu, u64 time_limit, uns vcpu->arch.psscr =mfspr (SPRN_PSSCR_PR );mtspr (SPRN_PSSCR_PR , host_psscr); +store_vcpu_state (vcpu); + dec =mfspr (SPRN_DEC );if (!(lpcr &LPCR_LD ))/* Sign extend if not using large decrementer */ dec = (s32 ) dec; *tb =mftb (); vcpu->arch.dec_expires = dec + (*tb + vc->tb_offset); +timer_rearm_host_dec (*tb); + +restore_p9_host_os_sprs (vcpu, &host_os_sprs); + +switch_pmu_to_host (vcpu, &host_os_sprs); +return trap; }
@@ -3895,9 +3930,7 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcr, u64 *tb) { struct kvmppc_vcore *vc = vcpu->arch.vcore; -struct p9_host_os_sprs host_os_sprs;u64 next_timer; -unsigned long msr;int trap; next_timer =timer_get_next_tb ();
@@ -3908,33 +3941,6 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, vcpu->arch.ceded =0 ; -save_p9_host_os_sprs (&host_os_sprs); - -/* -* This could be combined with MSR[RI] clearing, but that expands -* the unrecoverable window. It would be better to cover unrecoverable -* with KVM bad interrupt handling rather than use MSR[RI] at all. -* -* Much more difficult and less worthwhile to combine with IR/DR -* disable. -*/ -hard_irq_disable (); -if (lazy_irq_pending ()) -return 0 ; - -/* MSR bits may have been cleared by context switch */ - msr =0 ; -if (IS_ENABLED (CONFIG_PPC_FPU )) - msr |=MSR_FP ; -if (cpu_has_feature (CPU_FTR_ALTIVEC )) - msr |=MSR_VEC ; -if (cpu_has_feature (CPU_FTR_VSX )) - msr |=MSR_VSX ; -if (cpu_has_feature (CPU_FTR_TM ) || -cpu_has_feature (CPU_FTR_P9_TM_HV_ASSIST )) - msr |=MSR_TM ; - msr =msr_check_and_set (msr); -kvmppc_subcore_enter_guest (); vc->entry_exit_map =1 ;
@@ -3942,11 +3948,6 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,vcpu_vpa_increment_dispatch (vcpu); -if (unlikely (load_vcpu_state (vcpu, &host_os_sprs))) - msr =mfmsr ();/* MSR may have been updated */ - -switch_pmu_to_guest (vcpu, &host_os_sprs); -if (kvmhv_on_pseries ()) { trap =kvmhv_vcpu_entry_p9_nested (vcpu, time_limit, lpcr, tb);
@@ -3989,16 +3990,8 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, vcpu->arch.slb_max =0 ; } -switch_pmu_to_host (vcpu, &host_os_sprs); - -store_vcpu_state (vcpu); -vcpu_vpa_increment_dispatch (vcpu); -timer_rearm_host_dec (*tb); - -restore_p9_host_os_sprs (vcpu, &host_os_sprs); - vc->entry_exit_map =0x101 ; vc->in_guest =0 ;
arch/powerpc/kvm/book3s_hv_p9_entry.c +73 -23
138 lines not on this page · raw message
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 32/53 KVM: PPC: Book3S HV P9: Implement TM fastpath for guest entry/exit
In reply to Nicholas PigginIf TM is not active, only TM register state needs to be saved and restored, avoiding several mfmsr/mtmsrd instructions and improving performance.
--- arch/powerpc/kvm/book3s_hv_p9_entry.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-)
arch/powerpc/kvm/book3s_hv_p9_entry.c +23 -4
@@ -287,11 +287,20 @@ bool load_vcpu_state(struct kvm_vcpu *vcpu, {bool ret = false; +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM if (cpu_has_feature (CPU_FTR_TM ) ||cpu_has_feature (CPU_FTR_P9_TM_HV_ASSIST )) { -kvmppc_restore_tm_hv (vcpu, vcpu->arch.shregs.msr, true); - ret = true; +unsigned long guest_msr = vcpu->arch.shregs.msr; +if (MSR_TM_ACTIVE (guest_msr)) { +kvmppc_restore_tm_hv (vcpu, guest_msr, true); + ret = true; + }else { +mtspr (SPRN_TEXASR , vcpu->arch.texasr); +mtspr (SPRN_TFHAR , vcpu->arch.tfhar); +mtspr (SPRN_TFIAR , vcpu->arch.tfiar); + } } +#endif load_spr_state (vcpu, host_os_sprs);
@@ -315,9 +324,19 @@ void store_vcpu_state(struct kvm_vcpu *vcpu)#endif vcpu->arch.vrsave =mfspr (SPRN_VRSAVE ); +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM if (cpu_has_feature (CPU_FTR_TM ) || -cpu_has_feature (CPU_FTR_P9_TM_HV_ASSIST )) -kvmppc_save_tm_hv (vcpu, vcpu->arch.shregs.msr, true); +cpu_has_feature (CPU_FTR_P9_TM_HV_ASSIST )) { +unsigned long guest_msr = vcpu->arch.shregs.msr; +if (MSR_TM_ACTIVE (guest_msr)) { +kvmppc_save_tm_hv (vcpu, guest_msr, true); + }else { + vcpu->arch.texasr =mfspr (SPRN_TEXASR ); + vcpu->arch.tfhar =mfspr (SPRN_TFHAR ); + vcpu->arch.tfiar =mfspr (SPRN_TFIAR ); + } + } +#endif }EXPORT_SYMBOL_GPL (store_vcpu_state);
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 33/53 KVM: PPC: Book3S HV P9: Switch PMU to guest as late as possible
In reply to Nicholas PigginThis moves PMU switch to guest as late as possible in entry, and switch back to host as early as possible at exit. This helps the host get the most perf coverage of KVM entry/exit code as possible.
This is slightly suboptimal for SPR scheduling point of view when the PMU is enabled, but when perf is disabled there is no real difference.
--- arch/powerpc/kvm/book3s_hv.c | 6 ++---- arch/powerpc/kvm/book3s_hv_p9_entry.c | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-)
arch/powerpc/kvm/book3s_hv.c +2 -4
@@ -3833,8 +3833,6 @@ static int kvmhv_vcpu_entry_p9_nested(struct kvm_vcpu *vcpu, u64 time_limit, unss64 dec;int trap; -switch_pmu_to_guest (vcpu, &host_os_sprs); -save_p9_host_os_sprs (&host_os_sprs);/*
@@ -3897,9 +3895,11 @@ static int kvmhv_vcpu_entry_p9_nested(struct kvm_vcpu *vcpu, u64 time_limit, unsmtspr (SPRN_DAR , vcpu->arch.shregs.dar);mtspr (SPRN_DSISR , vcpu->arch.shregs.dsisr); +switch_pmu_to_guest (vcpu, &host_os_sprs); trap =plpar_hcall_norets (H_ENTER_NESTED ,__pa (&hvregs),__pa (&vcpu->arch.regs));kvmhv_restore_hv_return_state (vcpu, &hvregs); +switch_pmu_to_host (vcpu, &host_os_sprs); vcpu->arch.shregs.msr = vcpu->arch.regs.msr; vcpu->arch.shregs.dar =mfspr (SPRN_DAR ); vcpu->arch.shregs.dsisr =mfspr (SPRN_DSISR );
@@ -3918,8 +3918,6 @@ static int kvmhv_vcpu_entry_p9_nested(struct kvm_vcpu *vcpu, u64 time_limit, unsrestore_p9_host_os_sprs (vcpu, &host_os_sprs); -switch_pmu_to_host (vcpu, &host_os_sprs); -return trap; }
arch/powerpc/kvm/book3s_hv_p9_entry.c +2 -4
@@ -601,8 +601,6 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc local_paca->kvm_hstate.host_purr =mfspr (SPRN_PURR ); local_paca->kvm_hstate.host_spurr =mfspr (SPRN_SPURR ); -switch_pmu_to_guest (vcpu, &host_os_sprs); -save_p9_host_os_sprs (&host_os_sprs);/*
@@ -744,7 +742,9 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcaccumulate_time (vcpu, &vcpu->arch.guest_time); +switch_pmu_to_guest (vcpu, &host_os_sprs);kvmppc_p9_enter_guest (vcpu); +switch_pmu_to_host (vcpu, &host_os_sprs);accumulate_time (vcpu, &vcpu->arch.rm_intr);
@@ -955,8 +955,6 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc asm volatile(PPC_CP_ABORT); out: -switch_pmu_to_host (vcpu, &host_os_sprs); -end_timing (vcpu);return trap;
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 34/53 KVM: PPC: Book3S HV P9: Restrict DSISR canary workaround to processors that require it
In reply to Nicholas PigginUse CPU_FTR_P9_RADIX_PREFETCH_BUG to apply the workaround, to test for DD2.1 and below processors. This saves a mtSPR in guest entry.
--- arch/powerpc/kvm/book3s_hv.c | 3 ++- arch/powerpc/kvm/book3s_hv_p9_entry.c | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-)
arch/powerpc/kvm/book3s_hv.c +2 -1
@@ -1590,7 +1590,8 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu,unsigned long vsid;long err; -if (vcpu->arch.fault_dsisr ==HDSISR_CANARY ) { +if (cpu_has_feature (CPU_FTR_P9_RADIX_PREFETCH_BUG ) && +unlikely (vcpu->arch.fault_dsisr ==HDSISR_CANARY )) { r =RESUME_GUEST ;/* Just retry if it's the canary */ break ; }
arch/powerpc/kvm/book3s_hv_p9_entry.c +4 -2
@@ -683,9 +683,11 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc* HDSI which should correctly update the HDSISR the second time HDSI * entry. * -* Just do this on all p9 processors for now. +* The "radix prefetch bug" test can be used to test for this bug, as +* it also exists fo DD2.1 and below. */ -mtspr (SPRN_HDSISR ,HDSISR_CANARY ); +if (cpu_has_feature (CPU_FTR_P9_RADIX_PREFETCH_BUG )) +mtspr (SPRN_HDSISR ,HDSISR_CANARY );mtspr (SPRN_SPRG0 , vcpu->arch.shregs.sprg0);mtspr (SPRN_SPRG1 , vcpu->arch.shregs.sprg1);
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 35/53 KVM: PPC: Book3S HV P9: More SPR speed improvements
In reply to Nicholas PigginThis avoids more scoreboard stalls and reduces mtSPRs.
--- arch/powerpc/kvm/book3s_hv_p9_entry.c | 73 ++++++++++++++++----------- 1 file changed, 43 insertions(+), 30 deletions(-)
arch/powerpc/kvm/book3s_hv_p9_entry.c +43 -30
@@ -645,24 +645,29 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc vc->tb_offset_applied = vc->tb_offset; } -if (vc->pcr) -mtspr (SPRN_PCR , vc->pcr |PCR_MASK ); -mtspr (SPRN_DPDES , vc->dpdes);mtspr (SPRN_VTB , vc->vtb); -mtspr (SPRN_PURR , vcpu->arch.purr);mtspr (SPRN_SPURR , vcpu->arch.spurr); +if (vc->pcr) +mtspr (SPRN_PCR , vc->pcr |PCR_MASK ); +if (vc->dpdes) +mtspr (SPRN_DPDES , vc->dpdes); +if (dawr_enabled ()) { -mtspr (SPRN_DAWR0 , vcpu->arch.dawr0); -mtspr (SPRN_DAWRX0 , vcpu->arch.dawrx0); +if (vcpu->arch.dawr0 != host_dawr0) +mtspr (SPRN_DAWR0 , vcpu->arch.dawr0); +if (vcpu->arch.dawrx0 != host_dawrx0) +mtspr (SPRN_DAWRX0 , vcpu->arch.dawrx0);if (cpu_has_feature (CPU_FTR_DAWR1 )) { -mtspr (SPRN_DAWR1 , vcpu->arch.dawr1); -mtspr (SPRN_DAWRX1 , vcpu->arch.dawrx1); +if (vcpu->arch.dawr1 != host_dawr1) +mtspr (SPRN_DAWR1 , vcpu->arch.dawr1); +if (vcpu->arch.dawrx1 != host_dawrx1) +mtspr (SPRN_DAWRX1 , vcpu->arch.dawrx1); } } -mtspr (SPRN_CIABR , vcpu->arch.ciabr); -mtspr (SPRN_IC , vcpu->arch.ic); +if (vcpu->arch.ciabr != host_ciabr) +mtspr (SPRN_CIABR , vcpu->arch.ciabr);mtspr (SPRN_PSSCR , vcpu->arch.psscr |PSSCR_EC | (local_paca->kvm_hstate.fake_suspend <<PSSCR_FAKE_SUSPEND_LG ));
@@ -881,20 +886,6 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc vc->dpdes =mfspr (SPRN_DPDES ); vc->vtb =mfspr (SPRN_VTB ); -save_clear_guest_mmu (kvm, vcpu); -switch_mmu_to_host (kvm, host_pidr); - -/* -* If we are in real mode, only switch MMU on after the MMU is -* switched to host, to avoid the P9_RADIX_PREFETCH_BUG. -*/ -if (IS_ENABLED (CONFIG_PPC_TRANSACTIONAL_MEM ) && - vcpu->arch.shregs.msr &MSR_TS_MASK ) - msr |=MSR_TS_S ; -__mtmsrd (msr,0 ); - -store_vcpu_state (vcpu); - dec =mfspr (SPRN_DEC );if (!(lpcr &LPCR_LD ))/* Sign extend if not using large decrementer */ dec = (s32 ) dec;
@@ -912,6 +903,22 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc vc->tb_offset_applied =0 ; } +save_clear_guest_mmu (kvm, vcpu); +switch_mmu_to_host (kvm, host_pidr); + +/* +* Enable MSR here in order to have facilities enabled to save +* guest registers. This enables MMU (if we were in realmode), so +* only switch MMU on after the MMU is switched to host, to avoid +* the P9_RADIX_PREFETCH_BUG or hash guest context. +*/ +if (IS_ENABLED (CONFIG_PPC_TRANSACTIONAL_MEM ) && + vcpu->arch.shregs.msr &MSR_TS_MASK ) + msr |=MSR_TS_S ; +__mtmsrd (msr,0 ); + +store_vcpu_state (vcpu); +mtspr (SPRN_PURR , local_paca->kvm_hstate.host_purr);mtspr (SPRN_SPURR , local_paca->kvm_hstate.host_spurr);
@@ -919,15 +926,21 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcmtspr (SPRN_PSSCR , host_psscr | (local_paca->kvm_hstate.fake_suspend <<PSSCR_FAKE_SUSPEND_LG ));mtspr (SPRN_HFSCR , host_hfscr); -mtspr (SPRN_CIABR , host_ciabr); -mtspr (SPRN_DAWR0 , host_dawr0); -mtspr (SPRN_DAWRX0 , host_dawrx0); +if (vcpu->arch.ciabr != host_ciabr) +mtspr (SPRN_CIABR , host_ciabr); +if (vcpu->arch.dawr0 != host_dawr0) +mtspr (SPRN_DAWR0 , host_dawr0); +if (vcpu->arch.dawrx0 != host_dawrx0) +mtspr (SPRN_DAWRX0 , host_dawrx0);if (cpu_has_feature (CPU_FTR_DAWR1 )) { -mtspr (SPRN_DAWR1 , host_dawr1); -mtspr (SPRN_DAWRX1 , host_dawrx1); +if (vcpu->arch.dawr1 != host_dawr1) +mtspr (SPRN_DAWR1 , host_dawr1); +if (vcpu->arch.dawrx1 != host_dawrx1) +mtspr (SPRN_DAWRX1 , host_dawrx1); } -mtspr (SPRN_DPDES ,0 ); +if (vc->dpdes) +mtspr (SPRN_DPDES ,0 );if (vc->pcr)mtspr (SPRN_PCR ,PCR_MASK );
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 36/53 KVM: PPC: Book3S HV P9: Demand fault EBB facility registers
In reply to Nicholas PigginUse HFSCR facility disabling to implement demand faulting for EBB, with a hysteresis counter similar to the load_fp etc counters in context switching that implement the equivalent demand faulting for userspace facilities.
This speeds up guest entry/exit by avoiding the register save/restore when a guest is not frequently using them. When a guest does use them often, there will be some additional demand fault overhead, but these are not commonly used facilities.
--- arch/powerpc/include/asm/kvm_host.h | 1 + arch/powerpc/kvm/book3s_hv.c | 16 +++++++++++++-- arch/powerpc/kvm/book3s_hv_p9_entry.c | 28 +++++++++++++++++++++------ 3 files changed, 37 insertions(+), 8 deletions(-)
arch/powerpc/include/asm/kvm_host.h +1 -0
@@ -579,6 +579,7 @@ struct kvm_vcpu_arch {ulong cfar;ulong ppr;u32 pspb; +u8 load_ebb;ulong fscr;ulong shadow_fscr;ulong ebbhr;
arch/powerpc/kvm/book3s_hv.c +14 -2
@@ -1436,6 +1436,16 @@ static int kvmppc_pmu_unavailable(struct kvm_vcpu *vcpu)return RESUME_GUEST ; } +static int kvmppc_ebb_unavailable (struct kvm_vcpu *vcpu) +{ +if (!(vcpu->arch.hfscr_permitted &HFSCR_EBB )) +return EMULATE_FAIL ; + + vcpu->arch.hfscr |=HFSCR_EBB ; + +return RESUME_GUEST ; +} +static int kvmppc_handle_exit_hv (struct kvm_vcpu *vcpu,struct task_struct *tsk) {
@@ -1727,6 +1737,8 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, r =kvmppc_emulate_doorbell_instr (vcpu);if (cause ==FSCR_PM_LG ) r =kvmppc_pmu_unavailable (vcpu); +if (cause ==FSCR_EBB_LG ) + r =kvmppc_ebb_unavailable (vcpu); }if (r ==EMULATE_FAIL ) {kvmppc_core_queue_program (vcpu,SRR1_PROGILL );
@@ -2771,9 +2783,9 @@ static int kvmppc_core_vcpu_create_hv(struct kvm_vcpu *vcpu) vcpu->arch.hfscr_permitted = vcpu->arch.hfscr;/* -* PM is demand-faulted so start with it clear. +* PM, EBB is demand-faulted so start with it clear. */ - vcpu->arch.hfscr &= ~HFSCR_PM ; + vcpu->arch.hfscr &= ~(HFSCR_PM |HFSCR_EBB );kvmppc_mmu_book3s_hv_init (vcpu);
arch/powerpc/kvm/book3s_hv_p9_entry.c +22 -6
@@ -232,9 +232,12 @@ static void load_spr_state(struct kvm_vcpu *vcpu, struct p9_host_os_sprs *host_os_sprs) {mtspr (SPRN_TAR , vcpu->arch.tar); -mtspr (SPRN_EBBHR , vcpu->arch.ebbhr); -mtspr (SPRN_EBBRR , vcpu->arch.ebbrr); -mtspr (SPRN_BESCR , vcpu->arch.bescr); + +if (vcpu->arch.hfscr &HFSCR_EBB ) { +mtspr (SPRN_EBBHR , vcpu->arch.ebbhr); +mtspr (SPRN_EBBRR , vcpu->arch.ebbrr); +mtspr (SPRN_BESCR , vcpu->arch.bescr); + }if (cpu_has_feature (CPU_FTR_P9_TIDR ))mtspr (SPRN_TIDR , vcpu->arch.tid);
@@ -265,9 +268,22 @@ static void load_spr_state(struct kvm_vcpu *vcpu,static void store_spr_state (struct kvm_vcpu *vcpu) { vcpu->arch.tar =mfspr (SPRN_TAR ); - vcpu->arch.ebbhr =mfspr (SPRN_EBBHR ); - vcpu->arch.ebbrr =mfspr (SPRN_EBBRR ); - vcpu->arch.bescr =mfspr (SPRN_BESCR ); + +if (vcpu->arch.hfscr &HFSCR_EBB ) { + vcpu->arch.ebbhr =mfspr (SPRN_EBBHR ); + vcpu->arch.ebbrr =mfspr (SPRN_EBBRR ); + vcpu->arch.bescr =mfspr (SPRN_BESCR ); +/* +* This is like load_fp in context switching, turn off the +* facility after it wraps the u8 to try avoiding saving +* and restoring the registers each partition switch. +*/ +if (!vcpu->arch.nested) { + vcpu->arch.load_ebb++; +if (!vcpu->arch.load_ebb) + vcpu->arch.hfscr &= ~HFSCR_EBB ; + } + }if (cpu_has_feature (CPU_FTR_P9_TIDR )) vcpu->arch.tid =mfspr (SPRN_TIDR );
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 37/53 KVM: PPC: Book3S HV P9: Demand fault TM facility registers
In reply to Nicholas PigginUse HFSCR facility disabling to implement demand faulting for TM, with a hysteresis counter similar to the load_fp etc counters in context switching that implement the equivalent demand faulting for userspace facilities.
This speeds up guest entry/exit by avoiding the register save/restore when a guest is not frequently using them. When a guest does use them often, there will be some additional demand fault overhead, but these are not commonly used facilities.
--- arch/powerpc/include/asm/kvm_host.h | 3 +++ arch/powerpc/kvm/book3s_hv.c | 26 ++++++++++++++++++++------ arch/powerpc/kvm/book3s_hv_p9_entry.c | 15 +++++++++++---- 3 files changed, 34 insertions(+), 10 deletions(-)
arch/powerpc/include/asm/kvm_host.h +3 -0
@@ -580,6 +580,9 @@ struct kvm_vcpu_arch {ulong ppr;u32 pspb;u8 load_ebb; +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +u8 load_tm; +#endif ulong fscr;ulong shadow_fscr;ulong ebbhr;
arch/powerpc/kvm/book3s_hv.c +20 -6
@@ -1446,6 +1446,16 @@ static int kvmppc_ebb_unavailable(struct kvm_vcpu *vcpu)return RESUME_GUEST ; } +static int kvmppc_tm_unavailable (struct kvm_vcpu *vcpu) +{ +if (!(vcpu->arch.hfscr_permitted &HFSCR_TM )) +return EMULATE_FAIL ; + + vcpu->arch.hfscr |=HFSCR_TM ; + +return RESUME_GUEST ; +} +static int kvmppc_handle_exit_hv (struct kvm_vcpu *vcpu,struct task_struct *tsk) {
@@ -1739,6 +1749,8 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, r =kvmppc_pmu_unavailable (vcpu);if (cause ==FSCR_EBB_LG ) r =kvmppc_ebb_unavailable (vcpu); +if (cause ==FSCR_TM_LG ) + r =kvmppc_tm_unavailable (vcpu); }if (r ==EMULATE_FAIL ) {kvmppc_core_queue_program (vcpu,SRR1_PROGILL );
@@ -2783,9 +2795,9 @@ static int kvmppc_core_vcpu_create_hv(struct kvm_vcpu *vcpu) vcpu->arch.hfscr_permitted = vcpu->arch.hfscr;/* -* PM, EBB is demand-faulted so start with it clear. +* PM, EBB, TM are demand-faulted so start with it clear. */ - vcpu->arch.hfscr &= ~(HFSCR_PM |HFSCR_EBB ); + vcpu->arch.hfscr &= ~(HFSCR_PM |HFSCR_EBB |HFSCR_TM );kvmppc_mmu_book3s_hv_init (vcpu);
@@ -3868,8 +3880,9 @@ static int kvmhv_vcpu_entry_p9_nested(struct kvm_vcpu *vcpu, u64 time_limit, uns msr |=MSR_VEC ;if (cpu_has_feature (CPU_FTR_VSX )) msr |=MSR_VSX ; -if (cpu_has_feature (CPU_FTR_TM ) || -cpu_has_feature (CPU_FTR_P9_TM_HV_ASSIST )) +if ((cpu_has_feature (CPU_FTR_TM ) || +cpu_has_feature (CPU_FTR_P9_TM_HV_ASSIST )) && + (vcpu->arch.hfscr &HFSCR_TM )) msr |=MSR_TM ; msr =msr_check_and_set (msr);
@@ -4608,8 +4621,9 @@ static int kvmppc_vcpu_run_hv(struct kvm_vcpu *vcpu) msr |=MSR_VEC ;if (cpu_has_feature (CPU_FTR_VSX )) msr |=MSR_VSX ; -if (cpu_has_feature (CPU_FTR_TM ) || -cpu_has_feature (CPU_FTR_P9_TM_HV_ASSIST )) +if ((cpu_has_feature (CPU_FTR_TM ) || +cpu_has_feature (CPU_FTR_P9_TM_HV_ASSIST )) && + (vcpu->arch.hfscr &HFSCR_TM )) msr |=MSR_TM ; msr =msr_check_and_set (msr);
arch/powerpc/kvm/book3s_hv_p9_entry.c +11 -4
@@ -310,7 +310,7 @@ bool load_vcpu_state(struct kvm_vcpu *vcpu,if (MSR_TM_ACTIVE (guest_msr)) {kvmppc_restore_tm_hv (vcpu, guest_msr, true); ret = true; - }else { + }else if (vcpu->arch.hfscr &HFSCR_TM ) {mtspr (SPRN_TEXASR , vcpu->arch.texasr);mtspr (SPRN_TFHAR , vcpu->arch.tfhar);mtspr (SPRN_TFIAR , vcpu->arch.tfiar);
@@ -346,10 +346,16 @@ void store_vcpu_state(struct kvm_vcpu *vcpu)unsigned long guest_msr = vcpu->arch.shregs.msr;if (MSR_TM_ACTIVE (guest_msr)) {kvmppc_save_tm_hv (vcpu, guest_msr, true); - }else { + }else if (vcpu->arch.hfscr &HFSCR_TM ) { vcpu->arch.texasr =mfspr (SPRN_TEXASR ); vcpu->arch.tfhar =mfspr (SPRN_TFHAR ); vcpu->arch.tfiar =mfspr (SPRN_TFIAR ); + +if (!vcpu->arch.nested) { + vcpu->arch.load_tm++;/* see load_ebb comment */ +if (!vcpu->arch.load_tm) + vcpu->arch.hfscr &= ~HFSCR_TM ; + } } }#endif
@@ -641,8 +647,9 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc msr |=MSR_VEC ;if (cpu_has_feature (CPU_FTR_VSX )) msr |=MSR_VSX ; -if (cpu_has_feature (CPU_FTR_TM ) || -cpu_has_feature (CPU_FTR_P9_TM_HV_ASSIST )) +if ((cpu_has_feature (CPU_FTR_TM ) || +cpu_has_feature (CPU_FTR_P9_TM_HV_ASSIST )) && + (vcpu->arch.hfscr &HFSCR_TM )) msr |=MSR_TM ; msr =msr_check_and_set (msr);/* Save MSR for restore. This is after hard disable, so EE is clear. */
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 38/53 KVM: PPC: Book3S HV P9: Use Linux SPR save/restore to manage some host SPRs
In reply to Nicholas PigginLinux implements SPR save/restore including storage space for registers in the task struct for process context switching. Make use of this similarly to the way we make use of the context switching fp/vec save restore.
This improves code reuse, allows some stack space to be saved, and helps with avoiding VRSAVE updates if they are not required.
--- arch/powerpc/include/asm/switch_to.h | 1 + arch/powerpc/kernel/process.c | 6 ++ arch/powerpc/kvm/book3s_hv.c | 21 +----- arch/powerpc/kvm/book3s_hv.h | 3 - arch/powerpc/kvm/book3s_hv_p9_entry.c | 93 +++++++++++++++++++-------- 5 files changed, 73 insertions(+), 51 deletions(-)
arch/powerpc/include/asm/switch_to.h +1 -0
@@ -113,6 +113,7 @@ static inline void clear_task_ebb(struct task_struct *t) }void kvmppc_save_user_regs (void ); +void kvmppc_save_current_sprs (void );extern int set_thread_tidr (struct task_struct *t);
arch/powerpc/kernel/process.c +6 -0
@@ -1182,6 +1182,12 @@ void kvmppc_save_user_regs(void)#endif }EXPORT_SYMBOL_GPL (kvmppc_save_user_regs); + +void kvmppc_save_current_sprs (void ) +{ +save_sprs (¤t->thread); +} +EXPORT_SYMBOL_GPL (kvmppc_save_current_sprs);#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */ static inline void restore_sprs(struct thread_struct *old_thread,
arch/powerpc/kvm/book3s_hv.c +1 -20
@@ -4566,9 +4566,6 @@ static int kvmppc_vcpu_run_hv(struct kvm_vcpu *vcpu)struct kvm_run *run = vcpu->run;int r;int srcu_idx; -unsigned long ebb_regs[3 ] = {};/* shut up GCC */ -unsigned long user_tar =0 ; -unsigned int user_vrsave;struct kvm *kvm;unsigned long msr;
@@ -4629,14 +4626,7 @@ static int kvmppc_vcpu_run_hv(struct kvm_vcpu *vcpu)kvmppc_save_user_regs (); -/* Save userspace EBB and other register values */ -if (cpu_has_feature (CPU_FTR_ARCH_207S )) { - ebb_regs[0 ] =mfspr (SPRN_EBBHR ); - ebb_regs[1 ] =mfspr (SPRN_EBBRR ); - ebb_regs[2 ] =mfspr (SPRN_BESCR ); - user_tar =mfspr (SPRN_TAR ); - } - user_vrsave =mfspr (SPRN_VRSAVE ); +kvmppc_save_current_sprs (); vcpu->arch.waitp = &vcpu->arch.vcore->wait; vcpu->arch.pgdir = kvm->mm->pgd;
@@ -4677,15 +4667,6 @@ static int kvmppc_vcpu_run_hv(struct kvm_vcpu *vcpu) } }while (is_kvmppc_resume_guest (r)); -/* Restore userspace EBB and other register values */ -if (cpu_has_feature (CPU_FTR_ARCH_207S )) { -mtspr (SPRN_EBBHR , ebb_regs[0 ]); -mtspr (SPRN_EBBRR , ebb_regs[1 ]); -mtspr (SPRN_BESCR , ebb_regs[2 ]); -mtspr (SPRN_TAR , user_tar); - } -mtspr (SPRN_VRSAVE , user_vrsave); - vcpu->arch.state =KVMPPC_VCPU_NOTREADY ;atomic_dec (&kvm->arch.vcpus_running);
arch/powerpc/kvm/book3s_hv.h +0 -3
@@ -4,11 +4,8 @@* Privileged (non-hypervisor) host registers to save. */ struct p9_host_os_sprs { -unsigned long dscr; -unsigned long tidr;unsigned long iamr;unsigned long amr; -unsigned long fscr;unsigned int pmc1;unsigned int pmc2;
arch/powerpc/kvm/book3s_hv_p9_entry.c +65 -28
161 lines not on this page · raw message
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 39/53 KVM: PPC: Book3S HV P9: Comment and fix MMU context switching code
In reply to Nicholas PigginTighten up partition switching code synchronisation and comments.
In particular, hwsync ; isync is required after the last access that is performed in the context of a partition, before the partition is switched away from.
--- arch/powerpc/kvm/book3s_64_entry.S | 11 +++++-- arch/powerpc/kvm/book3s_64_mmu_radix.c | 4 +++ arch/powerpc/kvm/book3s_hv_p9_entry.c | 40 +++++++++++++++++++------- 3 files changed, 42 insertions(+), 13 deletions(-)
arch/powerpc/kvm/book3s_64_entry.S +9 -2
@@ -374,11 +374,16 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX) BEGIN_FTR_SECTION mtspr SPRN_DAWRX1,r10 END_FTR_SECTION_IFSET(CPU_FTR_DAWR1) - mtspr SPRN_PID,r10 /* - * Switch to host MMU mode + * Switch to host MMU mode (don't have the real host PID but we aren't + * going back to userspace). */ + hwsync + isync + + mtspr SPRN_PID,r10 + ld r10, HSTATE_KVM_VCPU(r13) ld r10, VCPU_KVM(r10) lwz r10, KVM_HOST_LPID(r10)
@@ -389,6 +394,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_DAWR1) ld r10, KVM_HOST_LPCR(r10) mtspr SPRN_LPCR,r10 + isync + /* * Set GUEST_MODE_NONE so the handler won't branch to KVM, and clear * MSR_RI in r12 ([H]SRR1) so the handler won't try to return.
arch/powerpc/kvm/book3s_64_mmu_radix.c +4 -0
@@ -57,6 +57,8 @@ unsigned long __kvmhv_copy_tofrom_guest_radix(int lpid, int pid,preempt_disable (); + asmvolatile ("hwsync" :::"memory" ); +isync ();/* switch the lpid first to avoid running host with unallocated pid */ old_lpid =mfspr (SPRN_LPID );if (old_lpid != lpid)
@@ -75,6 +77,8 @@ unsigned long __kvmhv_copy_tofrom_guest_radix(int lpid, int pid, ret =__copy_to_user_inatomic ((void __user *)to, from, n);pagefault_enable (); + asmvolatile ("hwsync" :::"memory" ); +isync ();/* switch the pid first to avoid running host with unallocated pid */ if (quadrant ==1 && pid != old_pid)mtspr (SPRN_PID , old_pid);
arch/powerpc/kvm/book3s_hv_p9_entry.c +29 -11
@@ -531,17 +531,19 @@ static void switch_mmu_to_guest_radix(struct kvm *kvm, struct kvm_vcpu *vcpu, u6 lpid = nested ? nested->shadow_lpid : kvm->arch.lpid;/* -* All the isync()s are overkill but trivially follow the ISA -* requirements. Some can likely be replaced with justification -* comment for why they are not needed. +* Prior memory accesses to host PID Q3 must be completed before we +* start switching, and stores must be drained to avoid not-my-LPAR +* logic (see switch_mmu_to_host). */ + asmvolatile ("hwsync" :::"memory" );isync ();mtspr (SPRN_LPID , lpid); -isync ();mtspr (SPRN_LPCR , lpcr); -isync ();mtspr (SPRN_PID , vcpu->arch.pid); -isync (); +/* +* isync not required here because we are HRFID'ing to guest before +* any guest context access, which is context synchronising. +*/ }static void switch_mmu_to_guest_hpt (struct kvm *kvm,struct kvm_vcpu *vcpu,u64 lpcr)
@@ -551,25 +553,41 @@ static void switch_mmu_to_guest_hpt(struct kvm *kvm, struct kvm_vcpu *vcpu, u64 lpid = kvm->arch.lpid; +/* +* See switch_mmu_to_guest_radix. ptesync should not be required here +* even if the host is in HPT mode because speculative accesses would +* not cause RC updates (we are in real mode). +*/ + asmvolatile ("hwsync" :::"memory" ); +isync ();mtspr (SPRN_LPID , lpid);mtspr (SPRN_LPCR , lpcr);mtspr (SPRN_PID , vcpu->arch.pid);for (i =0 ; i < vcpu->arch.slb_max; i++)mtslb (vcpu->arch.slb[i].orige, vcpu->arch.slb[i].origv); - -isync (); +/* +* isync not required here, see switch_mmu_to_guest_radix. +*/ }static void switch_mmu_to_host (struct kvm *kvm,u32 pid) { +/* +* The guest has exited, so guest MMU context is no longer being +* non-speculatively accessed, but a hwsync is needed before the +* mtLPIDR / mtPIDR switch, in order to ensure all stores are drained, +* so the not-my-LPAR tlbie logic does not overlook them. +*/ + asmvolatile ("hwsync" :::"memory" );isync ();mtspr (SPRN_PID , pid); -isync ();mtspr (SPRN_LPID , kvm->arch.host_lpid); -isync ();mtspr (SPRN_LPCR , kvm->arch.host_lpcr); -isync (); +/* +* isync is not required after the switch, because mtmsrd with L=0 +* is performed after this switch, which is context synchronising. +*/ if (!radix_enabled ())slb_restore_bolted_realmode ();
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 40/53 KVM: PPC: Book3S HV P9: Test dawr_enabled() before saving host DAWR SPRs
In reply to Nicholas PigginSome of the DAWR SPR access is already predicated on dawr_enabled(), apply this to the remainder of the accesses.
--- arch/powerpc/kvm/book3s_hv_p9_entry.c | 34 ++++++++++++++++----------- 1 file changed, 20 insertions(+), 14 deletions(-)
arch/powerpc/kvm/book3s_hv_p9_entry.c +20 -14
@@ -666,13 +666,16 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc host_hfscr =mfspr (SPRN_HFSCR ); host_ciabr =mfspr (SPRN_CIABR ); - host_dawr0 =mfspr (SPRN_DAWR0 ); - host_dawrx0 =mfspr (SPRN_DAWRX0 ); host_psscr =mfspr (SPRN_PSSCR ); host_pidr =mfspr (SPRN_PID ); -if (cpu_has_feature (CPU_FTR_DAWR1 )) { - host_dawr1 =mfspr (SPRN_DAWR1 ); - host_dawrx1 =mfspr (SPRN_DAWRX1 ); + +if (dawr_enabled ()) { + host_dawr0 =mfspr (SPRN_DAWR0 ); + host_dawrx0 =mfspr (SPRN_DAWRX0 ); +if (cpu_has_feature (CPU_FTR_DAWR1 )) { + host_dawr1 =mfspr (SPRN_DAWR1 ); + host_dawrx1 =mfspr (SPRN_DAWRX1 ); + } } local_paca->kvm_hstate.host_purr =mfspr (SPRN_PURR );
@@ -1006,15 +1009,18 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcmtspr (SPRN_HFSCR , host_hfscr);if (vcpu->arch.ciabr != host_ciabr)mtspr (SPRN_CIABR , host_ciabr); -if (vcpu->arch.dawr0 != host_dawr0) -mtspr (SPRN_DAWR0 , host_dawr0); -if (vcpu->arch.dawrx0 != host_dawrx0) -mtspr (SPRN_DAWRX0 , host_dawrx0); -if (cpu_has_feature (CPU_FTR_DAWR1 )) { -if (vcpu->arch.dawr1 != host_dawr1) -mtspr (SPRN_DAWR1 , host_dawr1); -if (vcpu->arch.dawrx1 != host_dawrx1) -mtspr (SPRN_DAWRX1 , host_dawrx1); + +if (dawr_enabled ()) { +if (vcpu->arch.dawr0 != host_dawr0) +mtspr (SPRN_DAWR0 , host_dawr0); +if (vcpu->arch.dawrx0 != host_dawrx0) +mtspr (SPRN_DAWRX0 , host_dawrx0); +if (cpu_has_feature (CPU_FTR_DAWR1 )) { +if (vcpu->arch.dawr1 != host_dawr1) +mtspr (SPRN_DAWR1 , host_dawr1); +if (vcpu->arch.dawrx1 != host_dawrx1) +mtspr (SPRN_DAWRX1 , host_dawrx1); + } }if (vc->dpdes)
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 41/53 KVM: PPC: Book3S HV P9: Don't restore PSSCR if not needed
In reply to Nicholas PigginThis also moves the PSSCR update in nested entry to avoid a SPR scoreboard stall.
--- arch/powerpc/kvm/book3s_hv.c | 7 +++++-- arch/powerpc/kvm/book3s_hv_p9_entry.c | 26 +++++++++++++++++++------- 2 files changed, 24 insertions(+), 9 deletions(-)
arch/powerpc/kvm/book3s_hv.c +5 -2
@@ -3889,7 +3889,9 @@ static int kvmhv_vcpu_entry_p9_nested(struct kvm_vcpu *vcpu, u64 time_limit, unsif (unlikely (load_vcpu_state (vcpu, &host_os_sprs))) msr =mfmsr ();/* TM restore can update msr */ -mtspr (SPRN_PSSCR_PR , vcpu->arch.psscr); +if (vcpu->arch.psscr != host_psscr) +mtspr (SPRN_PSSCR_PR , vcpu->arch.psscr); +kvmhv_save_hv_regs (vcpu, &hvregs); hvregs.lpcr = lpcr; vcpu->arch.regs.msr = vcpu->arch.shregs.msr;
@@ -3930,7 +3932,6 @@ static int kvmhv_vcpu_entry_p9_nested(struct kvm_vcpu *vcpu, u64 time_limit, uns vcpu->arch.shregs.dar =mfspr (SPRN_DAR ); vcpu->arch.shregs.dsisr =mfspr (SPRN_DSISR ); vcpu->arch.psscr =mfspr (SPRN_PSSCR_PR ); -mtspr (SPRN_PSSCR_PR , host_psscr);store_vcpu_state (vcpu);
@@ -3943,6 +3944,8 @@ static int kvmhv_vcpu_entry_p9_nested(struct kvm_vcpu *vcpu, u64 time_limit, unstimer_rearm_host_dec (*tb);restore_p9_host_os_sprs (vcpu, &host_os_sprs); +if (vcpu->arch.psscr != host_psscr) +mtspr (SPRN_PSSCR_PR , host_psscr);return trap; }
arch/powerpc/kvm/book3s_hv_p9_entry.c +19 -7
@@ -649,6 +649,7 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcunsigned long host_dawr0;unsigned long host_dawrx0;unsigned long host_psscr; +unsigned long host_hpsscr;unsigned long host_pidr;unsigned long host_dawr1;unsigned long host_dawrx1;
@@ -666,7 +667,9 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc host_hfscr =mfspr (SPRN_HFSCR ); host_ciabr =mfspr (SPRN_CIABR ); - host_psscr =mfspr (SPRN_PSSCR ); + host_psscr =mfspr (SPRN_PSSCR_PR ); +if (cpu_has_feature (CPU_FTR_P9_TM_HV_ASSIST )) + host_hpsscr =mfspr (SPRN_PSSCR ); host_pidr =mfspr (SPRN_PID );if (dawr_enabled ()) {
@@ -750,8 +753,14 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcif (vcpu->arch.ciabr != host_ciabr)mtspr (SPRN_CIABR , vcpu->arch.ciabr); -mtspr (SPRN_PSSCR , vcpu->arch.psscr |PSSCR_EC | - (local_paca->kvm_hstate.fake_suspend <<PSSCR_FAKE_SUSPEND_LG )); + +if (cpu_has_feature (CPU_FTR_P9_TM_HV_ASSIST )) { +mtspr (SPRN_PSSCR , vcpu->arch.psscr |PSSCR_EC | + (local_paca->kvm_hstate.fake_suspend <<PSSCR_FAKE_SUSPEND_LG )); + }else { +if (vcpu->arch.psscr != host_psscr) +mtspr (SPRN_PSSCR_PR , vcpu->arch.psscr); + }mtspr (SPRN_HFSCR , vcpu->arch.hfscr);
@@ -957,7 +966,7 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc vcpu->arch.ic =mfspr (SPRN_IC ); vcpu->arch.pid =mfspr (SPRN_PID ); - vcpu->arch.psscr =mfspr (SPRN_PSSCR ) &PSSCR_GUEST_VIS ; + vcpu->arch.psscr =mfspr (SPRN_PSSCR_PR ); vcpu->arch.shregs.sprg0 =mfspr (SPRN_SPRG0 ); vcpu->arch.shregs.sprg1 =mfspr (SPRN_SPRG1 );
@@ -1003,9 +1012,12 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcmtspr (SPRN_PURR , local_paca->kvm_hstate.host_purr);mtspr (SPRN_SPURR , local_paca->kvm_hstate.host_spurr); -/* Preserve PSSCR[FAKE_SUSPEND] until we've called kvmppc_save_tm_hv */ -mtspr (SPRN_PSSCR , host_psscr | - (local_paca->kvm_hstate.fake_suspend <<PSSCR_FAKE_SUSPEND_LG )); +if (cpu_has_feature (CPU_FTR_P9_TM_HV_ASSIST )) { +/* Preserve PSSCR[FAKE_SUSPEND] until we've called kvmppc_save_tm_hv */ +mtspr (SPRN_PSSCR , host_hpsscr | + (local_paca->kvm_hstate.fake_suspend <<PSSCR_FAKE_SUSPEND_LG )); + } +mtspr (SPRN_HFSCR , host_hfscr);if (vcpu->arch.ciabr != host_ciabr)mtspr (SPRN_CIABR , host_ciabr);
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 42/53 KVM: PPC: Book3S HV: Split P8 from P9 path guest vCPU TLB flushing
In reply to Nicholas PigginThis creates separate functions for old and new paths for vCPU TLB flushing, which will reduce complexity of the next change.
--- arch/powerpc/include/asm/kvm_ppc.h | 3 +- arch/powerpc/kvm/book3s_hv_builtin.c | 53 ++++------------------- arch/powerpc/kvm/book3s_hv_p9_entry.c | 62 ++++++++++++++++++++++++++- 3 files changed, 70 insertions(+), 48 deletions(-)
arch/powerpc/include/asm/kvm_ppc.h +1 -2
@@ -552,8 +552,7 @@ extern void kvm_hv_vm_activated(void);extern void kvm_hv_vm_deactivated (void );extern bool kvm_hv_mode_active (void ); -extern void kvmppc_check_need_tlb_flush (struct kvm *kvm,int pcpu, -struct kvm_nested_guest *nested); +extern void kvmppc_check_need_tlb_flush (struct kvm *kvm,int pcpu);#else static inline void __init kvm_cma_reserve (void )
arch/powerpc/kvm/book3s_hv_builtin.c +8 -45
68 lines not on this page · raw message
arch/powerpc/kvm/book3s_hv_p9_entry.c +61 -1
74 lines not on this page · raw message
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 43/53 KVM: PPC: Book3S HV P9: Avoid tlbsync sequence on radix guest exit
In reply to Nicholas PigginUse the existing TLB flushing logic to IPI the previous CPU and run the necessary barriers before running a guest vCPU on a new physical CPU, to do the necessary radix GTSE barriers for handling the case of an interrupted guest tlbie sequence.
This requires the vCPU TLB flush sequence that is currently just done on one thread, to be expanded to ensure the other threads execute a ptesync, because causing them to exit the guest will no longer cause a ptesync by itself.
This results in more IPIs than the TLB flush logic requires, but it's a significant win for common case scheduling when the vCPU remains on the same physical CPU.
This saves about 520 cycles (nearly 10%) on a guest entry+exit micro benchmark on a POWER9.
--- arch/powerpc/kvm/book3s_hv.c | 48 +++++++++++++++++++++------ arch/powerpc/kvm/book3s_hv_p9_entry.c | 48 +++++++++++++++------------ arch/powerpc/kvm/book3s_hv_rm_mmu.c | 6 ---- 3 files changed, 65 insertions(+), 37 deletions(-)
arch/powerpc/kvm/book3s_hv.c +38 -10
@@ -3002,29 +3002,54 @@ static void kvmppc_release_hwthread(int cpu)static void radix_flush_cpu (struct kvm *kvm,int cpu,struct kvm_vcpu *vcpu) {struct kvm_nested_guest *nested = vcpu->arch.nested; -cpumask_t *cpu_in_guest; +cpumask_t *cpu_in_guest, *need_tlb_flush;int i; - cpu =cpu_first_tlb_thread_sibling (cpu);if (nested) { -cpumask_set_cpu (cpu, &nested->need_tlb_flush); + need_tlb_flush = &nested->need_tlb_flush; cpu_in_guest = &nested->cpu_in_guest; }else { -cpumask_set_cpu (cpu, &kvm->arch.need_tlb_flush); + need_tlb_flush = &kvm->arch.need_tlb_flush; cpu_in_guest = &kvm->arch.cpu_in_guest; } + + cpu =cpu_first_tlb_thread_sibling (cpu); +for (i = cpu; i <=cpu_last_tlb_thread_sibling (cpu); + i +=cpu_tlb_thread_sibling_step ()) +cpumask_set_cpu (i, need_tlb_flush); +/* * Make sure setting of bit in need_tlb_flush precedes * testing of cpu_in_guest bits. The matching barrier on * the other side is the first smp_mb() in kvmppc_run_core(). */ smp_mb (); +for (i = cpu; i <=cpu_last_tlb_thread_sibling (cpu); i +=cpu_tlb_thread_sibling_step ())if (cpumask_test_cpu (i, cpu_in_guest))smp_call_function_single (i, do_nothing,NULL ,1 ); } +static void do_migrate_away_vcpu (void *arg) +{ +struct kvm_vcpu *vcpu = arg; +struct kvm *kvm = vcpu->kvm; + +/* +* If the guest has GTSE, it may execute tlbie, so do a eieio; tlbsync; +* ptesync sequence on the old CPU before migrating to a new one, in +* case we interrupted the guest between a tlbie ; eieio ; +* tlbsync; ptesync sequence. +* +* Otherwise, ptesync is sufficient for ordering tlbiel sequences. +*/ +if (kvm->arch.lpcr &LPCR_GTSE ) + asmvolatile ("eieio; tlbsync; ptesync" ); +else + asmvolatile ("ptesync" ); +} +static void kvmppc_prepare_radix_vcpu (struct kvm_vcpu *vcpu,int pcpu) {struct kvm_nested_guest *nested = vcpu->arch.nested;
@@ -3048,14 +3073,17 @@ static void kvmppc_prepare_radix_vcpu(struct kvm_vcpu *vcpu, int pcpu)* can move around between pcpus. To cope with this, when * a vcpu moves from one pcpu to another, we need to tell * any vcpus running on the same core as this vcpu previously -* ran to flush the TLB. The TLB is shared between threads, -* so we use a single bit in .need_tlb_flush for all 4 threads. +* ran to flush the TLB. */ if (prev_cpu != pcpu) { -if (prev_cpu >=0 && -cpu_first_tlb_thread_sibling (prev_cpu) != -cpu_first_tlb_thread_sibling (pcpu)) -radix_flush_cpu (kvm, prev_cpu, vcpu); +if (prev_cpu >=0 ) { +if (cpu_first_tlb_thread_sibling (prev_cpu) != +cpu_first_tlb_thread_sibling (pcpu)) +radix_flush_cpu (kvm, prev_cpu, vcpu); + +smp_call_function_single (prev_cpu, + do_migrate_away_vcpu, vcpu,1 ); + }if (nested) nested->prev_cpu[vcpu->arch.nested_vcpu_id] = pcpu;else
arch/powerpc/kvm/book3s_hv_p9_entry.c +27 -21
68 lines not on this page · raw message
arch/powerpc/kvm/book3s_hv_rm_mmu.c +0 -6
@@ -55,12 +55,6 @@ static int global_invalidates(struct kvm *kvm)smp_wmb ();cpumask_setall (&kvm->arch.need_tlb_flush); cpu = local_paca->kvm_hstate.kvm_vcore->pcpu; -/* -* On POWER9, threads are independent but the TLB is shared, -* so use the bit for the first thread to represent the core. -*/ -if (cpu_has_feature (CPU_FTR_ARCH_300 )) - cpu =cpu_first_tlb_thread_sibling (cpu);cpumask_clear_cpu (cpu, &kvm->arch.need_tlb_flush); }
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 44/53 KVM: PPC: Book3S HV Nested: Avoid extra mftb() in nested entry
In reply to Nicholas Pigginmftb() is expensive and one can be avoided on nested guest dispatch.
If the time checking code distinguishes between the L0 timer and the nested HV timer, then both can be tested in the same place with the same mftb() value.
This also nicely illustrates the relationship between the L0 and nested HV timers.
--- arch/powerpc/include/asm/kvm_asm.h | 1 + arch/powerpc/kvm/book3s_hv.c | 12 ++++++++++++ arch/powerpc/kvm/book3s_hv_nested.c | 5 ----- 3 files changed, 13 insertions(+), 5 deletions(-)
arch/powerpc/include/asm/kvm_asm.h +1 -0
@@ -79,6 +79,7 @@#define BOOK3S_INTERRUPT_FP_UNAVAIL 0x800#define BOOK3S_INTERRUPT_DECREMENTER 0x900#define BOOK3S_INTERRUPT_HV_DECREMENTER 0x980 +#define BOOK3S_INTERRUPT_NESTED_HV_DECREMENTER 0x1980#define BOOK3S_INTERRUPT_DOORBELL 0xa00#define BOOK3S_INTERRUPT_SYSCALL 0xc00#define BOOK3S_INTERRUPT_TRACE 0xd00
arch/powerpc/kvm/book3s_hv.c +12 -0
@@ -1486,6 +1486,10 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, run->ready_for_interrupt_injection =1 ;switch (vcpu->arch.trap) {/* We're good on these - the host merely wanted to get our attention */ +case BOOK3S_INTERRUPT_NESTED_HV_DECREMENTER : +WARN_ON_ONCE (1 );/* Should never happen */ + vcpu->arch.trap =BOOK3S_INTERRUPT_HV_DECREMENTER ; + fallthrough;case BOOK3S_INTERRUPT_HV_DECREMENTER : vcpu->stat.dec_exits++; r =RESUME_GUEST ;
@@ -1814,6 +1818,12 @@ static int kvmppc_handle_nested_exit(struct kvm_vcpu *vcpu) vcpu->stat.ext_intr_exits++; r =RESUME_GUEST ;break ; +/* These need to go to the nested HV */ +case BOOK3S_INTERRUPT_NESTED_HV_DECREMENTER : + vcpu->arch.trap =BOOK3S_INTERRUPT_HV_DECREMENTER ; + vcpu->stat.dec_exits++; + r =RESUME_HOST ; +break ;/* SR/HMI/PMI are HV interrupts that host has handled. Resume guest.*/ case BOOK3S_INTERRUPT_HMI :case BOOK3S_INTERRUPT_PERFMON :
@@ -3993,6 +4003,8 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,return BOOK3S_INTERRUPT_HV_DECREMENTER ;if (next_timer < time_limit) time_limit = next_timer; +else if (*tb >= time_limit)/* nested time limit */ +return BOOK3S_INTERRUPT_NESTED_HV_DECREMENTER ; vcpu->arch.ceded =0 ;
arch/powerpc/kvm/book3s_hv_nested.c +0 -5
@@ -375,11 +375,6 @@ long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu) vcpu->arch.ret =RESUME_GUEST ; vcpu->arch.trap =0 ;do { -if (mftb () >= hdec_exp) { - vcpu->arch.trap =BOOK3S_INTERRUPT_HV_DECREMENTER ; - r =RESUME_HOST ; -break ; - } r =kvmhv_run_single_vcpu (vcpu, hdec_exp, lpcr); }while (is_kvmppc_resume_guest (r));
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 45/53 KVM: PPC: Book3S HV P9: Improve mfmsr performance on entry
In reply to Nicholas PigginRearrange the MSR saving on entry so it does not follow the mtmsrd to disable interrupts, avoiding a possible RAW scoreboard stall.
--- arch/powerpc/include/asm/kvm_book3s_64.h | 2 + arch/powerpc/kvm/book3s_hv.c | 18 ++----- arch/powerpc/kvm/book3s_hv_p9_entry.c | 66 +++++++++++++++--------- 3 files changed, 47 insertions(+), 39 deletions(-)
arch/powerpc/include/asm/kvm_book3s_64.h +2 -0
@@ -154,6 +154,8 @@ static inline bool kvmhv_vcpu_is_radix(struct kvm_vcpu *vcpu)return radix; } +unsigned long kvmppc_msr_hard_disable_set_facilities (struct kvm_vcpu *vcpu,unsigned long msr); +int kvmhv_vcpu_entry_p9 (struct kvm_vcpu *vcpu,u64 time_limit,unsigned long lpcr,u64 *tb);#define KVM_DEFAULT_HPT_ORDER 24/* 16MB HPT by default */
arch/powerpc/kvm/book3s_hv.c +3 -15
@@ -3896,6 +3896,8 @@ static int kvmhv_vcpu_entry_p9_nested(struct kvm_vcpu *vcpu, u64 time_limit, unss64 dec;int trap; + msr =mfmsr (); +save_p9_host_os_sprs (&host_os_sprs);/*
@@ -3906,24 +3908,10 @@ static int kvmhv_vcpu_entry_p9_nested(struct kvm_vcpu *vcpu, u64 time_limit, uns*/ host_psscr =mfspr (SPRN_PSSCR_PR ); -hard_irq_disable (); +kvmppc_msr_hard_disable_set_facilities (vcpu, msr);if (lazy_irq_pending ())return 0 ; -/* MSR bits may have been cleared by context switch */ - msr =0 ; -if (IS_ENABLED (CONFIG_PPC_FPU )) - msr |=MSR_FP ; -if (cpu_has_feature (CPU_FTR_ALTIVEC )) - msr |=MSR_VEC ; -if (cpu_has_feature (CPU_FTR_VSX )) - msr |=MSR_VSX ; -if ((cpu_has_feature (CPU_FTR_TM ) || -cpu_has_feature (CPU_FTR_P9_TM_HV_ASSIST )) && - (vcpu->arch.hfscr &HFSCR_TM )) - msr |=MSR_TM ; - msr =msr_check_and_set (msr); -if (unlikely (load_vcpu_state (vcpu, &host_os_sprs))) msr =mfmsr ();/* TM restore can update msr */
arch/powerpc/kvm/book3s_hv_p9_entry.c +42 -24
89 lines not on this page · raw message
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 46/53 KVM: PPC: Book3S HV P9: Optimise hash guest SLB saving
In reply to Nicholas Pigginslbmfee/slbmfev instructions are very expensive, moreso than a regular mfspr instruction, so minimising them significantly improves hash guest exit performance. The slbmfev is only required if slbmfee found a valid SLB entry.
--- arch/powerpc/kvm/book3s_hv_p9_entry.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-)
arch/powerpc/kvm/book3s_hv_p9_entry.c +18 -4
@@ -487,10 +487,22 @@ static void __accumulate_time(struct kvm_vcpu *vcpu, struct kvmhv_tb_accumulator#define accumulate_time (vcpu, next) do {} while (0)#endif -static inline void mfslb (unsigned int idx,u64 *slbee,u64 *slbev) +static inline u64 mfslbv (unsigned int idx) { - asmvolatile ("slbmfev %0,%1" :"=r" (*slbev) :"r" (idx)); - asmvolatile ("slbmfee %0,%1" :"=r" (*slbee) :"r" (idx)); +u64 slbev; + + asmvolatile ("slbmfev %0,%1" :"=r" (slbev) :"r" (idx)); + +return slbev; +} + +static inline u64 mfslbe (unsigned int idx) +{ +u64 slbee; + + asmvolatile ("slbmfee %0,%1" :"=r" (slbee) :"r" (idx)); + +return slbee; }static inline void mtslb (u64 slbee,u64 slbev)
@@ -620,8 +632,10 @@ static void save_clear_guest_mmu(struct kvm *kvm, struct kvm_vcpu *vcpu)*/ for (i =0 ; i < vcpu->arch.slb_nr; i++) {u64 slbee, slbev; -mfslb (i, &slbee, &slbev); + + slbee =mfslbe (i);if (slbee &SLB_ESID_V ) { + slbev =mfslbv (i); vcpu->arch.slb[nr].orige = slbee | i; vcpu->arch.slb[nr].origv = slbev; nr++;
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 47/53 KVM: PPC: Book3S HV P9: Avoid changing MSR[RI] in entry and exit
In reply to Nicholas Pigginkvm_hstate.in_guest provides the equivalent of MSR[RI]=0 protection, and it covers the existing MSR[RI]=0 section in late entry and early exit, so clearing and setting MSR[RI] in those cases does not actually do anything useful.
Remove the RI manipulation and replace it with comments. Make the in_guest memory accesses a bit closer to a proper critical section pattern. This speeds up guest entry/exit performance.
This also removes the MSR[RI] warnings which aren't very interesting and would cause crashes if they hit due to causing an interrupt in non-recoverable code.
--- arch/powerpc/kvm/book3s_hv_p9_entry.c | 50 ++++++++++++--------------- 1 file changed, 23 insertions(+), 27 deletions(-)
arch/powerpc/kvm/book3s_hv_p9_entry.c +23 -27
@@ -904,7 +904,15 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc* But TM could be split out if this would be a significant benefit. */ - local_paca->kvm_hstate.in_guest =KVM_GUEST_MODE_HV_P9 ; +/* +* MSR[RI] does not need to be cleared (and is not, for radix guests +* with no prefetch bug), because in_guest is set. If we take a SRESET +* or MCE with in_guest set but still in HV mode, then +* kvmppc_p9_bad_interrupt handles the interrupt, which effectively +* clears MSR[RI] and doesn't return. +*/ +WRITE_ONCE (local_paca->kvm_hstate.in_guest,KVM_GUEST_MODE_HV_P9 ); +barrier ();/* Open in_guest critical section */ /* * Hash host, hash guest, or radix guest with prefetch bug, all have
@@ -916,14 +924,10 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcsave_clear_host_mmu (kvm); -if (kvm_is_radix (kvm)) { +if (kvm_is_radix (kvm))switch_mmu_to_guest_radix (kvm, vcpu, lpcr); -if (!cpu_has_feature (CPU_FTR_P9_RADIX_PREFETCH_BUG )) -__mtmsrd (0 ,1 );/* clear RI */ - - }else { +else switch_mmu_to_guest_hpt (kvm, vcpu, lpcr); - }/* TLBIEL uses LPID=LPIDR, so run this after setting guest LPID */ check_need_tlb_flush (kvm, vc->pcpu, nested);
@@ -978,19 +982,16 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc vcpu->arch.regs.gpr[3 ] = local_paca->kvm_hstate.scratch2;/* -* Only set RI after reading machine check regs (DAR, DSISR, SRR0/1) -* and hstate scratch (which we need to move into exsave to make -* re-entrant vs SRESET/MCE) +* After reading machine check regs (DAR, DSISR, SRR0/1) and hstate +* scratch (which we need to move into exsave to make re-entrant vs +* SRESET/MCE), register state is protected from reentrancy. However +* timebase, MMU, among other state is still set to guest, so don't +* enable MSR[RI] here. It gets enabled at the end, after in_guest +* is cleared. +* +* It is possible an NMI could come in here, which is why it is +* important to save the above state early so it can be debugged. */ -if (ri_set) { -if (unlikely (!(mfmsr () &MSR_RI ))) { -__mtmsrd (MSR_RI ,1 ); -WARN_ON_ONCE (1 ); - } - }else { -WARN_ON_ONCE (mfmsr () &MSR_RI ); -__mtmsrd (MSR_RI ,1 ); - } vcpu->arch.regs.gpr[9 ] = exsave[EX_R9 /sizeof (u64)]; vcpu->arch.regs.gpr[10 ] = exsave[EX_R10 /sizeof (u64)];
@@ -1048,13 +1049,6 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc*/ mtspr (SPRN_HSRR0 , vcpu->arch.regs.nip);mtspr (SPRN_HSRR1 , vcpu->arch.shregs.msr); - -/* -* tm_return_to_guest re-loads SRR0/1, DAR, -* DSISR after RI is cleared, in case they had -* been clobbered by a MCE. -*/ -__mtmsrd (0 ,1 );/* clear RI */ goto tm_return_to_guest; } }
@@ -1154,7 +1148,9 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcrestore_p9_host_os_sprs (vcpu, &host_os_sprs); - local_paca->kvm_hstate.in_guest =KVM_GUEST_MODE_NONE ; +barrier ();/* Close in_guest critical section */ +WRITE_ONCE (local_paca->kvm_hstate.in_guest,KVM_GUEST_MODE_NONE ); +/* Interrupts are recoverable at this point */ /* * cp_abort is required if the processor supports local copy-paste
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 48/53 KVM: PPC: Book3S HV P9: Add unlikely annotation for !mmu_ready
In reply to Nicholas PigginThe mmu will almost always be ready.
--- arch/powerpc/kvm/book3s_hv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/powerpc/kvm/book3s_hv.c +1 -1
@@ -4426,7 +4426,7 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit, vc->runner = vcpu;/* See if the MMU is ready to go */ -if (!kvm->arch.mmu_ready) { +if (unlikely (!kvm->arch.mmu_ready)) { r =kvmhv_setup_mmu (vcpu);if (r) { run->exit_reason =KVM_EXIT_FAIL_ENTRY ;
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 49/53 KVM: PPC: Book3S HV P9: Avoid cpu_in_guest atomics on entry and exit
In reply to Nicholas Piggincpu_in_guest is set to determine if a CPU needs to be IPI'ed to exit the guest and notice the need_tlb_flush bit.
This can be implemented as a global per-CPU pointer to the currently running guest instead of per-guest cpumasks, saving 2 atomics per entry/exit. P7/8 doesn't require cpu_in_guest, nor does a nested HV (only the L0 does), so move it to the P9 HV path.
--- arch/powerpc/include/asm/kvm_book3s_64.h | 1 - arch/powerpc/include/asm/kvm_host.h | 1 - arch/powerpc/kvm/book3s_hv.c | 39 +++++++++++++----------- 3 files changed, 22 insertions(+), 19 deletions(-)
arch/powerpc/include/asm/kvm_book3s_64.h +0 -1
@@ -44,7 +44,6 @@ struct kvm_nested_guest {struct mutex tlb_lock;/* serialize page faults and tlbies */ struct kvm_nested_guest *next;cpumask_t need_tlb_flush; -cpumask_t cpu_in_guest;short prev_cpu[NR_CPUS ];u8 radix;/* is this nested guest radix */ };
arch/powerpc/include/asm/kvm_host.h +0 -1
@@ -287,7 +287,6 @@ struct kvm_arch {u32 online_vcores;atomic_t hpte_mod_interest;cpumask_t need_tlb_flush; -cpumask_t cpu_in_guest;u8 radix;u8 fwnmi_enabled;u8 secure_guest;
arch/powerpc/kvm/book3s_hv.c +22 -17
@@ -3009,19 +3009,18 @@ static void kvmppc_release_hwthread(int cpu) tpaca->kvm_hstate.kvm_split_mode =NULL ; } +static DEFINE_PER_CPU(struct kvm *, cpu_in_guest); +static void radix_flush_cpu (struct kvm *kvm,int cpu,struct kvm_vcpu *vcpu) {struct kvm_nested_guest *nested = vcpu->arch.nested; -cpumask_t *cpu_in_guest, *need_tlb_flush; +cpumask_t *need_tlb_flush;int i; -if (nested) { +if (nested) need_tlb_flush = &nested->need_tlb_flush; - cpu_in_guest = &nested->cpu_in_guest; - }else { +else need_tlb_flush = &kvm->arch.need_tlb_flush; - cpu_in_guest = &kvm->arch.cpu_in_guest; - } cpu =cpu_first_tlb_thread_sibling (cpu); for (i = cpu; i <= cpu_last_tlb_thread_sibling(cpu);
@@ -3029,16 +3028,21 @@ static void radix_flush_cpu(struct kvm *kvm, int cpu, struct kvm_vcpu *vcpu)cpumask_set_cpu (i, need_tlb_flush);/* -* Make sure setting of bit in need_tlb_flush precedes -* testing of cpu_in_guest bits. The matching barrier on -* the other side is the first smp_mb() in kvmppc_run_core(). +* Make sure setting of bit in need_tlb_flush precedes testing of +* cpu_in_guest. The matching barrier on the other side is hwsync +* when switching to guest MMU mode, which happens between +* cpu_in_guest being set to the guest kvm, and need_tlb_flush bit +* being tested. */ smp_mb ();for (i = cpu; i <=cpu_last_tlb_thread_sibling (cpu); - i +=cpu_tlb_thread_sibling_step ()) -if (cpumask_test_cpu (i, cpu_in_guest)) + i +=cpu_tlb_thread_sibling_step ()) { +struct kvm *running = *per_cpu_ptr (&cpu_in_guest, i); + +if (running == kvm)smp_call_function_single (i, do_nothing,NULL ,1 ); + } }static void do_migrate_away_vcpu (void *arg)
@@ -3105,7 +3109,6 @@ static void kvmppc_start_thread(struct kvm_vcpu *vcpu, struct kvmppc_vcore *vc) {int cpu;struct paca_struct *tpaca; -struct kvm *kvm = vc->kvm; cpu = vc->pcpu;if (vcpu) {
@@ -3116,7 +3119,6 @@ static void kvmppc_start_thread(struct kvm_vcpu *vcpu, struct kvmppc_vcore *vc) cpu += vcpu->arch.ptid; vcpu->cpu = vc->pcpu; vcpu->arch.thread_cpu = cpu; -cpumask_set_cpu (cpu, &kvm->arch.cpu_in_guest); } tpaca = paca_ptrs[cpu]; tpaca->kvm_hstate.kvm_vcpu = vcpu;
@@ -3847,7 +3849,6 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)kvmppc_release_hwthread (pcpu + i);if (sip && sip->napped[i])kvmppc_ipi_thread (pcpu + i); -cpumask_clear_cpu (pcpu + i, &vc->kvm->arch.cpu_in_guest); }spin_unlock (&vc->lock);
@@ -4015,8 +4016,14 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, } }else { +struct kvm *kvm = vcpu->kvm; +kvmppc_xive_push_vcpu (vcpu); + +__this_cpu_write (cpu_in_guest, kvm); trap =kvmhv_vcpu_entry_p9 (vcpu, time_limit, lpcr, tb); +__this_cpu_write (cpu_in_guest,NULL ); +if (trap ==BOOK3S_INTERRUPT_SYSCALL && !vcpu->arch.nested && !(vcpu->arch.shregs.msr &MSR_PR )) {unsigned long req =kvmppc_get_gpr (vcpu,3 );
@@ -4041,7 +4048,7 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, }kvmppc_xive_pull_vcpu (vcpu); -if (kvm_is_radix (vcpu->kvm)) +if (kvm_is_radix (kvm)) vcpu->arch.slb_max =0 ; }
@@ -4531,8 +4538,6 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit,powerpc_local_irq_pmu_restore (flags); -cpumask_clear_cpu (pcpu, &kvm->arch.cpu_in_guest); -preempt_enable ();/*
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 50/53 KVM: PPC: Book3S HV P9: Remove most of the vcore logic
In reply to Nicholas PigginThe P9 path always uses one vcpu per vcore, so none of the vcore, locks, stolen time, blocking logic, shared waitq, etc., is required.
Remove most of it.
--- arch/powerpc/kvm/book3s_hv.c | 147 ++++++++++++++++++++--------------- 1 file changed, 85 insertions(+), 62 deletions(-)
arch/powerpc/kvm/book3s_hv.c +85 -62
@@ -276,6 +276,8 @@ static void kvmppc_core_start_stolen(struct kvmppc_vcore *vc, u64 tb) {unsigned long flags; +WARN_ON_ONCE (cpu_has_feature (CPU_FTR_ARCH_300 )); +spin_lock_irqsave (&vc->stoltb_lock, flags); vc->preempt_tb = tb;spin_unlock_irqrestore (&vc->stoltb_lock, flags);
@@ -285,6 +287,8 @@ static void kvmppc_core_end_stolen(struct kvmppc_vcore *vc, u64 tb) {unsigned long flags; +WARN_ON_ONCE (cpu_has_feature (CPU_FTR_ARCH_300 )); +spin_lock_irqsave (&vc->stoltb_lock, flags);if (vc->preempt_tb !=TB_NIL ) { vc->stolen_tb += tb - vc->preempt_tb;
@@ -297,7 +301,12 @@ static void kvmppc_core_vcpu_load_hv(struct kvm_vcpu *vcpu, int cpu) {struct kvmppc_vcore *vc = vcpu->arch.vcore;unsigned long flags; -u64 now =mftb (); +u64 now; + +if (cpu_has_feature (CPU_FTR_ARCH_300 )) +return ; + + now =mftb ();/* * We can test vc->runner without taking the vcore lock,
@@ -321,7 +330,12 @@ static void kvmppc_core_vcpu_put_hv(struct kvm_vcpu *vcpu) {struct kvmppc_vcore *vc = vcpu->arch.vcore;unsigned long flags; -u64 now =mftb (); +u64 now; + +if (cpu_has_feature (CPU_FTR_ARCH_300 )) +return ; + + now =mftb ();if (vc->runner == vcpu && vc->vcore_state >=VCORE_SLEEPING )kvmppc_core_start_stolen (vc, now);
@@ -673,6 +687,8 @@ static u64 vcore_stolen_time(struct kvmppc_vcore *vc, u64 now)u64 p;unsigned long flags; +WARN_ON_ONCE (cpu_has_feature (CPU_FTR_ARCH_300 )); +spin_lock_irqsave (&vc->stoltb_lock, flags); p = vc->stolen_tb; if (vc->vcore_state != VCORE_INACTIVE &&
@@ -695,13 +711,19 @@ static void kvmppc_create_dtl_entry(struct kvm_vcpu *vcpu, dt = vcpu->arch.dtl_ptr; vpa = vcpu->arch.vpa.pinned_addr; now = tb; - core_stolen =vcore_stolen_time (vc, now); - stolen = core_stolen - vcpu->arch.stolen_logged; - vcpu->arch.stolen_logged = core_stolen; -spin_lock_irqsave (&vcpu->arch.tbacct_lock, flags); - stolen += vcpu->arch.busy_stolen; - vcpu->arch.busy_stolen =0 ; -spin_unlock_irqrestore (&vcpu->arch.tbacct_lock, flags); + +if (cpu_has_feature (CPU_FTR_ARCH_300 )) { + stolen =0 ; + }else { + core_stolen =vcore_stolen_time (vc, now); + stolen = core_stolen - vcpu->arch.stolen_logged; + vcpu->arch.stolen_logged = core_stolen; +spin_lock_irqsave (&vcpu->arch.tbacct_lock, flags); + stolen += vcpu->arch.busy_stolen; + vcpu->arch.busy_stolen =0 ; +spin_unlock_irqrestore (&vcpu->arch.tbacct_lock, flags); + } +if (!dt || !vpa)return ;memset (dt,0 ,sizeof (struct dtl_entry ));
@@ -898,13 +920,14 @@ static int kvm_arch_vcpu_yield_to(struct kvm_vcpu *target)* mode handler is not called but no other threads are in the * source vcore. */ - -spin_lock (&vcore->lock); -if (target->arch.state ==KVMPPC_VCPU_RUNNABLE && - vcore->vcore_state !=VCORE_INACTIVE && - vcore->runner) - target = vcore->runner; -spin_unlock (&vcore->lock); +if (!cpu_has_feature (CPU_FTR_ARCH_300 )) { +spin_lock (&vcore->lock); +if (target->arch.state ==KVMPPC_VCPU_RUNNABLE && + vcore->vcore_state !=VCORE_INACTIVE && + vcore->runner) + target = vcore->runner; +spin_unlock (&vcore->lock); + }return kvm_vcpu_yield_to (target); }
@@ -3131,13 +3154,6 @@ static void kvmppc_start_thread(struct kvm_vcpu *vcpu, struct kvmppc_vcore *vc)kvmppc_ipi_thread (cpu); } -/* Old path does this in asm */ -static void kvmppc_stop_thread (struct kvm_vcpu *vcpu) -{ - vcpu->cpu =-1 ; - vcpu->arch.thread_cpu =-1 ; -} -static void kvmppc_wait_for_nap (int n_threads) {int cpu =smp_processor_id ();
@@ -3226,6 +3242,8 @@ static void kvmppc_vcore_preempt(struct kvmppc_vcore *vc) {struct preempted_vcore_list *lp =this_cpu_ptr (&preempted_vcores); +WARN_ON_ONCE (cpu_has_feature (CPU_FTR_ARCH_300 )); + vc->vcore_state =VCORE_PREEMPT ; vc->pcpu =smp_processor_id ();if (vc->num_threads <threads_per_vcore (vc->kvm)) {
@@ -3242,6 +3260,8 @@ static void kvmppc_vcore_end_preempt(struct kvmppc_vcore *vc) {struct preempted_vcore_list *lp; +WARN_ON_ONCE (cpu_has_feature (CPU_FTR_ARCH_300 )); +kvmppc_core_end_stolen (vc,mftb ());if (!list_empty (&vc->preempt_list)) { lp = &per_cpu (preempted_vcores, vc->pcpu);
@@ -3983,7 +4003,6 @@ static int kvmhv_vcpu_entry_p9_nested(struct kvm_vcpu *vcpu, u64 time_limit, unsstatic int kvmhv_p9_guest_entry (struct kvm_vcpu *vcpu,u64 time_limit,unsigned long lpcr,u64 *tb) { -struct kvmppc_vcore *vc = vcpu->arch.vcore;u64 next_timer;int trap;
@@ -3999,9 +4018,6 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,kvmppc_subcore_enter_guest (); - vc->entry_exit_map =1 ; - vc->in_guest =1 ; -vcpu_vpa_increment_dispatch (vcpu);if (kvmhv_on_pseries ()) {
@@ -4054,9 +4070,6 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,vcpu_vpa_increment_dispatch (vcpu); - vc->entry_exit_map =0x101 ; - vc->in_guest =0 ; -kvmppc_subcore_exit_guest ();return trap;
@@ -4122,6 +4135,13 @@ static bool kvmppc_vcpu_woken(struct kvm_vcpu *vcpu)return false; } +static bool kvmppc_vcpu_check_block (struct kvm_vcpu *vcpu) +{ +if (!vcpu->arch.ceded ||kvmppc_vcpu_woken (vcpu)) +return true; +return false; +} +/* * Check to see if any of the runnable vcpus on the vcore have pending * exceptions or are no longer ceded
@@ -4132,7 +4152,7 @@ static int kvmppc_vcore_check_block(struct kvmppc_vcore *vc)int i;for_each_runnable_thread (i, vcpu, vc) { -if (!vcpu->arch.ceded ||kvmppc_vcpu_woken (vcpu)) +if (kvmppc_vcpu_check_block (vcpu))return 1 ; }
@@ -4149,6 +4169,8 @@ static void kvmppc_vcore_blocked(struct kvmppc_vcore *vc)int do_sleep =1 ;u64 block_ns; +WARN_ON_ONCE (cpu_has_feature (CPU_FTR_ARCH_300 )); +/* Poll for pending exceptions and ceded state */ cur = start_poll =ktime_get ();if (vc->halt_poll_ns) {
@@ -4426,11 +4448,7 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit, vcpu->arch.ceded =0 ; vcpu->arch.run_task = current; vcpu->arch.state =KVMPPC_VCPU_RUNNABLE ; - vcpu->arch.busy_preempt =TB_NIL ; vcpu->arch.last_inst =KVM_INST_FETCH_FAILED ; - vc->runnable_threads[0 ] = vcpu; - vc->n_runnable =1 ; - vc->runner = vcpu;/* See if the MMU is ready to go */ if (unlikely (!kvm->arch.mmu_ready)) {
@@ -4448,11 +4466,8 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit,kvmppc_update_vpas (vcpu); -init_vcore_to_run (vc); -preempt_disable (); pcpu =smp_processor_id (); - vc->pcpu = pcpu;if (kvm_is_radix (kvm))kvmppc_prepare_radix_vcpu (vcpu, pcpu);
@@ -4481,21 +4496,23 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit, goto out; } - tb =mftb (); +if (vcpu->arch.timer_running) { +hrtimer_try_to_cancel (&vcpu->arch.dec_timer); + vcpu->arch.timer_running =0 ; + } - vcpu->arch.stolen_logged =vcore_stolen_time (vc, tb); - vc->preempt_tb =TB_NIL ; + tb =mftb (); -kvmppc_clear_host_core (pcpu); + vcpu->cpu = pcpu; + vcpu->arch.thread_cpu = pcpu; + vc->pcpu = pcpu; + local_paca->kvm_hstate.kvm_vcpu = vcpu; + local_paca->kvm_hstate.ptid =0 ; + local_paca->kvm_hstate.fake_suspend =0 ; - local_paca->kvm_hstate.napping =0 ; - local_paca->kvm_hstate.kvm_split_mode =NULL ; -kvmppc_start_thread (vcpu, vc);kvmppc_create_dtl_entry (vcpu, vc, tb); -trace_kvm_guest_enter (vcpu); - vc->vcore_state =VCORE_RUNNING ; -trace_kvmppc_run_core (vc,0 ); +trace_kvm_guest_enter (vcpu);guest_enter_irqoff ();
@@ -4517,8 +4534,6 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit,set_irq_happened (trap); -kvmppc_set_host_core (pcpu); -context_tracking_guest_exit ();if (!vtime_accounting_enabled_this_cpu ()) {local_irq_enable ();
@@ -4534,7 +4549,8 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit, }vtime_account_guest_exit (); -kvmppc_stop_thread (vcpu); + vcpu->cpu =-1 ; + vcpu->arch.thread_cpu =-1 ;powerpc_local_irq_pmu_restore (flags);
@@ -4561,28 +4577,31 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit, } vcpu->arch.ret = r; -if (is_kvmppc_resume_guest (r) && vcpu->arch.ceded && - !kvmppc_vcpu_woken (vcpu)) { +if (is_kvmppc_resume_guest (r) && !kvmppc_vcpu_check_block (vcpu)) {kvmppc_set_timer (vcpu); -while (vcpu->arch.ceded && !kvmppc_vcpu_woken (vcpu)) { + +prepare_to_rcuwait (&vcpu->wait); +for (;;) { +set_current_state (TASK_INTERRUPTIBLE );if (signal_pending (current)) { vcpu->stat.signal_exits++; run->exit_reason =KVM_EXIT_INTR ; vcpu->arch.ret = -EINTR ;break ; } -spin_lock (&vc->lock); -kvmppc_vcore_blocked (vc); -spin_unlock (&vc->lock); + +if (kvmppc_vcpu_check_block (vcpu)) +break ; + +trace_kvmppc_vcore_blocked (vc,0 ); +schedule (); +trace_kvmppc_vcore_blocked (vc,1 ); } +finish_rcuwait (&vcpu->wait); } vcpu->arch.ceded =0 ; - vc->vcore_state =VCORE_INACTIVE ; -trace_kvmppc_run_core (vc,1 ); - done: -kvmppc_remove_runnable (vc, vcpu, tb);trace_kvmppc_run_vcpu_exit (vcpu);return vcpu->arch.ret;
@@ -4664,7 +4683,8 @@ static int kvmppc_vcpu_run_hv(struct kvm_vcpu *vcpu)kvmppc_save_current_sprs (); - vcpu->arch.waitp = &vcpu->arch.vcore->wait; +if (!cpu_has_feature (CPU_FTR_ARCH_300 )) + vcpu->arch.waitp = &vcpu->arch.vcore->wait; vcpu->arch.pgdir = kvm->mm->pgd; vcpu->arch.state =KVMPPC_VCPU_BUSY_IN_HOST ;
@@ -5126,6 +5146,9 @@ void kvmppc_alloc_host_rm_ops(void)int cpu, core;int size; +if (cpu_has_feature (CPU_FTR_ARCH_300 )) +return ; +/* Not the first time here ? */ if (kvmppc_host_rm_ops_hv !=NULL )return ;
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 51/53 KVM: PPC: Book3S HV P9: Tidy kvmppc_create_dtl_entry
In reply to Nicholas PigginThis goes further to removing vcores from the P9 path. Also avoid the memset in favour of explicitly initialising all fields.
--- arch/powerpc/kvm/book3s_hv.c | 60 +++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 25 deletions(-)
arch/powerpc/kvm/book3s_hv.c +35 -25
@@ -698,41 +698,30 @@ static u64 vcore_stolen_time(struct kvmppc_vcore *vc, u64 now)return p; } -static void kvmppc_create_dtl_entry (struct kvm_vcpu *vcpu, -struct kvmppc_vcore *vc,u64 tb) +static void __kvmppc_create_dtl_entry (struct kvm_vcpu *vcpu, +unsigned int pcpu,u64 now, +unsigned long stolen) {struct dtl_entry *dt;struct lppaca *vpa; -unsigned long stolen; -unsigned long core_stolen; -u64 now; -unsigned long flags; dt = vcpu->arch.dtl_ptr; vpa = vcpu->arch.vpa.pinned_addr; - now = tb; - -if (cpu_has_feature (CPU_FTR_ARCH_300 )) { - stolen =0 ; - }else { - core_stolen =vcore_stolen_time (vc, now); - stolen = core_stolen - vcpu->arch.stolen_logged; - vcpu->arch.stolen_logged = core_stolen; -spin_lock_irqsave (&vcpu->arch.tbacct_lock, flags); - stolen += vcpu->arch.busy_stolen; - vcpu->arch.busy_stolen =0 ; -spin_unlock_irqrestore (&vcpu->arch.tbacct_lock, flags); - }if (!dt || !vpa)return ; -memset (dt,0 ,sizeof (struct dtl_entry )); + dt->dispatch_reason =7 ; - dt->processor_id =cpu_to_be16 (vc->pcpu + vcpu->arch.ptid); - dt->timebase =cpu_to_be64 (now + vc->tb_offset); + dt->preempt_reason =0 ; + dt->processor_id =cpu_to_be16 (pcpu + vcpu->arch.ptid); dt->enqueue_to_dispatch_time =cpu_to_be32 (stolen); + dt->ready_to_enqueue_time =0 ; + dt->waiting_to_ready_time =0 ; + dt->timebase =cpu_to_be64 (now); + dt->fault_addr =0 ; dt->srr0 =cpu_to_be64 (kvmppc_get_pc (vcpu)); dt->srr1 =cpu_to_be64 (vcpu->arch.shregs.msr); + ++dt;if (dt == vcpu->arch.dtl.pinned_end) dt = vcpu->arch.dtl.pinned_addr;
@@ -743,6 +732,27 @@ static void kvmppc_create_dtl_entry(struct kvm_vcpu *vcpu, vcpu->arch.dtl.dirty = true; } +static void kvmppc_create_dtl_entry (struct kvm_vcpu *vcpu, +struct kvmppc_vcore *vc) +{ +unsigned long stolen; +unsigned long core_stolen; +u64 now; +unsigned long flags; + + now =mftb (); + + core_stolen =vcore_stolen_time (vc, now); + stolen = core_stolen - vcpu->arch.stolen_logged; + vcpu->arch.stolen_logged = core_stolen; +spin_lock_irqsave (&vcpu->arch.tbacct_lock, flags); + stolen += vcpu->arch.busy_stolen; + vcpu->arch.busy_stolen =0 ; +spin_unlock_irqrestore (&vcpu->arch.tbacct_lock, flags); + +__kvmppc_create_dtl_entry (vcpu, vc->pcpu, now + vc->tb_offset, stolen); +} +/* See if there is a doorbell interrupt pending for a vcpu */ static bool kvmppc_doorbell_pending (struct kvm_vcpu *vcpu) {
@@ -3756,7 +3766,7 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) pvc->pcpu = pcpu + thr;for_each_runnable_thread (i, vcpu, pvc) {kvmppc_start_thread (vcpu, pvc); -kvmppc_create_dtl_entry (vcpu, pvc,mftb ()); +kvmppc_create_dtl_entry (vcpu, pvc);trace_kvm_guest_enter (vcpu);if (!vcpu->arch.ptid) thr0_done = true;
@@ -4332,7 +4342,7 @@ static int kvmppc_run_vcpu(struct kvm_vcpu *vcpu)if ((vc->vcore_state ==VCORE_PIGGYBACK || vc->vcore_state ==VCORE_RUNNING ) && !VCORE_IS_EXITING (vc)) { -kvmppc_create_dtl_entry (vcpu, vc,mftb ()); +kvmppc_create_dtl_entry (vcpu, vc);kvmppc_start_thread (vcpu, vc);trace_kvm_guest_enter (vcpu); }else if (vc->vcore_state ==VCORE_SLEEPING ) {
@@ -4510,7 +4520,7 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit, local_paca->kvm_hstate.ptid =0 ; local_paca->kvm_hstate.fake_suspend =0 ; -kvmppc_create_dtl_entry (vcpu, vc, tb); +__kvmppc_create_dtl_entry (vcpu, pcpu, tb + vc->tb_offset,0 );trace_kvm_guest_enter (vcpu);
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 52/53 KVM: PPC: Book3S HV P9: Stop using vc->dpdes
In reply to Nicholas PigginThe P9 path uses vc->dpdes only for msgsndp / SMT emulation. This adds an ordering requirement between vcpu->doorbell_request and vc->dpdes for no real benefit. Use vcpu->doorbell_request directly.
--- arch/powerpc/kvm/book3s_hv.c | 18 ++++++++++-------- arch/powerpc/kvm/book3s_hv_builtin.c | 2 ++ arch/powerpc/kvm/book3s_hv_p9_entry.c | 14 ++++++++++---- 3 files changed, 22 insertions(+), 12 deletions(-)
arch/powerpc/kvm/book3s_hv.c +10 -8
@@ -761,6 +761,8 @@ static bool kvmppc_doorbell_pending(struct kvm_vcpu *vcpu)if (vcpu->arch.doorbell_request)return true; +if (cpu_has_feature (CPU_FTR_ARCH_300 )) +return false;/* * Ensure that the read of vcore->dpdes comes after the read * of vcpu->doorbell_request. This barrier matches the
@@ -2185,8 +2187,10 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,* either vcore->dpdes or doorbell_request. * On POWER8, doorbell_request is 0. */ - *val =get_reg_val (id, vcpu->arch.vcore->dpdes | - vcpu->arch.doorbell_request); +if (cpu_has_feature (CPU_FTR_ARCH_300 )) + *val =get_reg_val (id, vcpu->arch.doorbell_request); +else + *val =get_reg_val (id, vcpu->arch.vcore->dpdes);break ;case KVM_REG_PPC_VTB : *val =get_reg_val (id, vcpu->arch.vcore->vtb);
@@ -2423,7 +2427,10 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, vcpu->arch.pspb =set_reg_val (id, *val);break ;case KVM_REG_PPC_DPDES : - vcpu->arch.vcore->dpdes =set_reg_val (id, *val); +if (cpu_has_feature (CPU_FTR_ARCH_300 )) + vcpu->arch.doorbell_request =set_reg_val (id, *val) &1 ; +else + vcpu->arch.vcore->dpdes =set_reg_val (id, *val);break ;case KVM_REG_PPC_VTB : vcpu->arch.vcore->vtb =set_reg_val (id, *val);
@@ -4491,11 +4498,6 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit,if (!nested) {kvmppc_core_prepare_to_enter (vcpu); -if (vcpu->arch.doorbell_request) { - vc->dpdes =1 ; -smp_wmb (); - vcpu->arch.doorbell_request =0 ; - }if (test_bit (BOOK3S_IRQPRIO_EXTERNAL , &vcpu->arch.pending_exceptions)) lpcr |=LPCR_MER ;
arch/powerpc/kvm/book3s_hv_builtin.c +2 -0
@@ -649,6 +649,8 @@ void kvmppc_guest_entry_inject_int(struct kvm_vcpu *vcpu)int ext;unsigned long lpcr; +WARN_ON_ONCE (cpu_has_feature (CPU_FTR_ARCH_300 )); +/* Insert EXTERNAL bit into LPCR at the MER bit position */ ext = (vcpu->arch.pending_exceptions >>BOOK3S_IRQPRIO_EXTERNAL ) &1 ; lpcr =mfspr (SPRN_LPCR );
arch/powerpc/kvm/book3s_hv_p9_entry.c +10 -4
@@ -780,6 +780,7 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcunsigned long host_pidr;unsigned long host_dawr1;unsigned long host_dawrx1; +unsigned long dpdes; hdec = time_limit - *tb;if (hdec <0 )
@@ -842,8 +843,10 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcif (vc->pcr)mtspr (SPRN_PCR , vc->pcr |PCR_MASK ); -if (vc->dpdes) -mtspr (SPRN_DPDES , vc->dpdes); +if (vcpu->arch.doorbell_request) { + vcpu->arch.doorbell_request =0 ; +mtspr (SPRN_DPDES ,1 ); + }if (dawr_enabled ()) {if (vcpu->arch.dawr0 != host_dawr0)
@@ -1074,7 +1077,10 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc vcpu->arch.shregs.sprg2 =mfspr (SPRN_SPRG2 ); vcpu->arch.shregs.sprg3 =mfspr (SPRN_SPRG3 ); - vc->dpdes =mfspr (SPRN_DPDES ); + dpdes =mfspr (SPRN_DPDES ); +if (dpdes) + vcpu->arch.doorbell_request =1 ; + vc->vtb =mfspr (SPRN_VTB ); dec =mfspr (SPRN_DEC );
@@ -1136,7 +1142,7 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc } } -if (vc->dpdes) +if (dpdes)mtspr (SPRN_DPDES ,0 );if (vc->pcr)mtspr (SPRN_PCR ,PCR_MASK );
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH v4 53/53 KVM: PPC: Book3S HV P9: Remove subcore HMI handling
In reply to Nicholas PigginOn POWER9 and newer, rather than the complex HMI synchronisation and subcore state, have each thread un-apply the guest TB offset before calling into the early HMI handler.
This allows the subcore state to be avoided, including subcore enter / exit guest, which includes an expensive divide that shows up slightly in profiles.
--- arch/powerpc/include/asm/kvm_ppc.h | 1 + arch/powerpc/kvm/book3s_hv.c | 12 +++--- arch/powerpc/kvm/book3s_hv_hmi.c | 7 +++- arch/powerpc/kvm/book3s_hv_p9_entry.c | 2 +- arch/powerpc/kvm/book3s_hv_ras.c | 54 +++++++++++++++++++++++++++ 5 files changed, 67 insertions(+), 9 deletions(-)
arch/powerpc/include/asm/kvm_ppc.h +1 -0
@@ -759,6 +759,7 @@ void kvmppc_realmode_machine_check(struct kvm_vcpu *vcpu);void kvmppc_subcore_enter_guest (void );void kvmppc_subcore_exit_guest (void );long kvmppc_realmode_hmi_handler (void ); +long kvmppc_p9_realmode_hmi_handler (struct kvm_vcpu *vcpu);long kvmppc_h_enter (struct kvm_vcpu *vcpu,unsigned long flags,long pte_index,unsigned long pteh,unsigned long ptel); long kvmppc_h_remove(struct kvm_vcpu *vcpu, unsigned long flags,
arch/powerpc/kvm/book3s_hv.c +5 -7
@@ -4033,8 +4033,6 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, vcpu->arch.ceded =0 ; -kvmppc_subcore_enter_guest (); -vcpu_vpa_increment_dispatch (vcpu);if (kvmhv_on_pseries ()) {
@@ -4087,8 +4085,6 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,vcpu_vpa_increment_dispatch (vcpu); -kvmppc_subcore_exit_guest (); -return trap; }
@@ -6102,9 +6098,11 @@ static int kvmppc_book3s_init_hv(void)if (r)return r; - r =kvm_init_subcore_bitmap (); -if (r) -return r; +if (!cpu_has_feature (CPU_FTR_ARCH_300 )) { + r =kvm_init_subcore_bitmap (); +if (r) +return r; + }/* * We need a way of accessing the XICS interrupt controller,
arch/powerpc/kvm/book3s_hv_hmi.c +6 -1
@@ -20,10 +20,15 @@ void wait_for_subcore_guest_exit(void)/* * NULL bitmap pointer indicates that KVM module hasn't -* been loaded yet and hence no guests are running. +* been loaded yet and hence no guests are running, or running +* on POWER9 or newer CPU. +* * If no KVM is in use, no need to co-ordinate among threads * as all of them will always be in host and no one is going * to modify TB other than the opal hmi handler. +* +* POWER9 and newer don't need this synchronisation. +* * Hence, just return from here. */ if (!local_paca->sibling_subcore_state)
arch/powerpc/kvm/book3s_hv_p9_entry.c +1 -1
@@ -1013,7 +1013,7 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpckvmppc_realmode_machine_check (vcpu); }else if (unlikely (trap ==BOOK3S_INTERRUPT_HMI )) { -kvmppc_realmode_hmi_handler (); +kvmppc_p9_realmode_hmi_handler (vcpu); }else if (trap ==BOOK3S_INTERRUPT_H_EMUL_ASSIST ) { vcpu->arch.emul_inst =mfspr (SPRN_HEIR );
arch/powerpc/kvm/book3s_hv_ras.c +54 -0
60 lines not on this page · raw message
Signature · 1 line
2.23.0
Michael Ellerman
AppliedQuoted 10 lines · Nicholas Piggin
This reduces radix guest full entry/exit latency on POWER9 and POWER10 by 2x.
Nested HV guests should see smaller improvements in their L1 entry/exit, but this is also combined with most L0 speedups also applying to nested entry. nginx localhost throughput test in a SMP nested guest is improved about 10% (in a direct guest it doesn't change much because it uses XIVE for IPIs) when L0 and L1 are patched.
[...]
Applied to powerpc/next.
[01/53] powerpc/64s: Remove WORT SPR from POWER9/10 (take 2)
https://git.kernel.org/powerpc/c/f53884b1bf28497e9596cac8b44ef1d41bd6dfc5 [02/53] powerpc/64s: guard optional TIDR SPR with CPU ftr test https://git.kernel.org/powerpc/c/736df58fd5bcd02f811f7d474bbe02a35ffaa8f0 [03/53] KMV: PPC: Book3S HV P9: Use set_dec to set decrementer to host https://git.kernel.org/powerpc/c/5955c7469a73033f607ebd6d418058943fe13dd3 [04/53] KVM: PPC: Book3S HV P9: Use host timer accounting to avoid decrementer read https://git.kernel.org/powerpc/c/4ebbd075bcde7884e078d4360510b989f559bfec [05/53] KVM: PPC: Book3S HV P9: Use large decrementer for HDEC https://git.kernel.org/powerpc/c/9581991a60817abe311c2581ae4554b28bfa32f1 [06/53] KVM: PPC: Book3S HV P9: Reduce mftb per guest entry/exit https://git.kernel.org/powerpc/c/34bf08a2079fffc7206a1ae93086ab8167e0afb6 [07/53] powerpc/time: add API for KVM to re-arm the host timer/decrementer https://git.kernel.org/powerpc/c/25aa145856cd0d94864bf501218be84a7c8062ae [08/53] KVM: PPC: Book3S HV: POWER10 enable HAIL when running radix guests https://git.kernel.org/powerpc/c/eacc818864bb01828280f4d64334c4e5ae6a4daf [09/53] powerpc/64s: Keep AMOR SPR a constant ~0 at runtime https://git.kernel.org/powerpc/c/46f9caf1a246a5c0622fa8cc7e673658e925f97e [10/53] KVM: PPC: Book3S HV: Don't always save PMU for guest capable of nesting https://git.kernel.org/powerpc/c/d3c8a2d3740d93778ea102d4c781746d284177bf [11/53] powerpc/64s: Always set PMU control registers to frozen/disabled when not in use https://git.kernel.org/powerpc/c/245ebf8e7380b3d84c0aac37fbfd9306b45a3a7a [12/53] powerpc/64s: Implement PMU override command line option https://git.kernel.org/powerpc/c/0a4b4327ce867e3ac1b3ad15f4d2b686b516b3a2 [13/53] KVM: PPC: Book3S HV P9: Implement PMU save/restore in C https://git.kernel.org/powerpc/c/57dc0eed73caa31bfe36ce8fed234e214e37a5ae [14/53] KVM: PPC: Book3S HV P9: Factor PMU save/load into context switch functions https://git.kernel.org/powerpc/c/401e1ae372673664465d45a86975c006dc6a488d [15/53] KVM: PPC: Book3S HV P9: Demand fault PMU SPRs when marked not inuse https://git.kernel.org/powerpc/c/9d3ddb86d96d9f0314f3baaf0e37f987b40d3eee [16/53] KVM: PPC: Book3S HV P9: Factor out yield_count increment https://git.kernel.org/powerpc/c/b1adcf57ceca7eab9bfdafc754802e05e634bfcc [17/53] KVM: PPC: Book3S HV: CTRL SPR does not require read-modify-write https://git.kernel.org/powerpc/c/a1a19e1154e4e9c6c1136474cb040657b1c17817 [18/53] KVM: PPC: Book3S HV P9: Move SPRG restore to restore_p9_host_os_sprs https://git.kernel.org/powerpc/c/174a3ab633392859888fc1a5cff278d5546d8474 [19/53] KVM: PPC: Book3S HV P9: Reduce mtmsrd instructions required to save host SPRs https://git.kernel.org/powerpc/c/34e119c96b2b381278d1ddf6b1708678462daba4 [20/53] KVM: PPC: Book3S HV P9: Improve mtmsrd scheduling by delaying MSR[EE] disable https://git.kernel.org/powerpc/c/2251fbe76395e4d89c31099984714c5f1135f052 [21/53] KVM: PPC: Book3S HV P9: Add kvmppc_stop_thread to match kvmppc_start_thread https://git.kernel.org/powerpc/c/cf99dedb4b2d2a18e004b1c84852fffa810dc44c [22/53] KVM: PPC: Book3S HV: Change dec_expires to be relative to guest timebase https://git.kernel.org/powerpc/c/3c1a4322bba79aad2d3f6f996b7e1c336bd909b3 [23/53] KVM: PPC: Book3S HV P9: Move TB updates https://git.kernel.org/powerpc/c/6547af3eba88e4806e853fee7547031b2cc6a560 [24/53] KVM: PPC: Book3S HV P9: Optimise timebase reads https://git.kernel.org/powerpc/c/cb2553a093093ae46cfaee31321bcedcd0312c5d [25/53] KVM: PPC: Book3S HV P9: Avoid SPR scoreboard stalls https://git.kernel.org/powerpc/c/9a1e530bbbdaa2184993a7d7fc61d78871540ccd [26/53] KVM: PPC: Book3S HV P9: Only execute mtSPR if the value changed https://git.kernel.org/powerpc/c/9dfe7aa7bc50556063c8658f59ad475131c09b65 [27/53] KVM: PPC: Book3S HV P9: Juggle SPR switching around https://git.kernel.org/powerpc/c/0f3b6c4851aef7a98b435c6f08b2c9c88165d254 [28/53] KVM: PPC: Book3S HV P9: Move vcpu register save/restore into functions https://git.kernel.org/powerpc/c/516b334210b831827e0491676625323f484275dd [29/53] KVM: PPC: Book3S HV P9: Move host OS save/restore functions to built-in https://git.kernel.org/powerpc/c/aabcaf6ae2a0912898bd243f0aec0ce6853983fc [30/53] KVM: PPC: Book3S HV P9: Move nested guest entry into its own function https://git.kernel.org/powerpc/c/08b3f08af583c01b3cfdc15bda68063c2a401512 [31/53] KVM: PPC: Book3S HV P9: Move remaining SPR and MSR access into low level entry https://git.kernel.org/powerpc/c/d5f480194577423731ee8413791a5486f26a95ab [32/53] KVM: PPC: Book3S HV P9: Implement TM fastpath for guest entry/exit https://git.kernel.org/powerpc/c/3f9e2966d1b0dd81bcfaeb816335e0ddeedde3c1 [33/53] KVM: PPC: Book3S HV P9: Switch PMU to guest as late as possible https://git.kernel.org/powerpc/c/3e7b3379023dad2e78c3200373a6368f5d0ee599 [34/53] KVM: PPC: Book3S HV P9: Restrict DSISR canary workaround to processors that require it https://git.kernel.org/powerpc/c/d55b1eccc7aa14a1750aecf271806365478ca805 [35/53] KVM: PPC: Book3S HV P9: More SPR speed improvements https://git.kernel.org/powerpc/c/34e02d555d8fa36cc756a083de1eeb56edab0e00 [36/53] KVM: PPC: Book3S HV P9: Demand fault EBB facility registers https://git.kernel.org/powerpc/c/a3e18ca8ab6f7f2260978f0a3842845414d799c0 [37/53] KVM: PPC: Book3S HV P9: Demand fault TM facility registers https://git.kernel.org/powerpc/c/022ecb960c89faad42ff0b417a71d9255dd115a3 [38/53] KVM: PPC: Book3S HV P9: Use Linux SPR save/restore to manage some host SPRs https://git.kernel.org/powerpc/c/5236756d04454c7ce9f45e27b434d75b8d6f8759 [39/53] KVM: PPC: Book3S HV P9: Comment and fix MMU context switching code https://git.kernel.org/powerpc/c/cf3b16cfa6503b1fe5e680f9711262e6a51ef097 [40/53] KVM: PPC: Book3S HV P9: Test dawr_enabled() before saving host DAWR SPRs https://git.kernel.org/powerpc/c/9c75f65f3583b0cf467c378a1076f0b50bbc2fb1 [41/53] KVM: PPC: Book3S HV P9: Don't restore PSSCR if not needed https://git.kernel.org/powerpc/c/a089a6869e7f613a8d961ac65bafd127317e4c5c [42/53] KVM: PPC: Book3S HV: Split P8 from P9 path guest vCPU TLB flushing https://git.kernel.org/powerpc/c/0ba0e5d5a691806cca3d4f290dcc61f656049872 [43/53] KVM: PPC: Book3S HV P9: Avoid tlbsync sequence on radix guest exit https://git.kernel.org/powerpc/c/d5c0e8332d82c04deee25dd6f28c5bbe84d49a73 [44/53] KVM: PPC: Book3S HV Nested: Avoid extra mftb() in nested entry https://git.kernel.org/powerpc/c/46dea77f790c1e7ab2e9f7452e34de0dc5da9b13 [45/53] KVM: PPC: Book3S HV P9: Improve mfmsr performance on entry https://git.kernel.org/powerpc/c/b49c65c5f9f1dac4ef1764578ad55bacf526eb38 [46/53] KVM: PPC: Book3S HV P9: Optimise hash guest SLB saving https://git.kernel.org/powerpc/c/241d1f19f0e5c257881a0661f201b51dc3e57f8c [47/53] KVM: PPC: Book3S HV P9: Avoid changing MSR[RI] in entry and exit https://git.kernel.org/powerpc/c/f08cbf5c7d1f86f12143a1dce23740411b03a807 [48/53] KVM: PPC: Book3S HV P9: Add unlikely annotation for !mmu_ready https://git.kernel.org/powerpc/c/4c9a68914eab1f17f6c428c579ffd75c4448461e [49/53] KVM: PPC: Book3S HV P9: Avoid cpu_in_guest atomics on entry and exit https://git.kernel.org/powerpc/c/434398ab5eed03dbc0075af9436e871712bfb45a [50/53] KVM: PPC: Book3S HV P9: Remove most of the vcore logic https://git.kernel.org/powerpc/c/ecb6a7207f92e33c2b7a1271165ecf5d8f420bba [51/53] KVM: PPC: Book3S HV P9: Tidy kvmppc_create_dtl_entry https://git.kernel.org/powerpc/c/617326ff01df30796d897895ebd18ce583c9b883 [52/53] KVM: PPC: Book3S HV P9: Stop using vc->dpdes https://git.kernel.org/powerpc/c/6398326b9ba182936bdc9d66475c09e39b701aa2 [53/53] KVM: PPC: Book3S HV P9: Remove subcore HMI handling https://git.kernel.org/powerpc/c/9c5a432a558105d6145b058fad78eb6fcf3d4c38
cheers