aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kvm
diff options
context:
space:
mode:
authorMihai Caraman <mihai.caraman@freescale.com>2014-08-20 09:36:23 -0400
committerAlexander Graf <agraf@suse.de>2014-09-22 04:11:32 -0400
commit95d80a294b1eec83eb58c57e101b05828d97a851 (patch)
treeba3cd2f22c938638926ee4fff629d594f8c79b2d /arch/powerpc/kvm
parent3efc7da61f6c5af78f67f03df8b0e1a473d8bc45 (diff)
KVM: PPC: Book3e: Add AltiVec support
Add AltiVec support in KVM for Book3e. FPU support gracefully reuse host infrastructure so follow the same approach for AltiVec. Book3e specification defines shared interrupt numbers for SPE and AltiVec units. Still SPE is present in e200/e500v2 cores while AltiVec is present in e6500 core. So we can currently decide at compile-time which of the SPE or AltiVec units to support exclusively by using CONFIG_SPE_POSSIBLE and CONFIG_PPC_E500MC defines. As Alexander Graf suggested, keep SPE and AltiVec exception handlers distinct to improve code readability. Guests have the privilege to enable AltiVec, so we always need to support AltiVec in KVM and implicitly in host to reflect interrupts and to save/restore the unit context. KVM will be loaded on cores with AltiVec unit only if CONFIG_ALTIVEC is defined. Use this define to guard KVM AltiVec logic. Signed-off-by: Mihai Caraman <mihai.caraman@freescale.com> Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'arch/powerpc/kvm')
-rw-r--r--arch/powerpc/kvm/booke.c74
-rw-r--r--arch/powerpc/kvm/booke.h6
-rw-r--r--arch/powerpc/kvm/bookehv_interrupts.S9
-rw-r--r--arch/powerpc/kvm/e500_emulate.c20
4 files changed, 101 insertions, 8 deletions
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index 91e7217db9d9..8ace6120ef9b 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)
168#endif 168#endif
169} 169}
170 170
171/*
172 * Simulate AltiVec unavailable fault to load guest state
173 * from thread to AltiVec unit.
174 * It requires to be called with preemption disabled.
175 */
176static inline void kvmppc_load_guest_altivec(struct kvm_vcpu *vcpu)
177{
178#ifdef CONFIG_ALTIVEC
179 if (cpu_has_feature(CPU_FTR_ALTIVEC)) {
180 if (!(current->thread.regs->msr & MSR_VEC)) {
181 enable_kernel_altivec();
182 load_vr_state(&vcpu->arch.vr);
183 current->thread.vr_save_area = &vcpu->arch.vr;
184 current->thread.regs->msr |= MSR_VEC;
185 }
186 }
187#endif
188}
189
190/*
191 * Save guest vcpu AltiVec state into thread.
192 * It requires to be called with preemption disabled.
193 */
194static inline void kvmppc_save_guest_altivec(struct kvm_vcpu *vcpu)
195{
196#ifdef CONFIG_ALTIVEC
197 if (cpu_has_feature(CPU_FTR_ALTIVEC)) {
198 if (current->thread.regs->msr & MSR_VEC)
199 giveup_altivec(current);
200 current->thread.vr_save_area = NULL;
201 }
202#endif
203}
204
171static void kvmppc_vcpu_sync_debug(struct kvm_vcpu *vcpu) 205static void kvmppc_vcpu_sync_debug(struct kvm_vcpu *vcpu)
172{ 206{
173 /* Synchronize guest's desire to get debug interrupts into shadow MSR */ 207 /* Synchronize guest's desire to get debug interrupts into shadow MSR */
@@ -375,9 +409,15 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
375 case BOOKE_IRQPRIO_ITLB_MISS: 409 case BOOKE_IRQPRIO_ITLB_MISS:
376 case BOOKE_IRQPRIO_SYSCALL: 410 case BOOKE_IRQPRIO_SYSCALL:
377 case BOOKE_IRQPRIO_FP_UNAVAIL: 411 case BOOKE_IRQPRIO_FP_UNAVAIL:
412#ifdef CONFIG_SPE_POSSIBLE
378 case BOOKE_IRQPRIO_SPE_UNAVAIL: 413 case BOOKE_IRQPRIO_SPE_UNAVAIL:
379 case BOOKE_IRQPRIO_SPE_FP_DATA: 414 case BOOKE_IRQPRIO_SPE_FP_DATA:
380 case BOOKE_IRQPRIO_SPE_FP_ROUND: 415 case BOOKE_IRQPRIO_SPE_FP_ROUND:
416#endif
417#ifdef CONFIG_ALTIVEC
418 case BOOKE_IRQPRIO_ALTIVEC_UNAVAIL:
419 case BOOKE_IRQPRIO_ALTIVEC_ASSIST:
420#endif
381 case BOOKE_IRQPRIO_AP_UNAVAIL: 421 case BOOKE_IRQPRIO_AP_UNAVAIL:
382 allowed = 1; 422 allowed = 1;
383 msr_mask = MSR_CE | MSR_ME | MSR_DE; 423 msr_mask = MSR_CE | MSR_ME | MSR_DE;
@@ -697,6 +737,17 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
697 kvmppc_load_guest_fp(vcpu); 737 kvmppc_load_guest_fp(vcpu);
698#endif 738#endif
699 739
740#ifdef CONFIG_ALTIVEC
741 /* Save userspace AltiVec state in stack */
742 if (cpu_has_feature(CPU_FTR_ALTIVEC))
743 enable_kernel_altivec();
744 /*
745 * Since we can't trap on MSR_VEC in GS-mode, we consider the guest
746 * as always using the AltiVec.
747 */
748 kvmppc_load_guest_altivec(vcpu);
749#endif
750
700 /* Switch to guest debug context */ 751 /* Switch to guest debug context */
701 debug = vcpu->arch.dbg_reg; 752 debug = vcpu->arch.dbg_reg;
702 switch_booke_debug_regs(&debug); 753 switch_booke_debug_regs(&debug);
@@ -719,6 +770,10 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
719 kvmppc_save_guest_fp(vcpu); 770 kvmppc_save_guest_fp(vcpu);
720#endif 771#endif
721 772
773#ifdef CONFIG_ALTIVEC
774 kvmppc_save_guest_altivec(vcpu);
775#endif
776
722out: 777out:
723 vcpu->mode = OUTSIDE_GUEST_MODE; 778 vcpu->mode = OUTSIDE_GUEST_MODE;
724 return ret; 779 return ret;
@@ -1025,7 +1080,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
1025 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SPE_FP_ROUND); 1080 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SPE_FP_ROUND);
1026 r = RESUME_GUEST; 1081 r = RESUME_GUEST;
1027 break; 1082 break;
1028#else 1083#elif defined(CONFIG_SPE_POSSIBLE)
1029 case BOOKE_INTERRUPT_SPE_UNAVAIL: 1084 case BOOKE_INTERRUPT_SPE_UNAVAIL:
1030 /* 1085 /*
1031 * Guest wants SPE, but host kernel doesn't support it. Send 1086 * Guest wants SPE, but host kernel doesn't support it. Send
@@ -1046,6 +1101,22 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
1046 run->hw.hardware_exit_reason = exit_nr; 1101 run->hw.hardware_exit_reason = exit_nr;
1047 r = RESUME_HOST; 1102 r = RESUME_HOST;
1048 break; 1103 break;
1104#endif /* CONFIG_SPE_POSSIBLE */
1105
1106/*
1107 * On cores with Vector category, KVM is loaded only if CONFIG_ALTIVEC,
1108 * see kvmppc_core_check_processor_compat().
1109 */
1110#ifdef CONFIG_ALTIVEC
1111 case BOOKE_INTERRUPT_ALTIVEC_UNAVAIL:
1112 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_ALTIVEC_UNAVAIL);
1113 r = RESUME_GUEST;
1114 break;
1115
1116 case BOOKE_INTERRUPT_ALTIVEC_ASSIST:
1117 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_ALTIVEC_ASSIST);
1118 r = RESUME_GUEST;
1119 break;
1049#endif 1120#endif
1050 1121
1051 case BOOKE_INTERRUPT_DATA_STORAGE: 1122 case BOOKE_INTERRUPT_DATA_STORAGE:
@@ -1223,6 +1294,7 @@ out:
1223 /* interrupts now hard-disabled */ 1294 /* interrupts now hard-disabled */
1224 kvmppc_fix_ee_before_entry(); 1295 kvmppc_fix_ee_before_entry();
1225 kvmppc_load_guest_fp(vcpu); 1296 kvmppc_load_guest_fp(vcpu);
1297 kvmppc_load_guest_altivec(vcpu);
1226 } 1298 }
1227 } 1299 }
1228 1300
diff --git a/arch/powerpc/kvm/booke.h b/arch/powerpc/kvm/booke.h
index e73d513f72d0..22ba08ea68e9 100644
--- a/arch/powerpc/kvm/booke.h
+++ b/arch/powerpc/kvm/booke.h
@@ -32,9 +32,15 @@
32#define BOOKE_IRQPRIO_ALIGNMENT 2 32#define BOOKE_IRQPRIO_ALIGNMENT 2
33#define BOOKE_IRQPRIO_PROGRAM 3 33#define BOOKE_IRQPRIO_PROGRAM 3
34#define BOOKE_IRQPRIO_FP_UNAVAIL 4 34#define BOOKE_IRQPRIO_FP_UNAVAIL 4
35#ifdef CONFIG_SPE_POSSIBLE
35#define BOOKE_IRQPRIO_SPE_UNAVAIL 5 36#define BOOKE_IRQPRIO_SPE_UNAVAIL 5
36#define BOOKE_IRQPRIO_SPE_FP_DATA 6 37#define BOOKE_IRQPRIO_SPE_FP_DATA 6
37#define BOOKE_IRQPRIO_SPE_FP_ROUND 7 38#define BOOKE_IRQPRIO_SPE_FP_ROUND 7
39#endif
40#ifdef CONFIG_PPC_E500MC
41#define BOOKE_IRQPRIO_ALTIVEC_UNAVAIL 5
42#define BOOKE_IRQPRIO_ALTIVEC_ASSIST 6
43#endif
38#define BOOKE_IRQPRIO_SYSCALL 8 44#define BOOKE_IRQPRIO_SYSCALL 8
39#define BOOKE_IRQPRIO_AP_UNAVAIL 9 45#define BOOKE_IRQPRIO_AP_UNAVAIL 9
40#define BOOKE_IRQPRIO_DTLB_MISS 10 46#define BOOKE_IRQPRIO_DTLB_MISS 10
diff --git a/arch/powerpc/kvm/bookehv_interrupts.S b/arch/powerpc/kvm/bookehv_interrupts.S
index e9fa56a911fd..c8e4da55cb43 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, \
256 SPRN_SRR0, SPRN_SRR1, (NEED_EMU | NEED_DEAR | NEED_ESR) 256 SPRN_SRR0, SPRN_SRR1, (NEED_EMU | NEED_DEAR | NEED_ESR)
257kvm_handler BOOKE_INTERRUPT_ITLB_MISS, EX_PARAMS_TLB, \ 257kvm_handler BOOKE_INTERRUPT_ITLB_MISS, EX_PARAMS_TLB, \
258 SPRN_SRR0, SPRN_SRR1, 0 258 SPRN_SRR0, SPRN_SRR1, 0
259kvm_handler BOOKE_INTERRUPT_SPE_UNAVAIL, EX_PARAMS(GEN), \ 259kvm_handler BOOKE_INTERRUPT_ALTIVEC_UNAVAIL, EX_PARAMS(GEN), \
260 SPRN_SRR0, SPRN_SRR1, 0 260 SPRN_SRR0, SPRN_SRR1, 0
261kvm_handler BOOKE_INTERRUPT_SPE_FP_DATA, EX_PARAMS(GEN), \ 261kvm_handler BOOKE_INTERRUPT_ALTIVEC_ASSIST, EX_PARAMS(GEN), \
262 SPRN_SRR0, SPRN_SRR1, 0
263kvm_handler BOOKE_INTERRUPT_SPE_FP_ROUND, EX_PARAMS(GEN), \
264 SPRN_SRR0, SPRN_SRR1, 0 262 SPRN_SRR0, SPRN_SRR1, 0
265kvm_handler BOOKE_INTERRUPT_PERFORMANCE_MONITOR, EX_PARAMS(GEN), \ 263kvm_handler BOOKE_INTERRUPT_PERFORMANCE_MONITOR, EX_PARAMS(GEN), \
266 SPRN_SRR0, SPRN_SRR1, 0 264 SPRN_SRR0, SPRN_SRR1, 0
@@ -361,9 +359,6 @@ kvm_lvl_handler BOOKE_INTERRUPT_WATCHDOG, \
361kvm_handler BOOKE_INTERRUPT_DTLB_MISS, \ 359kvm_handler BOOKE_INTERRUPT_DTLB_MISS, \
362 SPRN_SRR0, SPRN_SRR1, (NEED_EMU | NEED_DEAR | NEED_ESR) 360 SPRN_SRR0, SPRN_SRR1, (NEED_EMU | NEED_DEAR | NEED_ESR)
363kvm_handler BOOKE_INTERRUPT_ITLB_MISS, SPRN_SRR0, SPRN_SRR1, 0 361kvm_handler BOOKE_INTERRUPT_ITLB_MISS, SPRN_SRR0, SPRN_SRR1, 0
364kvm_handler BOOKE_INTERRUPT_SPE_UNAVAIL, SPRN_SRR0, SPRN_SRR1, 0
365kvm_handler BOOKE_INTERRUPT_SPE_FP_DATA, SPRN_SRR0, SPRN_SRR1, 0
366kvm_handler BOOKE_INTERRUPT_SPE_FP_ROUND, SPRN_SRR0, SPRN_SRR1, 0
367kvm_handler BOOKE_INTERRUPT_PERFORMANCE_MONITOR, SPRN_SRR0, SPRN_SRR1, 0 362kvm_handler BOOKE_INTERRUPT_PERFORMANCE_MONITOR, SPRN_SRR0, SPRN_SRR1, 0
368kvm_handler BOOKE_INTERRUPT_DOORBELL, SPRN_SRR0, SPRN_SRR1, 0 363kvm_handler BOOKE_INTERRUPT_DOORBELL, SPRN_SRR0, SPRN_SRR1, 0
369kvm_lvl_handler BOOKE_INTERRUPT_DOORBELL_CRITICAL, \ 364kvm_lvl_handler BOOKE_INTERRUPT_DOORBELL_CRITICAL, \
diff --git a/arch/powerpc/kvm/e500_emulate.c b/arch/powerpc/kvm/e500_emulate.c
index c99c40e9182a..ce7291c79f6c 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
259 break; 259 break;
260 260
261 /* extra exceptions */ 261 /* extra exceptions */
262#ifdef CONFIG_SPE_POSSIBLE
262 case SPRN_IVOR32: 263 case SPRN_IVOR32:
263 vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL] = spr_val; 264 vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL] = spr_val;
264 break; 265 break;
@@ -268,6 +269,15 @@ int kvmppc_core_emulate_mtspr_e500(struct kvm_vcpu *vcpu, int sprn, ulong spr_va
268 case SPRN_IVOR34: 269 case SPRN_IVOR34:
269 vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND] = spr_val; 270 vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND] = spr_val;
270 break; 271 break;
272#endif
273#ifdef CONFIG_ALTIVEC
274 case SPRN_IVOR32:
275 vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_UNAVAIL] = spr_val;
276 break;
277 case SPRN_IVOR33:
278 vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_ASSIST] = spr_val;
279 break;
280#endif
271 case SPRN_IVOR35: 281 case SPRN_IVOR35:
272 vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR] = spr_val; 282 vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR] = spr_val;
273 break; 283 break;
@@ -381,6 +391,7 @@ int kvmppc_core_emulate_mfspr_e500(struct kvm_vcpu *vcpu, int sprn, ulong *spr_v
381 break; 391 break;
382 392
383 /* extra exceptions */ 393 /* extra exceptions */
394#ifdef CONFIG_SPE_POSSIBLE
384 case SPRN_IVOR32: 395 case SPRN_IVOR32:
385 *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL]; 396 *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL];
386 break; 397 break;
@@ -390,6 +401,15 @@ int kvmppc_core_emulate_mfspr_e500(struct kvm_vcpu *vcpu, int sprn, ulong *spr_v
390 case SPRN_IVOR34: 401 case SPRN_IVOR34:
391 *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND]; 402 *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND];
392 break; 403 break;
404#endif
405#ifdef CONFIG_ALTIVEC
406 case SPRN_IVOR32:
407 *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_UNAVAIL];
408 break;
409 case SPRN_IVOR33:
410 *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_ASSIST];
411 break;
412#endif
393 case SPRN_IVOR35: 413 case SPRN_IVOR35:
394 *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR]; 414 *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR];
395 break; 415 break;