aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/smp.c1
-rw-r--r--include/linux/hrtimer.h25
-rw-r--r--kernel/hrtimer.c80
3 files changed, 106 insertions, 0 deletions
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c
index e83f79de863c..a93528bc16e9 100644
--- a/arch/x86/kernel/smp.c
+++ b/arch/x86/kernel/smp.c
@@ -246,6 +246,7 @@ void smp_pull_timers_interrupt(struct pt_regs *regs)
246{ 246{
247 ack_APIC_irq(); 247 ack_APIC_irq();
248 TRACE("pull timer interrupt\n"); 248 TRACE("pull timer interrupt\n");
249 hrtimer_pull();
249} 250}
250 251
251struct smp_ops smp_ops = { 252struct smp_ops smp_ops = {
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index ff037f0b1b4e..b984b947f5db 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -166,6 +166,7 @@ struct hrtimer_clock_base {
166 * event devices whether high resolution mode can be 166 * event devices whether high resolution mode can be
167 * activated. 167 * activated.
168 * @nr_events: Total number of timer interrupt events 168 * @nr_events: Total number of timer interrupt events
169 * @to_pull: LITMUS^RT list of timers to be pulled on this cpu
169 */ 170 */
170struct hrtimer_cpu_base { 171struct hrtimer_cpu_base {
171 spinlock_t lock; 172 spinlock_t lock;
@@ -175,6 +176,26 @@ struct hrtimer_cpu_base {
175 int hres_active; 176 int hres_active;
176 unsigned long nr_events; 177 unsigned long nr_events;
177#endif 178#endif
179 struct list_head to_pull;
180};
181
182#define HRTIMER_START_ON_INACTIVE 0
183#define HRTIMER_START_ON_QUEUED 1
184
185/*
186 * struct hrtimer_start_on_info - save timer info on remote cpu
187 * @list: list of hrtimer_start_on_info on remote cpu (to_pull)
188 * @timer: timer to be triggered on remote cpu
189 * @time: time event
190 * @mode: timer mode
191 * @state: activity flag
192 */
193struct hrtimer_start_on_info {
194 struct list_head list;
195 struct hrtimer *timer;
196 ktime_t time;
197 enum hrtimer_mode mode;
198 atomic_t state;
178}; 199};
179 200
180static inline void hrtimer_set_expires(struct hrtimer *timer, ktime_t time) 201static inline void hrtimer_set_expires(struct hrtimer *timer, ktime_t time)
@@ -343,6 +364,10 @@ __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
343 unsigned long delta_ns, 364 unsigned long delta_ns,
344 const enum hrtimer_mode mode, int wakeup); 365 const enum hrtimer_mode mode, int wakeup);
345 366
367extern int hrtimer_start_on(int cpu, struct hrtimer_start_on_info *info,
368 struct hrtimer *timer, ktime_t time,
369 const enum hrtimer_mode mode);
370
346extern int hrtimer_cancel(struct hrtimer *timer); 371extern int hrtimer_cancel(struct hrtimer *timer);
347extern int hrtimer_try_to_cancel(struct hrtimer *timer); 372extern int hrtimer_try_to_cancel(struct hrtimer *timer);
348 373
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 3e1c36e7998f..509ecaea3016 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -46,6 +46,8 @@
46#include <linux/sched.h> 46#include <linux/sched.h>
47#include <linux/timer.h> 47#include <linux/timer.h>
48 48
49#include <litmus/litmus.h>
50
49#include <asm/uaccess.h> 51#include <asm/uaccess.h>
50 52
51#include <trace/events/timer.h> 53#include <trace/events/timer.h>
@@ -1016,6 +1018,83 @@ hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
1016} 1018}
1017EXPORT_SYMBOL_GPL(hrtimer_start); 1019EXPORT_SYMBOL_GPL(hrtimer_start);
1018 1020
1021/**
1022 * hrtimer_pull - PULL_TIMERS_VECTOR callback on remote cpu
1023 */
1024void hrtimer_pull(void)
1025{
1026 struct hrtimer_cpu_base *base = &__get_cpu_var(hrtimer_bases);
1027 struct hrtimer_start_on_info *info;
1028 struct list_head *pos, *safe, list;
1029
1030 spin_lock(&base->lock);
1031 list_replace_init(&base->to_pull, &list);
1032 spin_unlock(&base->lock);
1033
1034 list_for_each_safe(pos, safe, &list) {
1035 info = list_entry(pos, struct hrtimer_start_on_info, list);
1036 TRACE("pulled timer 0x%x\n", info->timer);
1037 list_del(pos);
1038 hrtimer_start(info->timer, info->time, info->mode);
1039 }
1040}
1041
1042/**
1043 * hrtimer_start_on - trigger timer arming on remote cpu
1044 * @cpu: remote cpu
1045 * @info: save timer information for enqueuing on remote cpu
1046 * @timer: timer to be pulled
1047 * @time: expire time
1048 * @mode: timer mode
1049 */
1050int hrtimer_start_on(int cpu, struct hrtimer_start_on_info* info,
1051 struct hrtimer *timer, ktime_t time,
1052 const enum hrtimer_mode mode)
1053{
1054 unsigned long flags;
1055 struct hrtimer_cpu_base* base;
1056 int in_use = 0, was_empty;
1057
1058 /* serialize access to info through the timer base */
1059 lock_hrtimer_base(timer, &flags);
1060
1061 in_use = (atomic_read(&info->state) != HRTIMER_START_ON_INACTIVE);
1062 if (!in_use) {
1063 INIT_LIST_HEAD(&info->list);
1064 info->timer = timer;
1065 info->time = time;
1066 info->mode = mode;
1067 /* mark as in use */
1068 atomic_set(&info->state, HRTIMER_START_ON_QUEUED);
1069 }
1070
1071 unlock_hrtimer_base(timer, &flags);
1072
1073 if (!in_use) {
1074 /* initiate pull */
1075 preempt_disable();
1076 if (cpu == smp_processor_id()) {
1077 /* start timer locally; we may get called
1078 * with rq->lock held, do not wake up anything
1079 */
1080 __hrtimer_start_range_ns(info->timer, info->time,
1081 0, info->mode, 0);
1082 } else {
1083 base = &per_cpu(hrtimer_bases, cpu);
1084 spin_lock_irqsave(&base->lock, flags);
1085 was_empty = list_empty(&base->to_pull);
1086 list_add(&info->list, &base->to_pull);
1087 spin_unlock_irqrestore(&base->lock, flags);
1088 if (was_empty)
1089 /* only send IPI if other no else
1090 * has done so already
1091 */
1092 smp_send_pull_timers(cpu);
1093 }
1094 preempt_enable();
1095 }
1096 return in_use;
1097}
1019 1098
1020/** 1099/**
1021 * hrtimer_try_to_cancel - try to deactivate a timer 1100 * hrtimer_try_to_cancel - try to deactivate a timer
@@ -1597,6 +1676,7 @@ static void __cpuinit init_hrtimers_cpu(int cpu)
1597 cpu_base->clock_base[i].cpu_base = cpu_base; 1676 cpu_base->clock_base[i].cpu_base = cpu_base;
1598 1677
1599 hrtimer_init_hres(cpu_base); 1678 hrtimer_init_hres(cpu_base);
1679 INIT_LIST_HEAD(&cpu_base->to_pull);
1600} 1680}
1601 1681
1602#ifdef CONFIG_HOTPLUG_CPU 1682#ifdef CONFIG_HOTPLUG_CPU