diff options
Diffstat (limited to 'arch/mn10300/kernel/mn10300-watchdog.c')
-rw-r--r-- | arch/mn10300/kernel/mn10300-watchdog.c | 100 |
1 files changed, 61 insertions, 39 deletions
diff --git a/arch/mn10300/kernel/mn10300-watchdog.c b/arch/mn10300/kernel/mn10300-watchdog.c index f362d9d138f1..965dd61656c3 100644 --- a/arch/mn10300/kernel/mn10300-watchdog.c +++ b/arch/mn10300/kernel/mn10300-watchdog.c | |||
@@ -30,7 +30,7 @@ | |||
30 | static DEFINE_SPINLOCK(watchdog_print_lock); | 30 | static DEFINE_SPINLOCK(watchdog_print_lock); |
31 | static unsigned int watchdog; | 31 | static unsigned int watchdog; |
32 | static unsigned int watchdog_hz = 1; | 32 | static unsigned int watchdog_hz = 1; |
33 | unsigned int watchdog_alert_counter; | 33 | unsigned int watchdog_alert_counter[NR_CPUS]; |
34 | 34 | ||
35 | EXPORT_SYMBOL(touch_nmi_watchdog); | 35 | EXPORT_SYMBOL(touch_nmi_watchdog); |
36 | 36 | ||
@@ -39,9 +39,6 @@ EXPORT_SYMBOL(touch_nmi_watchdog); | |||
39 | * is to check its timer makes IRQ counts. If they are not | 39 | * is to check its timer makes IRQ counts. If they are not |
40 | * changing then that CPU has some problem. | 40 | * changing then that CPU has some problem. |
41 | * | 41 | * |
42 | * as these watchdog NMI IRQs are generated on every CPU, we only | ||
43 | * have to check the current processor. | ||
44 | * | ||
45 | * since NMIs dont listen to _any_ locks, we have to be extremely | 42 | * since NMIs dont listen to _any_ locks, we have to be extremely |
46 | * careful not to rely on unsafe variables. The printk might lock | 43 | * careful not to rely on unsafe variables. The printk might lock |
47 | * up though, so we have to break up any console locks first ... | 44 | * up though, so we have to break up any console locks first ... |
@@ -69,8 +66,8 @@ int __init check_watchdog(void) | |||
69 | 66 | ||
70 | printk(KERN_INFO "OK.\n"); | 67 | printk(KERN_INFO "OK.\n"); |
71 | 68 | ||
72 | /* now that we know it works we can reduce NMI frequency to | 69 | /* now that we know it works we can reduce NMI frequency to something |
73 | * something more reasonable; makes a difference in some configs | 70 | * more reasonable; makes a difference in some configs |
74 | */ | 71 | */ |
75 | watchdog_hz = 1; | 72 | watchdog_hz = 1; |
76 | 73 | ||
@@ -121,15 +118,22 @@ void __init watchdog_go(void) | |||
121 | } | 118 | } |
122 | } | 119 | } |
123 | 120 | ||
121 | #ifdef CONFIG_SMP | ||
122 | static void watchdog_dump_register(void *dummy) | ||
123 | { | ||
124 | printk(KERN_ERR "--- Register Dump (CPU%d) ---\n", CPUID); | ||
125 | show_registers(__frame); | ||
126 | } | ||
127 | #endif | ||
128 | |||
124 | asmlinkage | 129 | asmlinkage |
125 | void watchdog_interrupt(struct pt_regs *regs, enum exception_code excep) | 130 | void watchdog_interrupt(struct pt_regs *regs, enum exception_code excep) |
126 | { | 131 | { |
127 | |||
128 | /* | 132 | /* |
129 | * Since current-> is always on the stack, and we always switch | 133 | * Since current-> is always on the stack, and we always switch |
130 | * the stack NMI-atomically, it's safe to use smp_processor_id(). | 134 | * the stack NMI-atomically, it's safe to use smp_processor_id(). |
131 | */ | 135 | */ |
132 | int sum, cpu = smp_processor_id(); | 136 | int sum, cpu; |
133 | int irq = NMIIRQ; | 137 | int irq = NMIIRQ; |
134 | u8 wdt, tmp; | 138 | u8 wdt, tmp; |
135 | 139 | ||
@@ -138,43 +142,61 @@ void watchdog_interrupt(struct pt_regs *regs, enum exception_code excep) | |||
138 | tmp = WDCTR; | 142 | tmp = WDCTR; |
139 | NMICR = NMICR_WDIF; | 143 | NMICR = NMICR_WDIF; |
140 | 144 | ||
141 | nmi_count(cpu)++; | 145 | nmi_count(smp_processor_id())++; |
142 | kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq)); | 146 | kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq)); |
143 | sum = irq_stat[cpu].__irq_count; | 147 | |
144 | 148 | for_each_online_cpu(cpu) { | |
145 | if (last_irq_sums[cpu] == sum) { | 149 | |
146 | /* | 150 | sum = irq_stat[cpu].__irq_count; |
147 | * Ayiee, looks like this CPU is stuck ... | 151 | |
148 | * wait a few IRQs (5 seconds) before doing the oops ... | 152 | if ((last_irq_sums[cpu] == sum) |
149 | */ | 153 | #if defined(CONFIG_GDBSTUB) && defined(CONFIG_SMP) |
150 | watchdog_alert_counter++; | 154 | && !(CHK_GDBSTUB_BUSY() |
151 | if (watchdog_alert_counter == 5 * watchdog_hz) { | 155 | || atomic_read(&cpu_doing_single_step)) |
152 | spin_lock(&watchdog_print_lock); | 156 | #endif |
157 | ) { | ||
153 | /* | 158 | /* |
154 | * We are in trouble anyway, lets at least try | 159 | * Ayiee, looks like this CPU is stuck ... |
155 | * to get a message out. | 160 | * wait a few IRQs (5 seconds) before doing the oops ... |
156 | */ | 161 | */ |
157 | bust_spinlocks(1); | 162 | watchdog_alert_counter[cpu]++; |
158 | printk(KERN_ERR | 163 | if (watchdog_alert_counter[cpu] == 5 * watchdog_hz) { |
159 | "NMI Watchdog detected LOCKUP on CPU%d," | 164 | spin_lock(&watchdog_print_lock); |
160 | " pc %08lx, registers:\n", | 165 | /* |
161 | cpu, regs->pc); | 166 | * We are in trouble anyway, lets at least try |
162 | show_registers(regs); | 167 | * to get a message out. |
163 | printk("console shuts up ...\n"); | 168 | */ |
164 | console_silent(); | 169 | bust_spinlocks(1); |
165 | spin_unlock(&watchdog_print_lock); | 170 | printk(KERN_ERR |
166 | bust_spinlocks(0); | 171 | "NMI Watchdog detected LOCKUP on CPU%d," |
172 | " pc %08lx, registers:\n", | ||
173 | cpu, regs->pc); | ||
174 | #ifdef CONFIG_SMP | ||
175 | printk(KERN_ERR | ||
176 | "--- Register Dump (CPU%d) ---\n", | ||
177 | CPUID); | ||
178 | #endif | ||
179 | show_registers(regs); | ||
180 | #ifdef CONFIG_SMP | ||
181 | smp_nmi_call_function(watchdog_dump_register, | ||
182 | NULL, 1); | ||
183 | #endif | ||
184 | printk(KERN_NOTICE "console shuts up ...\n"); | ||
185 | console_silent(); | ||
186 | spin_unlock(&watchdog_print_lock); | ||
187 | bust_spinlocks(0); | ||
167 | #ifdef CONFIG_GDBSTUB | 188 | #ifdef CONFIG_GDBSTUB |
168 | if (gdbstub_busy) | 189 | if (CHK_GDBSTUB_BUSY_AND_ACTIVE()) |
169 | gdbstub_exception(regs, excep); | 190 | gdbstub_exception(regs, excep); |
170 | else | 191 | else |
171 | gdbstub_intercept(regs, excep); | 192 | gdbstub_intercept(regs, excep); |
172 | #endif | 193 | #endif |
173 | do_exit(SIGSEGV); | 194 | do_exit(SIGSEGV); |
195 | } | ||
196 | } else { | ||
197 | last_irq_sums[cpu] = sum; | ||
198 | watchdog_alert_counter[cpu] = 0; | ||
174 | } | 199 | } |
175 | } else { | ||
176 | last_irq_sums[cpu] = sum; | ||
177 | watchdog_alert_counter = 0; | ||
178 | } | 200 | } |
179 | 201 | ||
180 | WDCTR = wdt | WDCTR_WDRST; | 202 | WDCTR = wdt | WDCTR_WDRST; |