Skip to content

Commit

Permalink
KVM: PPC: Book3S HV P9: Remove subcore HMI handling
Browse files Browse the repository at this point in the history
On 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.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20211123095231.1036501-54-npiggin@gmail.com
  • Loading branch information
Nicholas Piggin authored and Michael Ellerman committed Nov 24, 2021
1 parent 6398326 commit 9c5a432
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 9 deletions.
1 change: 1 addition & 0 deletions arch/powerpc/include/asm/kvm_ppc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
12 changes: 5 additions & 7 deletions arch/powerpc/kvm/book3s_hv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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,
Expand Down
7 changes: 6 additions & 1 deletion arch/powerpc/kvm/book3s_hv_hmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion arch/powerpc/kvm/book3s_hv_p9_entry.c
Original file line number Diff line number Diff line change
Expand Up @@ -1013,7 +1013,7 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc
kvmppc_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);
Expand Down
54 changes: 54 additions & 0 deletions arch/powerpc/kvm/book3s_hv_ras.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,60 @@ void kvmppc_realmode_machine_check(struct kvm_vcpu *vcpu)
vcpu->arch.mce_evt = mce_evt;
}


long kvmppc_p9_realmode_hmi_handler(struct kvm_vcpu *vcpu)
{
struct kvmppc_vcore *vc = vcpu->arch.vcore;
long ret = 0;

/*
* Unapply and clear the offset first. That way, if the TB was not
* resynced then it will remain in host-offset, and if it was resynced
* then it is brought into host-offset. Then the tb offset is
* re-applied before continuing with the KVM exit.
*
* This way, we don't need to actually know whether not OPAL resynced
* the timebase or do any of the complicated dance that the P7/8
* path requires.
*/
if (vc->tb_offset_applied) {
u64 new_tb = mftb() - vc->tb_offset_applied;
mtspr(SPRN_TBU40, new_tb);
if ((mftb() & 0xffffff) < (new_tb & 0xffffff)) {
new_tb += 0x1000000;
mtspr(SPRN_TBU40, new_tb);
}
vc->tb_offset_applied = 0;
}

local_paca->hmi_irqs++;

if (hmi_handle_debugtrig(NULL) >= 0) {
ret = 1;
goto out;
}

if (ppc_md.hmi_exception_early)
ppc_md.hmi_exception_early(NULL);

out:
if (vc->tb_offset) {
u64 new_tb = mftb() + vc->tb_offset;
mtspr(SPRN_TBU40, new_tb);
if ((mftb() & 0xffffff) < (new_tb & 0xffffff)) {
new_tb += 0x1000000;
mtspr(SPRN_TBU40, new_tb);
}
vc->tb_offset_applied = vc->tb_offset;
}

return ret;
}

/*
* The following subcore HMI handling is all only for pre-POWER9 CPUs.
*/

/* Check if dynamic split is in force and return subcore size accordingly. */
static inline int kvmppc_cur_subcore_size(void)
{
Expand Down

0 comments on commit 9c5a432

Please sign in to comment.