diff options
author | will schmidt <will_schmidt@vnet.ibm.com> | 2007-10-30 14:59:33 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-11-07 22:15:31 -0500 |
commit | 465ccab9eb8209a2a402710b24a9bff127b25b94 (patch) | |
tree | 2cd2c3012b7cc5da8d582e9dc221b3ff60c1c806 | |
parent | e7bda183d4e3f6027ae9181c176a459423d04748 (diff) |
[POWERPC] Fix switch_slb handling of 1T ESID values
Now that we have 1TB segment size support, we need to be using the
GET_ESID_1T macro when comparing ESID values for pc, stack, and
unmapped_base within switch_slb(). A new helper function called
esids_match() contains the logic for deciding when to call GET_ESID
and GET_ESID_1T.
This fixes a duplicate-slb-entry inspired machine-check exception I
was seeing when trying to run java on a power6 partition.
Tested on power6 and power5.
Signed-off-by: Will Schmidt <will_schmidt@vnet.ibm.com>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r-- | arch/powerpc/mm/slb.c | 34 |
1 files changed, 31 insertions, 3 deletions
diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 637afb2386b7..27922dff8b94 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c | |||
@@ -149,6 +149,35 @@ void slb_vmalloc_update(void) | |||
149 | slb_flush_and_rebolt(); | 149 | slb_flush_and_rebolt(); |
150 | } | 150 | } |
151 | 151 | ||
152 | /* Helper function to compare esids. There are four cases to handle. | ||
153 | * 1. The system is not 1T segment size capable. Use the GET_ESID compare. | ||
154 | * 2. The system is 1T capable, both addresses are < 1T, use the GET_ESID compare. | ||
155 | * 3. The system is 1T capable, only one of the two addresses is > 1T. This is not a match. | ||
156 | * 4. The system is 1T capable, both addresses are > 1T, use the GET_ESID_1T macro to compare. | ||
157 | */ | ||
158 | static inline int esids_match(unsigned long addr1, unsigned long addr2) | ||
159 | { | ||
160 | int esid_1t_count; | ||
161 | |||
162 | /* System is not 1T segment size capable. */ | ||
163 | if (!cpu_has_feature(CPU_FTR_1T_SEGMENT)) | ||
164 | return (GET_ESID(addr1) == GET_ESID(addr2)); | ||
165 | |||
166 | esid_1t_count = (((addr1 >> SID_SHIFT_1T) != 0) + | ||
167 | ((addr2 >> SID_SHIFT_1T) != 0)); | ||
168 | |||
169 | /* both addresses are < 1T */ | ||
170 | if (esid_1t_count == 0) | ||
171 | return (GET_ESID(addr1) == GET_ESID(addr2)); | ||
172 | |||
173 | /* One address < 1T, the other > 1T. Not a match */ | ||
174 | if (esid_1t_count == 1) | ||
175 | return 0; | ||
176 | |||
177 | /* Both addresses are > 1T. */ | ||
178 | return (GET_ESID_1T(addr1) == GET_ESID_1T(addr2)); | ||
179 | } | ||
180 | |||
152 | /* Flush all user entries from the segment table of the current processor. */ | 181 | /* Flush all user entries from the segment table of the current processor. */ |
153 | void switch_slb(struct task_struct *tsk, struct mm_struct *mm) | 182 | void switch_slb(struct task_struct *tsk, struct mm_struct *mm) |
154 | { | 183 | { |
@@ -194,15 +223,14 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) | |||
194 | return; | 223 | return; |
195 | slb_allocate(pc); | 224 | slb_allocate(pc); |
196 | 225 | ||
197 | if (GET_ESID(pc) == GET_ESID(stack)) | 226 | if (esids_match(pc,stack)) |
198 | return; | 227 | return; |
199 | 228 | ||
200 | if (is_kernel_addr(stack)) | 229 | if (is_kernel_addr(stack)) |
201 | return; | 230 | return; |
202 | slb_allocate(stack); | 231 | slb_allocate(stack); |
203 | 232 | ||
204 | if ((GET_ESID(pc) == GET_ESID(unmapped_base)) | 233 | if (esids_match(pc,unmapped_base) || esids_match(stack,unmapped_base)) |
205 | || (GET_ESID(stack) == GET_ESID(unmapped_base))) | ||
206 | return; | 234 | return; |
207 | 235 | ||
208 | if (is_kernel_addr(unmapped_base)) | 236 | if (is_kernel_addr(unmapped_base)) |