aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorBjoern Brandenburg <bbb@mpi-sws.org>2015-08-09 07:18:46 -0400
committerBjoern Brandenburg <bbb@mpi-sws.org>2015-08-09 06:21:17 -0400
commit5014e7011964ff46b2d73cf91a05ed9eed5a8fa2 (patch)
tree76fad060cf673112d92a4f5f2d9b9423383610f6 /kernel
parentfc6ac04ddc314b9cff5bdb92c8330569658076a3 (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/time/hrtimer.c95
1 files changed, 95 insertions, 0 deletions
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index 93ef7190bdea..22f9156f19d2 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -50,6 +50,8 @@
50#include <linux/timer.h> 50#include <linux/timer.h>
51#include <linux/freezer.h> 51#include <linux/freezer.h>
52 52
53#include <litmus/debug_trace.h>
54
53#include <asm/uaccess.h> 55#include <asm/uaccess.h>
54 56
55#include <trace/events/timer.h> 57#include <trace/events/timer.h>
@@ -1045,6 +1047,98 @@ hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
1045} 1047}
1046EXPORT_SYMBOL_GPL(hrtimer_start); 1048EXPORT_SYMBOL_GPL(hrtimer_start);
1047 1049
1050#if defined(CONFIG_ARCH_HAS_SEND_PULL_TIMERS) && defined(CONFIG_SMP)
1051
1052/**
1053 * hrtimer_start_on_info_init - Initialize hrtimer_start_on_info
1054 */
1055void hrtimer_start_on_info_init(struct hrtimer_start_on_info *info)
1056{
1057 memset(info, 0, sizeof(struct hrtimer_start_on_info));
1058 atomic_set(&info->state, HRTIMER_START_ON_INACTIVE);
1059}
1060
1061/**
1062 * hrtimer_pull - PULL_TIMERS_VECTOR callback on remote cpu
1063 */
1064void hrtimer_pull(void)
1065{
1066 struct hrtimer_cpu_base *base = this_cpu_ptr(&hrtimer_bases);
1067 struct hrtimer_start_on_info *info;
1068 struct list_head *pos, *safe, list;
1069
1070 raw_spin_lock(&base->lock);
1071 list_replace_init(&base->to_pull, &list);
1072 raw_spin_unlock(&base->lock);
1073
1074 list_for_each_safe(pos, safe, &list) {
1075 info = list_entry(pos, struct hrtimer_start_on_info, list);
1076 TRACE("pulled timer 0x%x\n", info->timer);
1077 list_del(pos);
1078 hrtimer_start(info->timer, info->time, info->mode);
1079 }
1080}
1081
1082/**
1083 * hrtimer_start_on - trigger timer arming on remote cpu
1084 * @cpu: remote cpu
1085 * @info: save timer information for enqueuing on remote cpu
1086 * @timer: timer to be pulled
1087 * @time: expire time
1088 * @mode: timer mode
1089 */
1090int hrtimer_start_on(int cpu, struct hrtimer_start_on_info* info,
1091 struct hrtimer *timer, ktime_t time,
1092 const enum hrtimer_mode mode)
1093{
1094 unsigned long flags;
1095 struct hrtimer_cpu_base* base;
1096 int in_use = 0, was_empty;
1097
1098 /* serialize access to info through the timer base */
1099 lock_hrtimer_base(timer, &flags);
1100
1101 in_use = (atomic_read(&info->state) != HRTIMER_START_ON_INACTIVE);
1102 if (!in_use) {
1103 INIT_LIST_HEAD(&info->list);
1104 info->timer = timer;
1105 info->time = time;
1106 info->mode = mode;
1107 /* mark as in use */
1108 atomic_set(&info->state, HRTIMER_START_ON_QUEUED);
1109 }
1110
1111 unlock_hrtimer_base(timer, &flags);
1112
1113 if (!in_use) {
1114 /* initiate pull */
1115 preempt_disable();
1116 if (cpu == smp_processor_id()) {
1117 /* start timer locally; we may get called
1118 * with rq->lock held, do not wake up anything
1119 */
1120 TRACE("hrtimer_start_on: starting on local CPU\n");
1121 __hrtimer_start_range_ns(info->timer, info->time,
1122 0, info->mode, 0);
1123 } else {
1124 TRACE("hrtimer_start_on: pulling to remote CPU\n");
1125 base = &per_cpu(hrtimer_bases, cpu);
1126 raw_spin_lock_irqsave(&base->lock, flags);
1127 was_empty = list_empty(&base->to_pull);
1128 list_add(&info->list, &base->to_pull);
1129 raw_spin_unlock_irqrestore(&base->lock, flags);
1130 if (was_empty)
1131 /* only send IPI if other no else
1132 * has done so already
1133 */
1134 smp_send_pull_timers(cpu);
1135 }
1136 preempt_enable();
1137 }
1138 return in_use;
1139}
1140
1141#endif
1048 1142
1049/** 1143/**
1050 * hrtimer_try_to_cancel - try to deactivate a timer 1144 * hrtimer_try_to_cancel - try to deactivate a timer
@@ -1626,6 +1720,7 @@ static void init_hrtimers_cpu(int cpu)
1626 1720
1627 cpu_base->cpu = cpu; 1721 cpu_base->cpu = cpu;
1628 hrtimer_init_hres(cpu_base); 1722 hrtimer_init_hres(cpu_base);
1723 INIT_LIST_HEAD(&cpu_base->to_pull);
1629} 1724}
1630 1725
1631#ifdef CONFIG_HOTPLUG_CPU 1726#ifdef CONFIG_HOTPLUG_CPU