Fix conflicts between memslot overhaul and commit 511d25d6b7 ("KVM:
PPC: Book3S: Suppress warnings when allocating too big memory slots")
from the powerpc tree.
This commit is contained in:
Paolo Bonzini 2021-12-19 15:27:21 +01:00
commit 5a213b9220
30 changed files with 1582 additions and 746 deletions

View File

@ -4144,6 +4144,14 @@
Override pmtimer IOPort with a hex value. Override pmtimer IOPort with a hex value.
e.g. pmtmr=0x508 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] pm_debug_messages [SUSPEND,KNL]
Enable suspend/resume debug messages during boot up. Enable suspend/resume debug messages during boot up.

View File

@ -141,11 +141,6 @@ static inline void kvmppc_restore_tm_hv(struct kvm_vcpu *vcpu, u64 msr,
bool preserve_nv) { } bool preserve_nv) { }
#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ #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); void kvmppc_p9_enter_guest(struct kvm_vcpu *vcpu);
long kvmppc_h_set_dabr(struct kvm_vcpu *vcpu, unsigned long dabr); long kvmppc_h_set_dabr(struct kvm_vcpu *vcpu, unsigned long dabr);

View File

@ -79,6 +79,7 @@
#define BOOK3S_INTERRUPT_FP_UNAVAIL 0x800 #define BOOK3S_INTERRUPT_FP_UNAVAIL 0x800
#define BOOK3S_INTERRUPT_DECREMENTER 0x900 #define BOOK3S_INTERRUPT_DECREMENTER 0x900
#define BOOK3S_INTERRUPT_HV_DECREMENTER 0x980 #define BOOK3S_INTERRUPT_HV_DECREMENTER 0x980
#define BOOK3S_INTERRUPT_NESTED_HV_DECREMENTER 0x1980
#define BOOK3S_INTERRUPT_DOORBELL 0xa00 #define BOOK3S_INTERRUPT_DOORBELL 0xa00
#define BOOK3S_INTERRUPT_SYSCALL 0xc00 #define BOOK3S_INTERRUPT_SYSCALL 0xc00
#define BOOK3S_INTERRUPT_TRACE 0xd00 #define BOOK3S_INTERRUPT_TRACE 0xd00

View File

@ -406,6 +406,12 @@ static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu)
return vcpu->arch.fault_dar; 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) static inline bool is_kvmppc_resume_guest(int r)
{ {
return (r == RESUME_GUEST || r == RESUME_GUEST_NV); return (r == RESUME_GUEST || r == RESUME_GUEST_NV);

View File

@ -44,7 +44,6 @@ struct kvm_nested_guest {
struct mutex tlb_lock; /* serialize page faults and tlbies */ struct mutex tlb_lock; /* serialize page faults and tlbies */
struct kvm_nested_guest *next; struct kvm_nested_guest *next;
cpumask_t need_tlb_flush; cpumask_t need_tlb_flush;
cpumask_t cpu_in_guest;
short prev_cpu[NR_CPUS]; short prev_cpu[NR_CPUS];
u8 radix; /* is this nested guest radix */ u8 radix; /* is this nested guest radix */
}; };
@ -154,7 +153,9 @@ static inline bool kvmhv_vcpu_is_radix(struct kvm_vcpu *vcpu)
return radix; return radix;
} }
int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcr); 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 */ #define KVM_DEFAULT_HPT_ORDER 24 /* 16MB HPT by default */
#endif #endif

View File

@ -287,7 +287,6 @@ struct kvm_arch {
u32 online_vcores; u32 online_vcores;
atomic_t hpte_mod_interest; atomic_t hpte_mod_interest;
cpumask_t need_tlb_flush; cpumask_t need_tlb_flush;
cpumask_t cpu_in_guest;
u8 radix; u8 radix;
u8 fwnmi_enabled; u8 fwnmi_enabled;
u8 secure_guest; u8 secure_guest;
@ -579,6 +578,10 @@ struct kvm_vcpu_arch {
ulong cfar; ulong cfar;
ulong ppr; ulong ppr;
u32 pspb; u32 pspb;
u8 load_ebb;
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
u8 load_tm;
#endif
ulong fscr; ulong fscr;
ulong shadow_fscr; ulong shadow_fscr;
ulong ebbhr; ulong ebbhr;
@ -741,7 +744,7 @@ struct kvm_vcpu_arch {
struct hrtimer dec_timer; struct hrtimer dec_timer;
u64 dec_jiffies; u64 dec_jiffies;
u64 dec_expires; u64 dec_expires; /* Relative to guest timebase. */
unsigned long pending_exceptions; unsigned long pending_exceptions;
u8 ceded; u8 ceded;
u8 prodded; u8 prodded;

View File

@ -550,8 +550,7 @@ extern void kvm_hv_vm_activated(void);
extern void kvm_hv_vm_deactivated(void); extern void kvm_hv_vm_deactivated(void);
extern bool kvm_hv_mode_active(void); extern bool kvm_hv_mode_active(void);
extern void kvmppc_check_need_tlb_flush(struct kvm *kvm, int pcpu, extern void kvmppc_check_need_tlb_flush(struct kvm *kvm, int pcpu);
struct kvm_nested_guest *nested);
#else #else
static inline void __init kvm_cma_reserve(void) static inline void __init kvm_cma_reserve(void)
@ -758,6 +757,7 @@ void kvmppc_realmode_machine_check(struct kvm_vcpu *vcpu);
void kvmppc_subcore_enter_guest(void); void kvmppc_subcore_enter_guest(void);
void kvmppc_subcore_exit_guest(void); void kvmppc_subcore_exit_guest(void);
long kvmppc_realmode_hmi_handler(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 kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
long pte_index, unsigned long pteh, unsigned long ptel); long pte_index, unsigned long pteh, unsigned long ptel);
long kvmppc_h_remove(struct kvm_vcpu *vcpu, unsigned long flags, long kvmppc_h_remove(struct kvm_vcpu *vcpu, unsigned long flags,

View File

@ -112,6 +112,9 @@ static inline void clear_task_ebb(struct task_struct *t)
#endif #endif
} }
void kvmppc_save_user_regs(void);
void kvmppc_save_current_sprs(void);
extern int set_thread_tidr(struct task_struct *t); extern int set_thread_tidr(struct task_struct *t);
#endif /* _ASM_POWERPC_SWITCH_TO_H */ #endif /* _ASM_POWERPC_SWITCH_TO_H */

View File

@ -18,6 +18,8 @@
#include <asm/vdso/timebase.h> #include <asm/vdso/timebase.h>
/* time.c */ /* time.c */
extern u64 decrementer_max;
extern unsigned long tb_ticks_per_jiffy; extern unsigned long tb_ticks_per_jiffy;
extern unsigned long tb_ticks_per_usec; extern unsigned long tb_ticks_per_usec;
extern unsigned long tb_ticks_per_sec; extern unsigned long tb_ticks_per_sec;
@ -97,20 +99,17 @@ extern void div128_by_32(u64 dividend_high, u64 dividend_low,
extern void secondary_cpu_time_init(void); extern void secondary_cpu_time_init(void);
extern void __init time_init(void); extern void __init time_init(void);
#ifdef CONFIG_PPC64
static inline unsigned long test_irq_work_pending(void)
{
unsigned long x;
asm volatile("lbz %0,%1(13)"
: "=r" (x)
: "i" (offsetof(struct paca_struct, irq_work_pending)));
return x;
}
#endif
DECLARE_PER_CPU(u64, decrementers_next_tb); DECLARE_PER_CPU(u64, decrementers_next_tb);
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 */ /* Convert timebase ticks to nanoseconds */
unsigned long long tb_to_ns(unsigned long long tb_ticks); unsigned long long tb_to_ns(unsigned long long tb_ticks);

View File

@ -109,7 +109,7 @@ static void init_PMU_HV_ISA207(void)
static void init_PMU(void) static void init_PMU(void)
{ {
mtspr(SPRN_MMCRA, 0); mtspr(SPRN_MMCRA, 0);
mtspr(SPRN_MMCR0, 0); mtspr(SPRN_MMCR0, MMCR0_FC);
mtspr(SPRN_MMCR1, 0); mtspr(SPRN_MMCR1, 0);
mtspr(SPRN_MMCR2, 0); mtspr(SPRN_MMCR2, 0);
} }
@ -123,7 +123,7 @@ static void init_PMU_ISA31(void)
{ {
mtspr(SPRN_MMCR3, 0); mtspr(SPRN_MMCR3, 0);
mtspr(SPRN_MMCRA, MMCRA_BHRB_DISABLE); mtspr(SPRN_MMCRA, MMCRA_BHRB_DISABLE);
mtspr(SPRN_MMCR0, MMCR0_PMCCEXT); mtspr(SPRN_MMCR0, MMCR0_FC | MMCR0_PMCCEXT);
} }
/* /*
@ -137,6 +137,7 @@ void __setup_cpu_power7(unsigned long offset, struct cpu_spec *t)
return; return;
mtspr(SPRN_LPID, 0); mtspr(SPRN_LPID, 0);
mtspr(SPRN_AMOR, ~0);
mtspr(SPRN_PCR, PCR_MASK); mtspr(SPRN_PCR, PCR_MASK);
init_LPCR_ISA206(mfspr(SPRN_LPCR), LPCR_LPES1 >> LPCR_LPES_SH); init_LPCR_ISA206(mfspr(SPRN_LPCR), LPCR_LPES1 >> LPCR_LPES_SH);
} }
@ -150,6 +151,7 @@ void __restore_cpu_power7(void)
return; return;
mtspr(SPRN_LPID, 0); mtspr(SPRN_LPID, 0);
mtspr(SPRN_AMOR, ~0);
mtspr(SPRN_PCR, PCR_MASK); mtspr(SPRN_PCR, PCR_MASK);
init_LPCR_ISA206(mfspr(SPRN_LPCR), LPCR_LPES1 >> LPCR_LPES_SH); 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; return;
mtspr(SPRN_LPID, 0); mtspr(SPRN_LPID, 0);
mtspr(SPRN_AMOR, ~0);
mtspr(SPRN_PCR, PCR_MASK); mtspr(SPRN_PCR, PCR_MASK);
init_LPCR_ISA206(mfspr(SPRN_LPCR) | LPCR_PECEDH, 0); /* LPES = 0 */ init_LPCR_ISA206(mfspr(SPRN_LPCR) | LPCR_PECEDH, 0); /* LPES = 0 */
init_HFSCR(); init_HFSCR();
@ -184,6 +187,7 @@ void __restore_cpu_power8(void)
return; return;
mtspr(SPRN_LPID, 0); mtspr(SPRN_LPID, 0);
mtspr(SPRN_AMOR, ~0);
mtspr(SPRN_PCR, PCR_MASK); mtspr(SPRN_PCR, PCR_MASK);
init_LPCR_ISA206(mfspr(SPRN_LPCR) | LPCR_PECEDH, 0); /* LPES = 0 */ init_LPCR_ISA206(mfspr(SPRN_LPCR) | LPCR_PECEDH, 0); /* LPES = 0 */
init_HFSCR(); init_HFSCR();
@ -202,6 +206,7 @@ void __setup_cpu_power9(unsigned long offset, struct cpu_spec *t)
mtspr(SPRN_PSSCR, 0); mtspr(SPRN_PSSCR, 0);
mtspr(SPRN_LPID, 0); mtspr(SPRN_LPID, 0);
mtspr(SPRN_PID, 0); mtspr(SPRN_PID, 0);
mtspr(SPRN_AMOR, ~0);
mtspr(SPRN_PCR, PCR_MASK); mtspr(SPRN_PCR, PCR_MASK);
init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\ init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\
LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0); LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0);
@ -223,6 +228,7 @@ void __restore_cpu_power9(void)
mtspr(SPRN_PSSCR, 0); mtspr(SPRN_PSSCR, 0);
mtspr(SPRN_LPID, 0); mtspr(SPRN_LPID, 0);
mtspr(SPRN_PID, 0); mtspr(SPRN_PID, 0);
mtspr(SPRN_AMOR, ~0);
mtspr(SPRN_PCR, PCR_MASK); mtspr(SPRN_PCR, PCR_MASK);
init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\ init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\
LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0); 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_PSSCR, 0);
mtspr(SPRN_LPID, 0); mtspr(SPRN_LPID, 0);
mtspr(SPRN_PID, 0); mtspr(SPRN_PID, 0);
mtspr(SPRN_AMOR, ~0);
mtspr(SPRN_PCR, PCR_MASK); mtspr(SPRN_PCR, PCR_MASK);
init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\ init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\
LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0); LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0);
@ -264,6 +271,7 @@ void __restore_cpu_power10(void)
mtspr(SPRN_PSSCR, 0); mtspr(SPRN_PSSCR, 0);
mtspr(SPRN_LPID, 0); mtspr(SPRN_LPID, 0);
mtspr(SPRN_PID, 0); mtspr(SPRN_PID, 0);
mtspr(SPRN_AMOR, ~0);
mtspr(SPRN_PCR, PCR_MASK); mtspr(SPRN_PCR, PCR_MASK);
init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\ init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\
LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0); LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0);

View File

@ -80,6 +80,7 @@ static void __restore_cpu_cpufeatures(void)
mtspr(SPRN_LPCR, system_registers.lpcr); mtspr(SPRN_LPCR, system_registers.lpcr);
if (hv_mode) { if (hv_mode) {
mtspr(SPRN_LPID, 0); mtspr(SPRN_LPID, 0);
mtspr(SPRN_AMOR, ~0);
mtspr(SPRN_HFSCR, system_registers.hfscr); mtspr(SPRN_HFSCR, system_registers.hfscr);
mtspr(SPRN_PCR, system_registers.pcr); 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_LPID, 0);
mtspr(SPRN_AMOR, ~0);
lpcr = mfspr(SPRN_LPCR); lpcr = mfspr(SPRN_LPCR);
lpcr &= ~LPCR_LPES0; /* HV external interrupts */ lpcr &= ~LPCR_LPES0; /* HV external interrupts */
@ -351,7 +353,7 @@ static void init_pmu_power8(void)
} }
mtspr(SPRN_MMCRA, 0); mtspr(SPRN_MMCRA, 0);
mtspr(SPRN_MMCR0, 0); mtspr(SPRN_MMCR0, MMCR0_FC);
mtspr(SPRN_MMCR1, 0); mtspr(SPRN_MMCR1, 0);
mtspr(SPRN_MMCR2, 0); mtspr(SPRN_MMCR2, 0);
mtspr(SPRN_MMCRS, 0); mtspr(SPRN_MMCRS, 0);
@ -390,7 +392,7 @@ static void init_pmu_power9(void)
mtspr(SPRN_MMCRC, 0); mtspr(SPRN_MMCRC, 0);
mtspr(SPRN_MMCRA, 0); mtspr(SPRN_MMCRA, 0);
mtspr(SPRN_MMCR0, 0); mtspr(SPRN_MMCR0, MMCR0_FC);
mtspr(SPRN_MMCR1, 0); mtspr(SPRN_MMCR1, 0);
mtspr(SPRN_MMCR2, 0); mtspr(SPRN_MMCR2, 0);
} }
@ -426,7 +428,7 @@ static void init_pmu_power10(void)
mtspr(SPRN_MMCR3, 0); mtspr(SPRN_MMCR3, 0);
mtspr(SPRN_MMCRA, MMCRA_BHRB_DISABLE); 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) static int __init feat_enable_pmu_power10(struct dt_cpu_feature *f)

View File

@ -1156,6 +1156,40 @@ static inline void save_sprs(struct thread_struct *t)
#endif #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);
void kvmppc_save_current_sprs(void)
{
save_sprs(&current->thread);
}
EXPORT_SYMBOL_GPL(kvmppc_save_current_sprs);
#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
static inline void restore_sprs(struct thread_struct *old_thread, static inline void restore_sprs(struct thread_struct *old_thread,
struct thread_struct *new_thread) struct thread_struct *new_thread)
{ {

View File

@ -88,6 +88,7 @@ static struct clocksource clocksource_timebase = {
#define DECREMENTER_DEFAULT_MAX 0x7FFFFFFF #define DECREMENTER_DEFAULT_MAX 0x7FFFFFFF
u64 decrementer_max = DECREMENTER_DEFAULT_MAX; u64 decrementer_max = DECREMENTER_DEFAULT_MAX;
EXPORT_SYMBOL_GPL(decrementer_max); /* for KVM HDEC */
static int decrementer_set_next_event(unsigned long evt, static int decrementer_set_next_event(unsigned long evt,
struct clock_event_device *dev); struct clock_event_device *dev);
@ -107,6 +108,7 @@ struct clock_event_device decrementer_clockevent = {
EXPORT_SYMBOL(decrementer_clockevent); EXPORT_SYMBOL(decrementer_clockevent);
DEFINE_PER_CPU(u64, decrementers_next_tb); DEFINE_PER_CPU(u64, decrementers_next_tb);
EXPORT_SYMBOL_GPL(decrementers_next_tb);
static DEFINE_PER_CPU(struct clock_event_device, decrementers); static DEFINE_PER_CPU(struct clock_event_device, decrementers);
#define XSEC_PER_SEC (1024*1024) #define XSEC_PER_SEC (1024*1024)
@ -496,6 +498,16 @@ EXPORT_SYMBOL(profile_pc);
* 64-bit uses a byte in the PACA, 32-bit uses a per-cpu variable... * 64-bit uses a byte in the PACA, 32-bit uses a per-cpu variable...
*/ */
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
static inline unsigned long test_irq_work_pending(void)
{
unsigned long x;
asm volatile("lbz %0,%1(13)"
: "=r" (x)
: "i" (offsetof(struct paca_struct, irq_work_pending)));
return x;
}
static inline void set_irq_work_pending_flag(void) static inline void set_irq_work_pending_flag(void)
{ {
asm volatile("stb %0,%1(13)" : : asm volatile("stb %0,%1(13)" : :
@ -539,13 +551,44 @@ void arch_irq_work_raise(void)
preempt_enable(); preempt_enable();
} }
static void set_dec_or_work(u64 val)
{
set_dec(val);
/* We may have raced with new irq work */
if (unlikely(test_irq_work_pending()))
set_dec(1);
}
#else /* CONFIG_IRQ_WORK */ #else /* CONFIG_IRQ_WORK */
#define test_irq_work_pending() 0 #define test_irq_work_pending() 0
#define clear_irq_work_pending() #define clear_irq_work_pending()
static void set_dec_or_work(u64 val)
{
set_dec(val);
}
#endif /* CONFIG_IRQ_WORK */ #endif /* CONFIG_IRQ_WORK */
#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
void timer_rearm_host_dec(u64 now)
{
u64 *next_tb = this_cpu_ptr(&decrementers_next_tb);
WARN_ON_ONCE(!arch_irqs_disabled());
WARN_ON_ONCE(mfmsr() & MSR_EE);
if (now >= *next_tb) {
local_paca->irq_happened |= PACA_IRQ_DEC;
} else {
now = *next_tb - now;
if (now <= decrementer_max)
set_dec_or_work(now);
}
}
EXPORT_SYMBOL_GPL(timer_rearm_host_dec);
#endif
/* /*
* timer_interrupt - gets called when the decrementer overflows, * timer_interrupt - gets called when the decrementer overflows,
* with interrupts disabled. * with interrupts disabled.
@ -606,10 +649,7 @@ DEFINE_INTERRUPT_HANDLER_ASYNC(timer_interrupt)
} else { } else {
now = *next_tb - now; now = *next_tb - now;
if (now <= decrementer_max) if (now <= decrementer_max)
set_dec(now); set_dec_or_work(now);
/* We may have raced with new irq work */
if (test_irq_work_pending())
set_dec(1);
__this_cpu_inc(irq_stat.timer_irqs_others); __this_cpu_inc(irq_stat.timer_irqs_others);
} }
@ -843,11 +883,7 @@ static int decrementer_set_next_event(unsigned long evt,
struct clock_event_device *dev) struct clock_event_device *dev)
{ {
__this_cpu_write(decrementers_next_tb, get_tb() + evt); __this_cpu_write(decrementers_next_tb, get_tb() + evt);
set_dec(evt); set_dec_or_work(evt);
/* We may have raced with new irq work */
if (test_irq_work_pending())
set_dec(1);
return 0; return 0;
} }

View File

@ -131,6 +131,21 @@ config KVM_BOOK3S_HV_EXIT_TIMING
If unsure, say N. 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 config KVM_BOOKE_HV
bool bool

View File

@ -374,11 +374,16 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX)
BEGIN_FTR_SECTION BEGIN_FTR_SECTION
mtspr SPRN_DAWRX1,r10 mtspr SPRN_DAWRX1,r10
END_FTR_SECTION_IFSET(CPU_FTR_DAWR1) 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, HSTATE_KVM_VCPU(r13)
ld r10, VCPU_KVM(r10) ld r10, VCPU_KVM(r10)
lwz r10, KVM_HOST_LPID(r10) lwz r10, KVM_HOST_LPID(r10)
@ -389,6 +394,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_DAWR1)
ld r10, KVM_HOST_LPCR(r10) ld r10, KVM_HOST_LPCR(r10)
mtspr SPRN_LPCR,r10 mtspr SPRN_LPCR,r10
isync
/* /*
* Set GUEST_MODE_NONE so the handler won't branch to KVM, and clear * 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. * MSR_RI in r12 ([H]SRR1) so the handler won't try to return.

View File

@ -57,6 +57,8 @@ unsigned long __kvmhv_copy_tofrom_guest_radix(int lpid, int pid,
preempt_disable(); preempt_disable();
asm volatile("hwsync" ::: "memory");
isync();
/* switch the lpid first to avoid running host with unallocated pid */ /* switch the lpid first to avoid running host with unallocated pid */
old_lpid = mfspr(SPRN_LPID); old_lpid = mfspr(SPRN_LPID);
if (old_lpid != 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); ret = __copy_to_user_inatomic((void __user *)to, from, n);
pagefault_enable(); pagefault_enable();
asm volatile("hwsync" ::: "memory");
isync();
/* switch the pid first to avoid running host with unallocated pid */ /* switch the pid first to avoid running host with unallocated pid */
if (quadrant == 1 && pid != old_pid) if (quadrant == 1 && pid != old_pid)
mtspr(SPRN_PID, old_pid); mtspr(SPRN_PID, old_pid);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,42 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Privileged (non-hypervisor) host registers to save.
*/
struct p9_host_os_sprs {
unsigned long iamr;
unsigned long amr;
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 inline bool nesting_enabled(struct kvm *kvm)
{
return kvm->arch.nested_enable && kvm_is_radix(kvm);
}
bool load_vcpu_state(struct kvm_vcpu *vcpu,
struct p9_host_os_sprs *host_os_sprs);
void store_vcpu_state(struct kvm_vcpu *vcpu);
void save_p9_host_os_sprs(struct p9_host_os_sprs *host_os_sprs);
void restore_p9_host_os_sprs(struct kvm_vcpu *vcpu,
struct p9_host_os_sprs *host_os_sprs);
void switch_pmu_to_guest(struct kvm_vcpu *vcpu,
struct p9_host_os_sprs *host_os_sprs);
void switch_pmu_to_host(struct kvm_vcpu *vcpu,
struct p9_host_os_sprs *host_os_sprs);

View File

@ -649,6 +649,8 @@ void kvmppc_guest_entry_inject_int(struct kvm_vcpu *vcpu)
int ext; int ext;
unsigned long lpcr; unsigned long lpcr;
WARN_ON_ONCE(cpu_has_feature(CPU_FTR_ARCH_300));
/* Insert EXTERNAL bit into LPCR at the MER bit position */ /* Insert EXTERNAL bit into LPCR at the MER bit position */
ext = (vcpu->arch.pending_exceptions >> BOOK3S_IRQPRIO_EXTERNAL) & 1; ext = (vcpu->arch.pending_exceptions >> BOOK3S_IRQPRIO_EXTERNAL) & 1;
lpcr = mfspr(SPRN_LPCR); lpcr = mfspr(SPRN_LPCR);
@ -682,60 +684,23 @@ static void flush_guest_tlb(struct kvm *kvm)
unsigned long rb, set; unsigned long rb, set;
rb = PPC_BIT(52); /* IS = 2 */ rb = PPC_BIT(52); /* IS = 2 */
if (kvm_is_radix(kvm)) { for (set = 0; set < kvm->arch.tlb_sets; ++set) {
/* R=1 PRS=1 RIC=2 */ /* R=0 PRS=0 RIC=0 */
asm volatile(PPC_TLBIEL(%0, %4, %3, %2, %1) 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"); "r" (0) : "memory");
for (set = 1; set < kvm->arch.tlb_sets; ++set) { rb += PPC_BIT(51); /* increment set number */
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");
} }
asm volatile("ptesync": : :"memory");
} }
void kvmppc_check_need_tlb_flush(struct kvm *kvm, int pcpu, void kvmppc_check_need_tlb_flush(struct kvm *kvm, int pcpu)
struct kvm_nested_guest *nested)
{ {
cpumask_t *need_tlb_flush; if (cpumask_test_cpu(pcpu, &kvm->arch.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)) {
flush_guest_tlb(kvm); flush_guest_tlb(kvm);
/* Clear the bit after the TLB flush */ /* 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); EXPORT_SYMBOL_GPL(kvmppc_check_need_tlb_flush);

View File

@ -20,10 +20,15 @@ void wait_for_subcore_guest_exit(void)
/* /*
* NULL bitmap pointer indicates that KVM module hasn't * 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 * 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 * as all of them will always be in host and no one is going
* to modify TB other than the opal hmi handler. * to modify TB other than the opal hmi handler.
*
* POWER9 and newer don't need this synchronisation.
*
* Hence, just return from here. * Hence, just return from here.
*/ */
if (!local_paca->sibling_subcore_state) if (!local_paca->sibling_subcore_state)

View File

@ -104,7 +104,10 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
mtlr r0 mtlr r0
blr blr
_GLOBAL(kvmhv_save_host_pmu) /*
* void kvmhv_save_host_pmu(void)
*/
kvmhv_save_host_pmu:
BEGIN_FTR_SECTION BEGIN_FTR_SECTION
/* Work around P8 PMAE bug */ /* Work around P8 PMAE bug */
li r3, -1 li r3, -1
@ -138,14 +141,6 @@ BEGIN_FTR_SECTION
std r8, HSTATE_MMCR2(r13) std r8, HSTATE_MMCR2(r13)
std r9, HSTATE_SIER(r13) std r9, HSTATE_SIER(r13)
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) 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 r3, SPRN_PMC1
mfspr r5, SPRN_PMC2 mfspr r5, SPRN_PMC2
mfspr r6, SPRN_PMC3 mfspr r6, SPRN_PMC3

View File

@ -358,6 +358,7 @@ long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu)
/* convert TB values/offsets to host (L0) values */ /* convert TB values/offsets to host (L0) values */
hdec_exp = l2_hv.hdec_expiry - vc->tb_offset; hdec_exp = l2_hv.hdec_expiry - vc->tb_offset;
vc->tb_offset += l2_hv.tb_offset; vc->tb_offset += l2_hv.tb_offset;
vcpu->arch.dec_expires += l2_hv.tb_offset;
/* set L1 state to L2 state */ /* set L1 state to L2 state */
vcpu->arch.nested = l2; vcpu->arch.nested = l2;
@ -374,11 +375,6 @@ long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu)
vcpu->arch.ret = RESUME_GUEST; vcpu->arch.ret = RESUME_GUEST;
vcpu->arch.trap = 0; vcpu->arch.trap = 0;
do { 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); r = kvmhv_run_single_vcpu(vcpu, hdec_exp, lpcr);
} while (is_kvmppc_resume_guest(r)); } while (is_kvmppc_resume_guest(r));
@ -399,6 +395,8 @@ long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu)
if (l2_regs.msr & MSR_TS_MASK) if (l2_regs.msr & MSR_TS_MASK)
vcpu->arch.shregs.msr |= MSR_TS_S; vcpu->arch.shregs.msr |= MSR_TS_S;
vc->tb_offset = saved_l1_hv.tb_offset; 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); restore_hv_regs(vcpu, &saved_l1_hv);
vcpu->arch.purr += delta_purr; vcpu->arch.purr += delta_purr;
vcpu->arch.spurr += delta_spurr; vcpu->arch.spurr += delta_spurr;
@ -582,7 +580,7 @@ long kvmhv_copy_tofrom_guest_nested(struct kvm_vcpu *vcpu)
if (eaddr & (0xFFFUL << 52)) if (eaddr & (0xFFFUL << 52))
return H_PARAMETER; return H_PARAMETER;
buf = kzalloc(n, GFP_KERNEL); buf = kzalloc(n, GFP_KERNEL | __GFP_NOWARN);
if (!buf) if (!buf)
return H_NO_MEM; return H_NO_MEM;

File diff suppressed because it is too large Load Diff

View File

@ -136,6 +136,60 @@ void kvmppc_realmode_machine_check(struct kvm_vcpu *vcpu)
vcpu->arch.mce_evt = mce_evt; 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. */ /* Check if dynamic split is in force and return subcore size accordingly. */
static inline int kvmppc_cur_subcore_size(void) static inline int kvmppc_cur_subcore_size(void)
{ {

View File

@ -55,12 +55,6 @@ static int global_invalidates(struct kvm *kvm)
smp_wmb(); smp_wmb();
cpumask_setall(&kvm->arch.need_tlb_flush); cpumask_setall(&kvm->arch.need_tlb_flush);
cpu = local_paca->kvm_hstate.kvm_vcore->pcpu; 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); cpumask_clear_cpu(cpu, &kvm->arch.need_tlb_flush);
} }

View File

@ -778,17 +778,14 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
/* Restore AMR and UAMOR, set AMOR to all 1s */ /* Restore AMR and UAMOR, set AMOR to all 1s */
ld r5,VCPU_AMR(r4) ld r5,VCPU_AMR(r4)
ld r6,VCPU_UAMOR(r4) ld r6,VCPU_UAMOR(r4)
li r7,-1
mtspr SPRN_AMR,r5 mtspr SPRN_AMR,r5
mtspr SPRN_UAMOR,r6 mtspr SPRN_UAMOR,r6
mtspr SPRN_AMOR,r7
/* 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) lwz r5,VCPU_CTRL(r4)
andi. r5,r5,1 andi. r5,r5,1
bne 4f bne 4f
mfspr r6,SPRN_CTRLF li r6,0
clrrdi r6,r6,1
mtspr SPRN_CTRLT,r6 mtspr SPRN_CTRLT,r6
4: 4:
/* Secondary threads wait for primary to have done partition switch */ /* Secondary threads wait for primary to have done partition switch */
@ -817,10 +814,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
* Set the decrementer to the guest decrementer. * Set the decrementer to the guest decrementer.
*/ */
ld r8,VCPU_DEC_EXPIRES(r4) 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 mftb r7
subf r3,r7,r8 subf r3,r7,r8
mtspr SPRN_DEC,r3 mtspr SPRN_DEC,r3
@ -1195,9 +1188,6 @@ guest_bypass:
mftb r6 mftb r6
extsw r5,r5 extsw r5,r5
16: add r5,r5,r6 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) std r5,VCPU_DEC_EXPIRES(r9)
/* Increment exit count, poke other threads to exit */ /* Increment exit count, poke other threads to exit */
@ -1211,12 +1201,12 @@ guest_bypass:
stw r0, VCPU_CPU(r9) stw r0, VCPU_CPU(r9)
stw r0, VCPU_THREAD_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 mfspr r6,SPRN_CTRLF
stw r6,VCPU_CTRL(r9) stw r6,VCPU_CTRL(r9)
andi. r0,r6,1 andi. r0,r6,1
bne 4f bne 4f
ori r6,r6,1 li r6,1
mtspr SPRN_CTRLT,r6 mtspr SPRN_CTRLT,r6
4: 4:
/* /*
@ -2163,9 +2153,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_TM)
/* save expiry time of guest decrementer */ /* save expiry time of guest decrementer */
add r3, r3, r5 add r3, r3, r5
ld r4, HSTATE_KVM_VCPU(r13) 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) std r3, VCPU_DEC_EXPIRES(r4)
#ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING #ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
@ -2186,8 +2173,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_TM)
* Also clear the runlatch bit before napping. * Also clear the runlatch bit before napping.
*/ */
kvm_do_nap: kvm_do_nap:
mfspr r0, SPRN_CTRLF li r0,0
clrrdi r0, r0, 1
mtspr SPRN_CTRLT, r0 mtspr SPRN_CTRLT, r0
li r0,1 li r0,1
@ -2206,8 +2192,7 @@ kvm_nap_sequence: /* desired LPCR value in r5 */
bl isa206_idle_insn_mayloss bl isa206_idle_insn_mayloss
mfspr r0, SPRN_CTRLF li r0,1
ori r0, r0, 1
mtspr SPRN_CTRLT, r0 mtspr SPRN_CTRLT, r0
mtspr SPRN_SRR1, r3 mtspr SPRN_SRR1, r3
@ -2264,9 +2249,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_TM)
/* Restore guest decrementer */ /* Restore guest decrementer */
ld r3, VCPU_DEC_EXPIRES(r4) 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 mftb r7
subf r3, r7, r3 subf r3, r7, r3
mtspr SPRN_DEC, r3 mtspr SPRN_DEC, r3
@ -2778,10 +2760,11 @@ kvmppc_msr_interrupt:
blr blr
/* /*
* void kvmhv_load_guest_pmu(struct kvm_vcpu *vcpu)
*
* Load up guest PMU state. R3 points to the vcpu struct. * Load up guest PMU state. R3 points to the vcpu struct.
*/ */
_GLOBAL(kvmhv_load_guest_pmu) kvmhv_load_guest_pmu:
EXPORT_SYMBOL_GPL(kvmhv_load_guest_pmu)
mr r4, r3 mr r4, r3
mflr r0 mflr r0
li r3, 1 li r3, 1
@ -2815,27 +2798,17 @@ END_FTR_SECTION_IFSET(CPU_FTR_PMAO_BUG)
mtspr SPRN_MMCRA, r6 mtspr SPRN_MMCRA, r6
mtspr SPRN_SIAR, r7 mtspr SPRN_SIAR, r7
mtspr SPRN_SDAR, r8 mtspr SPRN_SDAR, r8
BEGIN_FTR_SECTION
ld r5, VCPU_MMCR + 24(r4)
ld r6, VCPU_SIER + 8(r4)
ld r7, VCPU_SIER + 16(r4)
mtspr SPRN_MMCR3, r5
mtspr SPRN_SIER2, r6
mtspr SPRN_SIER3, r7
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_31)
BEGIN_FTR_SECTION BEGIN_FTR_SECTION
ld r5, VCPU_MMCR + 16(r4) ld r5, VCPU_MMCR + 16(r4)
ld r6, VCPU_SIER(r4) ld r6, VCPU_SIER(r4)
mtspr SPRN_MMCR2, r5 mtspr SPRN_MMCR2, r5
mtspr SPRN_SIER, r6 mtspr SPRN_SIER, r6
BEGIN_FTR_SECTION_NESTED(96)
lwz r7, VCPU_PMC + 24(r4) lwz r7, VCPU_PMC + 24(r4)
lwz r8, VCPU_PMC + 28(r4) lwz r8, VCPU_PMC + 28(r4)
ld r9, VCPU_MMCRS(r4) ld r9, VCPU_MMCRS(r4)
mtspr SPRN_SPMC1, r7 mtspr SPRN_SPMC1, r7
mtspr SPRN_SPMC2, r8 mtspr SPRN_SPMC2, r8
mtspr SPRN_MMCRS, r9 mtspr SPRN_MMCRS, r9
END_FTR_SECTION_NESTED(CPU_FTR_ARCH_300, 0, 96)
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
mtspr SPRN_MMCR0, r3 mtspr SPRN_MMCR0, r3
isync isync
@ -2843,10 +2816,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
blr blr
/* /*
* void kvmhv_load_host_pmu(void)
*
* Reload host PMU state saved in the PACA by kvmhv_save_host_pmu. * Reload host PMU state saved in the PACA by kvmhv_save_host_pmu.
*/ */
_GLOBAL(kvmhv_load_host_pmu) kvmhv_load_host_pmu:
EXPORT_SYMBOL_GPL(kvmhv_load_host_pmu)
mflr r0 mflr r0
lbz r4, PACA_PMCINUSE(r13) /* is the host using the PMU? */ lbz r4, PACA_PMCINUSE(r13) /* is the host using the PMU? */
cmpwi r4, 0 cmpwi r4, 0
@ -2884,25 +2858,18 @@ BEGIN_FTR_SECTION
mtspr SPRN_MMCR2, r8 mtspr SPRN_MMCR2, r8
mtspr SPRN_SIER, r9 mtspr SPRN_SIER, r9
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
BEGIN_FTR_SECTION
ld r5, HSTATE_MMCR3(r13)
ld r6, HSTATE_SIER2(r13)
ld r7, HSTATE_SIER3(r13)
mtspr SPRN_MMCR3, r5
mtspr SPRN_SIER2, r6
mtspr SPRN_SIER3, r7
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_31)
mtspr SPRN_MMCR0, r3 mtspr SPRN_MMCR0, r3
isync isync
mtlr r0 mtlr r0
23: blr 23: blr
/* /*
* void kvmhv_save_guest_pmu(struct kvm_vcpu *vcpu, bool pmu_in_use)
*
* Save guest PMU state into the vcpu struct. * Save guest PMU state into the vcpu struct.
* r3 = vcpu, r4 = full save flag (PMU in use flag set in VPA) * r3 = vcpu, r4 = full save flag (PMU in use flag set in VPA)
*/ */
_GLOBAL(kvmhv_save_guest_pmu) kvmhv_save_guest_pmu:
EXPORT_SYMBOL_GPL(kvmhv_save_guest_pmu)
mr r9, r3 mr r9, r3
mr r8, r4 mr r8, r4
BEGIN_FTR_SECTION BEGIN_FTR_SECTION
@ -2951,14 +2918,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
BEGIN_FTR_SECTION BEGIN_FTR_SECTION
std r10, VCPU_MMCR + 16(r9) std r10, VCPU_MMCR + 16(r9)
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) 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, VCPU_MMCR + 24(r9)
std r6, VCPU_SIER + 8(r9)
std r7, VCPU_SIER + 16(r9)
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_31)
std r7, VCPU_SIAR(r9) std r7, VCPU_SIAR(r9)
std r8, VCPU_SDAR(r9) std r8, VCPU_SDAR(r9)
mfspr r3, SPRN_PMC1 mfspr r3, SPRN_PMC1
@ -2976,7 +2935,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_31)
BEGIN_FTR_SECTION BEGIN_FTR_SECTION
mfspr r5, SPRN_SIER mfspr r5, SPRN_SIER
std r5, VCPU_SIER(r9) std r5, VCPU_SIER(r9)
BEGIN_FTR_SECTION_NESTED(96)
mfspr r6, SPRN_SPMC1 mfspr r6, SPRN_SPMC1
mfspr r7, SPRN_SPMC2 mfspr r7, SPRN_SPMC2
mfspr r8, SPRN_MMCRS mfspr r8, SPRN_MMCRS
@ -2985,7 +2943,6 @@ BEGIN_FTR_SECTION_NESTED(96)
std r8, VCPU_MMCRS(r9) std r8, VCPU_MMCRS(r9)
lis r4, 0x8000 lis r4, 0x8000
mtspr SPRN_MMCRS, r4 mtspr SPRN_MMCRS, r4
END_FTR_SECTION_NESTED(CPU_FTR_ARCH_300, 0, 96)
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
22: blr 22: blr

View File

@ -572,18 +572,6 @@ void __init radix__early_init_devtree(void)
return; 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) void __init radix__early_init_mmu(void)
{ {
unsigned long lpcr; unsigned long lpcr;
@ -644,7 +632,6 @@ void __init radix__early_init_mmu(void)
lpcr = mfspr(SPRN_LPCR); lpcr = mfspr(SPRN_LPCR);
mtspr(SPRN_LPCR, lpcr | LPCR_UPRT | LPCR_HR); mtspr(SPRN_LPCR, lpcr | LPCR_UPRT | LPCR_HR);
radix_init_partition_table(); radix_init_partition_table();
radix_init_amor();
} else { } else {
radix_init_pseries(); radix_init_pseries();
} }
@ -668,8 +655,6 @@ void radix__early_init_mmu_secondary(void)
set_ptcr_when_no_uv(__pa(partition_tb) | set_ptcr_when_no_uv(__pa(partition_tb) |
(PATB_SIZE_SHIFT - 12)); (PATB_SIZE_SHIFT - 12));
radix_init_amor();
} }
radix__switch_mmu_context(NULL, &init_mm); radix__switch_mmu_context(NULL, &init_mm);

View File

@ -2419,8 +2419,24 @@ int register_power_pmu(struct power_pmu *pmu)
} }
#ifdef CONFIG_PPC64 #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) 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 */ /* run through all the pmu drivers one at a time */
if (!init_power5_pmu()) if (!init_power5_pmu())
return 0; return 0;
@ -2442,4 +2458,23 @@ static int __init init_ppc64_pmu(void)
return init_generic_compat_pmu(); return init_generic_compat_pmu();
} }
early_initcall(init_ppc64_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 #endif

View File

@ -306,8 +306,8 @@ struct p7_sprs {
/* per thread SPRs that get lost in shallow states */ /* per thread SPRs that get lost in shallow states */
u64 amr; u64 amr;
u64 iamr; u64 iamr;
u64 amor;
u64 uamor; u64 uamor;
/* amor is restored to constant ~0 */
}; };
static unsigned long power7_idle_insn(unsigned long type) 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)) { if (cpu_has_feature(CPU_FTR_ARCH_207S)) {
sprs.amr = mfspr(SPRN_AMR); sprs.amr = mfspr(SPRN_AMR);
sprs.iamr = mfspr(SPRN_IAMR); sprs.iamr = mfspr(SPRN_IAMR);
sprs.amor = mfspr(SPRN_AMOR);
sprs.uamor = mfspr(SPRN_UAMOR); 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_AMR, sprs.amr);
mtspr(SPRN_IAMR, sprs.iamr); mtspr(SPRN_IAMR, sprs.iamr);
mtspr(SPRN_AMOR, sprs.amor); mtspr(SPRN_AMOR, ~0);
mtspr(SPRN_UAMOR, sprs.uamor); mtspr(SPRN_UAMOR, sprs.uamor);
} }
} }
@ -589,7 +588,6 @@ struct p9_sprs {
u64 purr; u64 purr;
u64 spurr; u64 spurr;
u64 dscr; u64 dscr;
u64 wort;
u64 ciabr; u64 ciabr;
u64 mmcra; u64 mmcra;
@ -687,7 +685,6 @@ static unsigned long power9_idle_stop(unsigned long psscr)
sprs.amr = mfspr(SPRN_AMR); sprs.amr = mfspr(SPRN_AMR);
sprs.iamr = mfspr(SPRN_IAMR); sprs.iamr = mfspr(SPRN_IAMR);
sprs.amor = mfspr(SPRN_AMOR);
sprs.uamor = mfspr(SPRN_UAMOR); sprs.uamor = mfspr(SPRN_UAMOR);
srr1 = isa300_idle_stop_mayloss(psscr); /* go idle */ srr1 = isa300_idle_stop_mayloss(psscr); /* go idle */
@ -708,7 +705,7 @@ static unsigned long power9_idle_stop(unsigned long psscr)
*/ */
mtspr(SPRN_AMR, sprs.amr); mtspr(SPRN_AMR, sprs.amr);
mtspr(SPRN_IAMR, sprs.iamr); mtspr(SPRN_IAMR, sprs.iamr);
mtspr(SPRN_AMOR, sprs.amor); mtspr(SPRN_AMOR, ~0);
mtspr(SPRN_UAMOR, sprs.uamor); mtspr(SPRN_UAMOR, sprs.uamor);
/* /*

View File

@ -2107,8 +2107,14 @@ static void dump_300_sprs(void)
if (!cpu_has_feature(CPU_FTR_ARCH_300)) if (!cpu_has_feature(CPU_FTR_ARCH_300))
return; return;
printf("pidr = %.16lx tidr = %.16lx\n", if (cpu_has_feature(CPU_FTR_P9_TIDR)) {
mfspr(SPRN_PID), mfspr(SPRN_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", printf("psscr = %.16lx\n",
hv ? mfspr(SPRN_PSSCR) : mfspr(SPRN_PSSCR_PR)); hv ? mfspr(SPRN_PSSCR) : mfspr(SPRN_PSSCR_PR));