public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/5] KVM: PPC: Book3e: AltiVec support
@ 2014-08-05 10:39 Mihai Caraman
  2014-08-05 10:39 ` [PATCH v3 1/5] KVM: PPC: Book3e: Increase FPU laziness Mihai Caraman
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Mihai Caraman @ 2014-08-05 10:39 UTC (permalink / raw)
  To: kvm-ppc; +Cc: kvm, Mihai Caraman

Add KVM Book3e AltiVec support and enable e6500 core.

Changes:

v3:
 - use distinct SPE/AltiVec exception handlers
 - make ONE_REG AltiVec support powerpc generic
 - add ONE_REG IVORs support

v2:
 - integrate Paul's FP/VMX/VSX changes that landed in kvm-ppc-queue
   in January and take into account feedback

Mihai Caraman (5):
  KVM: PPC: Book3e: Increase FPU laziness
  KVM: PPC: Book3e: Add AltiVec support
  KVM: PPC: Move ONE_REG AltiVec support to powerpc
  KVM: PPC: Booke: Add ONE_REG IVORs support
  KVM: PPC: Book3e: Enable e6500 core

 arch/powerpc/include/uapi/asm/kvm.h   |  29 +++
 arch/powerpc/kvm/book3s.c             | 151 +++++-----------
 arch/powerpc/kvm/booke.c              | 331 ++++++++++++++++++++++++++++------
 arch/powerpc/kvm/booke.h              |  39 +---
 arch/powerpc/kvm/bookehv_interrupts.S |  10 +-
 arch/powerpc/kvm/e500.c               |  42 ++++-
 arch/powerpc/kvm/e500_emulate.c       |  18 ++
 arch/powerpc/kvm/e500mc.c             |  44 ++++-
 arch/powerpc/kvm/powerpc.c            |  97 ++++++++++
 9 files changed, 554 insertions(+), 207 deletions(-)

-- 
1.7.11.7


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v3 1/5] KVM: PPC: Book3e: Increase FPU laziness
  2014-08-05 10:39 [PATCH v3 0/5] KVM: PPC: Book3e: AltiVec support Mihai Caraman
@ 2014-08-05 10:39 ` Mihai Caraman
  2014-08-05 10:39 ` [PATCH v3 2/5] KVM: PPC: Book3e: Add AltiVec support Mihai Caraman
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Mihai Caraman @ 2014-08-05 10:39 UTC (permalink / raw)
  To: kvm-ppc; +Cc: kvm, Mihai Caraman

Increase FPU laziness by calling kvmppc_load_guest_fp() just before
returning to guest instead of each sched in. Without this improvement
an interrupt may also claim floting point corrupting guest state.

Signed-off-by: Mihai Caraman <mihai.caraman@freescale.com>
---
v3:
 - no changes

v2:
 - remove fpu_active
 - add descriptive comments

 arch/powerpc/kvm/booke.c  | 43 ++++++++++++++++++++++++++++++++++++-------
 arch/powerpc/kvm/booke.h  | 34 ----------------------------------
 arch/powerpc/kvm/e500mc.c |  2 --
 3 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index b4c89fa..0c6f616 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -124,6 +124,40 @@ static void kvmppc_vcpu_sync_spe(struct kvm_vcpu *vcpu)
 }
 #endif
 
+/*
+ * Load up guest vcpu FP state if it's needed.
+ * It also set the MSR_FP in thread so that host know
+ * we're holding FPU, and then host can help to save
+ * guest vcpu FP state if other threads require to use FPU.
+ * This simulates an FP unavailable fault.
+ *
+ * It requires to be called with preemption disabled.
+ */
+static inline void kvmppc_load_guest_fp(struct kvm_vcpu *vcpu)
+{
+#ifdef CONFIG_PPC_FPU
+	if (!(current->thread.regs->msr & MSR_FP)) {
+		enable_kernel_fp();
+		load_fp_state(&vcpu->arch.fp);
+		current->thread.fp_save_area = &vcpu->arch.fp;
+		current->thread.regs->msr |= MSR_FP;
+	}
+#endif
+}
+
+/*
+ * Save guest vcpu FP state into thread.
+ * It requires to be called with preemption disabled.
+ */
+static inline void kvmppc_save_guest_fp(struct kvm_vcpu *vcpu)
+{
+#ifdef CONFIG_PPC_FPU
+	if (current->thread.regs->msr & MSR_FP)
+		giveup_fpu(current);
+	current->thread.fp_save_area = NULL;
+#endif
+}
+
 static void kvmppc_vcpu_sync_fpu(struct kvm_vcpu *vcpu)
 {
 #if defined(CONFIG_PPC_FPU) && !defined(CONFIG_KVM_BOOKE_HV)
@@ -654,12 +688,8 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 
 	/*
 	 * Since we can't trap on MSR_FP in GS-mode, we consider the guest
-	 * as always using the FPU.  Kernel usage of FP (via
-	 * enable_kernel_fp()) in this thread must not occur while
-	 * vcpu->fpu_active is set.
+	 * as always using the FPU.
 	 */
-	vcpu->fpu_active = 1;
-
 	kvmppc_load_guest_fp(vcpu);
 #endif
 
@@ -683,8 +713,6 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 
 #ifdef CONFIG_PPC_FPU
 	kvmppc_save_guest_fp(vcpu);
-
-	vcpu->fpu_active = 0;
 #endif
 
 out:
@@ -1188,6 +1216,7 @@ out:
 		else {
 			/* interrupts now hard-disabled */
 			kvmppc_fix_ee_before_entry();
+			kvmppc_load_guest_fp(vcpu);
 		}
 	}
 
diff --git a/arch/powerpc/kvm/booke.h b/arch/powerpc/kvm/booke.h
index f753543..e73d513 100644
--- a/arch/powerpc/kvm/booke.h
+++ b/arch/powerpc/kvm/booke.h
@@ -116,40 +116,6 @@ extern int kvmppc_core_emulate_mtspr_e500(struct kvm_vcpu *vcpu, int sprn,
 extern int kvmppc_core_emulate_mfspr_e500(struct kvm_vcpu *vcpu, int sprn,
 					  ulong *spr_val);
 
-/*
- * Load up guest vcpu FP state if it's needed.
- * It also set the MSR_FP in thread so that host know
- * we're holding FPU, and then host can help to save
- * guest vcpu FP state if other threads require to use FPU.
- * This simulates an FP unavailable fault.
- *
- * It requires to be called with preemption disabled.
- */
-static inline void kvmppc_load_guest_fp(struct kvm_vcpu *vcpu)
-{
-#ifdef CONFIG_PPC_FPU
-	if (vcpu->fpu_active && !(current->thread.regs->msr & MSR_FP)) {
-		enable_kernel_fp();
-		load_fp_state(&vcpu->arch.fp);
-		current->thread.fp_save_area = &vcpu->arch.fp;
-		current->thread.regs->msr |= MSR_FP;
-	}
-#endif
-}
-
-/*
- * Save guest vcpu FP state into thread.
- * It requires to be called with preemption disabled.
- */
-static inline void kvmppc_save_guest_fp(struct kvm_vcpu *vcpu)
-{
-#ifdef CONFIG_PPC_FPU
-	if (vcpu->fpu_active && (current->thread.regs->msr & MSR_FP))
-		giveup_fpu(current);
-	current->thread.fp_save_area = NULL;
-#endif
-}
-
 static inline void kvmppc_clear_dbsr(void)
 {
 	mtspr(SPRN_DBSR, mfspr(SPRN_DBSR));
diff --git a/arch/powerpc/kvm/e500mc.c b/arch/powerpc/kvm/e500mc.c
index 164bad2..67c06eb 100644
--- a/arch/powerpc/kvm/e500mc.c
+++ b/arch/powerpc/kvm/e500mc.c
@@ -145,8 +145,6 @@ static void kvmppc_core_vcpu_load_e500mc(struct kvm_vcpu *vcpu, int cpu)
 		kvmppc_e500_tlbil_all(vcpu_e500);
 		__get_cpu_var(last_vcpu_of_lpid)[vcpu->kvm->arch.lpid] = vcpu;
 	}
-
-	kvmppc_load_guest_fp(vcpu);
 }
 
 static void kvmppc_core_vcpu_put_e500mc(struct kvm_vcpu *vcpu)
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 2/5] KVM: PPC: Book3e: Add AltiVec support
  2014-08-05 10:39 [PATCH v3 0/5] KVM: PPC: Book3e: AltiVec support Mihai Caraman
  2014-08-05 10:39 ` [PATCH v3 1/5] KVM: PPC: Book3e: Increase FPU laziness Mihai Caraman
@ 2014-08-05 10:39 ` Mihai Caraman
  2014-08-12 11:45   ` Alexander Graf
  2014-08-05 10:39 ` [PATCH v3 3/5] KVM: PPC: Move ONE_REG AltiVec support to powerpc Mihai Caraman
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 9+ messages in thread
From: Mihai Caraman @ 2014-08-05 10:39 UTC (permalink / raw)
  To: kvm-ppc; +Cc: kvm, 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.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
 	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);
+			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
 #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.
+ */
 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
 	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
 	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;
-- 
1.7.11.7

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 3/5] KVM: PPC: Move ONE_REG AltiVec support to powerpc
  2014-08-05 10:39 [PATCH v3 0/5] KVM: PPC: Book3e: AltiVec support Mihai Caraman
  2014-08-05 10:39 ` [PATCH v3 1/5] KVM: PPC: Book3e: Increase FPU laziness Mihai Caraman
  2014-08-05 10:39 ` [PATCH v3 2/5] KVM: PPC: Book3e: Add AltiVec support Mihai Caraman
@ 2014-08-05 10:39 ` Mihai Caraman
  2014-08-12 11:47   ` Alexander Graf
  2014-08-05 10:39 ` [PATCH v3 4/5] KVM: PPC: Booke: Add ONE_REG IVORs support Mihai Caraman
  2014-08-05 10:39 ` [PATCH v3 5/5] KVM: PPC: Book3E: Enable e6500 core Mihai Caraman
  4 siblings, 1 reply; 9+ messages in thread
From: Mihai Caraman @ 2014-08-05 10:39 UTC (permalink / raw)
  To: kvm-ppc; +Cc: kvm, Mihai Caraman

Make ONE_REG AltiVec support common across server and embedded implementations
moving kvm_vcpu_ioctl_get_one_reg() and kvm_vcpu_ioctl_set_one_reg() functions
to powerpc layer.

Signed-off-by: Mihai Caraman <mihai.caraman@freescale.com>
---
v3:
 - make ONE_REG AltiVec support powerpc generic

v2:
 - add comment describing VCSR register representation in KVM vs kernel

 arch/powerpc/include/uapi/asm/kvm.h |   5 ++
 arch/powerpc/kvm/book3s.c           | 151 +++++++++++-------------------------
 arch/powerpc/kvm/booke.c            |  85 ++++++++------------
 arch/powerpc/kvm/powerpc.c          |  97 +++++++++++++++++++++++
 4 files changed, 179 insertions(+), 159 deletions(-)

diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h
index e0e49db..7a27ff0 100644
--- a/arch/powerpc/include/uapi/asm/kvm.h
+++ b/arch/powerpc/include/uapi/asm/kvm.h
@@ -476,6 +476,11 @@ struct kvm_get_htab_header {
 
 /* FP and vector status/control registers */
 #define KVM_REG_PPC_FPSCR	(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x80)
+/*
+ * VSCR register is documented as a 32-bit register in the ISA, but it can
+ * only be accesses via a vector register. Expose VSCR as a 32-bit register
+ * even though the kernel represents it as a 128-bit vector.
+ */
 #define KVM_REG_PPC_VSCR	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x81)
 
 /* Virtual processor areas */
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index dd03f6b..1b5adda 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -535,174 +535,111 @@ int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 	return -ENOTSUPP;
 }
 
-int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
+int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id,
+			union kvmppc_one_reg *val)
 {
-	int r;
-	union kvmppc_one_reg val;
-	int size;
+	int r = 0;
 	long int i;
 
-	size = one_reg_size(reg->id);
-	if (size > sizeof(val))
-		return -EINVAL;
-
-	r = vcpu->kvm->arch.kvm_ops->get_one_reg(vcpu, reg->id, &val);
+	r = vcpu->kvm->arch.kvm_ops->get_one_reg(vcpu, id, val);
 	if (r == -EINVAL) {
 		r = 0;
-		switch (reg->id) {
+		switch (id) {
 		case KVM_REG_PPC_DAR:
-			val = get_reg_val(reg->id, kvmppc_get_dar(vcpu));
+			*val = get_reg_val(id, kvmppc_get_dar(vcpu));
 			break;
 		case KVM_REG_PPC_DSISR:
-			val = get_reg_val(reg->id, kvmppc_get_dsisr(vcpu));
+			*val = get_reg_val(id, kvmppc_get_dsisr(vcpu));
 			break;
 		case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31:
-			i = reg->id - KVM_REG_PPC_FPR0;
-			val = get_reg_val(reg->id, VCPU_FPR(vcpu, i));
+			i = id - KVM_REG_PPC_FPR0;
+			*val = get_reg_val(id, VCPU_FPR(vcpu, i));
 			break;
 		case KVM_REG_PPC_FPSCR:
-			val = get_reg_val(reg->id, vcpu->arch.fp.fpscr);
-			break;
-#ifdef CONFIG_ALTIVEC
-		case KVM_REG_PPC_VR0 ... KVM_REG_PPC_VR31:
-			if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
-				r = -ENXIO;
-				break;
-			}
-			val.vval = vcpu->arch.vr.vr[reg->id - KVM_REG_PPC_VR0];
+			*val = get_reg_val(id, vcpu->arch.fp.fpscr);
 			break;
-		case KVM_REG_PPC_VSCR:
-			if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
-				r = -ENXIO;
-				break;
-			}
-			val = get_reg_val(reg->id, vcpu->arch.vr.vscr.u[3]);
-			break;
-		case KVM_REG_PPC_VRSAVE:
-			val = get_reg_val(reg->id, vcpu->arch.vrsave);
-			break;
-#endif /* CONFIG_ALTIVEC */
 #ifdef CONFIG_VSX
 		case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31:
 			if (cpu_has_feature(CPU_FTR_VSX)) {
-				long int i = reg->id - KVM_REG_PPC_VSR0;
-				val.vsxval[0] = vcpu->arch.fp.fpr[i][0];
-				val.vsxval[1] = vcpu->arch.fp.fpr[i][1];
+				i = id - KVM_REG_PPC_VSR0;
+				val->vsxval[0] = vcpu->arch.fp.fpr[i][0];
+				val->vsxval[1] = vcpu->arch.fp.fpr[i][1];
 			} else {
 				r = -ENXIO;
 			}
 			break;
 #endif /* CONFIG_VSX */
-		case KVM_REG_PPC_DEBUG_INST: {
-			u32 opcode = INS_TW;
-			r = copy_to_user((u32 __user *)(long)reg->addr,
-					 &opcode, sizeof(u32));
+		case KVM_REG_PPC_DEBUG_INST:
+			*val = get_reg_val(id, INS_TW);
 			break;
-		}
 #ifdef CONFIG_KVM_XICS
 		case KVM_REG_PPC_ICP_STATE:
 			if (!vcpu->arch.icp) {
 				r = -ENXIO;
 				break;
 			}
-			val = get_reg_val(reg->id, kvmppc_xics_get_icp(vcpu));
+			*val = get_reg_val(id, kvmppc_xics_get_icp(vcpu));
 			break;
 #endif /* CONFIG_KVM_XICS */
 		case KVM_REG_PPC_FSCR:
-			val = get_reg_val(reg->id, vcpu->arch.fscr);
+			*val = get_reg_val(id, vcpu->arch.fscr);
 			break;
 		case KVM_REG_PPC_TAR:
-			val = get_reg_val(reg->id, vcpu->arch.tar);
+			*val = get_reg_val(id, vcpu->arch.tar);
 			break;
 		case KVM_REG_PPC_EBBHR:
-			val = get_reg_val(reg->id, vcpu->arch.ebbhr);
+			*val = get_reg_val(id, vcpu->arch.ebbhr);
 			break;
 		case KVM_REG_PPC_EBBRR:
-			val = get_reg_val(reg->id, vcpu->arch.ebbrr);
+			*val = get_reg_val(id, vcpu->arch.ebbrr);
 			break;
 		case KVM_REG_PPC_BESCR:
-			val = get_reg_val(reg->id, vcpu->arch.bescr);
+			*val = get_reg_val(id, vcpu->arch.bescr);
 			break;
 		case KVM_REG_PPC_VTB:
-			val = get_reg_val(reg->id, vcpu->arch.vtb);
+			*val = get_reg_val(id, vcpu->arch.vtb);
 			break;
 		case KVM_REG_PPC_IC:
-			val = get_reg_val(reg->id, vcpu->arch.ic);
+			*val = get_reg_val(id, vcpu->arch.ic);
 			break;
 		default:
 			r = -EINVAL;
 			break;
 		}
 	}
-	if (r)
-		return r;
-
-	if (copy_to_user((char __user *)(unsigned long)reg->addr, &val, size))
-		r = -EFAULT;
 
 	return r;
 }
 
-int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
+int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id,
+			union kvmppc_one_reg *val)
 {
-	int r;
-	union kvmppc_one_reg val;
-	int size;
+	int r = 0;
 	long int i;
 
-	size = one_reg_size(reg->id);
-	if (size > sizeof(val))
-		return -EINVAL;
-
-	if (copy_from_user(&val, (char __user *)(unsigned long)reg->addr, size))
-		return -EFAULT;
-
-	r = vcpu->kvm->arch.kvm_ops->set_one_reg(vcpu, reg->id, &val);
+	r = vcpu->kvm->arch.kvm_ops->set_one_reg(vcpu, id, val);
 	if (r == -EINVAL) {
 		r = 0;
-		switch (reg->id) {
+		switch (id) {
 		case KVM_REG_PPC_DAR:
-			kvmppc_set_dar(vcpu, set_reg_val(reg->id, val));
+			kvmppc_set_dar(vcpu, set_reg_val(id, *val));
 			break;
 		case KVM_REG_PPC_DSISR:
-			kvmppc_set_dsisr(vcpu, set_reg_val(reg->id, val));
+			kvmppc_set_dsisr(vcpu, set_reg_val(id, *val));
 			break;
 		case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31:
-			i = reg->id - KVM_REG_PPC_FPR0;
-			VCPU_FPR(vcpu, i) = set_reg_val(reg->id, val);
+			i = id - KVM_REG_PPC_FPR0;
+			VCPU_FPR(vcpu, i) = set_reg_val(id, *val);
 			break;
 		case KVM_REG_PPC_FPSCR:
-			vcpu->arch.fp.fpscr = set_reg_val(reg->id, val);
-			break;
-#ifdef CONFIG_ALTIVEC
-		case KVM_REG_PPC_VR0 ... KVM_REG_PPC_VR31:
-			if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
-				r = -ENXIO;
-				break;
-			}
-			vcpu->arch.vr.vr[reg->id - KVM_REG_PPC_VR0] = val.vval;
-			break;
-		case KVM_REG_PPC_VSCR:
-			if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
-				r = -ENXIO;
-				break;
-			}
-			vcpu->arch.vr.vscr.u[3] = set_reg_val(reg->id, val);
-			break;
-		case KVM_REG_PPC_VRSAVE:
-			if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
-				r = -ENXIO;
-				break;
-			}
-			vcpu->arch.vrsave = set_reg_val(reg->id, val);
+			vcpu->arch.fp.fpscr = set_reg_val(id, *val);
 			break;
-#endif /* CONFIG_ALTIVEC */
 #ifdef CONFIG_VSX
 		case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31:
 			if (cpu_has_feature(CPU_FTR_VSX)) {
-				long int i = reg->id - KVM_REG_PPC_VSR0;
-				vcpu->arch.fp.fpr[i][0] = val.vsxval[0];
-				vcpu->arch.fp.fpr[i][1] = val.vsxval[1];
+				i = id - KVM_REG_PPC_VSR0;
+				vcpu->arch.fp.fpr[i][0] = val->vsxval[0];
+				vcpu->arch.fp.fpr[i][1] = val->vsxval[1];
 			} else {
 				r = -ENXIO;
 			}
@@ -715,29 +652,29 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
 				break;
 			}
 			r = kvmppc_xics_set_icp(vcpu,
-						set_reg_val(reg->id, val));
+						set_reg_val(id, *val));
 			break;
 #endif /* CONFIG_KVM_XICS */
 		case KVM_REG_PPC_FSCR:
-			vcpu->arch.fscr = set_reg_val(reg->id, val);
+			vcpu->arch.fscr = set_reg_val(id, *val);
 			break;
 		case KVM_REG_PPC_TAR:
-			vcpu->arch.tar = set_reg_val(reg->id, val);
+			vcpu->arch.tar = set_reg_val(id, *val);
 			break;
 		case KVM_REG_PPC_EBBHR:
-			vcpu->arch.ebbhr = set_reg_val(reg->id, val);
+			vcpu->arch.ebbhr = set_reg_val(id, *val);
 			break;
 		case KVM_REG_PPC_EBBRR:
-			vcpu->arch.ebbrr = set_reg_val(reg->id, val);
+			vcpu->arch.ebbrr = set_reg_val(id, *val);
 			break;
 		case KVM_REG_PPC_BESCR:
-			vcpu->arch.bescr = set_reg_val(reg->id, val);
+			vcpu->arch.bescr = set_reg_val(id, *val);
 			break;
 		case KVM_REG_PPC_VTB:
-			vcpu->arch.vtb = set_reg_val(reg->id, val);
+			vcpu->arch.vtb = set_reg_val(id, *val);
 			break;
 		case KVM_REG_PPC_IC:
-			vcpu->arch.ic = set_reg_val(reg->id, val);
+			vcpu->arch.ic = set_reg_val(id, *val);
 			break;
 		default:
 			r = -EINVAL;
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index c5cca09..4fe7f68 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -1559,144 +1559,125 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
 	return vcpu->kvm->arch.kvm_ops->set_sregs(vcpu, sregs);
 }
 
-int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
+int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id,
+			union kvmppc_one_reg *val)
 {
 	int r = 0;
-	union kvmppc_one_reg val;
-	int size;
 
-	size = one_reg_size(reg->id);
-	if (size > sizeof(val))
-		return -EINVAL;
-
-	switch (reg->id) {
+	switch (id) {
 	case KVM_REG_PPC_IAC1:
-		val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac1);
+		*val = get_reg_val(id, vcpu->arch.dbg_reg.iac1);
 		break;
 	case KVM_REG_PPC_IAC2:
-		val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac2);
+		*val = get_reg_val(id, vcpu->arch.dbg_reg.iac2);
 		break;
 #if CONFIG_PPC_ADV_DEBUG_IACS > 2
 	case KVM_REG_PPC_IAC3:
-		val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac3);
+		*val = get_reg_val(id, vcpu->arch.dbg_reg.iac3);
 		break;
 	case KVM_REG_PPC_IAC4:
-		val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac4);
+		*val = get_reg_val(id, vcpu->arch.dbg_reg.iac4);
 		break;
 #endif
 	case KVM_REG_PPC_DAC1:
-		val = get_reg_val(reg->id, vcpu->arch.dbg_reg.dac1);
+		*val = get_reg_val(id, vcpu->arch.dbg_reg.dac1);
 		break;
 	case KVM_REG_PPC_DAC2:
-		val = get_reg_val(reg->id, vcpu->arch.dbg_reg.dac2);
+		*val = get_reg_val(id, vcpu->arch.dbg_reg.dac2);
 		break;
 	case KVM_REG_PPC_EPR: {
 		u32 epr = kvmppc_get_epr(vcpu);
-		val = get_reg_val(reg->id, epr);
+		*val = get_reg_val(id, epr);
 		break;
 	}
 #if defined(CONFIG_64BIT)
 	case KVM_REG_PPC_EPCR:
-		val = get_reg_val(reg->id, vcpu->arch.epcr);
+		*val = get_reg_val(id, vcpu->arch.epcr);
 		break;
 #endif
 	case KVM_REG_PPC_TCR:
-		val = get_reg_val(reg->id, vcpu->arch.tcr);
+		*val = get_reg_val(id, vcpu->arch.tcr);
 		break;
 	case KVM_REG_PPC_TSR:
-		val = get_reg_val(reg->id, vcpu->arch.tsr);
+		*val = get_reg_val(id, vcpu->arch.tsr);
 		break;
 	case KVM_REG_PPC_DEBUG_INST:
-		val = get_reg_val(reg->id, KVMPPC_INST_EHPRIV_DEBUG);
+		*val = get_reg_val(id, KVMPPC_INST_EHPRIV_DEBUG);
 		break;
 	case KVM_REG_PPC_VRSAVE:
-		val = get_reg_val(reg->id, vcpu->arch.vrsave);
+		*val = get_reg_val(id, vcpu->arch.vrsave);
 		break;
 	default:
-		r = vcpu->kvm->arch.kvm_ops->get_one_reg(vcpu, reg->id, &val);
+		r = vcpu->kvm->arch.kvm_ops->get_one_reg(vcpu, id, val);
 		break;
 	}
 
-	if (r)
-		return r;
-
-	if (copy_to_user((char __user *)(unsigned long)reg->addr, &val, size))
-		r = -EFAULT;
-
 	return r;
 }
 
-int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
+int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id,
+			union kvmppc_one_reg *val)
 {
 	int r = 0;
-	union kvmppc_one_reg val;
-	int size;
-
-	size = one_reg_size(reg->id);
-	if (size > sizeof(val))
-		return -EINVAL;
-
-	if (copy_from_user(&val, (char __user *)(unsigned long)reg->addr, size))
-		return -EFAULT;
 
-	switch (reg->id) {
+	switch (id) {
 	case KVM_REG_PPC_IAC1:
-		vcpu->arch.dbg_reg.iac1 = set_reg_val(reg->id, val);
+		vcpu->arch.dbg_reg.iac1 = set_reg_val(id, *val);
 		break;
 	case KVM_REG_PPC_IAC2:
-		vcpu->arch.dbg_reg.iac2 = set_reg_val(reg->id, val);
+		vcpu->arch.dbg_reg.iac2 = set_reg_val(id, *val);
 		break;
 #if CONFIG_PPC_ADV_DEBUG_IACS > 2
 	case KVM_REG_PPC_IAC3:
-		vcpu->arch.dbg_reg.iac3 = set_reg_val(reg->id, val);
+		vcpu->arch.dbg_reg.iac3 = set_reg_val(id, *val);
 		break;
 	case KVM_REG_PPC_IAC4:
-		vcpu->arch.dbg_reg.iac4 = set_reg_val(reg->id, val);
+		vcpu->arch.dbg_reg.iac4 = set_reg_val(id, *val);
 		break;
 #endif
 	case KVM_REG_PPC_DAC1:
-		vcpu->arch.dbg_reg.dac1 = set_reg_val(reg->id, val);
+		vcpu->arch.dbg_reg.dac1 = set_reg_val(id, *val);
 		break;
 	case KVM_REG_PPC_DAC2:
-		vcpu->arch.dbg_reg.dac2 = set_reg_val(reg->id, val);
+		vcpu->arch.dbg_reg.dac2 = set_reg_val(id, *val);
 		break;
 	case KVM_REG_PPC_EPR: {
-		u32 new_epr = set_reg_val(reg->id, val);
+		u32 new_epr = set_reg_val(id, *val);
 		kvmppc_set_epr(vcpu, new_epr);
 		break;
 	}
 #if defined(CONFIG_64BIT)
 	case KVM_REG_PPC_EPCR: {
-		u32 new_epcr = set_reg_val(reg->id, val);
+		u32 new_epcr = set_reg_val(id, *val);
 		kvmppc_set_epcr(vcpu, new_epcr);
 		break;
 	}
 #endif
 	case KVM_REG_PPC_OR_TSR: {
-		u32 tsr_bits = set_reg_val(reg->id, val);
+		u32 tsr_bits = set_reg_val(id, *val);
 		kvmppc_set_tsr_bits(vcpu, tsr_bits);
 		break;
 	}
 	case KVM_REG_PPC_CLEAR_TSR: {
-		u32 tsr_bits = set_reg_val(reg->id, val);
+		u32 tsr_bits = set_reg_val(id, *val);
 		kvmppc_clr_tsr_bits(vcpu, tsr_bits);
 		break;
 	}
 	case KVM_REG_PPC_TSR: {
-		u32 tsr = set_reg_val(reg->id, val);
+		u32 tsr = set_reg_val(id, *val);
 		kvmppc_set_tsr(vcpu, tsr);
 		break;
 	}
 	case KVM_REG_PPC_TCR: {
-		u32 tcr = set_reg_val(reg->id, val);
+		u32 tcr = set_reg_val(id, *val);
 		kvmppc_set_tcr(vcpu, tcr);
 		break;
 	}
 	case KVM_REG_PPC_VRSAVE:
-		vcpu->arch.vrsave = set_reg_val(reg->id, val);
+		vcpu->arch.vrsave = set_reg_val(id, *val);
 		break;
 	default:
-		r = vcpu->kvm->arch.kvm_ops->set_one_reg(vcpu, reg->id, &val);
+		r = vcpu->kvm->arch.kvm_ops->set_one_reg(vcpu, id, val);
 		break;
 	}
 
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 288b4bb..2e10ddb 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -927,6 +927,103 @@ int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
 }
 EXPORT_SYMBOL_GPL(kvmppc_handle_store);
 
+int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
+{
+	int r = 0;
+	union kvmppc_one_reg val;
+	int size;
+
+	size = one_reg_size(reg->id);
+	if (size > sizeof(val))
+		return -EINVAL;
+
+	r = kvmppc_get_one_reg(vcpu, reg->id, &val);
+	if (r == -EINVAL) {
+		r = 0;
+		switch (reg->id) {
+#ifdef CONFIG_ALTIVEC
+		case KVM_REG_PPC_VR0 ... KVM_REG_PPC_VR31:
+			if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
+				r = -ENXIO;
+				break;
+			}
+			val.vval = vcpu->arch.vr.vr[reg->id - KVM_REG_PPC_VR0];
+			break;
+		case KVM_REG_PPC_VSCR:
+			if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
+				r = -ENXIO;
+				break;
+			}
+			val = get_reg_val(reg->id, vcpu->arch.vr.vscr.u[3]);
+			break;
+		case KVM_REG_PPC_VRSAVE:
+			val = get_reg_val(reg->id, vcpu->arch.vrsave);
+			break;
+#endif /* CONFIG_ALTIVEC */
+		default:
+			r = -EINVAL;
+			break;
+		}
+	}
+
+	if (r)
+		return r;
+
+	if (copy_to_user((char __user *)(unsigned long)reg->addr, &val, size))
+		r = -EFAULT;
+
+	return r;
+}
+
+int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
+{
+	int r;
+	union kvmppc_one_reg val;
+	int size;
+
+	size = one_reg_size(reg->id);
+	if (size > sizeof(val))
+		return -EINVAL;
+
+	if (copy_from_user(&val, (char __user *)(unsigned long)reg->addr, size))
+		return -EFAULT;
+
+	r = kvmppc_set_one_reg(vcpu, reg->id, &val);
+	if (r == -EINVAL) {
+		r = 0;
+		switch (reg->id) {
+#ifdef CONFIG_ALTIVEC
+		case KVM_REG_PPC_VR0 ... KVM_REG_PPC_VR31:
+			if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
+				r = -ENXIO;
+				break;
+			}
+			vcpu->arch.vr.vr[reg->id - KVM_REG_PPC_VR0] = val.vval;
+			break;
+		case KVM_REG_PPC_VSCR:
+			if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
+				r = -ENXIO;
+				break;
+			}
+			vcpu->arch.vr.vscr.u[3] = set_reg_val(reg->id, val);
+			break;
+		case KVM_REG_PPC_VRSAVE:
+			if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
+				r = -ENXIO;
+				break;
+			}
+			vcpu->arch.vrsave = set_reg_val(reg->id, val);
+			break;
+#endif /* CONFIG_ALTIVEC */
+		default:
+			r = -EINVAL;
+			break;
+		}
+	}
+
+	return r;
+}
+
 int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
 	int r;
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 4/5] KVM: PPC: Booke: Add ONE_REG IVORs support
  2014-08-05 10:39 [PATCH v3 0/5] KVM: PPC: Book3e: AltiVec support Mihai Caraman
                   ` (2 preceding siblings ...)
  2014-08-05 10:39 ` [PATCH v3 3/5] KVM: PPC: Move ONE_REG AltiVec support to powerpc Mihai Caraman
@ 2014-08-05 10:39 ` Mihai Caraman
  2014-08-12 11:48   ` Alexander Graf
  2014-08-05 10:39 ` [PATCH v3 5/5] KVM: PPC: Book3E: Enable e6500 core Mihai Caraman
  4 siblings, 1 reply; 9+ messages in thread
From: Mihai Caraman @ 2014-08-05 10:39 UTC (permalink / raw)
  To: kvm-ppc; +Cc: kvm, Mihai Caraman

Add ONE_REG IVORs support, with IVORs 0-15 and 35 booke common.

Signed-off-by: Mihai Caraman <mihai.caraman@freescale.com>
---
v3:
 - new patch

 arch/powerpc/include/uapi/asm/kvm.h |  24 +++++++
 arch/powerpc/kvm/booke.c            | 132 ++++++++++++++++++++++++++++++++++++
 arch/powerpc/kvm/e500.c             |  42 +++++++++++-
 arch/powerpc/kvm/e500mc.c           |  32 +++++++++
 4 files changed, 228 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h
index 7a27ff0..174fed0 100644
--- a/arch/powerpc/include/uapi/asm/kvm.h
+++ b/arch/powerpc/include/uapi/asm/kvm.h
@@ -563,6 +563,30 @@ struct kvm_get_htab_header {
 #define KVM_REG_PPC_WORT	(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb9)
 #define KVM_REG_PPC_SPRG9	(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xba)
 
+/* Booke IVOR registers */
+#define KVM_REG_PPC_IVOR0	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xc0)
+#define KVM_REG_PPC_IVOR1	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xc1)
+#define KVM_REG_PPC_IVOR2	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xc2)
+#define KVM_REG_PPC_IVOR3	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xc3)
+#define KVM_REG_PPC_IVOR4	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xc4)
+#define KVM_REG_PPC_IVOR5	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xc5)
+#define KVM_REG_PPC_IVOR6	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xc6)
+#define KVM_REG_PPC_IVOR7	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xc7)
+#define KVM_REG_PPC_IVOR8	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xc8)
+#define KVM_REG_PPC_IVOR9	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xc9)
+#define KVM_REG_PPC_IVOR10	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xca)
+#define KVM_REG_PPC_IVOR11	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xcb)
+#define KVM_REG_PPC_IVOR12	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xcc)
+#define KVM_REG_PPC_IVOR13	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xcd)
+#define KVM_REG_PPC_IVOR14	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xce)
+#define KVM_REG_PPC_IVOR15	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xcf)
+#define KVM_REG_PPC_IVOR32	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xd0)
+#define KVM_REG_PPC_IVOR33	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xd1)
+#define KVM_REG_PPC_IVOR34	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xd2)
+#define KVM_REG_PPC_IVOR35	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xd3)
+#define KVM_REG_PPC_IVOR36	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xd4)
+#define KVM_REG_PPC_IVOR37	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xd5)
+
 /* Transactional Memory checkpointed state:
  * This is all GPRs, all VSX regs and a subset of SPRs
  */
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index 4fe7f68..ffa82a5 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -1565,6 +1565,72 @@ int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id,
 	int r = 0;
 
 	switch (id) {
+	case KVM_REG_PPC_IVOR0:
+		*val = get_reg_val(id,
+				vcpu->arch.ivor[BOOKE_IRQPRIO_CRITICAL]);
+		break;
+	case KVM_REG_PPC_IVOR1:
+		*val = get_reg_val(id,
+				vcpu->arch.ivor[BOOKE_IRQPRIO_MACHINE_CHECK]);
+		break;
+	case KVM_REG_PPC_IVOR2:
+		*val = get_reg_val(id,
+				vcpu->arch.ivor[BOOKE_IRQPRIO_DATA_STORAGE]);
+		break;
+	case KVM_REG_PPC_IVOR3:
+		*val = get_reg_val(id,
+				vcpu->arch.ivor[BOOKE_IRQPRIO_INST_STORAGE]);
+		break;
+	case KVM_REG_PPC_IVOR4:
+		*val = get_reg_val(id,
+				vcpu->arch.ivor[BOOKE_IRQPRIO_EXTERNAL]);
+		break;
+	case KVM_REG_PPC_IVOR5:
+		*val = get_reg_val(id,
+				vcpu->arch.ivor[BOOKE_IRQPRIO_ALIGNMENT]);
+		break;
+	case KVM_REG_PPC_IVOR6:
+		*val = get_reg_val(id, vcpu->arch.ivor[BOOKE_IRQPRIO_PROGRAM]);
+		break;
+	case KVM_REG_PPC_IVOR7:
+		*val = get_reg_val(id,
+				vcpu->arch.ivor[BOOKE_IRQPRIO_FP_UNAVAIL]);
+		break;
+	case KVM_REG_PPC_IVOR8:
+		*val = get_reg_val(id,
+				vcpu->arch.ivor[BOOKE_IRQPRIO_CRITICAL]);
+		break;
+	case KVM_REG_PPC_IVOR9:
+		*val = get_reg_val(id,
+				vcpu->arch.ivor[BOOKE_IRQPRIO_AP_UNAVAIL]);
+		break;
+	case KVM_REG_PPC_IVOR10:
+		*val = get_reg_val(id,
+				vcpu->arch.ivor[BOOKE_IRQPRIO_DECREMENTER]);
+		break;
+	case KVM_REG_PPC_IVOR11:
+		*val = get_reg_val(id, vcpu->arch.ivor[BOOKE_IRQPRIO_FIT]);
+		break;
+	case KVM_REG_PPC_IVOR12:
+		*val = get_reg_val(id,
+				vcpu->arch.ivor[BOOKE_IRQPRIO_WATCHDOG]);
+		break;
+	case KVM_REG_PPC_IVOR13:
+		*val = get_reg_val(id,
+				vcpu->arch.ivor[BOOKE_IRQPRIO_DTLB_MISS]);
+		break;
+	case KVM_REG_PPC_IVOR14:
+		*val = get_reg_val(id,
+				vcpu->arch.ivor[BOOKE_IRQPRIO_ITLB_MISS]);
+		break;
+	case KVM_REG_PPC_IVOR15:
+		*val = get_reg_val(id,
+				vcpu->arch.ivor[BOOKE_IRQPRIO_DEBUG]);
+		break;
+	case KVM_REG_PPC_IVOR35:
+		*val = get_reg_val(id,
+			vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR]);
+		break;
 	case KVM_REG_PPC_IAC1:
 		*val = get_reg_val(id, vcpu->arch.dbg_reg.iac1);
 		break;
@@ -1621,6 +1687,72 @@ int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id,
 	int r = 0;
 
 	switch (id) {
+	case KVM_REG_PPC_IVOR0:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_CRITICAL] =
+			set_reg_val(id, *val);
+		break;
+	case KVM_REG_PPC_IVOR1:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_MACHINE_CHECK] =
+			set_reg_val(id, *val);
+		break;
+	case KVM_REG_PPC_IVOR2:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_DATA_STORAGE] =
+			set_reg_val(id, *val);
+		break;
+	case KVM_REG_PPC_IVOR3:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_INST_STORAGE] =
+			set_reg_val(id, *val);
+		break;
+	case KVM_REG_PPC_IVOR4:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_EXTERNAL] =
+			set_reg_val(id, *val);
+		break;
+	case KVM_REG_PPC_IVOR5:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_ALIGNMENT] =
+			set_reg_val(id, *val);
+		break;
+	case KVM_REG_PPC_IVOR6:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_PROGRAM] =
+			set_reg_val(id, *val);
+		break;
+	case KVM_REG_PPC_IVOR7:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_FP_UNAVAIL] =
+			set_reg_val(id, *val);
+		break;
+	case KVM_REG_PPC_IVOR8:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_CRITICAL] =
+			set_reg_val(id, *val);
+		break;
+	case KVM_REG_PPC_IVOR9:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_AP_UNAVAIL] =
+			set_reg_val(id, *val);
+		break;
+	case KVM_REG_PPC_IVOR10:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_DECREMENTER] =
+			set_reg_val(id, *val);
+		break;
+	case KVM_REG_PPC_IVOR11:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_FIT] = set_reg_val(id, *val);
+		break;
+	case KVM_REG_PPC_IVOR12:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_WATCHDOG] =
+			set_reg_val(id, *val);
+		break;
+	case KVM_REG_PPC_IVOR13:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_DTLB_MISS] =
+			set_reg_val(id, *val);
+		break;
+	case KVM_REG_PPC_IVOR14:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_ITLB_MISS] =
+			set_reg_val(id, *val);
+		break;
+	case KVM_REG_PPC_IVOR15:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_DEBUG] = set_reg_val(id, *val);
+		break;
+	case KVM_REG_PPC_IVOR35:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR] =
+			set_reg_val(id, *val);
+		break;
 	case KVM_REG_PPC_IAC1:
 		vcpu->arch.dbg_reg.iac1 = set_reg_val(id, *val);
 		break;
diff --git a/arch/powerpc/kvm/e500.c b/arch/powerpc/kvm/e500.c
index 2e02ed8..08f61bf 100644
--- a/arch/powerpc/kvm/e500.c
+++ b/arch/powerpc/kvm/e500.c
@@ -433,14 +433,52 @@ static int kvmppc_core_set_sregs_e500(struct kvm_vcpu *vcpu,
 static int kvmppc_get_one_reg_e500(struct kvm_vcpu *vcpu, u64 id,
 				   union kvmppc_one_reg *val)
 {
-	int r = kvmppc_get_one_reg_e500_tlb(vcpu, id, val);
+	int r = 0;
+
+	switch (id) {
+	case KVM_REG_PPC_IVOR32:
+		*val = get_reg_val(id,
+				vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL]);
+		break;
+	case KVM_REG_PPC_IVOR33:
+		*val = get_reg_val(id,
+				vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_DATA]);
+		break;
+	case KVM_REG_PPC_IVOR34:
+		*val = get_reg_val(id,
+				vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND]);
+		break;
+	default:
+		r = kvmppc_get_one_reg_e500_tlb(vcpu, id, val);
+		break;
+	}
+
 	return r;
 }
 
 static int kvmppc_set_one_reg_e500(struct kvm_vcpu *vcpu, u64 id,
 				   union kvmppc_one_reg *val)
 {
-	int r = kvmppc_get_one_reg_e500_tlb(vcpu, id, val);
+	int r = 0;
+
+	switch (id) {
+	case KVM_REG_PPC_IVOR32:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL] =
+			set_reg_val(id, *val);
+		break;
+	case KVM_REG_PPC_IVOR33:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_DATA] =
+			set_reg_val(id, *val);
+		break;
+	case KVM_REG_PPC_IVOR34:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND] =
+			set_reg_val(id, *val);
+		break;
+	default:
+		r = kvmppc_get_one_reg_e500_tlb(vcpu, id, val);
+		break;
+	}
+
 	return r;
 }
 
diff --git a/arch/powerpc/kvm/e500mc.c b/arch/powerpc/kvm/e500mc.c
index 67c06eb..19dd927 100644
--- a/arch/powerpc/kvm/e500mc.c
+++ b/arch/powerpc/kvm/e500mc.c
@@ -268,6 +268,22 @@ static int kvmppc_get_one_reg_e500mc(struct kvm_vcpu *vcpu, u64 id,
 	int r = 0;
 
 	switch (id) {
+	case KVM_REG_PPC_IVOR32:
+		*val = get_reg_val(id,
+			vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_UNAVAIL]);
+		break;
+	case KVM_REG_PPC_IVOR33:
+		*val = get_reg_val(id,
+			vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_ASSIST]);
+		break;
+	case KVM_REG_PPC_IVOR36:
+		*val = get_reg_val(id,
+			vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL]);
+		break;
+	case KVM_REG_PPC_IVOR37:
+		*val = get_reg_val(id,
+			vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL_CRIT]);
+		break;
 	case KVM_REG_PPC_SPRG9:
 		*val = get_reg_val(id, vcpu->arch.sprg9);
 		break;
@@ -284,6 +300,22 @@ static int kvmppc_set_one_reg_e500mc(struct kvm_vcpu *vcpu, u64 id,
 	int r = 0;
 
 	switch (id) {
+	case KVM_REG_PPC_IVOR32:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_UNAVAIL] =
+			set_reg_val(id, *val);
+		break;
+	case KVM_REG_PPC_IVOR33:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_ASSIST] =
+			set_reg_val(id, *val);
+		break;
+	case KVM_REG_PPC_IVOR36:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL] =
+			set_reg_val(id, *val);
+		break;
+	case KVM_REG_PPC_IVOR37:
+		vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL_CRIT] =
+			set_reg_val(id, *val);
+		break;
 	case KVM_REG_PPC_SPRG9:
 		vcpu->arch.sprg9 = set_reg_val(id, *val);
 		break;
-- 
1.7.11.7

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 5/5] KVM: PPC: Book3E: Enable e6500 core
  2014-08-05 10:39 [PATCH v3 0/5] KVM: PPC: Book3e: AltiVec support Mihai Caraman
                   ` (3 preceding siblings ...)
  2014-08-05 10:39 ` [PATCH v3 4/5] KVM: PPC: Booke: Add ONE_REG IVORs support Mihai Caraman
@ 2014-08-05 10:39 ` Mihai Caraman
  4 siblings, 0 replies; 9+ messages in thread
From: Mihai Caraman @ 2014-08-05 10:39 UTC (permalink / raw)
  To: kvm-ppc; +Cc: kvm, Mihai Caraman

Now that AltiVec support is in place enable e6500 core.

Signed-off-by: Mihai Caraman <mihai.caraman@freescale.com>
---
v2-v3:
 - no changes

 arch/powerpc/kvm/e500mc.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/powerpc/kvm/e500mc.c b/arch/powerpc/kvm/e500mc.c
index 19dd927..aa48dc3 100644
--- a/arch/powerpc/kvm/e500mc.c
+++ b/arch/powerpc/kvm/e500mc.c
@@ -177,6 +177,16 @@ int kvmppc_core_check_processor_compat(void)
 		r = 0;
 	else if (strcmp(cur_cpu_spec->cpu_name, "e5500") == 0)
 		r = 0;
+#ifdef CONFIG_ALTIVEC
+	/*
+	 * Since guests have the priviledge to enable AltiVec, we need AltiVec
+	 * support in the host to save/restore their context.
+	 * Don't use CPU_FTR_ALTIVEC to identify cores with AltiVec unit
+	 * because it's cleared in the absence of CONFIG_ALTIVEC!
+	 */
+	else if (strcmp(cur_cpu_spec->cpu_name, "e6500") == 0)
+		r = 0;
+#endif
 	else
 		r = -ENOTSUPP;
 
-- 
1.7.11.7

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 2/5] KVM: PPC: Book3e: Add AltiVec support
  2014-08-05 10:39 ` [PATCH v3 2/5] KVM: PPC: Book3e: Add AltiVec support Mihai Caraman
@ 2014-08-12 11:45   ` Alexander Graf
  0 siblings, 0 replies; 9+ messages in thread
From: Alexander Graf @ 2014-08-12 11:45 UTC (permalink / raw)
  To: Mihai Caraman, kvm-ppc; +Cc: kvm


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;

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 3/5] KVM: PPC: Move ONE_REG AltiVec support to powerpc
  2014-08-05 10:39 ` [PATCH v3 3/5] KVM: PPC: Move ONE_REG AltiVec support to powerpc Mihai Caraman
@ 2014-08-12 11:47   ` Alexander Graf
  0 siblings, 0 replies; 9+ messages in thread
From: Alexander Graf @ 2014-08-12 11:47 UTC (permalink / raw)
  To: Mihai Caraman, kvm-ppc; +Cc: kvm


On 05.08.14 12:39, Mihai Caraman wrote:
> Make ONE_REG AltiVec support common across server and embedded implementations
> moving kvm_vcpu_ioctl_get_one_reg() and kvm_vcpu_ioctl_set_one_reg() functions
> to powerpc layer.
>
> Signed-off-by: Mihai Caraman <mihai.caraman@freescale.com>

Please split this into 2 separate patches, one that makes ONE_REG 
generic and one that moves Altivec from book3s into the generic version.


Alex

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 4/5] KVM: PPC: Booke: Add ONE_REG IVORs support
  2014-08-05 10:39 ` [PATCH v3 4/5] KVM: PPC: Booke: Add ONE_REG IVORs support Mihai Caraman
@ 2014-08-12 11:48   ` Alexander Graf
  0 siblings, 0 replies; 9+ messages in thread
From: Alexander Graf @ 2014-08-12 11:48 UTC (permalink / raw)
  To: Mihai Caraman, kvm-ppc; +Cc: kvm


On 05.08.14 12:39, Mihai Caraman wrote:
> Add ONE_REG IVORs support, with IVORs 0-15 and 35 booke common.
>
> Signed-off-by: Mihai Caraman <mihai.caraman@freescale.com>
> ---
> v3:
>   - new patch
>
>   arch/powerpc/include/uapi/asm/kvm.h |  24 +++++++
>   arch/powerpc/kvm/booke.c            | 132 ++++++++++++++++++++++++++++++++++++
>   arch/powerpc/kvm/e500.c             |  42 +++++++++++-
>   arch/powerpc/kvm/e500mc.c           |  32 +++++++++
>   4 files changed, 228 insertions(+), 2 deletions(-)
>
> diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h
> index 7a27ff0..174fed0 100644
> --- a/arch/powerpc/include/uapi/asm/kvm.h
> +++ b/arch/powerpc/include/uapi/asm/kvm.h
> @@ -563,6 +563,30 @@ struct kvm_get_htab_header {
>   #define KVM_REG_PPC_WORT	(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb9)
>   #define KVM_REG_PPC_SPRG9	(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xba)
>   
> +/* Booke IVOR registers */
> +#define KVM_REG_PPC_IVOR0	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xc0)
> +#define KVM_REG_PPC_IVOR1	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xc1)
> +#define KVM_REG_PPC_IVOR2	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xc2)
> +#define KVM_REG_PPC_IVOR3	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xc3)
> +#define KVM_REG_PPC_IVOR4	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xc4)
> +#define KVM_REG_PPC_IVOR5	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xc5)
> +#define KVM_REG_PPC_IVOR6	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xc6)
> +#define KVM_REG_PPC_IVOR7	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xc7)
> +#define KVM_REG_PPC_IVOR8	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xc8)
> +#define KVM_REG_PPC_IVOR9	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xc9)
> +#define KVM_REG_PPC_IVOR10	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xca)
> +#define KVM_REG_PPC_IVOR11	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xcb)
> +#define KVM_REG_PPC_IVOR12	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xcc)
> +#define KVM_REG_PPC_IVOR13	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xcd)
> +#define KVM_REG_PPC_IVOR14	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xce)
> +#define KVM_REG_PPC_IVOR15	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xcf)
> +#define KVM_REG_PPC_IVOR32	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xd0)
> +#define KVM_REG_PPC_IVOR33	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xd1)
> +#define KVM_REG_PPC_IVOR34	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xd2)
> +#define KVM_REG_PPC_IVOR35	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xd3)
> +#define KVM_REG_PPC_IVOR36	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xd4)
> +#define KVM_REG_PPC_IVOR37	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xd5)

These should also get mentioned in Documentation/virtual/kvm/api.txt.

Otherwise looks nice :).


Alex

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2014-08-12 11:48 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-08-05 10:39 [PATCH v3 0/5] KVM: PPC: Book3e: AltiVec support Mihai Caraman
2014-08-05 10:39 ` [PATCH v3 1/5] KVM: PPC: Book3e: Increase FPU laziness Mihai Caraman
2014-08-05 10:39 ` [PATCH v3 2/5] KVM: PPC: Book3e: Add AltiVec support Mihai Caraman
2014-08-12 11:45   ` Alexander Graf
2014-08-05 10:39 ` [PATCH v3 3/5] KVM: PPC: Move ONE_REG AltiVec support to powerpc Mihai Caraman
2014-08-12 11:47   ` Alexander Graf
2014-08-05 10:39 ` [PATCH v3 4/5] KVM: PPC: Booke: Add ONE_REG IVORs support Mihai Caraman
2014-08-12 11:48   ` Alexander Graf
2014-08-05 10:39 ` [PATCH v3 5/5] KVM: PPC: Book3E: Enable e6500 core Mihai Caraman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox