/* * VFP support code initialisation. */ static int __init vfp_init(void) { unsigned int vfpsid; unsigned int cpu_arch = cpu_architecture(); #ifdef CONFIG_PROC_FS static struct proc_dir_entry *procfs_entry; #endif if (cpu_arch >= CPU_ARCH_ARMv6) on_each_cpu(vfp_enable, NULL, 1); /* * First check that there is a VFP that we can use. * The handler is already setup to just log calls, so * we just need to read the VFPSID register. */ vfp_vector = vfp_testing_entry; barrier(); vfpsid = fmrx(FPSID); barrier(); vfp_vector = vfp_null_entry; printk(KERN_INFO "VFP support v0.3: "); if (VFP_arch) printk("not present\n"); else if (vfpsid & FPSID_NODOUBLE) { printk("no double precision support\n"); } else { hotcpu_notifier(vfp_hotplug, 0); VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT; /* Extract the architecture version */ printk("implementor %02x architecture %d part %02x variant %x rev %x\n", (vfpsid & FPSID_IMPLEMENTER_MASK) >> FPSID_IMPLEMENTER_BIT, (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT, (vfpsid & FPSID_PART_MASK) >> FPSID_PART_BIT, (vfpsid & FPSID_VARIANT_MASK) >> FPSID_VARIANT_BIT, (vfpsid & FPSID_REV_MASK) >> FPSID_REV_BIT); vfp_vector = vfp_support_entry; thread_register_notifier(&vfp_notifier_block); vfp_pm_init(); /* * We detected VFP, and the support code is * in place; report VFP support to userspace. */ elf_hwcap |= HWCAP_VFP; #ifdef CONFIG_VFPv3 if (VFP_arch >= 2) { elf_hwcap |= HWCAP_VFPv3; /* * Check for VFPv3 D16. CPUs in this configuration * only have 16 x 64bit registers. */ if (((fmrx(MVFR0) & MVFR0_A_SIMD_MASK)) == 1) elf_hwcap |= HWCAP_VFPv3D16; } #endif /* * Check for the presence of the Advanced SIMD * load/store instructions, integer and single * precision floating point operations. Only check * for NEON if the hardware has the MVFR registers. */ if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) { #ifdef CONFIG_NEON if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100) elf_hwcap |= HWCAP_NEON; #endif if ((fmrx(MVFR1) & 0xf0000000) == 0x10000000 || (read_cpuid_id() & 0xff00fc00) == 0x51000400) elf_hwcap |= HWCAP_VFPv4; } } #ifdef CONFIG_PROC_FS procfs_entry = proc_create("cpu/vfp_bounce", S_IRUGO, NULL, &vfp_bounce_fops); if (!procfs_entry) pr_err("Failed to create procfs node for VFP bounce reporting\n"); #endif return 0; }
/* * Package up a bounce condition. */ void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs) { u32 fpscr, orig_fpscr, fpsid, exceptions; pr_debug("VFP: bounce: trigger %08x fpexc %08x\n", trigger, fpexc); /* * At this point, FPEXC can have the following configuration: * * EX DEX IXE * 0 1 x - synchronous exception * 1 x 0 - asynchronous exception * 1 x 1 - sychronous on VFP subarch 1 and asynchronous on later * 0 0 1 - synchronous on VFP9 (non-standard subarch 1 * implementation), undefined otherwise * * Clear various bits and enable access to the VFP so we can * handle the bounce. */ fmxr(FPEXC, fpexc & ~(FPEXC_EX|FPEXC_DEX|FPEXC_FP2V|FPEXC_VV|FPEXC_TRAP_MASK)); fpsid = fmrx(FPSID); orig_fpscr = fpscr = fmrx(FPSCR); /* * Check for the special VFP subarch 1 and FPSCR.IXE bit case */ if ((fpsid & FPSID_ARCH_MASK) == (1 << FPSID_ARCH_BIT) && (fpscr & FPSCR_IXE)) { /* * Synchronous exception, emulate the trigger instruction */ goto emulate; } if (fpexc & FPEXC_EX) { /* * Asynchronous exception. The instruction is read from FPINST * and the interrupted instruction has to be restarted. */ trigger = fmrx(FPINST); regs->ARM_pc -= 4; } else if (!(fpexc & FPEXC_DEX)) { /* * Illegal combination of bits. It can be caused by an * unallocated VFP instruction but with FPSCR.IXE set and not * on VFP subarch 1. */ vfp_raise_exceptions(VFP_EXCEPTION_ERROR, trigger, fpscr, regs); goto exit; } /* * Modify fpscr to indicate the number of iterations remaining. * If FPEXC.EX is 0, FPEXC.DEX is 1 and the FPEXC.VV bit indicates * whether FPEXC.VECITR or FPSCR.LEN is used. */ if (fpexc & (FPEXC_EX | FPEXC_VV)) { u32 len; len = fpexc + (1 << FPEXC_LENGTH_BIT); fpscr &= ~FPSCR_LENGTH_MASK; fpscr |= (len & FPEXC_LENGTH_MASK) << (FPSCR_LENGTH_BIT - FPEXC_LENGTH_BIT); } /* * Handle the first FP instruction. We used to take note of the * FPEXC bounce reason, but this appears to be unreliable. * Emulate the bounced instruction instead. */ exceptions = vfp_emulate_instruction(trigger, fpscr, regs); if (exceptions) vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs); /* * If there isn't a second FP instruction, exit now. Note that * the FPEXC.FP2V bit is valid only if FPEXC.EX is 1. */ if (fpexc ^ (FPEXC_EX | FPEXC_FP2V)) goto exit; /* * The barrier() here prevents fpinst2 being read * before the condition above. */ barrier(); trigger = fmrx(FPINST2); emulate: exceptions = vfp_emulate_instruction(trigger, orig_fpscr, regs); if (exceptions) vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs); exit: preempt_enable(); }
/* * VFP support code initialisation. */ static int __init vfp_init(void) { unsigned int vfpsid; unsigned int cpu_arch = cpu_architecture(); if (cpu_arch >= CPU_ARCH_ARMv6) vfp_enable(NULL); /* * First check that there is a VFP that we can use. * The handler is already setup to just log calls, so * we just need to read the VFPSID register. */ vfp_vector = vfp_testing_entry; barrier(); vfpsid = fmrx(FPSID); barrier(); vfp_vector = vfp_null_entry; printk(KERN_INFO "VFP support v0.3: "); if (VFP_arch) printk("not present\n"); else if (vfpsid & FPSID_NODOUBLE) { printk("no double precision support\n"); } else { smp_call_function(vfp_enable, NULL, 1); VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT; /* Extract the architecture version */ printk("implementor %02x architecture %d part %02x variant %x rev %x\n", (vfpsid & FPSID_IMPLEMENTER_MASK) >> FPSID_IMPLEMENTER_BIT, (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT, (vfpsid & FPSID_PART_MASK) >> FPSID_PART_BIT, (vfpsid & FPSID_VARIANT_MASK) >> FPSID_VARIANT_BIT, (vfpsid & FPSID_REV_MASK) >> FPSID_REV_BIT); vfp_vector = vfp_support_entry; thread_register_notifier(&vfp_notifier_block); vfp_pm_init(); /* * We detected VFP, and the support code is * in place; report VFP support to userspace. */ elf_hwcap |= HWCAP_VFP; #ifdef CONFIG_VFPv3 if (VFP_arch >= 2) { elf_hwcap |= HWCAP_VFPv3; /* * Check for VFPv3 D16. CPUs in this configuration * only have 16 x 64bit registers. */ if (((fmrx(MVFR0) & MVFR0_A_SIMD_MASK)) == 1) elf_hwcap |= HWCAP_VFPv3D16; } #endif #ifdef CONFIG_NEON /* * Check for the presence of the Advanced SIMD * load/store instructions, integer and single * precision floating point operations. */ if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100) elf_hwcap |= HWCAP_NEON; #endif } return 0; }
void kernel_neon_end(void) { /* Disable the NEON/VFP unit. */ fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); put_cpu(); }
static int __init vfp_init(void) { unsigned int vfpsid; unsigned int cpu_arch = cpu_architecture(); #ifdef CONFIG_PROC_FS static struct proc_dir_entry *procfs_entry; #endif if (cpu_arch >= CPU_ARCH_ARMv6) on_each_cpu(vfp_enable, NULL, 1); vfp_vector = vfp_testing_entry; barrier(); vfpsid = fmrx(FPSID); barrier(); vfp_vector = vfp_null_entry; printk(KERN_INFO "VFP support v0.3: "); if (VFP_arch) printk("not present\n"); else if (vfpsid & FPSID_NODOUBLE) { printk("no double precision support\n"); } else { hotcpu_notifier(vfp_hotplug, 0); VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT; printk("implementor %02x architecture %d part %02x variant %x rev %x\n", (vfpsid & FPSID_IMPLEMENTER_MASK) >> FPSID_IMPLEMENTER_BIT, (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT, (vfpsid & FPSID_PART_MASK) >> FPSID_PART_BIT, (vfpsid & FPSID_VARIANT_MASK) >> FPSID_VARIANT_BIT, (vfpsid & FPSID_REV_MASK) >> FPSID_REV_BIT); vfp_vector = vfp_support_entry; thread_register_notifier(&vfp_notifier_block); vfp_pm_init(); elf_hwcap |= HWCAP_VFP; #ifdef CONFIG_VFPv3 if (VFP_arch >= 2) { elf_hwcap |= HWCAP_VFPv3; if (((fmrx(MVFR0) & MVFR0_A_SIMD_MASK)) == 1) elf_hwcap |= HWCAP_VFPv3D16; } #endif if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) { #ifdef CONFIG_NEON if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100) elf_hwcap |= HWCAP_NEON; #endif if ((fmrx(MVFR1) & 0xf0000000) == 0x10000000 || (read_cpuid_id() & 0xff00fc00) == 0x51000400) elf_hwcap |= HWCAP_VFPv4; } } #ifdef CONFIG_PROC_FS procfs_entry = proc_create("cpu/vfp_bounce", S_IRUGO, NULL, &vfp_bounce_fops); if (!procfs_entry) pr_err("Failed to create procfs node for VFP bounce reporting\n"); #endif return 0; }
static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v) { struct thread_info *thread = v; union vfp_state *vfp; unsigned long flags; __u32 cpu = thread->cpu; if (likely(cmd == THREAD_NOTIFY_SWITCH)) { u32 fpexc; local_irq_save_hw_cond(flags); fpexc = fmrx(FPEXC); #ifdef CONFIG_SMP /* * On SMP, if VFP is enabled, save the old state in * case the thread migrates to a different CPU. The * restoring is done lazily. */ if ((fpexc & FPEXC_EN) && last_VFP_context[cpu]) { vfp_save_state(last_VFP_context[cpu], fpexc); last_VFP_context[cpu]->hard.cpu = cpu; } /* * Thread migration, just force the reloading of the * state on the new CPU in case the VFP registers * contain stale data. */ if (thread->vfpstate.hard.cpu != cpu) last_VFP_context[cpu] = NULL; #endif /* * Always disable VFP so we can lazily save/restore the * old state. */ fmxr(FPEXC, fpexc & ~FPEXC_EN); local_irq_restore_hw_cond(flags); return NOTIFY_DONE; } vfp = &thread->vfpstate; if (cmd == THREAD_NOTIFY_FLUSH) { /* * Per-thread VFP initialisation. */ memset(vfp, 0, sizeof(union vfp_state)); vfp->hard.fpexc = FPEXC_EN; vfp->hard.fpscr = FPSCR_ROUND_NEAREST; /* * Disable VFP to ensure we initialise it first. */ local_irq_save_hw_cond(flags); fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); } else local_irq_save_hw_cond(flags); /* flush and release case: Per-thread VFP cleanup. */ if (last_VFP_context[cpu] == vfp) last_VFP_context[cpu] = NULL; local_irq_restore_hw_cond(flags); return NOTIFY_DONE; }
/* * VFP support code initialisation. */ static int __init vfp_init(void) { unsigned int vfpsid; unsigned int cpu_arch = cpu_architecture(); struct cpumask cpus_curr, cpus; sched_getaffinity(current->pid, &cpus_curr); cpumask_clear(&cpus); cpumask_set_cpu(smp_processor_id(), &cpus); if (sched_setaffinity(current->pid, &cpus)) pr_err("%s: set CPU affinity failed.\n", __func__); else pr_err("%s : affinity set to CPU %d\n"\ , __func__, smp_processor_id()); if (cpu_arch >= CPU_ARCH_ARMv6) vfp_enable(NULL); /* * First check that there is a VFP that we can use. * The handler is already setup to just log calls, so * we just need to read the VFPSID register. */ vfp_vector = vfp_testing_entry; barrier(); vfpsid = fmrx(FPSID); barrier(); vfp_vector = vfp_null_entry; printk(KERN_INFO "VFP support v0.3: "); if (VFP_arch) printk("not present\n"); else if (vfpsid & FPSID_NODOUBLE) { printk("no double precision support\n"); } else { hotcpu_notifier(vfp_hotplug, 0); smp_call_function(vfp_enable, NULL, 1); VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT; /* Extract the architecture version */ printk("implementor %02x architecture %d part %02x variant %x rev %x\n", (vfpsid & FPSID_IMPLEMENTER_MASK) >> FPSID_IMPLEMENTER_BIT, (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT, (vfpsid & FPSID_PART_MASK) >> FPSID_PART_BIT, (vfpsid & FPSID_VARIANT_MASK) >> FPSID_VARIANT_BIT, (vfpsid & FPSID_REV_MASK) >> FPSID_REV_BIT); vfp_vector = vfp_support_entry; thread_register_notifier(&vfp_notifier_block); vfp_pm_init(); /* * We detected VFP, and the support code is * in place; report VFP support to userspace. */ elf_hwcap |= HWCAP_VFP; #ifdef CONFIG_VFPv3 if (VFP_arch >= 2) { elf_hwcap |= HWCAP_VFPv3; /* * Check for VFPv3 D16 and VFPv4 D16. CPUs in * this configuration only have 16 x 64bit * registers. */ if (((fmrx(MVFR0) & MVFR0_A_SIMD_MASK)) == 1) elf_hwcap |= HWCAP_VFPv3D16; /* also v4-D16 */ else elf_hwcap |= HWCAP_VFPD32; } #endif /* * Check for the presence of the Advanced SIMD * load/store instructions, integer and single * precision floating point operations. Only check * for NEON if the hardware has the MVFR registers. */ if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) { #ifdef CONFIG_NEON if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100) elf_hwcap |= HWCAP_NEON; #endif if ((fmrx(MVFR1) & 0xf0000000) == 0x10000000 || (read_cpuid_id() & 0xff00fc00) == 0x51000400) elf_hwcap |= HWCAP_VFPv4; } } if (sched_setaffinity(current->pid, &cpus_curr)) pr_err("%s: Restore CPU affinity failed !!\n", __func__); else pr_err("%s : affinity restored to %x\n" \ , __func__, *((int *)(cpus_curr.bits))); return 0; }
/* * VFP support code initialisation. */ static int __init vfp_init(void) { unsigned int vfpsid; unsigned int cpu_arch = cpu_architecture(); if (cpu_arch >= CPU_ARCH_ARMv6) on_each_cpu(vfp_enable, NULL, 1); /* * First check that there is a VFP that we can use. * The handler is already setup to just log calls, so * we just need to read the VFPSID register. */ vfp_vector = vfp_testing_entry; barrier(); vfpsid = fmrx(FPSID); barrier(); vfp_vector = vfp_null_entry; ; if (VFP_arch) ; else if (vfpsid & FPSID_NODOUBLE) { ; } else { hotcpu_notifier(vfp_hotplug, 0); VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT; /* Extract the architecture version */ // printk("implementor %02x architecture %d part %02x variant %x rev %x\n", // (vfpsid & FPSID_IMPLEMENTER_MASK) >> FPSID_IMPLEMENTER_BIT, // (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT, // (vfpsid & FPSID_PART_MASK) >> FPSID_PART_BIT, // (vfpsid & FPSID_VARIANT_MASK) >> FPSID_VARIANT_BIT, ; vfp_vector = vfp_support_entry; thread_register_notifier(&vfp_notifier_block); vfp_pm_init(); /* * We detected VFP, and the support code is * in place; report VFP support to userspace. */ elf_hwcap |= HWCAP_VFP; #ifdef CONFIG_VFPv3 if (VFP_arch >= 2) { elf_hwcap |= HWCAP_VFPv3; /* * Check for VFPv3 D16 and VFPv4 D16. CPUs in * this configuration only have 16 x 64bit * registers. */ if (((fmrx(MVFR0) & MVFR0_A_SIMD_MASK)) == 1) elf_hwcap |= HWCAP_VFPv3D16; /* also v4-D16 */ else elf_hwcap |= HWCAP_VFPD32; } #endif /* * Check for the presence of the Advanced SIMD * load/store instructions, integer and single * precision floating point operations. Only check * for NEON if the hardware has the MVFR registers. */ if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) { #ifdef CONFIG_NEON if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100) elf_hwcap |= HWCAP_NEON; #endif #ifdef CONFIG_VFPv3 if ((fmrx(MVFR1) & 0xf0000000) == 0x10000000) elf_hwcap |= HWCAP_VFPv4; #endif } } return 0; }
/* * Package up a bounce condition. */ void VFP9_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs) { u32 fpscr, orig_fpscr, exceptions, inst; pr_debug("VFP: bounce: trigger %08x fpexc %08x\n", trigger, fpexc); /* * Enable access to the VFP so we can handle the bounce. */ fmxr(FPEXC, fpexc & ~(FPEXC_EX|FPEXC_INV|FPEXC_UFC|FPEXC_IOC)); orig_fpscr = fpscr = fmrx(FPSCR); /* * If we are running with inexact exceptions enabled, we need to * emulate the trigger instruction. Note that as we're emulating * the trigger instruction, we need to increment PC. */ if (fpscr & FPSCR_IXE) { regs->ARM_pc += 4; goto emulate; } barrier(); /* * Modify fpscr to indicate the number of iterations remaining */ if (fpexc & FPEXC_EX) { u32 len; len = fpexc + (1 << FPEXC_LENGTH_BIT); fpscr &= ~FPSCR_LENGTH_MASK; fpscr |= (len & FPEXC_LENGTH_MASK) << (FPSCR_LENGTH_BIT - FPEXC_LENGTH_BIT); } /* * Handle the first FP instruction. We used to take note of the * FPEXC bounce reason, but this appears to be unreliable. * Emulate the bounced instruction instead. */ #ifndef CONFIG_VFPv3 inst = fmrx(FPINST); #else inst = trigger; #endif exceptions = vfp_emulate_instruction(inst, fpscr, regs); if (exceptions) vfp_raise_exceptions(exceptions, inst, orig_fpscr, regs); #ifndef CONFIG_VFPv3 /* * If there isn't a second FP instruction, exit now. */ if (!(fpexc & FPEXC_FPV2)) return; /* * The barrier() here prevents fpinst2 being read * before the condition above. */ barrier(); trigger = fmrx(FPINST2); orig_fpscr = fpscr = fmrx(FPSCR); #else return; #endif emulate: exceptions = vfp_emulate_instruction(trigger, fpscr, regs); if (exceptions) vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs); }