aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/unaligned.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2006-02-09 23:20:34 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-03-20 04:12:07 -0500
commited6b0b45437dcf7ef1c48b3be413bebcc84771d8 (patch)
treee52dbcebe1435f9d2957b55c100824cb7b8b1f98 /arch/sparc64/kernel/unaligned.c
parent618e9ed98aed924a1fc664eb6522db4a5e927043 (diff)
[SPARC64]: SUN4V memory exception trap handlers.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/unaligned.c')
-rw-r--r--arch/sparc64/kernel/unaligned.c45
1 files changed, 34 insertions, 11 deletions
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c
index 70faf630603b..001e8518331f 100644
--- a/arch/sparc64/kernel/unaligned.c
+++ b/arch/sparc64/kernel/unaligned.c
@@ -277,7 +277,7 @@ static void kernel_mna_trap_fault(void)
277 regs->tstate |= (ASI_AIUS << 24UL); 277 regs->tstate |= (ASI_AIUS << 24UL);
278} 278}
279 279
280asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, unsigned long sfar, unsigned long sfsr) 280asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
281{ 281{
282 enum direction dir = decode_direction(insn); 282 enum direction dir = decode_direction(insn);
283 int size = decode_access_size(insn); 283 int size = decode_access_size(insn);
@@ -405,6 +405,9 @@ extern void do_privact(struct pt_regs *regs);
405extern void spitfire_data_access_exception(struct pt_regs *regs, 405extern void spitfire_data_access_exception(struct pt_regs *regs,
406 unsigned long sfsr, 406 unsigned long sfsr,
407 unsigned long sfar); 407 unsigned long sfar);
408extern void sun4v_data_access_exception(struct pt_regs *regs,
409 unsigned long addr,
410 unsigned long type_ctx);
408 411
409int handle_ldf_stq(u32 insn, struct pt_regs *regs) 412int handle_ldf_stq(u32 insn, struct pt_regs *regs)
410{ 413{
@@ -447,14 +450,20 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs)
447 break; 450 break;
448 } 451 }
449 default: 452 default:
450 spitfire_data_access_exception(regs, 0, addr); 453 if (tlb_type == hypervisor)
454 sun4v_data_access_exception(regs, addr, 0);
455 else
456 spitfire_data_access_exception(regs, 0, addr);
451 return 1; 457 return 1;
452 } 458 }
453 if (put_user (first >> 32, (u32 __user *)addr) || 459 if (put_user (first >> 32, (u32 __user *)addr) ||
454 __put_user ((u32)first, (u32 __user *)(addr + 4)) || 460 __put_user ((u32)first, (u32 __user *)(addr + 4)) ||
455 __put_user (second >> 32, (u32 __user *)(addr + 8)) || 461 __put_user (second >> 32, (u32 __user *)(addr + 8)) ||
456 __put_user ((u32)second, (u32 __user *)(addr + 12))) { 462 __put_user ((u32)second, (u32 __user *)(addr + 12))) {
457 spitfire_data_access_exception(regs, 0, addr); 463 if (tlb_type == hypervisor)
464 sun4v_data_access_exception(regs, addr, 0);
465 else
466 spitfire_data_access_exception(regs, 0, addr);
458 return 1; 467 return 1;
459 } 468 }
460 } else { 469 } else {
@@ -467,7 +476,10 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs)
467 do_privact(regs); 476 do_privact(regs);
468 return 1; 477 return 1;
469 } else if (asi > ASI_SNFL) { 478 } else if (asi > ASI_SNFL) {
470 spitfire_data_access_exception(regs, 0, addr); 479 if (tlb_type == hypervisor)
480 sun4v_data_access_exception(regs, addr, 0);
481 else
482 spitfire_data_access_exception(regs, 0, addr);
471 return 1; 483 return 1;
472 } 484 }
473 switch (insn & 0x180000) { 485 switch (insn & 0x180000) {
@@ -484,7 +496,10 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs)
484 err |= __get_user (data[i], (u32 __user *)(addr + 4*i)); 496 err |= __get_user (data[i], (u32 __user *)(addr + 4*i));
485 } 497 }
486 if (err && !(asi & 0x2 /* NF */)) { 498 if (err && !(asi & 0x2 /* NF */)) {
487 spitfire_data_access_exception(regs, 0, addr); 499 if (tlb_type == hypervisor)
500 sun4v_data_access_exception(regs, addr, 0);
501 else
502 spitfire_data_access_exception(regs, 0, addr);
488 return 1; 503 return 1;
489 } 504 }
490 if (asi & 0x8) /* Little */ { 505 if (asi & 0x8) /* Little */ {
@@ -548,7 +563,7 @@ void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr
548 u32 insn; 563 u32 insn;
549 u32 first, second; 564 u32 first, second;
550 u64 value; 565 u64 value;
551 u8 asi, freg; 566 u8 freg;
552 int flag; 567 int flag;
553 struct fpustate *f = FPUSTATE; 568 struct fpustate *f = FPUSTATE;
554 569
@@ -557,7 +572,7 @@ void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr
557 if (test_thread_flag(TIF_32BIT)) 572 if (test_thread_flag(TIF_32BIT))
558 pc = (u32)pc; 573 pc = (u32)pc;
559 if (get_user(insn, (u32 __user *) pc) != -EFAULT) { 574 if (get_user(insn, (u32 __user *) pc) != -EFAULT) {
560 asi = sfsr >> 16; 575 int asi = decode_asi(insn, regs);
561 if ((asi > ASI_SNFL) || 576 if ((asi > ASI_SNFL) ||
562 (asi < ASI_P)) 577 (asi < ASI_P))
563 goto daex; 578 goto daex;
@@ -587,7 +602,11 @@ void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr
587 *(u64 *)(f->regs + freg) = value; 602 *(u64 *)(f->regs + freg) = value;
588 current_thread_info()->fpsaved[0] |= flag; 603 current_thread_info()->fpsaved[0] |= flag;
589 } else { 604 } else {
590daex: spitfire_data_access_exception(regs, sfsr, sfar); 605daex:
606 if (tlb_type == hypervisor)
607 sun4v_data_access_exception(regs, sfar, sfsr);
608 else
609 spitfire_data_access_exception(regs, sfsr, sfar);
591 return; 610 return;
592 } 611 }
593 advance(regs); 612 advance(regs);
@@ -600,7 +619,7 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr
600 unsigned long tstate = regs->tstate; 619 unsigned long tstate = regs->tstate;
601 u32 insn; 620 u32 insn;
602 u64 value; 621 u64 value;
603 u8 asi, freg; 622 u8 freg;
604 int flag; 623 int flag;
605 struct fpustate *f = FPUSTATE; 624 struct fpustate *f = FPUSTATE;
606 625
@@ -609,8 +628,8 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr
609 if (test_thread_flag(TIF_32BIT)) 628 if (test_thread_flag(TIF_32BIT))
610 pc = (u32)pc; 629 pc = (u32)pc;
611 if (get_user(insn, (u32 __user *) pc) != -EFAULT) { 630 if (get_user(insn, (u32 __user *) pc) != -EFAULT) {
631 int asi = decode_asi(insn, regs);
612 freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20); 632 freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20);
613 asi = sfsr >> 16;
614 value = 0; 633 value = 0;
615 flag = (freg < 32) ? FPRS_DL : FPRS_DU; 634 flag = (freg < 32) ? FPRS_DL : FPRS_DU;
616 if ((asi > ASI_SNFL) || 635 if ((asi > ASI_SNFL) ||
@@ -631,7 +650,11 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr
631 __put_user ((u32)value, (u32 __user *)(sfar + 4))) 650 __put_user ((u32)value, (u32 __user *)(sfar + 4)))
632 goto daex; 651 goto daex;
633 } else { 652 } else {
634daex: spitfire_data_access_exception(regs, sfsr, sfar); 653daex:
654 if (tlb_type == hypervisor)
655 sun4v_data_access_exception(regs, sfar, sfsr);
656 else
657 spitfire_data_access_exception(regs, sfsr, sfar);
635 return; 658 return;
636 } 659 }
637 advance(regs); 660 advance(regs);