diff options
Diffstat (limited to 'arch/powerpc/kernel/traps.c')
-rw-r--r-- | arch/powerpc/kernel/traps.c | 128 |
1 files changed, 95 insertions, 33 deletions
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index d069ff8a7e03..696626a2e835 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
@@ -60,13 +60,13 @@ | |||
60 | #endif | 60 | #endif |
61 | 61 | ||
62 | #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) | 62 | #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) |
63 | int (*__debugger)(struct pt_regs *regs); | 63 | int (*__debugger)(struct pt_regs *regs) __read_mostly; |
64 | int (*__debugger_ipi)(struct pt_regs *regs); | 64 | int (*__debugger_ipi)(struct pt_regs *regs) __read_mostly; |
65 | int (*__debugger_bpt)(struct pt_regs *regs); | 65 | int (*__debugger_bpt)(struct pt_regs *regs) __read_mostly; |
66 | int (*__debugger_sstep)(struct pt_regs *regs); | 66 | int (*__debugger_sstep)(struct pt_regs *regs) __read_mostly; |
67 | int (*__debugger_iabr_match)(struct pt_regs *regs); | 67 | int (*__debugger_iabr_match)(struct pt_regs *regs) __read_mostly; |
68 | int (*__debugger_dabr_match)(struct pt_regs *regs); | 68 | int (*__debugger_dabr_match)(struct pt_regs *regs) __read_mostly; |
69 | int (*__debugger_fault_handler)(struct pt_regs *regs); | 69 | int (*__debugger_fault_handler)(struct pt_regs *regs) __read_mostly; |
70 | 70 | ||
71 | EXPORT_SYMBOL(__debugger); | 71 | EXPORT_SYMBOL(__debugger); |
72 | EXPORT_SYMBOL(__debugger_ipi); | 72 | EXPORT_SYMBOL(__debugger_ipi); |
@@ -102,11 +102,11 @@ static inline void pmac_backlight_unblank(void) { } | |||
102 | int die(const char *str, struct pt_regs *regs, long err) | 102 | int die(const char *str, struct pt_regs *regs, long err) |
103 | { | 103 | { |
104 | static struct { | 104 | static struct { |
105 | spinlock_t lock; | 105 | raw_spinlock_t lock; |
106 | u32 lock_owner; | 106 | u32 lock_owner; |
107 | int lock_owner_depth; | 107 | int lock_owner_depth; |
108 | } die = { | 108 | } die = { |
109 | .lock = __SPIN_LOCK_UNLOCKED(die.lock), | 109 | .lock = __RAW_SPIN_LOCK_UNLOCKED(die.lock), |
110 | .lock_owner = -1, | 110 | .lock_owner = -1, |
111 | .lock_owner_depth = 0 | 111 | .lock_owner_depth = 0 |
112 | }; | 112 | }; |
@@ -120,7 +120,7 @@ int die(const char *str, struct pt_regs *regs, long err) | |||
120 | 120 | ||
121 | if (die.lock_owner != raw_smp_processor_id()) { | 121 | if (die.lock_owner != raw_smp_processor_id()) { |
122 | console_verbose(); | 122 | console_verbose(); |
123 | spin_lock_irqsave(&die.lock, flags); | 123 | raw_spin_lock_irqsave(&die.lock, flags); |
124 | die.lock_owner = smp_processor_id(); | 124 | die.lock_owner = smp_processor_id(); |
125 | die.lock_owner_depth = 0; | 125 | die.lock_owner_depth = 0; |
126 | bust_spinlocks(1); | 126 | bust_spinlocks(1); |
@@ -146,6 +146,11 @@ int die(const char *str, struct pt_regs *regs, long err) | |||
146 | #endif | 146 | #endif |
147 | printk("%s\n", ppc_md.name ? ppc_md.name : ""); | 147 | printk("%s\n", ppc_md.name ? ppc_md.name : ""); |
148 | 148 | ||
149 | sysfs_printk_last_file(); | ||
150 | if (notify_die(DIE_OOPS, str, regs, err, 255, | ||
151 | SIGSEGV) == NOTIFY_STOP) | ||
152 | return 1; | ||
153 | |||
149 | print_modules(); | 154 | print_modules(); |
150 | show_regs(regs); | 155 | show_regs(regs); |
151 | } else { | 156 | } else { |
@@ -155,7 +160,7 @@ int die(const char *str, struct pt_regs *regs, long err) | |||
155 | bust_spinlocks(0); | 160 | bust_spinlocks(0); |
156 | die.lock_owner = -1; | 161 | die.lock_owner = -1; |
157 | add_taint(TAINT_DIE); | 162 | add_taint(TAINT_DIE); |
158 | spin_unlock_irqrestore(&die.lock, flags); | 163 | raw_spin_unlock_irqrestore(&die.lock, flags); |
159 | 164 | ||
160 | if (kexec_should_crash(current) || | 165 | if (kexec_should_crash(current) || |
161 | kexec_sr_activated(smp_processor_id())) | 166 | kexec_sr_activated(smp_processor_id())) |
@@ -294,7 +299,7 @@ static inline int check_io_access(struct pt_regs *regs) | |||
294 | return 0; | 299 | return 0; |
295 | } | 300 | } |
296 | 301 | ||
297 | #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) | 302 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS |
298 | /* On 4xx, the reason for the machine check or program exception | 303 | /* On 4xx, the reason for the machine check or program exception |
299 | is in the ESR. */ | 304 | is in the ESR. */ |
300 | #define get_reason(regs) ((regs)->dsisr) | 305 | #define get_reason(regs) ((regs)->dsisr) |
@@ -478,6 +483,8 @@ void machine_check_exception(struct pt_regs *regs) | |||
478 | { | 483 | { |
479 | int recover = 0; | 484 | int recover = 0; |
480 | 485 | ||
486 | __get_cpu_var(irq_stat).mce_exceptions++; | ||
487 | |||
481 | /* See if any machine dependent calls. In theory, we would want | 488 | /* See if any machine dependent calls. In theory, we would want |
482 | * to call the CPU first, and call the ppc_md. one if the CPU | 489 | * to call the CPU first, and call the ppc_md. one if the CPU |
483 | * one returns a positive number. However there is existing code | 490 | * one returns a positive number. However there is existing code |
@@ -960,6 +967,8 @@ void vsx_unavailable_exception(struct pt_regs *regs) | |||
960 | 967 | ||
961 | void performance_monitor_exception(struct pt_regs *regs) | 968 | void performance_monitor_exception(struct pt_regs *regs) |
962 | { | 969 | { |
970 | __get_cpu_var(irq_stat).pmu_irqs++; | ||
971 | |||
963 | perf_irq(regs); | 972 | perf_irq(regs); |
964 | } | 973 | } |
965 | 974 | ||
@@ -1024,10 +1033,69 @@ void SoftwareEmulation(struct pt_regs *regs) | |||
1024 | } | 1033 | } |
1025 | #endif /* CONFIG_8xx */ | 1034 | #endif /* CONFIG_8xx */ |
1026 | 1035 | ||
1027 | #if defined(CONFIG_40x) || defined(CONFIG_BOOKE) | 1036 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS |
1037 | static void handle_debug(struct pt_regs *regs, unsigned long debug_status) | ||
1038 | { | ||
1039 | int changed = 0; | ||
1040 | /* | ||
1041 | * Determine the cause of the debug event, clear the | ||
1042 | * event flags and send a trap to the handler. Torez | ||
1043 | */ | ||
1044 | if (debug_status & (DBSR_DAC1R | DBSR_DAC1W)) { | ||
1045 | dbcr_dac(current) &= ~(DBCR_DAC1R | DBCR_DAC1W); | ||
1046 | #ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE | ||
1047 | current->thread.dbcr2 &= ~DBCR2_DAC12MODE; | ||
1048 | #endif | ||
1049 | do_send_trap(regs, mfspr(SPRN_DAC1), debug_status, TRAP_HWBKPT, | ||
1050 | 5); | ||
1051 | changed |= 0x01; | ||
1052 | } else if (debug_status & (DBSR_DAC2R | DBSR_DAC2W)) { | ||
1053 | dbcr_dac(current) &= ~(DBCR_DAC2R | DBCR_DAC2W); | ||
1054 | do_send_trap(regs, mfspr(SPRN_DAC2), debug_status, TRAP_HWBKPT, | ||
1055 | 6); | ||
1056 | changed |= 0x01; | ||
1057 | } else if (debug_status & DBSR_IAC1) { | ||
1058 | current->thread.dbcr0 &= ~DBCR0_IAC1; | ||
1059 | dbcr_iac_range(current) &= ~DBCR_IAC12MODE; | ||
1060 | do_send_trap(regs, mfspr(SPRN_IAC1), debug_status, TRAP_HWBKPT, | ||
1061 | 1); | ||
1062 | changed |= 0x01; | ||
1063 | } else if (debug_status & DBSR_IAC2) { | ||
1064 | current->thread.dbcr0 &= ~DBCR0_IAC2; | ||
1065 | do_send_trap(regs, mfspr(SPRN_IAC2), debug_status, TRAP_HWBKPT, | ||
1066 | 2); | ||
1067 | changed |= 0x01; | ||
1068 | } else if (debug_status & DBSR_IAC3) { | ||
1069 | current->thread.dbcr0 &= ~DBCR0_IAC3; | ||
1070 | dbcr_iac_range(current) &= ~DBCR_IAC34MODE; | ||
1071 | do_send_trap(regs, mfspr(SPRN_IAC3), debug_status, TRAP_HWBKPT, | ||
1072 | 3); | ||
1073 | changed |= 0x01; | ||
1074 | } else if (debug_status & DBSR_IAC4) { | ||
1075 | current->thread.dbcr0 &= ~DBCR0_IAC4; | ||
1076 | do_send_trap(regs, mfspr(SPRN_IAC4), debug_status, TRAP_HWBKPT, | ||
1077 | 4); | ||
1078 | changed |= 0x01; | ||
1079 | } | ||
1080 | /* | ||
1081 | * At the point this routine was called, the MSR(DE) was turned off. | ||
1082 | * Check all other debug flags and see if that bit needs to be turned | ||
1083 | * back on or not. | ||
1084 | */ | ||
1085 | if (DBCR_ACTIVE_EVENTS(current->thread.dbcr0, current->thread.dbcr1)) | ||
1086 | regs->msr |= MSR_DE; | ||
1087 | else | ||
1088 | /* Make sure the IDM flag is off */ | ||
1089 | current->thread.dbcr0 &= ~DBCR0_IDM; | ||
1090 | |||
1091 | if (changed & 0x01) | ||
1092 | mtspr(SPRN_DBCR0, current->thread.dbcr0); | ||
1093 | } | ||
1028 | 1094 | ||
1029 | void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status) | 1095 | void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status) |
1030 | { | 1096 | { |
1097 | current->thread.dbsr = debug_status; | ||
1098 | |||
1031 | /* Hack alert: On BookE, Branch Taken stops on the branch itself, while | 1099 | /* Hack alert: On BookE, Branch Taken stops on the branch itself, while |
1032 | * on server, it stops on the target of the branch. In order to simulate | 1100 | * on server, it stops on the target of the branch. In order to simulate |
1033 | * the server behaviour, we thus restart right away with a single step | 1101 | * the server behaviour, we thus restart right away with a single step |
@@ -1071,29 +1139,23 @@ void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status) | |||
1071 | if (debugger_sstep(regs)) | 1139 | if (debugger_sstep(regs)) |
1072 | return; | 1140 | return; |
1073 | 1141 | ||
1074 | if (user_mode(regs)) | ||
1075 | current->thread.dbcr0 &= ~(DBCR0_IC); | ||
1076 | |||
1077 | _exception(SIGTRAP, regs, TRAP_TRACE, regs->nip); | ||
1078 | } else if (debug_status & (DBSR_DAC1R | DBSR_DAC1W)) { | ||
1079 | regs->msr &= ~MSR_DE; | ||
1080 | |||
1081 | if (user_mode(regs)) { | 1142 | if (user_mode(regs)) { |
1082 | current->thread.dbcr0 &= ~(DBSR_DAC1R | DBSR_DAC1W | | 1143 | current->thread.dbcr0 &= ~DBCR0_IC; |
1083 | DBCR0_IDM); | 1144 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS |
1084 | } else { | 1145 | if (DBCR_ACTIVE_EVENTS(current->thread.dbcr0, |
1085 | /* Disable DAC interupts */ | 1146 | current->thread.dbcr1)) |
1086 | mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~(DBSR_DAC1R | | 1147 | regs->msr |= MSR_DE; |
1087 | DBSR_DAC1W | DBCR0_IDM)); | 1148 | else |
1088 | 1149 | /* Make sure the IDM bit is off */ | |
1089 | /* Clear the DAC event */ | 1150 | current->thread.dbcr0 &= ~DBCR0_IDM; |
1090 | mtspr(SPRN_DBSR, (DBSR_DAC1R | DBSR_DAC1W)); | 1151 | #endif |
1091 | } | 1152 | } |
1092 | /* Setup and send the trap to the handler */ | 1153 | |
1093 | do_dabr(regs, mfspr(SPRN_DAC1), debug_status); | 1154 | _exception(SIGTRAP, regs, TRAP_TRACE, regs->nip); |
1094 | } | 1155 | } else |
1156 | handle_debug(regs, debug_status); | ||
1095 | } | 1157 | } |
1096 | #endif /* CONFIG_4xx || CONFIG_BOOKE */ | 1158 | #endif /* CONFIG_PPC_ADV_DEBUG_REGS */ |
1097 | 1159 | ||
1098 | #if !defined(CONFIG_TAU_INT) | 1160 | #if !defined(CONFIG_TAU_INT) |
1099 | void TAUException(struct pt_regs *regs) | 1161 | void TAUException(struct pt_regs *regs) |