aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/traps.c')
-rw-r--r--arch/powerpc/kernel/traps.c128
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)
63int (*__debugger)(struct pt_regs *regs); 63int (*__debugger)(struct pt_regs *regs) __read_mostly;
64int (*__debugger_ipi)(struct pt_regs *regs); 64int (*__debugger_ipi)(struct pt_regs *regs) __read_mostly;
65int (*__debugger_bpt)(struct pt_regs *regs); 65int (*__debugger_bpt)(struct pt_regs *regs) __read_mostly;
66int (*__debugger_sstep)(struct pt_regs *regs); 66int (*__debugger_sstep)(struct pt_regs *regs) __read_mostly;
67int (*__debugger_iabr_match)(struct pt_regs *regs); 67int (*__debugger_iabr_match)(struct pt_regs *regs) __read_mostly;
68int (*__debugger_dabr_match)(struct pt_regs *regs); 68int (*__debugger_dabr_match)(struct pt_regs *regs) __read_mostly;
69int (*__debugger_fault_handler)(struct pt_regs *regs); 69int (*__debugger_fault_handler)(struct pt_regs *regs) __read_mostly;
70 70
71EXPORT_SYMBOL(__debugger); 71EXPORT_SYMBOL(__debugger);
72EXPORT_SYMBOL(__debugger_ipi); 72EXPORT_SYMBOL(__debugger_ipi);
@@ -102,11 +102,11 @@ static inline void pmac_backlight_unblank(void) { }
102int die(const char *str, struct pt_regs *regs, long err) 102int 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
961void performance_monitor_exception(struct pt_regs *regs) 968void 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
1037static 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
1029void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status) 1095void __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)
1099void TAUException(struct pt_regs *regs) 1161void TAUException(struct pt_regs *regs)