[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kvm-ppc
Subject:    Re: [PATCH v3 2/5] KVM: PPC: Book3e: Add AltiVec support
From:       Alexander Graf <agraf () suse ! de>
Date:       2014-08-12 11:45:07
Message-ID: 53E9FE43.80201 () suse ! de
[Download RAW message or body]


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 <mihai.caraman@freescale.com>
> ---
> 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;

--
To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic