diff options
author | Tony Luck <tony.luck@intel.com> | 2005-10-20 13:41:44 -0400 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2005-10-20 13:41:44 -0400 |
commit | 9cec58dc138d6fcad9f447a19c8ff69f6540e667 (patch) | |
tree | 4fe1cca94fdba8b705c87615bee06d3346f687ce /arch/sparc64/kernel/unaligned.c | |
parent | 17e5ad6c0ce5a970e2830d0de8bdd60a2f077d38 (diff) | |
parent | ac9b9c667c2e1194e22ebe0a441ae1c37aaa9b90 (diff) |
Update from upstream with manual merge of Yasunori Goto's
changes to swiotlb.c made in commit 281dd25cdc0d6903929b79183816d151ea626341
since this file has been moved from arch/ia64/lib/swiotlb.c to
lib/swiotlb.c
Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch/sparc64/kernel/unaligned.c')
-rw-r--r-- | arch/sparc64/kernel/unaligned.c | 101 |
1 files changed, 77 insertions, 24 deletions
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c index da9739f0d437..70faf630603b 100644 --- a/arch/sparc64/kernel/unaligned.c +++ b/arch/sparc64/kernel/unaligned.c | |||
@@ -180,17 +180,18 @@ static void __attribute_used__ unaligned_panic(char *str, struct pt_regs *regs) | |||
180 | die_if_kernel(str, regs); | 180 | die_if_kernel(str, regs); |
181 | } | 181 | } |
182 | 182 | ||
183 | extern void do_int_load(unsigned long *dest_reg, int size, | 183 | extern int do_int_load(unsigned long *dest_reg, int size, |
184 | unsigned long *saddr, int is_signed, int asi); | 184 | unsigned long *saddr, int is_signed, int asi); |
185 | 185 | ||
186 | extern void __do_int_store(unsigned long *dst_addr, int size, | 186 | extern int __do_int_store(unsigned long *dst_addr, int size, |
187 | unsigned long *src_val, int asi); | 187 | unsigned long src_val, int asi); |
188 | 188 | ||
189 | static inline void do_int_store(int reg_num, int size, unsigned long *dst_addr, | 189 | static inline int do_int_store(int reg_num, int size, unsigned long *dst_addr, |
190 | struct pt_regs *regs, int asi) | 190 | struct pt_regs *regs, int asi, int orig_asi) |
191 | { | 191 | { |
192 | unsigned long zero = 0; | 192 | unsigned long zero = 0; |
193 | unsigned long *src_val = &zero; | 193 | unsigned long *src_val_p = &zero; |
194 | unsigned long src_val; | ||
194 | 195 | ||
195 | if (size == 16) { | 196 | if (size == 16) { |
196 | size = 8; | 197 | size = 8; |
@@ -198,9 +199,27 @@ static inline void do_int_store(int reg_num, int size, unsigned long *dst_addr, | |||
198 | (unsigned)fetch_reg(reg_num, regs) : 0)) << 32) | | 199 | (unsigned)fetch_reg(reg_num, regs) : 0)) << 32) | |
199 | (unsigned)fetch_reg(reg_num + 1, regs); | 200 | (unsigned)fetch_reg(reg_num + 1, regs); |
200 | } else if (reg_num) { | 201 | } else if (reg_num) { |
201 | src_val = fetch_reg_addr(reg_num, regs); | 202 | src_val_p = fetch_reg_addr(reg_num, regs); |
202 | } | 203 | } |
203 | __do_int_store(dst_addr, size, src_val, asi); | 204 | src_val = *src_val_p; |
205 | if (unlikely(asi != orig_asi)) { | ||
206 | switch (size) { | ||
207 | case 2: | ||
208 | src_val = swab16(src_val); | ||
209 | break; | ||
210 | case 4: | ||
211 | src_val = swab32(src_val); | ||
212 | break; | ||
213 | case 8: | ||
214 | src_val = swab64(src_val); | ||
215 | break; | ||
216 | case 16: | ||
217 | default: | ||
218 | BUG(); | ||
219 | break; | ||
220 | }; | ||
221 | } | ||
222 | return __do_int_store(dst_addr, size, src_val, asi); | ||
204 | } | 223 | } |
205 | 224 | ||
206 | static inline void advance(struct pt_regs *regs) | 225 | static inline void advance(struct pt_regs *regs) |
@@ -223,14 +242,14 @@ static inline int ok_for_kernel(unsigned int insn) | |||
223 | return !floating_point_load_or_store_p(insn); | 242 | return !floating_point_load_or_store_p(insn); |
224 | } | 243 | } |
225 | 244 | ||
226 | void kernel_mna_trap_fault(void) | 245 | static void kernel_mna_trap_fault(void) |
227 | { | 246 | { |
228 | struct pt_regs *regs = current_thread_info()->kern_una_regs; | 247 | struct pt_regs *regs = current_thread_info()->kern_una_regs; |
229 | unsigned int insn = current_thread_info()->kern_una_insn; | 248 | unsigned int insn = current_thread_info()->kern_una_insn; |
230 | unsigned long g2 = regs->u_regs[UREG_G2]; | 249 | const struct exception_table_entry *entry; |
231 | unsigned long fixup = search_extables_range(regs->tpc, &g2); | ||
232 | 250 | ||
233 | if (!fixup) { | 251 | entry = search_exception_tables(regs->tpc); |
252 | if (!entry) { | ||
234 | unsigned long address; | 253 | unsigned long address; |
235 | 254 | ||
236 | address = compute_effective_address(regs, insn, | 255 | address = compute_effective_address(regs, insn, |
@@ -251,9 +270,8 @@ void kernel_mna_trap_fault(void) | |||
251 | die_if_kernel("Oops", regs); | 270 | die_if_kernel("Oops", regs); |
252 | /* Not reached */ | 271 | /* Not reached */ |
253 | } | 272 | } |
254 | regs->tpc = fixup; | 273 | regs->tpc = entry->fixup; |
255 | regs->tnpc = regs->tpc + 4; | 274 | regs->tnpc = regs->tpc + 4; |
256 | regs->u_regs [UREG_G2] = g2; | ||
257 | 275 | ||
258 | regs->tstate &= ~TSTATE_ASI; | 276 | regs->tstate &= ~TSTATE_ASI; |
259 | regs->tstate |= (ASI_AIUS << 24UL); | 277 | regs->tstate |= (ASI_AIUS << 24UL); |
@@ -275,7 +293,8 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u | |||
275 | 293 | ||
276 | kernel_mna_trap_fault(); | 294 | kernel_mna_trap_fault(); |
277 | } else { | 295 | } else { |
278 | unsigned long addr; | 296 | unsigned long addr, *reg_addr; |
297 | int orig_asi, asi, err; | ||
279 | 298 | ||
280 | addr = compute_effective_address(regs, insn, | 299 | addr = compute_effective_address(regs, insn, |
281 | ((insn >> 25) & 0x1f)); | 300 | ((insn >> 25) & 0x1f)); |
@@ -285,25 +304,59 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u | |||
285 | regs->tpc, dirstrings[dir], addr, size, | 304 | regs->tpc, dirstrings[dir], addr, size, |
286 | regs->u_regs[UREG_RETPC]); | 305 | regs->u_regs[UREG_RETPC]); |
287 | #endif | 306 | #endif |
307 | orig_asi = asi = decode_asi(insn, regs); | ||
308 | switch (asi) { | ||
309 | case ASI_NL: | ||
310 | case ASI_AIUPL: | ||
311 | case ASI_AIUSL: | ||
312 | case ASI_PL: | ||
313 | case ASI_SL: | ||
314 | case ASI_PNFL: | ||
315 | case ASI_SNFL: | ||
316 | asi &= ~0x08; | ||
317 | break; | ||
318 | }; | ||
288 | switch (dir) { | 319 | switch (dir) { |
289 | case load: | 320 | case load: |
290 | do_int_load(fetch_reg_addr(((insn>>25)&0x1f), regs), | 321 | reg_addr = fetch_reg_addr(((insn>>25)&0x1f), regs); |
291 | size, (unsigned long *) addr, | 322 | err = do_int_load(reg_addr, size, |
292 | decode_signedness(insn), | 323 | (unsigned long *) addr, |
293 | decode_asi(insn, regs)); | 324 | decode_signedness(insn), asi); |
325 | if (likely(!err) && unlikely(asi != orig_asi)) { | ||
326 | unsigned long val_in = *reg_addr; | ||
327 | switch (size) { | ||
328 | case 2: | ||
329 | val_in = swab16(val_in); | ||
330 | break; | ||
331 | case 4: | ||
332 | val_in = swab32(val_in); | ||
333 | break; | ||
334 | case 8: | ||
335 | val_in = swab64(val_in); | ||
336 | break; | ||
337 | case 16: | ||
338 | default: | ||
339 | BUG(); | ||
340 | break; | ||
341 | }; | ||
342 | *reg_addr = val_in; | ||
343 | } | ||
294 | break; | 344 | break; |
295 | 345 | ||
296 | case store: | 346 | case store: |
297 | do_int_store(((insn>>25)&0x1f), size, | 347 | err = do_int_store(((insn>>25)&0x1f), size, |
298 | (unsigned long *) addr, regs, | 348 | (unsigned long *) addr, regs, |
299 | decode_asi(insn, regs)); | 349 | asi, orig_asi); |
300 | break; | 350 | break; |
301 | 351 | ||
302 | default: | 352 | default: |
303 | panic("Impossible kernel unaligned trap."); | 353 | panic("Impossible kernel unaligned trap."); |
304 | /* Not reached... */ | 354 | /* Not reached... */ |
305 | } | 355 | } |
306 | advance(regs); | 356 | if (unlikely(err)) |
357 | kernel_mna_trap_fault(); | ||
358 | else | ||
359 | advance(regs); | ||
307 | } | 360 | } |
308 | } | 361 | } |
309 | 362 | ||