From mboxrd@z Thu Jan 1 00:00:00 1970 From: Alexander Graf Subject: Re: [PATCH v3 2/5] KVM: PPC: Book3e: Add AltiVec support Date: Tue, 12 Aug 2014 13:45:07 +0200 Message-ID: <53E9FE43.80201@suse.de> References: <1407235175-30994-1-git-send-email-mihai.caraman@freescale.com> <1407235175-30994-3-git-send-email-mihai.caraman@freescale.com> Mime-Version: 1.0 Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 7bit Cc: kvm@vger.kernel.org To: Mihai Caraman , kvm-ppc@vger.kernel.org Return-path: In-Reply-To: <1407235175-30994-3-git-send-email-mihai.caraman@freescale.com> Sender: kvm-ppc-owner@vger.kernel.org List-Id: kvm.vger.kernel.org On 05.08.14 12:39, Mihai Caraman wrote: > Add KVM Book3e AltiVec support. KVM Book3e FPU support gracefully reuse host > infrastructure so follow the same approach for AltiVec. > > Keep SPE/AltiVec exception handlers distinct using CONFIG_KVM_E500V2. > > Signed-off-by: Mihai Caraman > --- > v3: > - use distinct SPE/AltiVec exception handlers > > v2: > - integrate Paul's FP/VMX/VSX changes > > arch/powerpc/kvm/booke.c | 73 +++++++++++++++++++++++++++++++++++ > arch/powerpc/kvm/booke.h | 5 +++ > arch/powerpc/kvm/bookehv_interrupts.S | 10 +++-- > arch/powerpc/kvm/e500_emulate.c | 18 +++++++++ > 4 files changed, 102 insertions(+), 4 deletions(-) > > diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c > index 0c6f616..c5cca09 100644 > --- a/arch/powerpc/kvm/booke.c > +++ b/arch/powerpc/kvm/booke.c > @@ -168,6 +168,40 @@ static void kvmppc_vcpu_sync_fpu(struct kvm_vcpu *vcpu) > #endif > } > > +/* > + * Simulate AltiVec unavailable fault to load guest state > + * from thread to AltiVec unit. > + * It requires to be called with preemption disabled. > + */ > +static inline void kvmppc_load_guest_altivec(struct kvm_vcpu *vcpu) > +{ > +#ifdef CONFIG_ALTIVEC > + if (cpu_has_feature(CPU_FTR_ALTIVEC)) { > + if (!(current->thread.regs->msr & MSR_VEC)) { > + enable_kernel_altivec(); > + load_vr_state(&vcpu->arch.vr); > + current->thread.vr_save_area = &vcpu->arch.vr; > + current->thread.regs->msr |= MSR_VEC; > + } > + } > +#endif > +} > + > +/* > + * Save guest vcpu AltiVec state into thread. > + * It requires to be called with preemption disabled. > + */ > +static inline void kvmppc_save_guest_altivec(struct kvm_vcpu *vcpu) > +{ > +#ifdef CONFIG_ALTIVEC > + if (cpu_has_feature(CPU_FTR_ALTIVEC)) { > + if (current->thread.regs->msr & MSR_VEC) > + giveup_altivec(current); > + current->thread.vr_save_area = NULL; > + } > +#endif > +} > + > static void kvmppc_vcpu_sync_debug(struct kvm_vcpu *vcpu) > { > /* Synchronize guest's desire to get debug interrupts into shadow MSR */ > @@ -375,9 +409,14 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, > case BOOKE_IRQPRIO_ITLB_MISS: > case BOOKE_IRQPRIO_SYSCALL: > case BOOKE_IRQPRIO_FP_UNAVAIL: > +#ifdef CONFIG_KVM_E500V2 Why not use your new SPE_POSSIBLE define? > case BOOKE_IRQPRIO_SPE_UNAVAIL: > case BOOKE_IRQPRIO_SPE_FP_DATA: > case BOOKE_IRQPRIO_SPE_FP_ROUND: > +#else We only ever support altivec capable CPUs with CONFIG_ALTIVEC, no? So just make this a new #ifdef CONFIG_ALTIVEC > + case BOOKE_IRQPRIO_ALTIVEC_UNAVAIL: > + case BOOKE_IRQPRIO_ALTIVEC_ASSIST: > +#endif > case BOOKE_IRQPRIO_AP_UNAVAIL: > allowed = 1; > msr_mask = MSR_CE | MSR_ME | MSR_DE; > @@ -693,6 +732,17 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) > kvmppc_load_guest_fp(vcpu); > #endif > > +#ifdef CONFIG_ALTIVEC > + /* Save userspace AltiVec state in stack */ > + if (cpu_has_feature(CPU_FTR_ALTIVEC)) > + enable_kernel_altivec(); > + /* > + * Since we can't trap on MSR_VEC in GS-mode, we consider the guest > + * as always using the AltiVec. > + */ > + kvmppc_load_guest_altivec(vcpu); > +#endif > + > /* Switch to guest debug context */ > debug = vcpu->arch.shadow_dbg_reg; > switch_booke_debug_regs(&debug); > @@ -715,6 +765,10 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) > kvmppc_save_guest_fp(vcpu); > #endif > > +#ifdef CONFIG_ALTIVEC > + kvmppc_save_guest_altivec(vcpu); > +#endif > + > out: > vcpu->mode = OUTSIDE_GUEST_MODE; > return ret; > @@ -999,6 +1053,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, > r = RESUME_GUEST; > break; > > +#ifdef CONFIG_KVM_E500V2 Why? We're already guarded by CONFIG_SPE > #ifdef CONFIG_SPE > case BOOKE_INTERRUPT_SPE_UNAVAIL: { > if (vcpu->arch.shared->msr & MSR_SPE) > @@ -1040,7 +1095,24 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, > run->hw.hardware_exit_reason = exit_nr; > r = RESUME_HOST; > break; > +#endif /* !CONFIG_SPE */ > +#else > +/* > + * On cores with Vector category, KVM is loaded only if CONFIG_ALTIVEC, > + * see kvmppc_core_check_processor_compat(). > + */ > +#ifdef CONFIG_ALTIVEC ... and CONFIG_ALTIVEC > + case BOOKE_INTERRUPT_ALTIVEC_UNAVAIL: > + kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_ALTIVEC_UNAVAIL); > + r = RESUME_GUEST; > + break; > + > + case BOOKE_INTERRUPT_ALTIVEC_ASSIST: > + kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_ALTIVEC_ASSIST); > + r = RESUME_GUEST; > + break; > #endif > +#endif /* !CONFIG_KVM_E500V2 */ > > case BOOKE_INTERRUPT_DATA_STORAGE: > kvmppc_core_queue_data_storage(vcpu, vcpu->arch.fault_dear, > @@ -1217,6 +1289,7 @@ out: > /* interrupts now hard-disabled */ > kvmppc_fix_ee_before_entry(); > kvmppc_load_guest_fp(vcpu); > + kvmppc_load_guest_altivec(vcpu); > } > } > > diff --git a/arch/powerpc/kvm/booke.h b/arch/powerpc/kvm/booke.h > index e73d513..ce5b543 100644 > --- a/arch/powerpc/kvm/booke.h > +++ b/arch/powerpc/kvm/booke.h > @@ -32,9 +32,14 @@ > #define BOOKE_IRQPRIO_ALIGNMENT 2 > #define BOOKE_IRQPRIO_PROGRAM 3 > #define BOOKE_IRQPRIO_FP_UNAVAIL 4 > +#ifdef CONFIG_KVM_E500V2 Same comments as above > #define BOOKE_IRQPRIO_SPE_UNAVAIL 5 > #define BOOKE_IRQPRIO_SPE_FP_DATA 6 > #define BOOKE_IRQPRIO_SPE_FP_ROUND 7 > +#else > +#define BOOKE_IRQPRIO_ALTIVEC_UNAVAIL 5 > +#define BOOKE_IRQPRIO_ALTIVEC_ASSIST 6 > +#endif > #define BOOKE_IRQPRIO_SYSCALL 8 > #define BOOKE_IRQPRIO_AP_UNAVAIL 9 > #define BOOKE_IRQPRIO_DTLB_MISS 10 > diff --git a/arch/powerpc/kvm/bookehv_interrupts.S b/arch/powerpc/kvm/bookehv_interrupts.S > index e9fa56a..1d7c4d6 100644 > --- a/arch/powerpc/kvm/bookehv_interrupts.S > +++ b/arch/powerpc/kvm/bookehv_interrupts.S > @@ -256,11 +256,9 @@ kvm_handler BOOKE_INTERRUPT_DTLB_MISS, EX_PARAMS_TLB, \ > SPRN_SRR0, SPRN_SRR1, (NEED_EMU | NEED_DEAR | NEED_ESR) > kvm_handler BOOKE_INTERRUPT_ITLB_MISS, EX_PARAMS_TLB, \ > SPRN_SRR0, SPRN_SRR1, 0 > -kvm_handler BOOKE_INTERRUPT_SPE_UNAVAIL, EX_PARAMS(GEN), \ > +kvm_handler BOOKE_INTERRUPT_ALTIVEC_UNAVAIL, EX_PARAMS(GEN), \ > SPRN_SRR0, SPRN_SRR1, 0 > -kvm_handler BOOKE_INTERRUPT_SPE_FP_DATA, EX_PARAMS(GEN), \ > - SPRN_SRR0, SPRN_SRR1, 0 > -kvm_handler BOOKE_INTERRUPT_SPE_FP_ROUND, EX_PARAMS(GEN), \ > +kvm_handler BOOKE_INTERRUPT_ALTIVEC_ASSIST, EX_PARAMS(GEN), \ > SPRN_SRR0, SPRN_SRR1, 0 > kvm_handler BOOKE_INTERRUPT_PERFORMANCE_MONITOR, EX_PARAMS(GEN), \ > SPRN_SRR0, SPRN_SRR1, 0 > @@ -361,6 +359,10 @@ kvm_lvl_handler BOOKE_INTERRUPT_WATCHDOG, \ > kvm_handler BOOKE_INTERRUPT_DTLB_MISS, \ > SPRN_SRR0, SPRN_SRR1, (NEED_EMU | NEED_DEAR | NEED_ESR) > kvm_handler BOOKE_INTERRUPT_ITLB_MISS, SPRN_SRR0, SPRN_SRR1, 0 > +/* > + * TODO: SPE handlers should be available only for e500v2 cores. > + * HV does not target e500v2 so remove them after kernel cleanup. > + */ Let's do the cleanup first, then apply these patches. > kvm_handler BOOKE_INTERRUPT_SPE_UNAVAIL, SPRN_SRR0, SPRN_SRR1, 0 > kvm_handler BOOKE_INTERRUPT_SPE_FP_DATA, SPRN_SRR0, SPRN_SRR1, 0 > kvm_handler BOOKE_INTERRUPT_SPE_FP_ROUND, SPRN_SRR0, SPRN_SRR1, 0 > diff --git a/arch/powerpc/kvm/e500_emulate.c b/arch/powerpc/kvm/e500_emulate.c > index c99c40e..e6e0429 100644 > --- a/arch/powerpc/kvm/e500_emulate.c > +++ b/arch/powerpc/kvm/e500_emulate.c > @@ -259,6 +259,7 @@ int kvmppc_core_emulate_mtspr_e500(struct kvm_vcpu *vcpu, int sprn, ulong spr_va > break; > > /* extra exceptions */ > +#ifdef CONFIG_KVM_E500V2 Same comments as above > case SPRN_IVOR32: > vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL] = spr_val; > break; > @@ -268,6 +269,14 @@ int kvmppc_core_emulate_mtspr_e500(struct kvm_vcpu *vcpu, int sprn, ulong spr_va > case SPRN_IVOR34: > vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND] = spr_val; > break; > +#else > + case SPRN_IVOR32: > + vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_UNAVAIL] = spr_val; > + break; > + case SPRN_IVOR33: > + vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_ASSIST] = spr_val; > + break; > +#endif > case SPRN_IVOR35: > vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR] = spr_val; > break; > @@ -381,6 +390,7 @@ int kvmppc_core_emulate_mfspr_e500(struct kvm_vcpu *vcpu, int sprn, ulong *spr_v > break; > > /* extra exceptions */ > +#ifdef CONFIG_KVM_E500V2 Here too. Alex > case SPRN_IVOR32: > *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL]; > break; > @@ -390,6 +400,14 @@ int kvmppc_core_emulate_mfspr_e500(struct kvm_vcpu *vcpu, int sprn, ulong *spr_v > case SPRN_IVOR34: > *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND]; > break; > +#else > + case SPRN_IVOR32: > + *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_UNAVAIL]; > + break; > + case SPRN_IVOR33: > + *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_ASSIST]; > + break; > +#endif > case SPRN_IVOR35: > *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR]; > break;