diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2006-02-09 23:20:34 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-03-20 04:12:07 -0500 |
commit | ed6b0b45437dcf7ef1c48b3be413bebcc84771d8 (patch) | |
tree | e52dbcebe1435f9d2957b55c100824cb7b8b1f98 /arch/sparc64/kernel/unaligned.c | |
parent | 618e9ed98aed924a1fc664eb6522db4a5e927043 (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.c | 45 |
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 | ||
280 | asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, unsigned long sfar, unsigned long sfsr) | 280 | asmlinkage 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); | |||
405 | extern void spitfire_data_access_exception(struct pt_regs *regs, | 405 | extern 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); |
408 | extern void sun4v_data_access_exception(struct pt_regs *regs, | ||
409 | unsigned long addr, | ||
410 | unsigned long type_ctx); | ||
408 | 411 | ||
409 | int handle_ldf_stq(u32 insn, struct pt_regs *regs) | 412 | int 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 { |
590 | daex: spitfire_data_access_exception(regs, sfsr, sfar); | 605 | daex: |
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 { |
634 | daex: spitfire_data_access_exception(regs, sfsr, sfar); | 653 | daex: |
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); |