diff options
Diffstat (limited to 'arch/arm/vfp/vfpmodule.c')
-rw-r--r-- | arch/arm/vfp/vfpmodule.c | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 9f476a1be2ca..75457b30d813 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c | |||
@@ -377,6 +377,55 @@ static void vfp_pm_init(void) | |||
377 | static inline void vfp_pm_init(void) { } | 377 | static inline void vfp_pm_init(void) { } |
378 | #endif /* CONFIG_PM */ | 378 | #endif /* CONFIG_PM */ |
379 | 379 | ||
380 | /* | ||
381 | * Synchronise the hardware VFP state of a thread other than current with the | ||
382 | * saved one. This function is used by the ptrace mechanism. | ||
383 | */ | ||
384 | #ifdef CONFIG_SMP | ||
385 | void vfp_sync_state(struct thread_info *thread) | ||
386 | { | ||
387 | /* | ||
388 | * On SMP systems, the VFP state is automatically saved at every | ||
389 | * context switch. We mark the thread VFP state as belonging to a | ||
390 | * non-existent CPU so that the saved one will be reloaded when | ||
391 | * needed. | ||
392 | */ | ||
393 | thread->vfpstate.hard.cpu = NR_CPUS; | ||
394 | } | ||
395 | #else | ||
396 | void vfp_sync_state(struct thread_info *thread) | ||
397 | { | ||
398 | unsigned int cpu = get_cpu(); | ||
399 | u32 fpexc = fmrx(FPEXC); | ||
400 | |||
401 | /* | ||
402 | * If VFP is enabled, the previous state was already saved and | ||
403 | * last_VFP_context updated. | ||
404 | */ | ||
405 | if (fpexc & FPEXC_EN) | ||
406 | goto out; | ||
407 | |||
408 | if (!last_VFP_context[cpu]) | ||
409 | goto out; | ||
410 | |||
411 | /* | ||
412 | * Save the last VFP state on this CPU. | ||
413 | */ | ||
414 | fmxr(FPEXC, fpexc | FPEXC_EN); | ||
415 | vfp_save_state(last_VFP_context[cpu], fpexc); | ||
416 | fmxr(FPEXC, fpexc); | ||
417 | |||
418 | /* | ||
419 | * Set the context to NULL to force a reload the next time the thread | ||
420 | * uses the VFP. | ||
421 | */ | ||
422 | last_VFP_context[cpu] = NULL; | ||
423 | |||
424 | out: | ||
425 | put_cpu(); | ||
426 | } | ||
427 | #endif | ||
428 | |||
380 | #include <linux/smp.h> | 429 | #include <linux/smp.h> |
381 | 430 | ||
382 | /* | 431 | /* |
@@ -427,6 +476,18 @@ static int __init vfp_init(void) | |||
427 | * in place; report VFP support to userspace. | 476 | * in place; report VFP support to userspace. |
428 | */ | 477 | */ |
429 | elf_hwcap |= HWCAP_VFP; | 478 | elf_hwcap |= HWCAP_VFP; |
479 | #ifdef CONFIG_VFPv3 | ||
480 | if (VFP_arch >= 3) { | ||
481 | elf_hwcap |= HWCAP_VFPv3; | ||
482 | |||
483 | /* | ||
484 | * Check for VFPv3 D16. CPUs in this configuration | ||
485 | * only have 16 x 64bit registers. | ||
486 | */ | ||
487 | if (((fmrx(MVFR0) & MVFR0_A_SIMD_MASK)) == 1) | ||
488 | elf_hwcap |= HWCAP_VFPv3D16; | ||
489 | } | ||
490 | #endif | ||
430 | #ifdef CONFIG_NEON | 491 | #ifdef CONFIG_NEON |
431 | /* | 492 | /* |
432 | * Check for the presence of the Advanced SIMD | 493 | * Check for the presence of the Advanced SIMD |