diff options
Diffstat (limited to 'arch/powerpc/kernel/traps.c')
| -rw-r--r-- | arch/powerpc/kernel/traps.c | 178 |
1 files changed, 113 insertions, 65 deletions
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 6f0ae1a9bfae..29d128eb6c43 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
| @@ -21,7 +21,6 @@ | |||
| 21 | #include <linux/stddef.h> | 21 | #include <linux/stddef.h> |
| 22 | #include <linux/unistd.h> | 22 | #include <linux/unistd.h> |
| 23 | #include <linux/ptrace.h> | 23 | #include <linux/ptrace.h> |
| 24 | #include <linux/slab.h> | ||
| 25 | #include <linux/user.h> | 24 | #include <linux/user.h> |
| 26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
| 27 | #include <linux/init.h> | 26 | #include <linux/init.h> |
| @@ -60,13 +59,13 @@ | |||
| 60 | #endif | 59 | #endif |
| 61 | 60 | ||
| 62 | #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) | 61 | #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) |
| 63 | int (*__debugger)(struct pt_regs *regs); | 62 | int (*__debugger)(struct pt_regs *regs) __read_mostly; |
| 64 | int (*__debugger_ipi)(struct pt_regs *regs); | 63 | int (*__debugger_ipi)(struct pt_regs *regs) __read_mostly; |
| 65 | int (*__debugger_bpt)(struct pt_regs *regs); | 64 | int (*__debugger_bpt)(struct pt_regs *regs) __read_mostly; |
| 66 | int (*__debugger_sstep)(struct pt_regs *regs); | 65 | int (*__debugger_sstep)(struct pt_regs *regs) __read_mostly; |
| 67 | int (*__debugger_iabr_match)(struct pt_regs *regs); | 66 | int (*__debugger_iabr_match)(struct pt_regs *regs) __read_mostly; |
| 68 | int (*__debugger_dabr_match)(struct pt_regs *regs); | 67 | int (*__debugger_dabr_match)(struct pt_regs *regs) __read_mostly; |
| 69 | int (*__debugger_fault_handler)(struct pt_regs *regs); | 68 | int (*__debugger_fault_handler)(struct pt_regs *regs) __read_mostly; |
| 70 | 69 | ||
| 71 | EXPORT_SYMBOL(__debugger); | 70 | EXPORT_SYMBOL(__debugger); |
| 72 | EXPORT_SYMBOL(__debugger_ipi); | 71 | EXPORT_SYMBOL(__debugger_ipi); |
| @@ -102,11 +101,11 @@ static inline void pmac_backlight_unblank(void) { } | |||
| 102 | int die(const char *str, struct pt_regs *regs, long err) | 101 | int die(const char *str, struct pt_regs *regs, long err) |
| 103 | { | 102 | { |
| 104 | static struct { | 103 | static struct { |
| 105 | spinlock_t lock; | 104 | raw_spinlock_t lock; |
| 106 | u32 lock_owner; | 105 | u32 lock_owner; |
| 107 | int lock_owner_depth; | 106 | int lock_owner_depth; |
| 108 | } die = { | 107 | } die = { |
| 109 | .lock = __SPIN_LOCK_UNLOCKED(die.lock), | 108 | .lock = __RAW_SPIN_LOCK_UNLOCKED(die.lock), |
| 110 | .lock_owner = -1, | 109 | .lock_owner = -1, |
| 111 | .lock_owner_depth = 0 | 110 | .lock_owner_depth = 0 |
| 112 | }; | 111 | }; |
| @@ -120,7 +119,7 @@ int die(const char *str, struct pt_regs *regs, long err) | |||
| 120 | 119 | ||
| 121 | if (die.lock_owner != raw_smp_processor_id()) { | 120 | if (die.lock_owner != raw_smp_processor_id()) { |
| 122 | console_verbose(); | 121 | console_verbose(); |
| 123 | spin_lock_irqsave(&die.lock, flags); | 122 | raw_spin_lock_irqsave(&die.lock, flags); |
| 124 | die.lock_owner = smp_processor_id(); | 123 | die.lock_owner = smp_processor_id(); |
| 125 | die.lock_owner_depth = 0; | 124 | die.lock_owner_depth = 0; |
| 126 | bust_spinlocks(1); | 125 | bust_spinlocks(1); |
| @@ -146,6 +145,11 @@ int die(const char *str, struct pt_regs *regs, long err) | |||
| 146 | #endif | 145 | #endif |
| 147 | printk("%s\n", ppc_md.name ? ppc_md.name : ""); | 146 | printk("%s\n", ppc_md.name ? ppc_md.name : ""); |
| 148 | 147 | ||
| 148 | sysfs_printk_last_file(); | ||
| 149 | if (notify_die(DIE_OOPS, str, regs, err, 255, | ||
| 150 | SIGSEGV) == NOTIFY_STOP) | ||
| 151 | return 1; | ||
| 152 | |||
| 149 | print_modules(); | 153 | print_modules(); |
| 150 | show_regs(regs); | 154 | show_regs(regs); |
| 151 | } else { | 155 | } else { |
| @@ -155,7 +159,7 @@ int die(const char *str, struct pt_regs *regs, long err) | |||
| 155 | bust_spinlocks(0); | 159 | bust_spinlocks(0); |
| 156 | die.lock_owner = -1; | 160 | die.lock_owner = -1; |
| 157 | add_taint(TAINT_DIE); | 161 | add_taint(TAINT_DIE); |
| 158 | spin_unlock_irqrestore(&die.lock, flags); | 162 | raw_spin_unlock_irqrestore(&die.lock, flags); |
| 159 | 163 | ||
| 160 | if (kexec_should_crash(current) || | 164 | if (kexec_should_crash(current) || |
| 161 | kexec_sr_activated(smp_processor_id())) | 165 | kexec_sr_activated(smp_processor_id())) |
| @@ -174,6 +178,15 @@ int die(const char *str, struct pt_regs *regs, long err) | |||
| 174 | return 0; | 178 | return 0; |
| 175 | } | 179 | } |
| 176 | 180 | ||
| 181 | void user_single_step_siginfo(struct task_struct *tsk, | ||
| 182 | struct pt_regs *regs, siginfo_t *info) | ||
| 183 | { | ||
| 184 | memset(info, 0, sizeof(*info)); | ||
| 185 | info->si_signo = SIGTRAP; | ||
| 186 | info->si_code = TRAP_TRACE; | ||
| 187 | info->si_addr = (void __user *)regs->nip; | ||
| 188 | } | ||
| 189 | |||
| 177 | void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) | 190 | void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) |
| 178 | { | 191 | { |
| 179 | siginfo_t info; | 192 | siginfo_t info; |
| @@ -198,28 +211,6 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) | |||
| 198 | info.si_code = code; | 211 | info.si_code = code; |
| 199 | info.si_addr = (void __user *) addr; | 212 | info.si_addr = (void __user *) addr; |
| 200 | force_sig_info(signr, &info, current); | 213 | force_sig_info(signr, &info, current); |
| 201 | |||
| 202 | /* | ||
| 203 | * Init gets no signals that it doesn't have a handler for. | ||
| 204 | * That's all very well, but if it has caused a synchronous | ||
| 205 | * exception and we ignore the resulting signal, it will just | ||
| 206 | * generate the same exception over and over again and we get | ||
| 207 | * nowhere. Better to kill it and let the kernel panic. | ||
| 208 | */ | ||
| 209 | if (is_global_init(current)) { | ||
| 210 | __sighandler_t handler; | ||
| 211 | |||
| 212 | spin_lock_irq(¤t->sighand->siglock); | ||
| 213 | handler = current->sighand->action[signr-1].sa.sa_handler; | ||
| 214 | spin_unlock_irq(¤t->sighand->siglock); | ||
| 215 | if (handler == SIG_DFL) { | ||
| 216 | /* init has generated a synchronous exception | ||
| 217 | and it doesn't have a handler for the signal */ | ||
| 218 | printk(KERN_CRIT "init has generated signal %d " | ||
| 219 | "but has no handler for it\n", signr); | ||
| 220 | do_exit(signr); | ||
| 221 | } | ||
| 222 | } | ||
| 223 | } | 214 | } |
| 224 | 215 | ||
| 225 | #ifdef CONFIG_PPC64 | 216 | #ifdef CONFIG_PPC64 |
| @@ -307,7 +298,7 @@ static inline int check_io_access(struct pt_regs *regs) | |||
| 307 | return 0; | 298 | return 0; |
| 308 | } | 299 | } |
| 309 | 300 | ||
| 310 | #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) | 301 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS |
| 311 | /* On 4xx, the reason for the machine check or program exception | 302 | /* On 4xx, the reason for the machine check or program exception |
| 312 | is in the ESR. */ | 303 | is in the ESR. */ |
| 313 | #define get_reason(regs) ((regs)->dsisr) | 304 | #define get_reason(regs) ((regs)->dsisr) |
| @@ -491,6 +482,8 @@ void machine_check_exception(struct pt_regs *regs) | |||
| 491 | { | 482 | { |
| 492 | int recover = 0; | 483 | int recover = 0; |
| 493 | 484 | ||
| 485 | __get_cpu_var(irq_stat).mce_exceptions++; | ||
| 486 | |||
| 494 | /* See if any machine dependent calls. In theory, we would want | 487 | /* See if any machine dependent calls. In theory, we would want |
| 495 | * to call the CPU first, and call the ppc_md. one if the CPU | 488 | * to call the CPU first, and call the ppc_md. one if the CPU |
| 496 | * one returns a positive number. However there is existing code | 489 | * one returns a positive number. However there is existing code |
| @@ -759,7 +752,7 @@ static int emulate_instruction(struct pt_regs *regs) | |||
| 759 | 752 | ||
| 760 | /* Emulate the mfspr rD, PVR. */ | 753 | /* Emulate the mfspr rD, PVR. */ |
| 761 | if ((instword & PPC_INST_MFSPR_PVR_MASK) == PPC_INST_MFSPR_PVR) { | 754 | if ((instword & PPC_INST_MFSPR_PVR_MASK) == PPC_INST_MFSPR_PVR) { |
| 762 | PPC_WARN_EMULATED(mfpvr); | 755 | PPC_WARN_EMULATED(mfpvr, regs); |
| 763 | rd = (instword >> 21) & 0x1f; | 756 | rd = (instword >> 21) & 0x1f; |
| 764 | regs->gpr[rd] = mfspr(SPRN_PVR); | 757 | regs->gpr[rd] = mfspr(SPRN_PVR); |
| 765 | return 0; | 758 | return 0; |
| @@ -767,7 +760,7 @@ static int emulate_instruction(struct pt_regs *regs) | |||
| 767 | 760 | ||
| 768 | /* Emulating the dcba insn is just a no-op. */ | 761 | /* Emulating the dcba insn is just a no-op. */ |
| 769 | if ((instword & PPC_INST_DCBA_MASK) == PPC_INST_DCBA) { | 762 | if ((instword & PPC_INST_DCBA_MASK) == PPC_INST_DCBA) { |
| 770 | PPC_WARN_EMULATED(dcba); | 763 | PPC_WARN_EMULATED(dcba, regs); |
| 771 | return 0; | 764 | return 0; |
| 772 | } | 765 | } |
| 773 | 766 | ||
| @@ -776,7 +769,7 @@ static int emulate_instruction(struct pt_regs *regs) | |||
| 776 | int shift = (instword >> 21) & 0x1c; | 769 | int shift = (instword >> 21) & 0x1c; |
| 777 | unsigned long msk = 0xf0000000UL >> shift; | 770 | unsigned long msk = 0xf0000000UL >> shift; |
| 778 | 771 | ||
| 779 | PPC_WARN_EMULATED(mcrxr); | 772 | PPC_WARN_EMULATED(mcrxr, regs); |
| 780 | regs->ccr = (regs->ccr & ~msk) | ((regs->xer >> shift) & msk); | 773 | regs->ccr = (regs->ccr & ~msk) | ((regs->xer >> shift) & msk); |
| 781 | regs->xer &= ~0xf0000000UL; | 774 | regs->xer &= ~0xf0000000UL; |
| 782 | return 0; | 775 | return 0; |
| @@ -784,19 +777,19 @@ static int emulate_instruction(struct pt_regs *regs) | |||
| 784 | 777 | ||
| 785 | /* Emulate load/store string insn. */ | 778 | /* Emulate load/store string insn. */ |
| 786 | if ((instword & PPC_INST_STRING_GEN_MASK) == PPC_INST_STRING) { | 779 | if ((instword & PPC_INST_STRING_GEN_MASK) == PPC_INST_STRING) { |
| 787 | PPC_WARN_EMULATED(string); | 780 | PPC_WARN_EMULATED(string, regs); |
| 788 | return emulate_string_inst(regs, instword); | 781 | return emulate_string_inst(regs, instword); |
| 789 | } | 782 | } |
| 790 | 783 | ||
| 791 | /* Emulate the popcntb (Population Count Bytes) instruction. */ | 784 | /* Emulate the popcntb (Population Count Bytes) instruction. */ |
| 792 | if ((instword & PPC_INST_POPCNTB_MASK) == PPC_INST_POPCNTB) { | 785 | if ((instword & PPC_INST_POPCNTB_MASK) == PPC_INST_POPCNTB) { |
| 793 | PPC_WARN_EMULATED(popcntb); | 786 | PPC_WARN_EMULATED(popcntb, regs); |
| 794 | return emulate_popcntb_inst(regs, instword); | 787 | return emulate_popcntb_inst(regs, instword); |
| 795 | } | 788 | } |
| 796 | 789 | ||
| 797 | /* Emulate isel (Integer Select) instruction */ | 790 | /* Emulate isel (Integer Select) instruction */ |
| 798 | if ((instword & PPC_INST_ISEL_MASK) == PPC_INST_ISEL) { | 791 | if ((instword & PPC_INST_ISEL_MASK) == PPC_INST_ISEL) { |
| 799 | PPC_WARN_EMULATED(isel); | 792 | PPC_WARN_EMULATED(isel, regs); |
| 800 | return emulate_isel(regs, instword); | 793 | return emulate_isel(regs, instword); |
| 801 | } | 794 | } |
| 802 | 795 | ||
| @@ -973,6 +966,8 @@ void vsx_unavailable_exception(struct pt_regs *regs) | |||
| 973 | 966 | ||
| 974 | void performance_monitor_exception(struct pt_regs *regs) | 967 | void performance_monitor_exception(struct pt_regs *regs) |
| 975 | { | 968 | { |
| 969 | __get_cpu_var(irq_stat).pmu_irqs++; | ||
| 970 | |||
| 976 | perf_irq(regs); | 971 | perf_irq(regs); |
| 977 | } | 972 | } |
| 978 | 973 | ||
| @@ -995,7 +990,7 @@ void SoftwareEmulation(struct pt_regs *regs) | |||
| 995 | #ifdef CONFIG_MATH_EMULATION | 990 | #ifdef CONFIG_MATH_EMULATION |
| 996 | errcode = do_mathemu(regs); | 991 | errcode = do_mathemu(regs); |
| 997 | if (errcode >= 0) | 992 | if (errcode >= 0) |
| 998 | PPC_WARN_EMULATED(math); | 993 | PPC_WARN_EMULATED(math, regs); |
| 999 | 994 | ||
| 1000 | switch (errcode) { | 995 | switch (errcode) { |
| 1001 | case 0: | 996 | case 0: |
| @@ -1018,7 +1013,7 @@ void SoftwareEmulation(struct pt_regs *regs) | |||
| 1018 | #elif defined(CONFIG_8XX_MINIMAL_FPEMU) | 1013 | #elif defined(CONFIG_8XX_MINIMAL_FPEMU) |
| 1019 | errcode = Soft_emulate_8xx(regs); | 1014 | errcode = Soft_emulate_8xx(regs); |
| 1020 | if (errcode >= 0) | 1015 | if (errcode >= 0) |
| 1021 | PPC_WARN_EMULATED(8xx); | 1016 | PPC_WARN_EMULATED(8xx, regs); |
| 1022 | 1017 | ||
| 1023 | switch (errcode) { | 1018 | switch (errcode) { |
| 1024 | case 0: | 1019 | case 0: |
| @@ -1037,10 +1032,69 @@ void SoftwareEmulation(struct pt_regs *regs) | |||
| 1037 | } | 1032 | } |
| 1038 | #endif /* CONFIG_8xx */ | 1033 | #endif /* CONFIG_8xx */ |
| 1039 | 1034 | ||
| 1040 | #if defined(CONFIG_40x) || defined(CONFIG_BOOKE) | 1035 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS |
| 1036 | static void handle_debug(struct pt_regs *regs, unsigned long debug_status) | ||
| 1037 | { | ||
| 1038 | int changed = 0; | ||
| 1039 | /* | ||
| 1040 | * Determine the cause of the debug event, clear the | ||
| 1041 | * event flags and send a trap to the handler. Torez | ||
| 1042 | */ | ||
| 1043 | if (debug_status & (DBSR_DAC1R | DBSR_DAC1W)) { | ||
| 1044 | dbcr_dac(current) &= ~(DBCR_DAC1R | DBCR_DAC1W); | ||
| 1045 | #ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE | ||
| 1046 | current->thread.dbcr2 &= ~DBCR2_DAC12MODE; | ||
| 1047 | #endif | ||
| 1048 | do_send_trap(regs, mfspr(SPRN_DAC1), debug_status, TRAP_HWBKPT, | ||
| 1049 | 5); | ||
| 1050 | changed |= 0x01; | ||
| 1051 | } else if (debug_status & (DBSR_DAC2R | DBSR_DAC2W)) { | ||
| 1052 | dbcr_dac(current) &= ~(DBCR_DAC2R | DBCR_DAC2W); | ||
| 1053 | do_send_trap(regs, mfspr(SPRN_DAC2), debug_status, TRAP_HWBKPT, | ||
| 1054 | 6); | ||
| 1055 | changed |= 0x01; | ||
| 1056 | } else if (debug_status & DBSR_IAC1) { | ||
| 1057 | current->thread.dbcr0 &= ~DBCR0_IAC1; | ||
| 1058 | dbcr_iac_range(current) &= ~DBCR_IAC12MODE; | ||
| 1059 | do_send_trap(regs, mfspr(SPRN_IAC1), debug_status, TRAP_HWBKPT, | ||
| 1060 | 1); | ||
| 1061 | changed |= 0x01; | ||
| 1062 | } else if (debug_status & DBSR_IAC2) { | ||
| 1063 | current->thread.dbcr0 &= ~DBCR0_IAC2; | ||
| 1064 | do_send_trap(regs, mfspr(SPRN_IAC2), debug_status, TRAP_HWBKPT, | ||
| 1065 | 2); | ||
| 1066 | changed |= 0x01; | ||
| 1067 | } else if (debug_status & DBSR_IAC3) { | ||
| 1068 | current->thread.dbcr0 &= ~DBCR0_IAC3; | ||
| 1069 | dbcr_iac_range(current) &= ~DBCR_IAC34MODE; | ||
| 1070 | do_send_trap(regs, mfspr(SPRN_IAC3), debug_status, TRAP_HWBKPT, | ||
| 1071 | 3); | ||
| 1072 | changed |= 0x01; | ||
| 1073 | } else if (debug_status & DBSR_IAC4) { | ||
| 1074 | current->thread.dbcr0 &= ~DBCR0_IAC4; | ||
| 1075 | do_send_trap(regs, mfspr(SPRN_IAC4), debug_status, TRAP_HWBKPT, | ||
| 1076 | 4); | ||
| 1077 | changed |= 0x01; | ||
| 1078 | } | ||
| 1079 | /* | ||
| 1080 | * At the point this routine was called, the MSR(DE) was turned off. | ||
| 1081 | * Check all other debug flags and see if that bit needs to be turned | ||
| 1082 | * back on or not. | ||
| 1083 | */ | ||
| 1084 | if (DBCR_ACTIVE_EVENTS(current->thread.dbcr0, current->thread.dbcr1)) | ||
| 1085 | regs->msr |= MSR_DE; | ||
| 1086 | else | ||
| 1087 | /* Make sure the IDM flag is off */ | ||
| 1088 | current->thread.dbcr0 &= ~DBCR0_IDM; | ||
| 1089 | |||
| 1090 | if (changed & 0x01) | ||
| 1091 | mtspr(SPRN_DBCR0, current->thread.dbcr0); | ||
| 1092 | } | ||
| 1041 | 1093 | ||
| 1042 | void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status) | 1094 | void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status) |
| 1043 | { | 1095 | { |
| 1096 | current->thread.dbsr = debug_status; | ||
| 1097 | |||
| 1044 | /* Hack alert: On BookE, Branch Taken stops on the branch itself, while | 1098 | /* Hack alert: On BookE, Branch Taken stops on the branch itself, while |
| 1045 | * on server, it stops on the target of the branch. In order to simulate | 1099 | * on server, it stops on the target of the branch. In order to simulate |
| 1046 | * the server behaviour, we thus restart right away with a single step | 1100 | * the server behaviour, we thus restart right away with a single step |
| @@ -1084,29 +1138,23 @@ void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status) | |||
| 1084 | if (debugger_sstep(regs)) | 1138 | if (debugger_sstep(regs)) |
| 1085 | return; | 1139 | return; |
| 1086 | 1140 | ||
| 1087 | if (user_mode(regs)) | ||
| 1088 | current->thread.dbcr0 &= ~(DBCR0_IC); | ||
| 1089 | |||
| 1090 | _exception(SIGTRAP, regs, TRAP_TRACE, regs->nip); | ||
| 1091 | } else if (debug_status & (DBSR_DAC1R | DBSR_DAC1W)) { | ||
| 1092 | regs->msr &= ~MSR_DE; | ||
| 1093 | |||
| 1094 | if (user_mode(regs)) { | 1141 | if (user_mode(regs)) { |
| 1095 | current->thread.dbcr0 &= ~(DBSR_DAC1R | DBSR_DAC1W | | 1142 | current->thread.dbcr0 &= ~DBCR0_IC; |
| 1096 | DBCR0_IDM); | 1143 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS |
| 1097 | } else { | 1144 | if (DBCR_ACTIVE_EVENTS(current->thread.dbcr0, |
| 1098 | /* Disable DAC interupts */ | 1145 | current->thread.dbcr1)) |
| 1099 | mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~(DBSR_DAC1R | | 1146 | regs->msr |= MSR_DE; |
| 1100 | DBSR_DAC1W | DBCR0_IDM)); | 1147 | else |
| 1101 | 1148 | /* Make sure the IDM bit is off */ | |
| 1102 | /* Clear the DAC event */ | 1149 | current->thread.dbcr0 &= ~DBCR0_IDM; |
| 1103 | mtspr(SPRN_DBSR, (DBSR_DAC1R | DBSR_DAC1W)); | 1150 | #endif |
| 1104 | } | 1151 | } |
| 1105 | /* Setup and send the trap to the handler */ | 1152 | |
| 1106 | do_dabr(regs, mfspr(SPRN_DAC1), debug_status); | 1153 | _exception(SIGTRAP, regs, TRAP_TRACE, regs->nip); |
| 1107 | } | 1154 | } else |
| 1155 | handle_debug(regs, debug_status); | ||
| 1108 | } | 1156 | } |
| 1109 | #endif /* CONFIG_4xx || CONFIG_BOOKE */ | 1157 | #endif /* CONFIG_PPC_ADV_DEBUG_REGS */ |
| 1110 | 1158 | ||
| 1111 | #if !defined(CONFIG_TAU_INT) | 1159 | #if !defined(CONFIG_TAU_INT) |
| 1112 | void TAUException(struct pt_regs *regs) | 1160 | void TAUException(struct pt_regs *regs) |
| @@ -1129,7 +1177,7 @@ void altivec_assist_exception(struct pt_regs *regs) | |||
| 1129 | 1177 | ||
| 1130 | flush_altivec_to_thread(current); | 1178 | flush_altivec_to_thread(current); |
| 1131 | 1179 | ||
| 1132 | PPC_WARN_EMULATED(altivec); | 1180 | PPC_WARN_EMULATED(altivec, regs); |
| 1133 | err = emulate_altivec(regs); | 1181 | err = emulate_altivec(regs); |
| 1134 | if (err == 0) { | 1182 | if (err == 0) { |
| 1135 | regs->nip += 4; /* skip emulated instruction */ | 1183 | regs->nip += 4; /* skip emulated instruction */ |
