aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/softlockup.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/softlockup.c')
-rw-r--r--kernel/softlockup.c54
1 files changed, 33 insertions, 21 deletions
diff --git a/kernel/softlockup.c b/kernel/softlockup.c
index 708d4882c0c..edeeef3a6a3 100644
--- a/kernel/softlockup.c
+++ b/kernel/softlockup.c
@@ -15,13 +15,16 @@
15#include <linux/notifier.h> 15#include <linux/notifier.h>
16#include <linux/module.h> 16#include <linux/module.h>
17 17
18#include <asm/irq_regs.h>
19
18static DEFINE_SPINLOCK(print_lock); 20static DEFINE_SPINLOCK(print_lock);
19 21
20static DEFINE_PER_CPU(unsigned long, touch_timestamp); 22static DEFINE_PER_CPU(unsigned long, touch_timestamp);
21static DEFINE_PER_CPU(unsigned long, print_timestamp); 23static DEFINE_PER_CPU(unsigned long, print_timestamp);
22static DEFINE_PER_CPU(struct task_struct *, watchdog_task); 24static DEFINE_PER_CPU(struct task_struct *, watchdog_task);
23 25
24static int did_panic = 0; 26static int did_panic;
27int softlockup_thresh = 10;
25 28
26static int 29static int
27softlock_panic(struct notifier_block *this, unsigned long event, void *ptr) 30softlock_panic(struct notifier_block *this, unsigned long event, void *ptr)
@@ -40,14 +43,16 @@ static struct notifier_block panic_block = {
40 * resolution, and we don't need to waste time with a big divide when 43 * resolution, and we don't need to waste time with a big divide when
41 * 2^30ns == 1.074s. 44 * 2^30ns == 1.074s.
42 */ 45 */
43static unsigned long get_timestamp(void) 46static unsigned long get_timestamp(int this_cpu)
44{ 47{
45 return sched_clock() >> 30; /* 2^30 ~= 10^9 */ 48 return cpu_clock(this_cpu) >> 30; /* 2^30 ~= 10^9 */
46} 49}
47 50
48void touch_softlockup_watchdog(void) 51void touch_softlockup_watchdog(void)
49{ 52{
50 __raw_get_cpu_var(touch_timestamp) = get_timestamp(); 53 int this_cpu = raw_smp_processor_id();
54
55 __raw_get_cpu_var(touch_timestamp) = get_timestamp(this_cpu);
51} 56}
52EXPORT_SYMBOL(touch_softlockup_watchdog); 57EXPORT_SYMBOL(touch_softlockup_watchdog);
53 58
@@ -70,6 +75,7 @@ void softlockup_tick(void)
70 int this_cpu = smp_processor_id(); 75 int this_cpu = smp_processor_id();
71 unsigned long touch_timestamp = per_cpu(touch_timestamp, this_cpu); 76 unsigned long touch_timestamp = per_cpu(touch_timestamp, this_cpu);
72 unsigned long print_timestamp; 77 unsigned long print_timestamp;
78 struct pt_regs *regs = get_irq_regs();
73 unsigned long now; 79 unsigned long now;
74 80
75 if (touch_timestamp == 0) { 81 if (touch_timestamp == 0) {
@@ -80,10 +86,11 @@ void softlockup_tick(void)
80 print_timestamp = per_cpu(print_timestamp, this_cpu); 86 print_timestamp = per_cpu(print_timestamp, this_cpu);
81 87
82 /* report at most once a second */ 88 /* report at most once a second */
83 if (print_timestamp < (touch_timestamp + 1) || 89 if ((print_timestamp >= touch_timestamp &&
84 did_panic || 90 print_timestamp < (touch_timestamp + 1)) ||
85 !per_cpu(watchdog_task, this_cpu)) 91 did_panic || !per_cpu(watchdog_task, this_cpu)) {
86 return; 92 return;
93 }
87 94
88 /* do not print during early bootup: */ 95 /* do not print during early bootup: */
89 if (unlikely(system_state != SYSTEM_RUNNING)) { 96 if (unlikely(system_state != SYSTEM_RUNNING)) {
@@ -91,28 +98,33 @@ void softlockup_tick(void)
91 return; 98 return;
92 } 99 }
93 100
94 now = get_timestamp(); 101 now = get_timestamp(this_cpu);
95 102
96 /* Wake up the high-prio watchdog task every second: */ 103 /* Wake up the high-prio watchdog task every second: */
97 if (now > (touch_timestamp + 1)) 104 if (now > (touch_timestamp + 1))
98 wake_up_process(per_cpu(watchdog_task, this_cpu)); 105 wake_up_process(per_cpu(watchdog_task, this_cpu));
99 106
100 /* Warn about unreasonable 10+ seconds delays: */ 107 /* Warn about unreasonable 10+ seconds delays: */
101 if (now > (touch_timestamp + 10)) { 108 if (now <= (touch_timestamp + softlockup_thresh))
102 per_cpu(print_timestamp, this_cpu) = touch_timestamp; 109 return;
103 110
104 spin_lock(&print_lock); 111 per_cpu(print_timestamp, this_cpu) = touch_timestamp;
105 printk(KERN_ERR "BUG: soft lockup detected on CPU#%d!\n", 112
106 this_cpu); 113 spin_lock(&print_lock);
114 printk(KERN_ERR "BUG: soft lockup - CPU#%d stuck for %lus! [%s:%d]\n",
115 this_cpu, now - touch_timestamp,
116 current->comm, current->pid);
117 if (regs)
118 show_regs(regs);
119 else
107 dump_stack(); 120 dump_stack();
108 spin_unlock(&print_lock); 121 spin_unlock(&print_lock);
109 }
110} 122}
111 123
112/* 124/*
113 * The watchdog thread - runs every second and touches the timestamp. 125 * The watchdog thread - runs every second and touches the timestamp.
114 */ 126 */
115static int watchdog(void * __bind_cpu) 127static int watchdog(void *__bind_cpu)
116{ 128{
117 struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; 129 struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
118 130
@@ -150,13 +162,13 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
150 BUG_ON(per_cpu(watchdog_task, hotcpu)); 162 BUG_ON(per_cpu(watchdog_task, hotcpu));
151 p = kthread_create(watchdog, hcpu, "watchdog/%d", hotcpu); 163 p = kthread_create(watchdog, hcpu, "watchdog/%d", hotcpu);
152 if (IS_ERR(p)) { 164 if (IS_ERR(p)) {
153 printk("watchdog for %i failed\n", hotcpu); 165 printk(KERN_ERR "watchdog for %i failed\n", hotcpu);
154 return NOTIFY_BAD; 166 return NOTIFY_BAD;
155 } 167 }
156 per_cpu(touch_timestamp, hotcpu) = 0; 168 per_cpu(touch_timestamp, hotcpu) = 0;
157 per_cpu(watchdog_task, hotcpu) = p; 169 per_cpu(watchdog_task, hotcpu) = p;
158 kthread_bind(p, hotcpu); 170 kthread_bind(p, hotcpu);
159 break; 171 break;
160 case CPU_ONLINE: 172 case CPU_ONLINE:
161 case CPU_ONLINE_FROZEN: 173 case CPU_ONLINE_FROZEN:
162 wake_up_process(per_cpu(watchdog_task, hotcpu)); 174 wake_up_process(per_cpu(watchdog_task, hotcpu));
@@ -176,7 +188,7 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
176 kthread_stop(p); 188 kthread_stop(p);
177 break; 189 break;
178#endif /* CONFIG_HOTPLUG_CPU */ 190#endif /* CONFIG_HOTPLUG_CPU */
179 } 191 }
180 return NOTIFY_OK; 192 return NOTIFY_OK;
181} 193}
182 194