aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/hrtimer.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/hrtimer.c')
-rw-r--r--kernel/hrtimer.c34
1 files changed, 30 insertions, 4 deletions
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index f78777abe769..dea4c9124ac8 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -590,7 +590,6 @@ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
590 list_add_tail(&timer->cb_entry, 590 list_add_tail(&timer->cb_entry,
591 &base->cpu_base->cb_pending); 591 &base->cpu_base->cb_pending);
592 timer->state = HRTIMER_STATE_PENDING; 592 timer->state = HRTIMER_STATE_PENDING;
593 raise_softirq(HRTIMER_SOFTIRQ);
594 return 1; 593 return 1;
595 default: 594 default:
596 BUG(); 595 BUG();
@@ -633,6 +632,11 @@ static int hrtimer_switch_to_hres(void)
633 return 1; 632 return 1;
634} 633}
635 634
635static inline void hrtimer_raise_softirq(void)
636{
637 raise_softirq(HRTIMER_SOFTIRQ);
638}
639
636#else 640#else
637 641
638static inline int hrtimer_hres_active(void) { return 0; } 642static inline int hrtimer_hres_active(void) { return 0; }
@@ -651,6 +655,7 @@ static inline int hrtimer_reprogram(struct hrtimer *timer,
651{ 655{
652 return 0; 656 return 0;
653} 657}
658static inline void hrtimer_raise_softirq(void) { }
654 659
655#endif /* CONFIG_HIGH_RES_TIMERS */ 660#endif /* CONFIG_HIGH_RES_TIMERS */
656 661
@@ -850,7 +855,7 @@ hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
850{ 855{
851 struct hrtimer_clock_base *base, *new_base; 856 struct hrtimer_clock_base *base, *new_base;
852 unsigned long flags; 857 unsigned long flags;
853 int ret; 858 int ret, raise;
854 859
855 base = lock_hrtimer_base(timer, &flags); 860 base = lock_hrtimer_base(timer, &flags);
856 861
@@ -884,8 +889,18 @@ hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
884 enqueue_hrtimer(timer, new_base, 889 enqueue_hrtimer(timer, new_base,
885 new_base->cpu_base == &__get_cpu_var(hrtimer_bases)); 890 new_base->cpu_base == &__get_cpu_var(hrtimer_bases));
886 891
892 /*
893 * The timer may be expired and moved to the cb_pending
894 * list. We can not raise the softirq with base lock held due
895 * to a possible deadlock with runqueue lock.
896 */
897 raise = timer->state == HRTIMER_STATE_PENDING;
898
887 unlock_hrtimer_base(timer, &flags); 899 unlock_hrtimer_base(timer, &flags);
888 900
901 if (raise)
902 hrtimer_raise_softirq();
903
889 return ret; 904 return ret;
890} 905}
891EXPORT_SYMBOL_GPL(hrtimer_start); 906EXPORT_SYMBOL_GPL(hrtimer_start);
@@ -1080,8 +1095,19 @@ static void run_hrtimer_pending(struct hrtimer_cpu_base *cpu_base)
1080 * If the timer was rearmed on another CPU, reprogram 1095 * If the timer was rearmed on another CPU, reprogram
1081 * the event device. 1096 * the event device.
1082 */ 1097 */
1083 if (timer->base->first == &timer->node) 1098 struct hrtimer_clock_base *base = timer->base;
1084 hrtimer_reprogram(timer, timer->base); 1099
1100 if (base->first == &timer->node &&
1101 hrtimer_reprogram(timer, base)) {
1102 /*
1103 * Timer is expired. Thus move it from tree to
1104 * pending list again.
1105 */
1106 __remove_hrtimer(timer, base,
1107 HRTIMER_STATE_PENDING, 0);
1108 list_add_tail(&timer->cb_entry,
1109 &base->cpu_base->cb_pending);
1110 }
1085 } 1111 }
1086 } 1112 }
1087 spin_unlock_irq(&cpu_base->lock); 1113 spin_unlock_irq(&cpu_base->lock);