diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-05-03 11:31:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-05-03 11:31:45 -0400 |
commit | 98facf0e1ee3d2db313863a283e499ed1c0b5b79 (patch) | |
tree | 909bb560a9100ebbc7b7b0e34f47a1357be1ac67 | |
parent | 00622e61eda46c7f8833afbee6bd34449a9a4e7e (diff) | |
parent | 98a01e779f3c66b0b11cd7e64d531c0e41c95762 (diff) |
Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer fixes from Thomas Gleixner:
"This update brings along:
- Two fixes for long standing bugs in the hrtimer code, one which
prevents remote enqueuing and the other preventing arbitrary delays
after a interrupt hang was detected
- A fix in the timer wheel which prevents math overflow
- A fix for a long standing issue with the architected ARM timer
related to the C3STOP mechanism.
- A trivial compile fix for nspire SoC clocksource"
* 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
timer: Prevent overflow in apply_slack
hrtimer: Prevent remote enqueue of leftmost timers
hrtimer: Prevent all reprogramming if hang detected
clocksource: nspire: Fix compiler warning
clocksource: arch_arm_timer: Fix age-old arch timer C3STOP detection issue
-rw-r--r-- | Documentation/devicetree/bindings/arm/arch_timer.txt | 3 | ||||
-rw-r--r-- | drivers/clocksource/arm_arch_timer.c | 6 | ||||
-rw-r--r-- | drivers/clocksource/zevio-timer.c | 7 | ||||
-rw-r--r-- | kernel/hrtimer.c | 22 | ||||
-rw-r--r-- | kernel/timer.c | 2 |
5 files changed, 37 insertions, 3 deletions
diff --git a/Documentation/devicetree/bindings/arm/arch_timer.txt b/Documentation/devicetree/bindings/arm/arch_timer.txt index 06fc7602593a..37b2cafa4e52 100644 --- a/Documentation/devicetree/bindings/arm/arch_timer.txt +++ b/Documentation/devicetree/bindings/arm/arch_timer.txt | |||
@@ -19,6 +19,9 @@ to deliver its interrupts via SPIs. | |||
19 | 19 | ||
20 | - clock-frequency : The frequency of the main counter, in Hz. Optional. | 20 | - clock-frequency : The frequency of the main counter, in Hz. Optional. |
21 | 21 | ||
22 | - always-on : a boolean property. If present, the timer is powered through an | ||
23 | always-on power domain, therefore it never loses context. | ||
24 | |||
22 | Example: | 25 | Example: |
23 | 26 | ||
24 | timer { | 27 | timer { |
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 57e823c44d2a..5163ec13429d 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c | |||
@@ -66,6 +66,7 @@ static int arch_timer_ppi[MAX_TIMER_PPI]; | |||
66 | static struct clock_event_device __percpu *arch_timer_evt; | 66 | static struct clock_event_device __percpu *arch_timer_evt; |
67 | 67 | ||
68 | static bool arch_timer_use_virtual = true; | 68 | static bool arch_timer_use_virtual = true; |
69 | static bool arch_timer_c3stop; | ||
69 | static bool arch_timer_mem_use_virtual; | 70 | static bool arch_timer_mem_use_virtual; |
70 | 71 | ||
71 | /* | 72 | /* |
@@ -263,7 +264,8 @@ static void __arch_timer_setup(unsigned type, | |||
263 | clk->features = CLOCK_EVT_FEAT_ONESHOT; | 264 | clk->features = CLOCK_EVT_FEAT_ONESHOT; |
264 | 265 | ||
265 | if (type == ARCH_CP15_TIMER) { | 266 | if (type == ARCH_CP15_TIMER) { |
266 | clk->features |= CLOCK_EVT_FEAT_C3STOP; | 267 | if (arch_timer_c3stop) |
268 | clk->features |= CLOCK_EVT_FEAT_C3STOP; | ||
267 | clk->name = "arch_sys_timer"; | 269 | clk->name = "arch_sys_timer"; |
268 | clk->rating = 450; | 270 | clk->rating = 450; |
269 | clk->cpumask = cpumask_of(smp_processor_id()); | 271 | clk->cpumask = cpumask_of(smp_processor_id()); |
@@ -665,6 +667,8 @@ static void __init arch_timer_init(struct device_node *np) | |||
665 | } | 667 | } |
666 | } | 668 | } |
667 | 669 | ||
670 | arch_timer_c3stop = !of_property_read_bool(np, "always-on"); | ||
671 | |||
668 | arch_timer_register(); | 672 | arch_timer_register(); |
669 | arch_timer_common_init(); | 673 | arch_timer_common_init(); |
670 | } | 674 | } |
diff --git a/drivers/clocksource/zevio-timer.c b/drivers/clocksource/zevio-timer.c index ca81809d159d..7ce442148c3f 100644 --- a/drivers/clocksource/zevio-timer.c +++ b/drivers/clocksource/zevio-timer.c | |||
@@ -212,4 +212,9 @@ error_free: | |||
212 | return ret; | 212 | return ret; |
213 | } | 213 | } |
214 | 214 | ||
215 | CLOCKSOURCE_OF_DECLARE(zevio_timer, "lsi,zevio-timer", zevio_timer_add); | 215 | static void __init zevio_timer_init(struct device_node *node) |
216 | { | ||
217 | BUG_ON(zevio_timer_add(node)); | ||
218 | } | ||
219 | |||
220 | CLOCKSOURCE_OF_DECLARE(zevio_timer, "lsi,zevio-timer", zevio_timer_init); | ||
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index d55092ceee29..6b715c0af1b1 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c | |||
@@ -234,6 +234,11 @@ again: | |||
234 | goto again; | 234 | goto again; |
235 | } | 235 | } |
236 | timer->base = new_base; | 236 | timer->base = new_base; |
237 | } else { | ||
238 | if (cpu != this_cpu && hrtimer_check_target(timer, new_base)) { | ||
239 | cpu = this_cpu; | ||
240 | goto again; | ||
241 | } | ||
237 | } | 242 | } |
238 | return new_base; | 243 | return new_base; |
239 | } | 244 | } |
@@ -569,6 +574,23 @@ hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base, int skip_equal) | |||
569 | 574 | ||
570 | cpu_base->expires_next.tv64 = expires_next.tv64; | 575 | cpu_base->expires_next.tv64 = expires_next.tv64; |
571 | 576 | ||
577 | /* | ||
578 | * If a hang was detected in the last timer interrupt then we | ||
579 | * leave the hang delay active in the hardware. We want the | ||
580 | * system to make progress. That also prevents the following | ||
581 | * scenario: | ||
582 | * T1 expires 50ms from now | ||
583 | * T2 expires 5s from now | ||
584 | * | ||
585 | * T1 is removed, so this code is called and would reprogram | ||
586 | * the hardware to 5s from now. Any hrtimer_start after that | ||
587 | * will not reprogram the hardware due to hang_detected being | ||
588 | * set. So we'd effectivly block all timers until the T2 event | ||
589 | * fires. | ||
590 | */ | ||
591 | if (cpu_base->hang_detected) | ||
592 | return; | ||
593 | |||
572 | if (cpu_base->expires_next.tv64 != KTIME_MAX) | 594 | if (cpu_base->expires_next.tv64 != KTIME_MAX) |
573 | tick_program_event(cpu_base->expires_next, 1); | 595 | tick_program_event(cpu_base->expires_next, 1); |
574 | } | 596 | } |
diff --git a/kernel/timer.c b/kernel/timer.c index 87bd529879c2..3bb01a323b2a 100644 --- a/kernel/timer.c +++ b/kernel/timer.c | |||
@@ -838,7 +838,7 @@ unsigned long apply_slack(struct timer_list *timer, unsigned long expires) | |||
838 | 838 | ||
839 | bit = find_last_bit(&mask, BITS_PER_LONG); | 839 | bit = find_last_bit(&mask, BITS_PER_LONG); |
840 | 840 | ||
841 | mask = (1 << bit) - 1; | 841 | mask = (1UL << bit) - 1; |
842 | 842 | ||
843 | expires_limit = expires_limit & ~(mask); | 843 | expires_limit = expires_limit & ~(mask); |
844 | 844 | ||