mirror of
https://github.com/torvalds/linux.git
synced 2024-11-28 23:21:31 +00:00
KVM: PPC: Book3S HV: Split P8 from P9 path guest vCPU TLB flushing
This creates separate functions for old and new paths for vCPU TLB flushing, which will reduce complexity of the next change. 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-43-npiggin@gmail.com
This commit is contained in:
parent
a089a6869e
commit
0ba0e5d5a6
@ -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)
|
||||
|
@ -682,60 +682,23 @@ static void flush_guest_tlb(struct kvm *kvm)
|
||||
unsigned long rb, set;
|
||||
|
||||
rb = PPC_BIT(52); /* IS = 2 */
|
||||
if (kvm_is_radix(kvm)) {
|
||||
/* R=1 PRS=1 RIC=2 */
|
||||
for (set = 0; set < kvm->arch.tlb_sets; ++set) {
|
||||
/* R=0 PRS=0 RIC=0 */
|
||||
asm volatile(PPC_TLBIEL(%0, %4, %3, %2, %1)
|
||||
: : "r" (rb), "i" (1), "i" (1), "i" (2),
|
||||
: : "r" (rb), "i" (0), "i" (0), "i" (0),
|
||||
"r" (0) : "memory");
|
||||
for (set = 1; set < kvm->arch.tlb_sets; ++set) {
|
||||
rb += PPC_BIT(51); /* increment set number */
|
||||
/* R=1 PRS=1 RIC=0 */
|
||||
asm volatile(PPC_TLBIEL(%0, %4, %3, %2, %1)
|
||||
: : "r" (rb), "i" (1), "i" (1), "i" (0),
|
||||
"r" (0) : "memory");
|
||||
}
|
||||
asm volatile("ptesync": : :"memory");
|
||||
// POWER9 congruence-class TLBIEL leaves ERAT. Flush it now.
|
||||
asm volatile(PPC_RADIX_INVALIDATE_ERAT_GUEST : : :"memory");
|
||||
} else {
|
||||
for (set = 0; set < kvm->arch.tlb_sets; ++set) {
|
||||
/* R=0 PRS=0 RIC=0 */
|
||||
asm volatile(PPC_TLBIEL(%0, %4, %3, %2, %1)
|
||||
: : "r" (rb), "i" (0), "i" (0), "i" (0),
|
||||
"r" (0) : "memory");
|
||||
rb += PPC_BIT(51); /* increment set number */
|
||||
}
|
||||
asm volatile("ptesync": : :"memory");
|
||||
// POWER9 congruence-class TLBIEL leaves ERAT. Flush it now.
|
||||
if (cpu_has_feature(CPU_FTR_ARCH_300))
|
||||
asm volatile(PPC_ISA_3_0_INVALIDATE_ERAT : : :"memory");
|
||||
rb += PPC_BIT(51); /* increment set number */
|
||||
}
|
||||
asm volatile("ptesync": : :"memory");
|
||||
}
|
||||
|
||||
void kvmppc_check_need_tlb_flush(struct kvm *kvm, int pcpu,
|
||||
struct kvm_nested_guest *nested)
|
||||
void kvmppc_check_need_tlb_flush(struct kvm *kvm, int pcpu)
|
||||
{
|
||||
cpumask_t *need_tlb_flush;
|
||||
|
||||
/*
|
||||
* On POWER9, individual threads can come in here, but the
|
||||
* TLB is shared between the 4 threads in a core, hence
|
||||
* invalidating on one thread invalidates for all.
|
||||
* Thus we make all 4 threads use the same bit.
|
||||
*/
|
||||
if (cpu_has_feature(CPU_FTR_ARCH_300))
|
||||
pcpu = cpu_first_tlb_thread_sibling(pcpu);
|
||||
|
||||
if (nested)
|
||||
need_tlb_flush = &nested->need_tlb_flush;
|
||||
else
|
||||
need_tlb_flush = &kvm->arch.need_tlb_flush;
|
||||
|
||||
if (cpumask_test_cpu(pcpu, need_tlb_flush)) {
|
||||
if (cpumask_test_cpu(pcpu, &kvm->arch.need_tlb_flush)) {
|
||||
flush_guest_tlb(kvm);
|
||||
|
||||
/* Clear the bit after the TLB flush */
|
||||
cpumask_clear_cpu(pcpu, need_tlb_flush);
|
||||
cpumask_clear_cpu(pcpu, &kvm->arch.need_tlb_flush);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvmppc_check_need_tlb_flush);
|
||||
|
@ -632,6 +632,66 @@ static void save_clear_guest_mmu(struct kvm *kvm, struct kvm_vcpu *vcpu)
|
||||
}
|
||||
}
|
||||
|
||||
static void flush_guest_tlb(struct kvm *kvm)
|
||||
{
|
||||
unsigned long rb, set;
|
||||
|
||||
rb = PPC_BIT(52); /* IS = 2 */
|
||||
if (kvm_is_radix(kvm)) {
|
||||
/* R=1 PRS=1 RIC=2 */
|
||||
asm volatile(PPC_TLBIEL(%0, %4, %3, %2, %1)
|
||||
: : "r" (rb), "i" (1), "i" (1), "i" (2),
|
||||
"r" (0) : "memory");
|
||||
for (set = 1; set < kvm->arch.tlb_sets; ++set) {
|
||||
rb += PPC_BIT(51); /* increment set number */
|
||||
/* R=1 PRS=1 RIC=0 */
|
||||
asm volatile(PPC_TLBIEL(%0, %4, %3, %2, %1)
|
||||
: : "r" (rb), "i" (1), "i" (1), "i" (0),
|
||||
"r" (0) : "memory");
|
||||
}
|
||||
asm volatile("ptesync": : :"memory");
|
||||
// POWER9 congruence-class TLBIEL leaves ERAT. Flush it now.
|
||||
asm volatile(PPC_RADIX_INVALIDATE_ERAT_GUEST : : :"memory");
|
||||
} else {
|
||||
for (set = 0; set < kvm->arch.tlb_sets; ++set) {
|
||||
/* R=0 PRS=0 RIC=0 */
|
||||
asm volatile(PPC_TLBIEL(%0, %4, %3, %2, %1)
|
||||
: : "r" (rb), "i" (0), "i" (0), "i" (0),
|
||||
"r" (0) : "memory");
|
||||
rb += PPC_BIT(51); /* increment set number */
|
||||
}
|
||||
asm volatile("ptesync": : :"memory");
|
||||
// POWER9 congruence-class TLBIEL leaves ERAT. Flush it now.
|
||||
asm volatile(PPC_ISA_3_0_INVALIDATE_ERAT : : :"memory");
|
||||
}
|
||||
}
|
||||
|
||||
static void check_need_tlb_flush(struct kvm *kvm, int pcpu,
|
||||
struct kvm_nested_guest *nested)
|
||||
{
|
||||
cpumask_t *need_tlb_flush;
|
||||
|
||||
/*
|
||||
* On POWER9, individual threads can come in here, but the
|
||||
* TLB is shared between the 4 threads in a core, hence
|
||||
* invalidating on one thread invalidates for all.
|
||||
* Thus we make all 4 threads use the same bit.
|
||||
*/
|
||||
pcpu = cpu_first_tlb_thread_sibling(pcpu);
|
||||
|
||||
if (nested)
|
||||
need_tlb_flush = &nested->need_tlb_flush;
|
||||
else
|
||||
need_tlb_flush = &kvm->arch.need_tlb_flush;
|
||||
|
||||
if (cpumask_test_cpu(pcpu, need_tlb_flush)) {
|
||||
flush_guest_tlb(kvm);
|
||||
|
||||
/* Clear the bit after the TLB flush */
|
||||
cpumask_clear_cpu(pcpu, need_tlb_flush);
|
||||
}
|
||||
}
|
||||
|
||||
int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcr, u64 *tb)
|
||||
{
|
||||
struct p9_host_os_sprs host_os_sprs;
|
||||
@ -819,7 +879,7 @@ int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpc
|
||||
}
|
||||
|
||||
/* TLBIEL uses LPID=LPIDR, so run this after setting guest LPID */
|
||||
kvmppc_check_need_tlb_flush(kvm, vc->pcpu, nested);
|
||||
check_need_tlb_flush(kvm, vc->pcpu, nested);
|
||||
|
||||
/*
|
||||
* P9 suppresses the HDEC exception when LPCR[HDICE] = 0,
|
||||
|
Loading…
Reference in New Issue
Block a user