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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




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@xxxxxxxxxxxxx>
---
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" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux