aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/unaligned.c
diff options
context:
space:
mode:
authorTony Luck <tony.luck@intel.com>2005-10-20 13:41:44 -0400
committerTony Luck <tony.luck@intel.com>2005-10-20 13:41:44 -0400
commit9cec58dc138d6fcad9f447a19c8ff69f6540e667 (patch)
tree4fe1cca94fdba8b705c87615bee06d3346f687ce /arch/sparc64/kernel/unaligned.c
parent17e5ad6c0ce5a970e2830d0de8bdd60a2f077d38 (diff)
parentac9b9c667c2e1194e22ebe0a441ae1c37aaa9b90 (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.c101
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
183extern void do_int_load(unsigned long *dest_reg, int size, 183extern 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
186extern void __do_int_store(unsigned long *dst_addr, int size, 186extern 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
189static inline void do_int_store(int reg_num, int size, unsigned long *dst_addr, 189static 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
206static inline void advance(struct pt_regs *regs) 225static 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
226void kernel_mna_trap_fault(void) 245static 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