diff options
| -rw-r--r-- | kernel/watchdog.c | 4 | ||||
| -rw-r--r-- | kernel/watchdog_hld.c | 88 |
2 files changed, 8 insertions, 84 deletions
diff --git a/kernel/watchdog.c b/kernel/watchdog.c index fd8a998eb197..5eb11960e4a2 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c | |||
| @@ -107,6 +107,7 @@ __setup("hardlockup_all_cpu_backtrace=", hardlockup_all_cpu_backtrace_setup); | |||
| 107 | */ | 107 | */ |
| 108 | int __weak watchdog_nmi_enable(unsigned int cpu) | 108 | int __weak watchdog_nmi_enable(unsigned int cpu) |
| 109 | { | 109 | { |
| 110 | hardlockup_detector_perf_enable(); | ||
| 110 | return 0; | 111 | return 0; |
| 111 | } | 112 | } |
| 112 | 113 | ||
| @@ -465,7 +466,8 @@ static void watchdog_enable(unsigned int cpu) | |||
| 465 | /* Initialize timestamp */ | 466 | /* Initialize timestamp */ |
| 466 | __touch_watchdog(); | 467 | __touch_watchdog(); |
| 467 | /* Enable the perf event */ | 468 | /* Enable the perf event */ |
| 468 | watchdog_nmi_enable(cpu); | 469 | if (watchdog_enabled & NMI_WATCHDOG_ENABLED) |
| 470 | watchdog_nmi_enable(cpu); | ||
| 469 | 471 | ||
| 470 | watchdog_set_prio(SCHED_FIFO, MAX_RT_PRIO - 1); | 472 | watchdog_set_prio(SCHED_FIFO, MAX_RT_PRIO - 1); |
| 471 | } | 473 | } |
diff --git a/kernel/watchdog_hld.c b/kernel/watchdog_hld.c index 99a3f22e48cc..509bb6b59c41 100644 --- a/kernel/watchdog_hld.c +++ b/kernel/watchdog_hld.c | |||
| @@ -25,7 +25,7 @@ static DEFINE_PER_CPU(struct perf_event *, dead_event); | |||
| 25 | static struct cpumask dead_events_mask; | 25 | static struct cpumask dead_events_mask; |
| 26 | 26 | ||
| 27 | static unsigned long hardlockup_allcpu_dumped; | 27 | static unsigned long hardlockup_allcpu_dumped; |
| 28 | static bool hardlockup_detector_disabled; | 28 | static unsigned int watchdog_cpus; |
| 29 | 29 | ||
| 30 | void arch_touch_nmi_watchdog(void) | 30 | void arch_touch_nmi_watchdog(void) |
| 31 | { | 31 | { |
| @@ -160,84 +160,6 @@ static void watchdog_overflow_callback(struct perf_event *event, | |||
| 160 | return; | 160 | return; |
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | /* | ||
| 164 | * People like the simple clean cpu node info on boot. | ||
| 165 | * Reduce the watchdog noise by only printing messages | ||
| 166 | * that are different from what cpu0 displayed. | ||
| 167 | */ | ||
| 168 | static unsigned long firstcpu_err; | ||
| 169 | static atomic_t watchdog_cpus; | ||
| 170 | |||
| 171 | int watchdog_nmi_enable(unsigned int cpu) | ||
| 172 | { | ||
| 173 | struct perf_event_attr *wd_attr; | ||
| 174 | struct perf_event *event = per_cpu(watchdog_ev, cpu); | ||
| 175 | int firstcpu = 0; | ||
| 176 | |||
| 177 | /* nothing to do if the hard lockup detector is disabled */ | ||
| 178 | if (!(watchdog_enabled & NMI_WATCHDOG_ENABLED)) | ||
| 179 | goto out; | ||
| 180 | |||
| 181 | /* A failure disabled the hardlockup detector permanently */ | ||
| 182 | if (hardlockup_detector_disabled) | ||
| 183 | return -ENODEV; | ||
| 184 | |||
| 185 | /* is it already setup and enabled? */ | ||
| 186 | if (event && event->state > PERF_EVENT_STATE_OFF) | ||
| 187 | goto out; | ||
| 188 | |||
| 189 | /* it is setup but not enabled */ | ||
| 190 | if (event != NULL) | ||
| 191 | goto out_enable; | ||
| 192 | |||
| 193 | if (atomic_inc_return(&watchdog_cpus) == 1) | ||
| 194 | firstcpu = 1; | ||
| 195 | |||
| 196 | wd_attr = &wd_hw_attr; | ||
| 197 | wd_attr->sample_period = hw_nmi_get_sample_period(watchdog_thresh); | ||
| 198 | |||
| 199 | /* Try to register using hardware perf events */ | ||
| 200 | event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback, NULL); | ||
| 201 | |||
| 202 | /* save the first cpu's error for future comparision */ | ||
| 203 | if (firstcpu && IS_ERR(event)) | ||
| 204 | firstcpu_err = PTR_ERR(event); | ||
| 205 | |||
| 206 | if (!IS_ERR(event)) { | ||
| 207 | /* only print for the first cpu initialized */ | ||
| 208 | if (firstcpu || firstcpu_err) | ||
| 209 | pr_info("enabled on all CPUs, permanently consumes one hw-PMU counter.\n"); | ||
| 210 | goto out_save; | ||
| 211 | } | ||
| 212 | |||
| 213 | /* skip displaying the same error again */ | ||
| 214 | if (!firstcpu && (PTR_ERR(event) == firstcpu_err)) | ||
| 215 | return PTR_ERR(event); | ||
| 216 | |||
| 217 | /* vary the KERN level based on the returned errno */ | ||
| 218 | if (PTR_ERR(event) == -EOPNOTSUPP) | ||
| 219 | pr_info("disabled (cpu%i): not supported (no LAPIC?)\n", cpu); | ||
| 220 | else if (PTR_ERR(event) == -ENOENT) | ||
| 221 | pr_warn("disabled (cpu%i): hardware events not enabled\n", | ||
| 222 | cpu); | ||
| 223 | else | ||
| 224 | pr_err("disabled (cpu%i): unable to create perf event: %ld\n", | ||
| 225 | cpu, PTR_ERR(event)); | ||
| 226 | |||
| 227 | pr_info("Disabling hard lockup detector permanently\n"); | ||
| 228 | hardlockup_detector_disabled = true; | ||
| 229 | |||
| 230 | return PTR_ERR(event); | ||
| 231 | |||
| 232 | /* success path */ | ||
| 233 | out_save: | ||
| 234 | per_cpu(watchdog_ev, cpu) = event; | ||
| 235 | out_enable: | ||
| 236 | perf_event_enable(per_cpu(watchdog_ev, cpu)); | ||
| 237 | out: | ||
| 238 | return 0; | ||
| 239 | } | ||
| 240 | |||
| 241 | static int hardlockup_detector_event_create(void) | 163 | static int hardlockup_detector_event_create(void) |
| 242 | { | 164 | { |
| 243 | unsigned int cpu = smp_processor_id(); | 165 | unsigned int cpu = smp_processor_id(); |
| @@ -267,6 +189,9 @@ void hardlockup_detector_perf_enable(void) | |||
| 267 | if (hardlockup_detector_event_create()) | 189 | if (hardlockup_detector_event_create()) |
| 268 | return; | 190 | return; |
| 269 | 191 | ||
| 192 | if (!watchdog_cpus++) | ||
| 193 | pr_info("Enabled. Permanently consumes one hw-PMU counter.\n"); | ||
| 194 | |||
| 270 | perf_event_enable(this_cpu_read(watchdog_ev)); | 195 | perf_event_enable(this_cpu_read(watchdog_ev)); |
| 271 | } | 196 | } |
| 272 | 197 | ||
| @@ -282,10 +207,7 @@ void hardlockup_detector_perf_disable(void) | |||
| 282 | this_cpu_write(watchdog_ev, NULL); | 207 | this_cpu_write(watchdog_ev, NULL); |
| 283 | this_cpu_write(dead_event, event); | 208 | this_cpu_write(dead_event, event); |
| 284 | cpumask_set_cpu(smp_processor_id(), &dead_events_mask); | 209 | cpumask_set_cpu(smp_processor_id(), &dead_events_mask); |
| 285 | 210 | watchdog_cpus--; | |
| 286 | /* watchdog_nmi_enable() expects this to be zero initially. */ | ||
| 287 | if (atomic_dec_and_test(&watchdog_cpus)) | ||
| 288 | firstcpu_err = 0; | ||
| 289 | } | 211 | } |
| 290 | } | 212 | } |
| 291 | 213 | ||
