Re: [PATCH v3 2/5] KVM: PPC: Book3e: Add AltiVec support

2014-08-12 Thread Alexander Graf


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.cara...@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:

   

[PATCH v3 2/5] KVM: PPC: Book3e: Add AltiVec support

2014-08-05 Thread Mihai Caraman
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.cara...@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
case BOOKE_IRQPRIO_SPE_UNAVAIL:
case BOOKE_IRQPRIO_SPE_FP_DATA:
case BOOKE_IRQPRIO_SPE_FP_ROUND:
+#else
+   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
 #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
+   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);
+   

[PATCH v3 2/5] KVM: PPC: Book3e: Add AltiVec support

2014-08-05 Thread Mihai Caraman
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.cara...@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
case BOOKE_IRQPRIO_SPE_UNAVAIL:
case BOOKE_IRQPRIO_SPE_FP_DATA:
case BOOKE_IRQPRIO_SPE_FP_ROUND:
+#else
+   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
 #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
+   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);
+