diff options
Diffstat (limited to 'arch/powerpc/kernel/traps.c')
-rw-r--r-- | arch/powerpc/kernel/traps.c | 79 |
1 files changed, 39 insertions, 40 deletions
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 5457e9575685..678fbff0d206 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
@@ -52,6 +52,10 @@ | |||
52 | #include <asm/processor.h> | 52 | #include <asm/processor.h> |
53 | #endif | 53 | #endif |
54 | #include <asm/kexec.h> | 54 | #include <asm/kexec.h> |
55 | #include <asm/ppc-opcode.h> | ||
56 | #ifdef CONFIG_FSL_BOOKE | ||
57 | #include <asm/dbell.h> | ||
58 | #endif | ||
55 | 59 | ||
56 | #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) | 60 | #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) |
57 | int (*__debugger)(struct pt_regs *regs); | 61 | int (*__debugger)(struct pt_regs *regs); |
@@ -637,29 +641,6 @@ static void parse_fpe(struct pt_regs *regs) | |||
637 | * bits is faster and easier. | 641 | * bits is faster and easier. |
638 | * | 642 | * |
639 | */ | 643 | */ |
640 | #define INST_MFSPR_PVR 0x7c1f42a6 | ||
641 | #define INST_MFSPR_PVR_MASK 0xfc1fffff | ||
642 | |||
643 | #define INST_DCBA 0x7c0005ec | ||
644 | #define INST_DCBA_MASK 0xfc0007fe | ||
645 | |||
646 | #define INST_MCRXR 0x7c000400 | ||
647 | #define INST_MCRXR_MASK 0xfc0007fe | ||
648 | |||
649 | #define INST_STRING 0x7c00042a | ||
650 | #define INST_STRING_MASK 0xfc0007fe | ||
651 | #define INST_STRING_GEN_MASK 0xfc00067e | ||
652 | #define INST_LSWI 0x7c0004aa | ||
653 | #define INST_LSWX 0x7c00042a | ||
654 | #define INST_STSWI 0x7c0005aa | ||
655 | #define INST_STSWX 0x7c00052a | ||
656 | |||
657 | #define INST_POPCNTB 0x7c0000f4 | ||
658 | #define INST_POPCNTB_MASK 0xfc0007fe | ||
659 | |||
660 | #define INST_ISEL 0x7c00001e | ||
661 | #define INST_ISEL_MASK 0xfc00003e | ||
662 | |||
663 | static int emulate_string_inst(struct pt_regs *regs, u32 instword) | 644 | static int emulate_string_inst(struct pt_regs *regs, u32 instword) |
664 | { | 645 | { |
665 | u8 rT = (instword >> 21) & 0x1f; | 646 | u8 rT = (instword >> 21) & 0x1f; |
@@ -670,20 +651,20 @@ static int emulate_string_inst(struct pt_regs *regs, u32 instword) | |||
670 | int pos = 0; | 651 | int pos = 0; |
671 | 652 | ||
672 | /* Early out if we are an invalid form of lswx */ | 653 | /* Early out if we are an invalid form of lswx */ |
673 | if ((instword & INST_STRING_MASK) == INST_LSWX) | 654 | if ((instword & PPC_INST_STRING_MASK) == PPC_INST_LSWX) |
674 | if ((rT == rA) || (rT == NB_RB)) | 655 | if ((rT == rA) || (rT == NB_RB)) |
675 | return -EINVAL; | 656 | return -EINVAL; |
676 | 657 | ||
677 | EA = (rA == 0) ? 0 : regs->gpr[rA]; | 658 | EA = (rA == 0) ? 0 : regs->gpr[rA]; |
678 | 659 | ||
679 | switch (instword & INST_STRING_MASK) { | 660 | switch (instword & PPC_INST_STRING_MASK) { |
680 | case INST_LSWX: | 661 | case PPC_INST_LSWX: |
681 | case INST_STSWX: | 662 | case PPC_INST_STSWX: |
682 | EA += NB_RB; | 663 | EA += NB_RB; |
683 | num_bytes = regs->xer & 0x7f; | 664 | num_bytes = regs->xer & 0x7f; |
684 | break; | 665 | break; |
685 | case INST_LSWI: | 666 | case PPC_INST_LSWI: |
686 | case INST_STSWI: | 667 | case PPC_INST_STSWI: |
687 | num_bytes = (NB_RB == 0) ? 32 : NB_RB; | 668 | num_bytes = (NB_RB == 0) ? 32 : NB_RB; |
688 | break; | 669 | break; |
689 | default: | 670 | default: |
@@ -695,9 +676,9 @@ static int emulate_string_inst(struct pt_regs *regs, u32 instword) | |||
695 | u8 val; | 676 | u8 val; |
696 | u32 shift = 8 * (3 - (pos & 0x3)); | 677 | u32 shift = 8 * (3 - (pos & 0x3)); |
697 | 678 | ||
698 | switch ((instword & INST_STRING_MASK)) { | 679 | switch ((instword & PPC_INST_STRING_MASK)) { |
699 | case INST_LSWX: | 680 | case PPC_INST_LSWX: |
700 | case INST_LSWI: | 681 | case PPC_INST_LSWI: |
701 | if (get_user(val, (u8 __user *)EA)) | 682 | if (get_user(val, (u8 __user *)EA)) |
702 | return -EFAULT; | 683 | return -EFAULT; |
703 | /* first time updating this reg, | 684 | /* first time updating this reg, |
@@ -706,8 +687,8 @@ static int emulate_string_inst(struct pt_regs *regs, u32 instword) | |||
706 | regs->gpr[rT] = 0; | 687 | regs->gpr[rT] = 0; |
707 | regs->gpr[rT] |= val << shift; | 688 | regs->gpr[rT] |= val << shift; |
708 | break; | 689 | break; |
709 | case INST_STSWI: | 690 | case PPC_INST_STSWI: |
710 | case INST_STSWX: | 691 | case PPC_INST_STSWX: |
711 | val = regs->gpr[rT] >> shift; | 692 | val = regs->gpr[rT] >> shift; |
712 | if (put_user(val, (u8 __user *)EA)) | 693 | if (put_user(val, (u8 __user *)EA)) |
713 | return -EFAULT; | 694 | return -EFAULT; |
@@ -775,18 +756,18 @@ static int emulate_instruction(struct pt_regs *regs) | |||
775 | return -EFAULT; | 756 | return -EFAULT; |
776 | 757 | ||
777 | /* Emulate the mfspr rD, PVR. */ | 758 | /* Emulate the mfspr rD, PVR. */ |
778 | if ((instword & INST_MFSPR_PVR_MASK) == INST_MFSPR_PVR) { | 759 | if ((instword & PPC_INST_MFSPR_PVR_MASK) == PPC_INST_MFSPR_PVR) { |
779 | rd = (instword >> 21) & 0x1f; | 760 | rd = (instword >> 21) & 0x1f; |
780 | regs->gpr[rd] = mfspr(SPRN_PVR); | 761 | regs->gpr[rd] = mfspr(SPRN_PVR); |
781 | return 0; | 762 | return 0; |
782 | } | 763 | } |
783 | 764 | ||
784 | /* Emulating the dcba insn is just a no-op. */ | 765 | /* Emulating the dcba insn is just a no-op. */ |
785 | if ((instword & INST_DCBA_MASK) == INST_DCBA) | 766 | if ((instword & PPC_INST_DCBA_MASK) == PPC_INST_DCBA) |
786 | return 0; | 767 | return 0; |
787 | 768 | ||
788 | /* Emulate the mcrxr insn. */ | 769 | /* Emulate the mcrxr insn. */ |
789 | if ((instword & INST_MCRXR_MASK) == INST_MCRXR) { | 770 | if ((instword & PPC_INST_MCRXR_MASK) == PPC_INST_MCRXR) { |
790 | int shift = (instword >> 21) & 0x1c; | 771 | int shift = (instword >> 21) & 0x1c; |
791 | unsigned long msk = 0xf0000000UL >> shift; | 772 | unsigned long msk = 0xf0000000UL >> shift; |
792 | 773 | ||
@@ -796,16 +777,16 @@ static int emulate_instruction(struct pt_regs *regs) | |||
796 | } | 777 | } |
797 | 778 | ||
798 | /* Emulate load/store string insn. */ | 779 | /* Emulate load/store string insn. */ |
799 | if ((instword & INST_STRING_GEN_MASK) == INST_STRING) | 780 | if ((instword & PPC_INST_STRING_GEN_MASK) == PPC_INST_STRING) |
800 | return emulate_string_inst(regs, instword); | 781 | return emulate_string_inst(regs, instword); |
801 | 782 | ||
802 | /* Emulate the popcntb (Population Count Bytes) instruction. */ | 783 | /* Emulate the popcntb (Population Count Bytes) instruction. */ |
803 | if ((instword & INST_POPCNTB_MASK) == INST_POPCNTB) { | 784 | if ((instword & PPC_INST_POPCNTB_MASK) == PPC_INST_POPCNTB) { |
804 | return emulate_popcntb_inst(regs, instword); | 785 | return emulate_popcntb_inst(regs, instword); |
805 | } | 786 | } |
806 | 787 | ||
807 | /* Emulate isel (Integer Select) instruction */ | 788 | /* Emulate isel (Integer Select) instruction */ |
808 | if ((instword & INST_ISEL_MASK) == INST_ISEL) { | 789 | if ((instword & PPC_INST_ISEL_MASK) == PPC_INST_ISEL) { |
809 | return emulate_isel(regs, instword); | 790 | return emulate_isel(regs, instword); |
810 | } | 791 | } |
811 | 792 | ||
@@ -1144,6 +1125,24 @@ void vsx_assist_exception(struct pt_regs *regs) | |||
1144 | #endif /* CONFIG_VSX */ | 1125 | #endif /* CONFIG_VSX */ |
1145 | 1126 | ||
1146 | #ifdef CONFIG_FSL_BOOKE | 1127 | #ifdef CONFIG_FSL_BOOKE |
1128 | |||
1129 | void doorbell_exception(struct pt_regs *regs) | ||
1130 | { | ||
1131 | #ifdef CONFIG_SMP | ||
1132 | int cpu = smp_processor_id(); | ||
1133 | int msg; | ||
1134 | |||
1135 | if (num_online_cpus() < 2) | ||
1136 | return; | ||
1137 | |||
1138 | for (msg = 0; msg < 4; msg++) | ||
1139 | if (test_and_clear_bit(msg, &dbell_smp_message[cpu])) | ||
1140 | smp_message_recv(msg); | ||
1141 | #else | ||
1142 | printk(KERN_WARNING "Received doorbell on non-smp system\n"); | ||
1143 | #endif | ||
1144 | } | ||
1145 | |||
1147 | void CacheLockingException(struct pt_regs *regs, unsigned long address, | 1146 | void CacheLockingException(struct pt_regs *regs, unsigned long address, |
1148 | unsigned long error_code) | 1147 | unsigned long error_code) |
1149 | { | 1148 | { |