diff options
| -rw-r--r-- | arch/arm/include/asm/thread_info.h | 3 | ||||
| -rw-r--r-- | arch/arm/kernel/ptrace.c | 6 | ||||
| -rw-r--r-- | arch/arm/vfp/vfpmodule.c | 25 |
3 files changed, 29 insertions, 5 deletions
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 2dfb7d7a66e9..b74970ec02c4 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h | |||
| @@ -115,7 +115,8 @@ extern void iwmmxt_task_restore(struct thread_info *, void *); | |||
| 115 | extern void iwmmxt_task_release(struct thread_info *); | 115 | extern void iwmmxt_task_release(struct thread_info *); |
| 116 | extern void iwmmxt_task_switch(struct thread_info *); | 116 | extern void iwmmxt_task_switch(struct thread_info *); |
| 117 | 117 | ||
| 118 | extern void vfp_sync_state(struct thread_info *thread); | 118 | extern void vfp_sync_hwstate(struct thread_info *); |
| 119 | extern void vfp_flush_hwstate(struct thread_info *); | ||
| 119 | 120 | ||
| 120 | #endif | 121 | #endif |
| 121 | 122 | ||
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index bdf002bab6a5..08f899fb76a6 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c | |||
| @@ -700,7 +700,7 @@ static int ptrace_getvfpregs(struct task_struct *tsk, void __user *data) | |||
| 700 | union vfp_state *vfp = &thread->vfpstate; | 700 | union vfp_state *vfp = &thread->vfpstate; |
| 701 | struct user_vfp __user *ufp = data; | 701 | struct user_vfp __user *ufp = data; |
| 702 | 702 | ||
| 703 | vfp_sync_state(thread); | 703 | vfp_sync_hwstate(thread); |
| 704 | 704 | ||
| 705 | /* copy the floating point registers */ | 705 | /* copy the floating point registers */ |
| 706 | if (copy_to_user(&ufp->fpregs, &vfp->hard.fpregs, | 706 | if (copy_to_user(&ufp->fpregs, &vfp->hard.fpregs, |
| @@ -723,7 +723,7 @@ static int ptrace_setvfpregs(struct task_struct *tsk, void __user *data) | |||
| 723 | union vfp_state *vfp = &thread->vfpstate; | 723 | union vfp_state *vfp = &thread->vfpstate; |
| 724 | struct user_vfp __user *ufp = data; | 724 | struct user_vfp __user *ufp = data; |
| 725 | 725 | ||
| 726 | vfp_sync_state(thread); | 726 | vfp_sync_hwstate(thread); |
| 727 | 727 | ||
| 728 | /* copy the floating point registers */ | 728 | /* copy the floating point registers */ |
| 729 | if (copy_from_user(&vfp->hard.fpregs, &ufp->fpregs, | 729 | if (copy_from_user(&vfp->hard.fpregs, &ufp->fpregs, |
| @@ -734,6 +734,8 @@ static int ptrace_setvfpregs(struct task_struct *tsk, void __user *data) | |||
| 734 | if (get_user(vfp->hard.fpscr, &ufp->fpscr)) | 734 | if (get_user(vfp->hard.fpscr, &ufp->fpscr)) |
| 735 | return -EFAULT; | 735 | return -EFAULT; |
| 736 | 736 | ||
| 737 | vfp_flush_hwstate(thread); | ||
| 738 | |||
| 737 | return 0; | 739 | return 0; |
| 738 | } | 740 | } |
| 739 | #endif | 741 | #endif |
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 86a57aeeda4a..def19f83d812 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c | |||
| @@ -430,7 +430,11 @@ static inline void vfp_pm_init(void) { } | |||
| 430 | * saved one. This function is used by the ptrace mechanism. | 430 | * saved one. This function is used by the ptrace mechanism. |
| 431 | */ | 431 | */ |
| 432 | #ifdef CONFIG_SMP | 432 | #ifdef CONFIG_SMP |
| 433 | void vfp_sync_state(struct thread_info *thread) | 433 | void vfp_sync_hwstate(struct thread_info *thread) |
| 434 | { | ||
| 435 | } | ||
| 436 | |||
| 437 | void vfp_flush_hwstate(struct thread_info *thread) | ||
| 434 | { | 438 | { |
| 435 | /* | 439 | /* |
| 436 | * On SMP systems, the VFP state is automatically saved at every | 440 | * On SMP systems, the VFP state is automatically saved at every |
| @@ -441,7 +445,7 @@ void vfp_sync_state(struct thread_info *thread) | |||
| 441 | thread->vfpstate.hard.cpu = NR_CPUS; | 445 | thread->vfpstate.hard.cpu = NR_CPUS; |
| 442 | } | 446 | } |
| 443 | #else | 447 | #else |
| 444 | void vfp_sync_state(struct thread_info *thread) | 448 | void vfp_sync_hwstate(struct thread_info *thread) |
| 445 | { | 449 | { |
| 446 | unsigned int cpu = get_cpu(); | 450 | unsigned int cpu = get_cpu(); |
| 447 | 451 | ||
| @@ -457,6 +461,23 @@ void vfp_sync_state(struct thread_info *thread) | |||
| 457 | */ | 461 | */ |
| 458 | fmxr(FPEXC, fpexc | FPEXC_EN); | 462 | fmxr(FPEXC, fpexc | FPEXC_EN); |
| 459 | vfp_save_state(&thread->vfpstate, fpexc | FPEXC_EN); | 463 | vfp_save_state(&thread->vfpstate, fpexc | FPEXC_EN); |
| 464 | fmxr(FPEXC, fpexc); | ||
| 465 | } | ||
| 466 | |||
| 467 | put_cpu(); | ||
| 468 | } | ||
| 469 | |||
| 470 | void vfp_flush_hwstate(struct thread_info *thread) | ||
| 471 | { | ||
| 472 | unsigned int cpu = get_cpu(); | ||
| 473 | |||
| 474 | /* | ||
| 475 | * If the thread we're interested in is the current owner of the | ||
| 476 | * hardware VFP state, then we need to save its state. | ||
| 477 | */ | ||
| 478 | if (last_VFP_context[cpu] == &thread->vfpstate) { | ||
| 479 | u32 fpexc = fmrx(FPEXC); | ||
| 480 | |||
| 460 | fmxr(FPEXC, fpexc & ~FPEXC_EN); | 481 | fmxr(FPEXC, fpexc & ~FPEXC_EN); |
| 461 | 482 | ||
| 462 | /* | 483 | /* |
