| From f03bec54ce456245669247c5cba3d38a2e672397 Mon Sep 17 00:00:00 2001 |
| From: Thomas Gleixner <tglx@linutronix.de> |
| Date: Mon, 13 Dec 2010 16:33:39 +0100 |
| Subject: [PATCH] x86: Convert mce timer to hrtimer |
| |
| mce_timer is started in atomic contexts of cpu bringup. This results |
| in might_sleep() warnings on RT. Convert mce_timer to a hrtimer to |
| avoid this. |
| |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| fold in: |
| |From: Mike Galbraith <bitbucket@online.de> |
| |Date: Wed, 29 May 2013 13:52:13 +0200 |
| |Subject: [PATCH] x86/mce: fix mce timer interval |
| | |
| |Seems mce timer fire at the wrong frequency in -rt kernels since roughly |
| |forever due to 32 bit overflow. 3.8-rt is also missing a multiplier. |
| | |
| |Add missing us -> ns conversion and 32 bit overflow prevention. |
| | |
| |Signed-off-by: Mike Galbraith <bitbucket@online.de> |
| |[bigeasy: use ULL instead of u64 cast] |
| |Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| |
| diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c |
| index 5abd4bf73d6e..f3bfda36b5dd 100644 |
| --- a/arch/x86/kernel/cpu/mcheck/mce.c |
| +++ b/arch/x86/kernel/cpu/mcheck/mce.c |
| @@ -42,6 +42,7 @@ |
| #include <linux/debugfs.h> |
| #include <linux/irq_work.h> |
| #include <linux/export.h> |
| +#include <linux/jiffies.h> |
| #include <linux/jump_label.h> |
| |
| #include <asm/intel-family.h> |
| @@ -1308,7 +1309,7 @@ int memory_failure(unsigned long pfn, int vector, int flags) |
| static unsigned long check_interval = INITIAL_CHECK_INTERVAL; |
| |
| static DEFINE_PER_CPU(unsigned long, mce_next_interval); /* in jiffies */ |
| -static DEFINE_PER_CPU(struct timer_list, mce_timer); |
| +static DEFINE_PER_CPU(struct hrtimer, mce_timer); |
| |
| static unsigned long mce_adjust_timer_default(unsigned long interval) |
| { |
| @@ -1317,27 +1318,19 @@ static unsigned long mce_adjust_timer_default(unsigned long interval) |
| |
| static unsigned long (*mce_adjust_timer)(unsigned long interval) = mce_adjust_timer_default; |
| |
| -static void __start_timer(struct timer_list *t, unsigned long interval) |
| +static void __start_timer(struct hrtimer *t, unsigned long iv) |
| { |
| - unsigned long when = jiffies + interval; |
| - unsigned long flags; |
| - |
| - local_irq_save(flags); |
| - |
| - if (!timer_pending(t) || time_before(when, t->expires)) |
| - mod_timer(t, round_jiffies(when)); |
| + if (!iv) |
| + return; |
| |
| - local_irq_restore(flags); |
| + hrtimer_start_range_ns(t, ns_to_ktime(jiffies_to_usecs(iv) * 1000ULL), |
| + 0, HRTIMER_MODE_REL_PINNED); |
| } |
| |
| -static void mce_timer_fn(unsigned long data) |
| +static enum hrtimer_restart mce_timer_fn(struct hrtimer *timer) |
| { |
| - struct timer_list *t = this_cpu_ptr(&mce_timer); |
| - int cpu = smp_processor_id(); |
| unsigned long iv; |
| |
| - WARN_ON(cpu != data); |
| - |
| iv = __this_cpu_read(mce_next_interval); |
| |
| if (mce_available(this_cpu_ptr(&cpu_info))) { |
| @@ -1360,7 +1353,11 @@ static void mce_timer_fn(unsigned long data) |
| |
| done: |
| __this_cpu_write(mce_next_interval, iv); |
| - __start_timer(t, iv); |
| + if (!iv) |
| + return HRTIMER_NORESTART; |
| + |
| + hrtimer_forward_now(timer, ns_to_ktime(jiffies_to_nsecs(iv))); |
| + return HRTIMER_RESTART; |
| } |
| |
| /* |
| @@ -1368,7 +1365,7 @@ static void mce_timer_fn(unsigned long data) |
| */ |
| void mce_timer_kick(unsigned long interval) |
| { |
| - struct timer_list *t = this_cpu_ptr(&mce_timer); |
| + struct hrtimer *t = this_cpu_ptr(&mce_timer); |
| unsigned long iv = __this_cpu_read(mce_next_interval); |
| |
| __start_timer(t, interval); |
| @@ -1383,7 +1380,7 @@ static void mce_timer_delete_all(void) |
| int cpu; |
| |
| for_each_online_cpu(cpu) |
| - del_timer_sync(&per_cpu(mce_timer, cpu)); |
| + hrtimer_cancel(&per_cpu(mce_timer, cpu)); |
| } |
| |
| /* |
| @@ -1712,7 +1709,7 @@ static void __mcheck_cpu_clear_vendor(struct cpuinfo_x86 *c) |
| } |
| } |
| |
| -static void mce_start_timer(struct timer_list *t) |
| +static void mce_start_timer(struct hrtimer *t) |
| { |
| unsigned long iv = check_interval * HZ; |
| |
| @@ -1725,18 +1722,19 @@ static void mce_start_timer(struct timer_list *t) |
| |
| static void __mcheck_cpu_setup_timer(void) |
| { |
| - struct timer_list *t = this_cpu_ptr(&mce_timer); |
| - unsigned int cpu = smp_processor_id(); |
| + struct hrtimer *t = this_cpu_ptr(&mce_timer); |
| |
| - setup_pinned_timer(t, mce_timer_fn, cpu); |
| + hrtimer_init(t, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
| + t->function = mce_timer_fn; |
| } |
| |
| static void __mcheck_cpu_init_timer(void) |
| { |
| - struct timer_list *t = this_cpu_ptr(&mce_timer); |
| - unsigned int cpu = smp_processor_id(); |
| + struct hrtimer *t = this_cpu_ptr(&mce_timer); |
| + |
| + hrtimer_init(t, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
| + t->function = mce_timer_fn; |
| |
| - setup_pinned_timer(t, mce_timer_fn, cpu); |
| mce_start_timer(t); |
| } |
| |
| @@ -2231,7 +2229,7 @@ static int mce_cpu_dead(unsigned int cpu) |
| |
| static int mce_cpu_online(unsigned int cpu) |
| { |
| - struct timer_list *t = this_cpu_ptr(&mce_timer); |
| + struct hrtimer *t = this_cpu_ptr(&mce_timer); |
| int ret; |
| |
| mce_device_create(cpu); |
| @@ -2248,10 +2246,10 @@ static int mce_cpu_online(unsigned int cpu) |
| |
| static int mce_cpu_pre_down(unsigned int cpu) |
| { |
| - struct timer_list *t = this_cpu_ptr(&mce_timer); |
| + struct hrtimer *t = this_cpu_ptr(&mce_timer); |
| |
| mce_disable_cpu(); |
| - del_timer_sync(t); |
| + hrtimer_cancel(t); |
| mce_threshold_remove_device(cpu); |
| mce_device_remove(cpu); |
| return 0; |
| -- |
| 2.1.4 |
| |