diff options
| author | Jeff Garzik <jgarzik@pobox.com> | 2005-09-24 00:25:02 -0400 |
|---|---|---|
| committer | Jeff Garzik <jgarzik@pobox.com> | 2005-09-24 00:25:02 -0400 |
| commit | c1d9728ecc5b560465df3c0c0d3b3825c2710b40 (patch) | |
| tree | d0abb5c923a7a3eca2d4b2c3e1964bf484870909 /arch/sparc64/kernel/unaligned.c | |
| parent | 165415f700b0c77fa1f8db6198f48582639adf78 (diff) | |
| parent | 87e807b6c461bbd449496a4c3ab78ab164a4ba97 (diff) | |
Merge /spare/repo/linux-2.6/
Diffstat (limited to 'arch/sparc64/kernel/unaligned.c')
| -rw-r--r-- | arch/sparc64/kernel/unaligned.c | 64 |
1 files changed, 57 insertions, 7 deletions
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c index da9739f0d437..42718f6a7d36 100644 --- a/arch/sparc64/kernel/unaligned.c +++ b/arch/sparc64/kernel/unaligned.c | |||
| @@ -184,13 +184,14 @@ extern void 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 void __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 void 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,7 +199,25 @@ 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); |
| 203 | } | ||
| 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 | }; | ||
| 202 | } | 221 | } |
| 203 | __do_int_store(dst_addr, size, src_val, asi); | 222 | __do_int_store(dst_addr, size, src_val, asi); |
| 204 | } | 223 | } |
| @@ -276,6 +295,7 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u | |||
| 276 | kernel_mna_trap_fault(); | 295 | kernel_mna_trap_fault(); |
| 277 | } else { | 296 | } else { |
| 278 | unsigned long addr; | 297 | unsigned long addr; |
| 298 | int orig_asi, asi; | ||
| 279 | 299 | ||
| 280 | addr = compute_effective_address(regs, insn, | 300 | addr = compute_effective_address(regs, insn, |
| 281 | ((insn >> 25) & 0x1f)); | 301 | ((insn >> 25) & 0x1f)); |
| @@ -285,18 +305,48 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u | |||
| 285 | regs->tpc, dirstrings[dir], addr, size, | 305 | regs->tpc, dirstrings[dir], addr, size, |
| 286 | regs->u_regs[UREG_RETPC]); | 306 | regs->u_regs[UREG_RETPC]); |
| 287 | #endif | 307 | #endif |
| 308 | orig_asi = asi = decode_asi(insn, regs); | ||
| 309 | switch (asi) { | ||
| 310 | case ASI_NL: | ||
| 311 | case ASI_AIUPL: | ||
| 312 | case ASI_AIUSL: | ||
| 313 | case ASI_PL: | ||
| 314 | case ASI_SL: | ||
| 315 | case ASI_PNFL: | ||
| 316 | case ASI_SNFL: | ||
| 317 | asi &= ~0x08; | ||
| 318 | break; | ||
| 319 | }; | ||
| 288 | switch (dir) { | 320 | switch (dir) { |
| 289 | case load: | 321 | case load: |
| 290 | do_int_load(fetch_reg_addr(((insn>>25)&0x1f), regs), | 322 | do_int_load(fetch_reg_addr(((insn>>25)&0x1f), regs), |
| 291 | size, (unsigned long *) addr, | 323 | size, (unsigned long *) addr, |
| 292 | decode_signedness(insn), | 324 | decode_signedness(insn), asi); |
| 293 | decode_asi(insn, regs)); | 325 | if (unlikely(asi != orig_asi)) { |
| 326 | unsigned long val_in = *(unsigned long *) 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 | *(unsigned long *) 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 | 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: |
