Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Mihai Caraman and committed by
Alexander Graf
95d80a29 3efc7da6

+101 -8
+73 -1
arch/powerpc/kvm/booke.c
··· 168 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 + */ 176 + static 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 + */ 194 + static 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 + 171 205 static void kvmppc_vcpu_sync_debug(struct kvm_vcpu *vcpu) 172 206 { 173 207 /* Synchronize guest's desire to get debug interrupts into shadow MSR */ ··· 409 375 case BOOKE_IRQPRIO_ITLB_MISS: 410 376 case BOOKE_IRQPRIO_SYSCALL: 411 377 case BOOKE_IRQPRIO_FP_UNAVAIL: 378 + #ifdef CONFIG_SPE_POSSIBLE 412 379 case BOOKE_IRQPRIO_SPE_UNAVAIL: 413 380 case BOOKE_IRQPRIO_SPE_FP_DATA: 414 381 case BOOKE_IRQPRIO_SPE_FP_ROUND: 382 + #endif 383 + #ifdef CONFIG_ALTIVEC 384 + case BOOKE_IRQPRIO_ALTIVEC_UNAVAIL: 385 + case BOOKE_IRQPRIO_ALTIVEC_ASSIST: 386 + #endif 415 387 case BOOKE_IRQPRIO_AP_UNAVAIL: 416 388 allowed = 1; 417 389 msr_mask = MSR_CE | MSR_ME | MSR_DE; ··· 737 697 kvmppc_load_guest_fp(vcpu); 738 698 #endif 739 699 700 + #ifdef CONFIG_ALTIVEC 701 + /* Save userspace AltiVec state in stack */ 702 + if (cpu_has_feature(CPU_FTR_ALTIVEC)) 703 + enable_kernel_altivec(); 704 + /* 705 + * Since we can't trap on MSR_VEC in GS-mode, we consider the guest 706 + * as always using the AltiVec. 707 + */ 708 + kvmppc_load_guest_altivec(vcpu); 709 + #endif 710 + 740 711 /* Switch to guest debug context */ 741 712 debug = vcpu->arch.dbg_reg; 742 713 switch_booke_debug_regs(&debug); ··· 768 717 769 718 #ifdef CONFIG_PPC_FPU 770 719 kvmppc_save_guest_fp(vcpu); 720 + #endif 721 + 722 + #ifdef CONFIG_ALTIVEC 723 + kvmppc_save_guest_altivec(vcpu); 771 724 #endif 772 725 773 726 out: ··· 1080 1025 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SPE_FP_ROUND); 1081 1026 r = RESUME_GUEST; 1082 1027 break; 1083 - #else 1028 + #elif defined(CONFIG_SPE_POSSIBLE) 1084 1029 case BOOKE_INTERRUPT_SPE_UNAVAIL: 1085 1030 /* 1086 1031 * Guest wants SPE, but host kernel doesn't support it. Send ··· 1100 1045 __func__, exit_nr, vcpu->arch.pc); 1101 1046 run->hw.hardware_exit_reason = exit_nr; 1102 1047 r = RESUME_HOST; 1048 + break; 1049 + #endif /* CONFIG_SPE_POSSIBLE */ 1050 + 1051 + /* 1052 + * On cores with Vector category, KVM is loaded only if CONFIG_ALTIVEC, 1053 + * see kvmppc_core_check_processor_compat(). 1054 + */ 1055 + #ifdef CONFIG_ALTIVEC 1056 + case BOOKE_INTERRUPT_ALTIVEC_UNAVAIL: 1057 + kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_ALTIVEC_UNAVAIL); 1058 + r = RESUME_GUEST; 1059 + break; 1060 + 1061 + case BOOKE_INTERRUPT_ALTIVEC_ASSIST: 1062 + kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_ALTIVEC_ASSIST); 1063 + r = RESUME_GUEST; 1103 1064 break; 1104 1065 #endif 1105 1066 ··· 1294 1223 /* interrupts now hard-disabled */ 1295 1224 kvmppc_fix_ee_before_entry(); 1296 1225 kvmppc_load_guest_fp(vcpu); 1226 + kvmppc_load_guest_altivec(vcpu); 1297 1227 } 1298 1228 } 1299 1229
+6
arch/powerpc/kvm/booke.h
··· 32 32 #define BOOKE_IRQPRIO_ALIGNMENT 2 33 33 #define BOOKE_IRQPRIO_PROGRAM 3 34 34 #define BOOKE_IRQPRIO_FP_UNAVAIL 4 35 + #ifdef CONFIG_SPE_POSSIBLE 35 36 #define BOOKE_IRQPRIO_SPE_UNAVAIL 5 36 37 #define BOOKE_IRQPRIO_SPE_FP_DATA 6 37 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 44 #define BOOKE_IRQPRIO_SYSCALL 8 39 45 #define BOOKE_IRQPRIO_AP_UNAVAIL 9 40 46 #define BOOKE_IRQPRIO_DTLB_MISS 10
+2 -7
arch/powerpc/kvm/bookehv_interrupts.S
··· 256 256 SPRN_SRR0, SPRN_SRR1, (NEED_EMU | NEED_DEAR | NEED_ESR) 257 257 kvm_handler BOOKE_INTERRUPT_ITLB_MISS, EX_PARAMS_TLB, \ 258 258 SPRN_SRR0, SPRN_SRR1, 0 259 - kvm_handler BOOKE_INTERRUPT_SPE_UNAVAIL, EX_PARAMS(GEN), \ 259 + kvm_handler BOOKE_INTERRUPT_ALTIVEC_UNAVAIL, EX_PARAMS(GEN), \ 260 260 SPRN_SRR0, SPRN_SRR1, 0 261 - kvm_handler BOOKE_INTERRUPT_SPE_FP_DATA, EX_PARAMS(GEN), \ 262 - SPRN_SRR0, SPRN_SRR1, 0 263 - kvm_handler BOOKE_INTERRUPT_SPE_FP_ROUND, EX_PARAMS(GEN), \ 261 + kvm_handler BOOKE_INTERRUPT_ALTIVEC_ASSIST, EX_PARAMS(GEN), \ 264 262 SPRN_SRR0, SPRN_SRR1, 0 265 263 kvm_handler BOOKE_INTERRUPT_PERFORMANCE_MONITOR, EX_PARAMS(GEN), \ 266 264 SPRN_SRR0, SPRN_SRR1, 0 ··· 359 361 kvm_handler BOOKE_INTERRUPT_DTLB_MISS, \ 360 362 SPRN_SRR0, SPRN_SRR1, (NEED_EMU | NEED_DEAR | NEED_ESR) 361 363 kvm_handler BOOKE_INTERRUPT_ITLB_MISS, SPRN_SRR0, SPRN_SRR1, 0 362 - kvm_handler BOOKE_INTERRUPT_SPE_UNAVAIL, SPRN_SRR0, SPRN_SRR1, 0 363 - kvm_handler BOOKE_INTERRUPT_SPE_FP_DATA, SPRN_SRR0, SPRN_SRR1, 0 364 - kvm_handler BOOKE_INTERRUPT_SPE_FP_ROUND, SPRN_SRR0, SPRN_SRR1, 0 365 364 kvm_handler BOOKE_INTERRUPT_PERFORMANCE_MONITOR, SPRN_SRR0, SPRN_SRR1, 0 366 365 kvm_handler BOOKE_INTERRUPT_DOORBELL, SPRN_SRR0, SPRN_SRR1, 0 367 366 kvm_lvl_handler BOOKE_INTERRUPT_DOORBELL_CRITICAL, \
+20
arch/powerpc/kvm/e500_emulate.c
··· 259 259 break; 260 260 261 261 /* extra exceptions */ 262 + #ifdef CONFIG_SPE_POSSIBLE 262 263 case SPRN_IVOR32: 263 264 vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL] = spr_val; 264 265 break; ··· 269 268 case SPRN_IVOR34: 270 269 vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND] = spr_val; 271 270 break; 271 + #endif 272 + #ifdef CONFIG_ALTIVEC 273 + case SPRN_IVOR32: 274 + vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_UNAVAIL] = spr_val; 275 + break; 276 + case SPRN_IVOR33: 277 + vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_ASSIST] = spr_val; 278 + break; 279 + #endif 272 280 case SPRN_IVOR35: 273 281 vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR] = spr_val; 274 282 break; ··· 391 381 break; 392 382 393 383 /* extra exceptions */ 384 + #ifdef CONFIG_SPE_POSSIBLE 394 385 case SPRN_IVOR32: 395 386 *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL]; 396 387 break; ··· 401 390 case SPRN_IVOR34: 402 391 *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND]; 403 392 break; 393 + #endif 394 + #ifdef CONFIG_ALTIVEC 395 + case SPRN_IVOR32: 396 + *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_UNAVAIL]; 397 + break; 398 + case SPRN_IVOR33: 399 + *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_ASSIST]; 400 + break; 401 + #endif 404 402 case SPRN_IVOR35: 405 403 *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR]; 406 404 break;