aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorFelipe Cerqueira <felipec@mpi-sws.org>2013-02-11 10:36:35 -0500
committerBjoern Brandenburg <bbb@mpi-sws.org>2013-08-07 03:46:43 -0400
commit25d4d1addba5f45d534682cc446e3157500d873e (patch)
tree5be6efbae27a4f93185b49aa2b0d3402e8f41454 /kernel
parent49fa66f74b78c9b08d2ba038db409b5bbde11fab (diff)
Add hrtimer_start_on() support
This patch adds hrtimer_start_on(), which allows arming timers on remote CPUs. This is needed to avoided timer interrupts on "shielded" CPUs and is also useful for implementing semi-partitioned schedulers.
Diffstat (limited to 'kernel')
-rw-r--r--kernel/hrtimer.c95
1 files changed, 95 insertions, 0 deletions
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 2288fbdada16..c7f0c79b2cb5 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -48,6 +48,8 @@
48#include <linux/sched/rt.h> 48#include <linux/sched/rt.h>
49#include <linux/timer.h> 49#include <linux/timer.h>
50 50
51#include <litmus/debug_trace.h>
52
51#include <asm/uaccess.h> 53#include <asm/uaccess.h>
52 54
53#include <trace/events/timer.h> 55#include <trace/events/timer.h>
@@ -1064,6 +1066,98 @@ hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
1064} 1066}
1065EXPORT_SYMBOL_GPL(hrtimer_start); 1067EXPORT_SYMBOL_GPL(hrtimer_start);
1066 1068
1069#if defined(CONFIG_ARCH_HAS_SEND_PULL_TIMERS) && defined(CONFIG_SMP)
1070
1071/**
1072 * hrtimer_start_on_info_init - Initialize hrtimer_start_on_info
1073 */
1074void hrtimer_start_on_info_init(struct hrtimer_start_on_info *info)
1075{
1076 memset(info, 0, sizeof(struct hrtimer_start_on_info));
1077 atomic_set(&info->state, HRTIMER_START_ON_INACTIVE);
1078}
1079
1080/**
1081 * hrtimer_pull - PULL_TIMERS_VECTOR callback on remote cpu
1082 */
1083void hrtimer_pull(void)
1084{
1085 struct hrtimer_cpu_base *base = &__get_cpu_var(hrtimer_bases);
1086 struct hrtimer_start_on_info *info;
1087 struct list_head *pos, *safe, list;
1088
1089 raw_spin_lock(&base->lock);
1090 list_replace_init(&base->to_pull, &list);
1091 raw_spin_unlock(&base->lock);
1092
1093 list_for_each_safe(pos, safe, &list) {
1094 info = list_entry(pos, struct hrtimer_start_on_info, list);
1095 TRACE("pulled timer 0x%x\n", info->timer);
1096 list_del(pos);
1097 hrtimer_start(info->timer, info->time, info->mode);
1098 }
1099}
1100
1101/**
1102 * hrtimer_start_on - trigger timer arming on remote cpu
1103 * @cpu: remote cpu
1104 * @info: save timer information for enqueuing on remote cpu
1105 * @timer: timer to be pulled
1106 * @time: expire time
1107 * @mode: timer mode
1108 */
1109int hrtimer_start_on(int cpu, struct hrtimer_start_on_info* info,
1110 struct hrtimer *timer, ktime_t time,
1111 const enum hrtimer_mode mode)
1112{
1113 unsigned long flags;
1114 struct hrtimer_cpu_base* base;
1115 int in_use = 0, was_empty;
1116
1117 /* serialize access to info through the timer base */
1118 lock_hrtimer_base(timer, &flags);
1119
1120 in_use = (atomic_read(&info->state) != HRTIMER_START_ON_INACTIVE);
1121 if (!in_use) {
1122 INIT_LIST_HEAD(&info->list);
1123 info->timer = timer;
1124 info->time = time;
1125 info->mode = mode;
1126 /* mark as in use */
1127 atomic_set(&info->state, HRTIMER_START_ON_QUEUED);
1128 }
1129
1130 unlock_hrtimer_base(timer, &flags);
1131
1132 if (!in_use) {
1133 /* initiate pull */
1134 preempt_disable();
1135 if (cpu == smp_processor_id()) {
1136 /* start timer locally; we may get called
1137 * with rq->lock held, do not wake up anything
1138 */
1139 TRACE("hrtimer_start_on: starting on local CPU\n");
1140 __hrtimer_start_range_ns(info->timer, info->time,
1141 0, info->mode, 0);
1142 } else {
1143 TRACE("hrtimer_start_on: pulling to remote CPU\n");
1144 base = &per_cpu(hrtimer_bases, cpu);
1145 raw_spin_lock_irqsave(&base->lock, flags);
1146 was_empty = list_empty(&base->to_pull);
1147 list_add(&info->list, &base->to_pull);
1148 raw_spin_unlock_irqrestore(&base->lock, flags);
1149 if (was_empty)
1150 /* only send IPI if other no else
1151 * has done so already
1152 */
1153 smp_send_pull_timers(cpu);
1154 }
1155 preempt_enable();
1156 }
1157 return in_use;
1158}
1159
1160#endif
1067 1161
1068/** 1162/**
1069 * hrtimer_try_to_cancel - try to deactivate a timer 1163 * hrtimer_try_to_cancel - try to deactivate a timer
@@ -1667,6 +1761,7 @@ static void __cpuinit init_hrtimers_cpu(int cpu)
1667 } 1761 }
1668 1762
1669 hrtimer_init_hres(cpu_base); 1763 hrtimer_init_hres(cpu_base);
1764 INIT_LIST_HEAD(&cpu_base->to_pull);
1670} 1765}
1671 1766
1672#ifdef CONFIG_HOTPLUG_CPU 1767#ifdef CONFIG_HOTPLUG_CPU