This patch works only for 64bit kernel and will break any 32bit kernel. Switching on altivec takes some time due to the MSR access. The speed-up is about 50% in my aes-code. It might be usefull for the raid module as well. Signed-off-by: Sebastian Siewior Index: linux/arch/powerpc/kernel/head_64.S =================================================================== --- linux.orig/arch/powerpc/kernel/head_64.S +++ linux/arch/powerpc/kernel/head_64.S @@ -1229,6 +1229,14 @@ altivec_unavailable_common: #ifdef CONFIG_ALTIVEC BEGIN_FTR_SECTION bne .load_up_altivec /* if from user, just load it up */ + /* + * the kernel is going to use AltiVec. + * hopefully enable_kernel_altivec() has been called + */ + addi r3,r1,STACK_FRAME_OVERHEAD + bl .altivec_enable_for_kernel_exception + b .ret_from_except + END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) #endif bl .save_nvgprs Index: linux/arch/powerpc/kernel/misc_64.S =================================================================== --- linux.orig/arch/powerpc/kernel/misc_64.S +++ linux/arch/powerpc/kernel/misc_64.S @@ -493,6 +493,8 @@ _GLOBAL(giveup_altivec) mfmsr r5 oris r5,r5,MSR_VEC@h mtmsrd r5 /* enable use of VMX now */ + +giveup_user_altivec_save_vmx: isync cmpdi 0,r3,0 beqlr- /* if no previous owner, done */ @@ -516,6 +518,14 @@ _GLOBAL(giveup_altivec) #endif /* CONFIG_SMP */ blr +/* + * giveup_user_altivec(tsk) + * Same as giveup_altivec() but lets the exception handler + * enable AltiVec + */ +_GLOBAL(giveup_user_altivec) + b giveup_user_altivec_save_vmx + #endif /* CONFIG_ALTIVEC */ _GLOBAL(kernel_execve) Index: linux/arch/powerpc/kernel/process.c =================================================================== --- linux.orig/arch/powerpc/kernel/process.c +++ linux/arch/powerpc/kernel/process.c @@ -119,15 +119,21 @@ int dump_task_fpu(struct task_struct *ts #ifdef CONFIG_ALTIVEC void enable_kernel_altivec(void) { - WARN_ON(preemptible()); + BUG_ON(preemptible()); + /* + * enable_kernel_altivec() will just save current AltiVec registers (if needed) and + * return to caller (with MSR_VEC unchanged (probably not set)). The first AltiVec + * instruction will raise an exception and the exception will enable the AltiVec for + * the kernel. This is done to avoid the expensive "enable altivec" operation if it + * is allready enabled. However, you have to disable preemtion while you are using + * AltiVec. + */ #ifdef CONFIG_SMP if (current->thread.regs && (current->thread.regs->msr & MSR_VEC)) - giveup_altivec(current); - else - giveup_altivec(NULL); /* just enable AltiVec for kernel - force */ + giveup_user_altivec(current); #else - giveup_altivec(last_task_used_altivec); + giveup_user_altivec(last_task_used_altivec); #endif /* CONFIG_SMP */ } EXPORT_SYMBOL(enable_kernel_altivec); Index: linux/arch/powerpc/kernel/traps.c =================================================================== --- linux.orig/arch/powerpc/kernel/traps.c +++ linux/arch/powerpc/kernel/traps.c @@ -886,6 +886,12 @@ void altivec_unavailable_exception(struc die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT); } +void altivec_enable_for_kernel_exception(struct pt_regs *regs) +{ + printk("altivec_enable_for_kernel_exception: AltiVec mode on for kernel\n"); + regs->msr |= MSR_VEC; +} + void performance_monitor_exception(struct pt_regs *regs) { perf_irq(regs); Index: linux/include/asm-powerpc/system.h =================================================================== --- linux.orig/include/asm-powerpc/system.h +++ linux/include/asm-powerpc/system.h @@ -129,6 +129,7 @@ extern void enable_kernel_fp(void); extern void flush_fp_to_thread(struct task_struct *); extern void enable_kernel_altivec(void); extern void giveup_altivec(struct task_struct *); +extern void giveup_user_altivec(struct task_struct *); extern void load_up_altivec(struct task_struct *); extern int emulate_altivec(struct pt_regs *); extern void giveup_spe(struct task_struct *); --