diff options
Diffstat (limited to 'arch/arm/vfp/vfphw.S')
-rw-r--r-- | arch/arm/vfp/vfphw.S | 63 |
1 files changed, 43 insertions, 20 deletions
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S index 9897dcfc16d6..2d30c7f6edd3 100644 --- a/arch/arm/vfp/vfphw.S +++ b/arch/arm/vfp/vfphw.S | |||
@@ -77,27 +77,27 @@ ENTRY(vfp_support_entry) | |||
77 | bne look_for_VFP_exceptions @ VFP is already enabled | 77 | bne look_for_VFP_exceptions @ VFP is already enabled |
78 | 78 | ||
79 | DBGSTR1 "enable %x", r10 | 79 | DBGSTR1 "enable %x", r10 |
80 | ldr r3, last_VFP_context_address | 80 | ldr r3, vfp_current_hw_state_address |
81 | orr r1, r1, #FPEXC_EN @ user FPEXC has the enable bit set | 81 | orr r1, r1, #FPEXC_EN @ user FPEXC has the enable bit set |
82 | ldr r4, [r3, r11, lsl #2] @ last_VFP_context pointer | 82 | ldr r4, [r3, r11, lsl #2] @ vfp_current_hw_state pointer |
83 | bic r5, r1, #FPEXC_EX @ make sure exceptions are disabled | 83 | bic r5, r1, #FPEXC_EX @ make sure exceptions are disabled |
84 | cmp r4, r10 | 84 | cmp r4, r10 @ this thread owns the hw context? |
85 | beq check_for_exception @ we are returning to the same | 85 | #ifndef CONFIG_SMP |
86 | @ process, so the registers are | 86 | @ For UP, checking that this thread owns the hw context is |
87 | @ still there. In this case, we do | 87 | @ sufficient to determine that the hardware state is valid. |
88 | @ not want to drop a pending exception. | 88 | beq vfp_hw_state_valid |
89 | |||
90 | @ On UP, we lazily save the VFP context. As a different | ||
91 | @ thread wants ownership of the VFP hardware, save the old | ||
92 | @ state if there was a previous (valid) owner. | ||
89 | 93 | ||
90 | VFPFMXR FPEXC, r5 @ enable VFP, disable any pending | 94 | VFPFMXR FPEXC, r5 @ enable VFP, disable any pending |
91 | @ exceptions, so we can get at the | 95 | @ exceptions, so we can get at the |
92 | @ rest of it | 96 | @ rest of it |
93 | 97 | ||
94 | #ifndef CONFIG_SMP | ||
95 | @ Save out the current registers to the old thread state | ||
96 | @ No need for SMP since this is not done lazily | ||
97 | |||
98 | DBGSTR1 "save old state %p", r4 | 98 | DBGSTR1 "save old state %p", r4 |
99 | cmp r4, #0 | 99 | cmp r4, #0 @ if the vfp_current_hw_state is NULL |
100 | beq no_old_VFP_process | 100 | beq vfp_reload_hw @ then the hw state needs reloading |
101 | VFPFSTMIA r4, r5 @ save the working registers | 101 | VFPFSTMIA r4, r5 @ save the working registers |
102 | VFPFMRX r5, FPSCR @ current status | 102 | VFPFMRX r5, FPSCR @ current status |
103 | #ifndef CONFIG_CPU_FEROCEON | 103 | #ifndef CONFIG_CPU_FEROCEON |
@@ -110,13 +110,35 @@ ENTRY(vfp_support_entry) | |||
110 | 1: | 110 | 1: |
111 | #endif | 111 | #endif |
112 | stmia r4, {r1, r5, r6, r8} @ save FPEXC, FPSCR, FPINST, FPINST2 | 112 | stmia r4, {r1, r5, r6, r8} @ save FPEXC, FPSCR, FPINST, FPINST2 |
113 | @ and point r4 at the word at the | 113 | vfp_reload_hw: |
114 | @ start of the register dump | 114 | |
115 | #else | ||
116 | @ For SMP, if this thread does not own the hw context, then we | ||
117 | @ need to reload it. No need to save the old state as on SMP, | ||
118 | @ we always save the state when we switch away from a thread. | ||
119 | bne vfp_reload_hw | ||
120 | |||
121 | @ This thread has ownership of the current hardware context. | ||
122 | @ However, it may have been migrated to another CPU, in which | ||
123 | @ case the saved state is newer than the hardware context. | ||
124 | @ Check this by looking at the CPU number which the state was | ||
125 | @ last loaded onto. | ||
126 | ldr ip, [r10, #VFP_CPU] | ||
127 | teq ip, r11 | ||
128 | beq vfp_hw_state_valid | ||
129 | |||
130 | vfp_reload_hw: | ||
131 | @ We're loading this threads state into the VFP hardware. Update | ||
132 | @ the CPU number which contains the most up to date VFP context. | ||
133 | str r11, [r10, #VFP_CPU] | ||
134 | |||
135 | VFPFMXR FPEXC, r5 @ enable VFP, disable any pending | ||
136 | @ exceptions, so we can get at the | ||
137 | @ rest of it | ||
115 | #endif | 138 | #endif |
116 | 139 | ||
117 | no_old_VFP_process: | ||
118 | DBGSTR1 "load state %p", r10 | 140 | DBGSTR1 "load state %p", r10 |
119 | str r10, [r3, r11, lsl #2] @ update the last_VFP_context pointer | 141 | str r10, [r3, r11, lsl #2] @ update the vfp_current_hw_state pointer |
120 | @ Load the saved state back into the VFP | 142 | @ Load the saved state back into the VFP |
121 | VFPFLDMIA r10, r5 @ reload the working registers while | 143 | VFPFLDMIA r10, r5 @ reload the working registers while |
122 | @ FPEXC is in a safe state | 144 | @ FPEXC is in a safe state |
@@ -132,7 +154,8 @@ no_old_VFP_process: | |||
132 | #endif | 154 | #endif |
133 | VFPFMXR FPSCR, r5 @ restore status | 155 | VFPFMXR FPSCR, r5 @ restore status |
134 | 156 | ||
135 | check_for_exception: | 157 | @ The context stored in the VFP hardware is up to date with this thread |
158 | vfp_hw_state_valid: | ||
136 | tst r1, #FPEXC_EX | 159 | tst r1, #FPEXC_EX |
137 | bne process_exception @ might as well handle the pending | 160 | bne process_exception @ might as well handle the pending |
138 | @ exception before retrying branch | 161 | @ exception before retrying branch |
@@ -207,8 +230,8 @@ ENTRY(vfp_save_state) | |||
207 | ENDPROC(vfp_save_state) | 230 | ENDPROC(vfp_save_state) |
208 | 231 | ||
209 | .align | 232 | .align |
210 | last_VFP_context_address: | 233 | vfp_current_hw_state_address: |
211 | .word last_VFP_context | 234 | .word vfp_current_hw_state |
212 | 235 | ||
213 | .macro tbl_branch, base, tmp, shift | 236 | .macro tbl_branch, base, tmp, shift |
214 | #ifdef CONFIG_THUMB2_KERNEL | 237 | #ifdef CONFIG_THUMB2_KERNEL |