aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/Kconfig3
-rw-r--r--arch/x86/Kconfig3
-rw-r--r--arch/x86/include/asm/entry_arch.h1
-rw-r--r--arch/x86/include/asm/hw_irq.h4
-rw-r--r--arch/x86/include/asm/irq_vectors.h6
-rw-r--r--arch/x86/kernel/entry_64.S2
-rw-r--r--arch/x86/kernel/irqinit.c3
-rw-r--r--arch/x86/kernel/smp.c38
-rw-r--r--include/linux/hrtimer.h32
-rw-r--r--include/linux/smp.h5
-rw-r--r--kernel/time/hrtimer.c95
11 files changed, 191 insertions, 1 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index ce948d46a1b3..d3bfc3a4e56a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -2123,5 +2123,8 @@ source "arch/arm/kvm/Kconfig"
2123config ARCH_HAS_FEATHER_TRACE 2123config ARCH_HAS_FEATHER_TRACE
2124 def_bool n 2124 def_bool n
2125 2125
2126config ARCH_HAS_SEND_PULL_TIMERS
2127 def_bool n
2128
2126source "litmus/Kconfig" 2129source "litmus/Kconfig"
2127 2130
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 6331227b4686..f9c9a4d70b24 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2598,4 +2598,7 @@ source "lib/Kconfig"
2598config ARCH_HAS_FEATHER_TRACE 2598config ARCH_HAS_FEATHER_TRACE
2599 def_bool y 2599 def_bool y
2600 2600
2601config ARCH_HAS_SEND_PULL_TIMERS
2602 def_bool y
2603
2601source "litmus/Kconfig" 2604source "litmus/Kconfig"
diff --git a/arch/x86/include/asm/entry_arch.h b/arch/x86/include/asm/entry_arch.h
index dc5fa661465f..e657219d7964 100644
--- a/arch/x86/include/asm/entry_arch.h
+++ b/arch/x86/include/asm/entry_arch.h
@@ -13,6 +13,7 @@
13BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR) 13BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR)
14BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR) 14BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR)
15BUILD_INTERRUPT(call_function_single_interrupt,CALL_FUNCTION_SINGLE_VECTOR) 15BUILD_INTERRUPT(call_function_single_interrupt,CALL_FUNCTION_SINGLE_VECTOR)
16BUILD_INTERRUPT(pull_timers_interrupt,PULL_TIMERS_VECTOR)
16BUILD_INTERRUPT3(irq_move_cleanup_interrupt, IRQ_MOVE_CLEANUP_VECTOR, 17BUILD_INTERRUPT3(irq_move_cleanup_interrupt, IRQ_MOVE_CLEANUP_VECTOR,
17 smp_irq_move_cleanup_interrupt) 18 smp_irq_move_cleanup_interrupt)
18BUILD_INTERRUPT3(reboot_interrupt, REBOOT_VECTOR, smp_reboot_interrupt) 19BUILD_INTERRUPT3(reboot_interrupt, REBOOT_VECTOR, smp_reboot_interrupt)
diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
index e9571ddabc4f..3e860d1f9416 100644
--- a/arch/x86/include/asm/hw_irq.h
+++ b/arch/x86/include/asm/hw_irq.h
@@ -77,6 +77,8 @@ extern asmlinkage void threshold_interrupt(void);
77extern asmlinkage void call_function_interrupt(void); 77extern asmlinkage void call_function_interrupt(void);
78extern asmlinkage void call_function_single_interrupt(void); 78extern asmlinkage void call_function_single_interrupt(void);
79 79
80extern asmlinkage void pull_timers_interrupt(void);
81
80#ifdef CONFIG_TRACING 82#ifdef CONFIG_TRACING
81/* Interrupt handlers registered during init_IRQ */ 83/* Interrupt handlers registered during init_IRQ */
82extern void trace_apic_timer_interrupt(void); 84extern void trace_apic_timer_interrupt(void);
@@ -89,6 +91,7 @@ extern void trace_reschedule_interrupt(void);
89extern void trace_threshold_interrupt(void); 91extern void trace_threshold_interrupt(void);
90extern void trace_call_function_interrupt(void); 92extern void trace_call_function_interrupt(void);
91extern void trace_call_function_single_interrupt(void); 93extern void trace_call_function_single_interrupt(void);
94extern void trace_pull_timers_interrupt(void);
92#define trace_irq_move_cleanup_interrupt irq_move_cleanup_interrupt 95#define trace_irq_move_cleanup_interrupt irq_move_cleanup_interrupt
93#define trace_reboot_interrupt reboot_interrupt 96#define trace_reboot_interrupt reboot_interrupt
94#define trace_kvm_posted_intr_ipi kvm_posted_intr_ipi 97#define trace_kvm_posted_intr_ipi kvm_posted_intr_ipi
@@ -179,6 +182,7 @@ extern __visible void smp_reschedule_interrupt(struct pt_regs *);
179extern __visible void smp_call_function_interrupt(struct pt_regs *); 182extern __visible void smp_call_function_interrupt(struct pt_regs *);
180extern __visible void smp_call_function_single_interrupt(struct pt_regs *); 183extern __visible void smp_call_function_single_interrupt(struct pt_regs *);
181extern __visible void smp_invalidate_interrupt(struct pt_regs *); 184extern __visible void smp_invalidate_interrupt(struct pt_regs *);
185extern __visible void smp_pull_timers_interrupt(struct pt_regs *);
182#endif 186#endif
183 187
184extern char irq_entries_start[]; 188extern char irq_entries_start[];
diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h
index 666c89ec4bd7..82545836e1a1 100644
--- a/arch/x86/include/asm/irq_vectors.h
+++ b/arch/x86/include/asm/irq_vectors.h
@@ -124,6 +124,12 @@
124 */ 124 */
125#define LOCAL_TIMER_VECTOR 0xef 125#define LOCAL_TIMER_VECTOR 0xef
126 126
127/*
128 * LITMUS^RT pull timers IRQ vector.
129 * Make sure it's not used by Linux.
130 */
131#define PULL_TIMERS_VECTOR 0xdf
132
127#define NR_VECTORS 256 133#define NR_VECTORS 256
128 134
129#ifdef CONFIG_X86_LOCAL_APIC 135#ifdef CONFIG_X86_LOCAL_APIC
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 02c2eff7478d..d810f5fea04f 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -947,6 +947,8 @@ apicinterrupt CALL_FUNCTION_VECTOR \
947 call_function_interrupt smp_call_function_interrupt 947 call_function_interrupt smp_call_function_interrupt
948apicinterrupt RESCHEDULE_VECTOR \ 948apicinterrupt RESCHEDULE_VECTOR \
949 reschedule_interrupt smp_reschedule_interrupt 949 reschedule_interrupt smp_reschedule_interrupt
950apicinterrupt PULL_TIMERS_VECTOR \
951 pull_timers_interrupt smp_pull_timers_interrupt
950#endif 952#endif
951 953
952apicinterrupt ERROR_APIC_VECTOR \ 954apicinterrupt ERROR_APIC_VECTOR \
diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c
index cd10a6437264..834496ed9536 100644
--- a/arch/x86/kernel/irqinit.c
+++ b/arch/x86/kernel/irqinit.c
@@ -115,6 +115,9 @@ static void __init smp_intr_init(void)
115 alloc_intr_gate(CALL_FUNCTION_SINGLE_VECTOR, 115 alloc_intr_gate(CALL_FUNCTION_SINGLE_VECTOR,
116 call_function_single_interrupt); 116 call_function_single_interrupt);
117 117
118 /* IPI for hrtimer pulling on remote cpus */
119 alloc_intr_gate(PULL_TIMERS_VECTOR, pull_timers_interrupt);
120
118 /* Low priority IPI to cleanup after moving an irq */ 121 /* Low priority IPI to cleanup after moving an irq */
119 set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt); 122 set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt);
120 set_bit(IRQ_MOVE_CLEANUP_VECTOR, used_vectors); 123 set_bit(IRQ_MOVE_CLEANUP_VECTOR, used_vectors);
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c
index be8e1bde07aa..7ce9fb210d55 100644
--- a/arch/x86/kernel/smp.c
+++ b/arch/x86/kernel/smp.c
@@ -24,6 +24,8 @@
24#include <linux/cpu.h> 24#include <linux/cpu.h>
25#include <linux/gfp.h> 25#include <linux/gfp.h>
26 26
27#include <litmus/debug_trace.h>
28
27#include <asm/mtrr.h> 29#include <asm/mtrr.h>
28#include <asm/tlbflush.h> 30#include <asm/tlbflush.h>
29#include <asm/mmu_context.h> 31#include <asm/mmu_context.h>
@@ -164,6 +166,16 @@ static int smp_stop_nmi_callback(unsigned int val, struct pt_regs *regs)
164 return NMI_HANDLED; 166 return NMI_HANDLED;
165} 167}
166 168
169/* trigger timers on remote cpu */
170void smp_send_pull_timers(int cpu)
171{
172 if (unlikely(cpu_is_offline(cpu))) {
173 WARN_ON(1);
174 return;
175 }
176 apic->send_IPI_mask(cpumask_of(cpu), PULL_TIMERS_VECTOR);
177}
178
167/* 179/*
168 * this function calls the 'stop' function on all other CPUs in the system. 180 * this function calls the 'stop' function on all other CPUs in the system.
169 */ 181 */
@@ -216,7 +228,7 @@ static void native_stop_other_cpus(int wait)
216 while (num_online_cpus() > 1 && (wait || timeout--)) 228 while (num_online_cpus() > 1 && (wait || timeout--))
217 udelay(1); 229 udelay(1);
218 } 230 }
219 231
220 /* if the REBOOT_VECTOR didn't work, try with the NMI */ 232 /* if the REBOOT_VECTOR didn't work, try with the NMI */
221 if ((num_online_cpus() > 1) && (!smp_no_nmi_ipi)) { 233 if ((num_online_cpus() > 1) && (!smp_no_nmi_ipi)) {
222 if (register_nmi_handler(NMI_LOCAL, smp_stop_nmi_callback, 234 if (register_nmi_handler(NMI_LOCAL, smp_stop_nmi_callback,
@@ -341,6 +353,30 @@ static int __init nonmi_ipi_setup(char *str)
341 353
342__setup("nonmi_ipi", nonmi_ipi_setup); 354__setup("nonmi_ipi", nonmi_ipi_setup);
343 355
356extern void hrtimer_pull(void);
357
358static inline void __smp_pull_timers_interrupt(void)
359{
360 TRACE("pull timer interrupt\n");
361 hrtimer_pull();
362}
363
364__visible void smp_pull_timers_interrupt(struct pt_regs *regs)
365{
366 smp_entering_irq();
367 __smp_pull_timers_interrupt();
368 exiting_irq();
369}
370
371__visible void smp_trace_pull_timers_interrupt(struct pt_regs *regs)
372{
373 smp_entering_irq();
374 trace_call_function_single_entry(PULL_TIMERS_VECTOR);
375 __smp_pull_timers_interrupt();
376 trace_call_function_single_exit(PULL_TIMERS_VECTOR);
377 exiting_irq();
378}
379
344struct smp_ops smp_ops = { 380struct smp_ops smp_ops = {
345 .smp_prepare_boot_cpu = native_smp_prepare_boot_cpu, 381 .smp_prepare_boot_cpu = native_smp_prepare_boot_cpu,
346 .smp_prepare_cpus = native_smp_prepare_cpus, 382 .smp_prepare_cpus = native_smp_prepare_cpus,
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 05f6df1fdf5b..d1be5d2cb8fc 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -178,6 +178,7 @@ enum hrtimer_base_type {
178 * @nr_hangs: Total number of hrtimer interrupt hangs 178 * @nr_hangs: Total number of hrtimer interrupt hangs
179 * @max_hang_time: Maximum time spent in hrtimer_interrupt 179 * @max_hang_time: Maximum time spent in hrtimer_interrupt
180 * @clock_base: array of clock bases for this cpu 180 * @clock_base: array of clock bases for this cpu
181 * @to_pull: LITMUS^RT list of timers to be pulled on this cpu
181 */ 182 */
182struct hrtimer_cpu_base { 183struct hrtimer_cpu_base {
183 raw_spinlock_t lock; 184 raw_spinlock_t lock;
@@ -195,8 +196,32 @@ struct hrtimer_cpu_base {
195 ktime_t max_hang_time; 196 ktime_t max_hang_time;
196#endif 197#endif
197 struct hrtimer_clock_base clock_base[HRTIMER_MAX_CLOCK_BASES]; 198 struct hrtimer_clock_base clock_base[HRTIMER_MAX_CLOCK_BASES];
199 struct list_head to_pull;
198}; 200};
199 201
202#ifdef CONFIG_ARCH_HAS_SEND_PULL_TIMERS
203
204#define HRTIMER_START_ON_INACTIVE 0
205#define HRTIMER_START_ON_QUEUED 1
206
207/*
208 * struct hrtimer_start_on_info - save timer info on remote cpu
209 * @list: list of hrtimer_start_on_info on remote cpu (to_pull)
210 * @timer: timer to be triggered on remote cpu
211 * @time: time event
212 * @mode: timer mode
213 * @state: activity flag
214 */
215struct hrtimer_start_on_info {
216 struct list_head list;
217 struct hrtimer *timer;
218 ktime_t time;
219 enum hrtimer_mode mode;
220 atomic_t state;
221};
222
223#endif
224
200static inline void hrtimer_set_expires(struct hrtimer *timer, ktime_t time) 225static inline void hrtimer_set_expires(struct hrtimer *timer, ktime_t time)
201{ 226{
202 timer->node.expires = time; 227 timer->node.expires = time;
@@ -362,6 +387,13 @@ __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
362 unsigned long delta_ns, 387 unsigned long delta_ns,
363 const enum hrtimer_mode mode, int wakeup); 388 const enum hrtimer_mode mode, int wakeup);
364 389
390#ifdef CONFIG_ARCH_HAS_SEND_PULL_TIMERS
391extern void hrtimer_start_on_info_init(struct hrtimer_start_on_info *info);
392extern int hrtimer_start_on(int cpu, struct hrtimer_start_on_info *info,
393 struct hrtimer *timer, ktime_t time,
394 const enum hrtimer_mode mode);
395#endif
396
365extern int hrtimer_cancel(struct hrtimer *timer); 397extern int hrtimer_cancel(struct hrtimer *timer);
366extern int hrtimer_try_to_cancel(struct hrtimer *timer); 398extern int hrtimer_try_to_cancel(struct hrtimer *timer);
367 399
diff --git a/include/linux/smp.h b/include/linux/smp.h
index c4414074bd88..dfc63fe33a63 100644
--- a/include/linux/smp.h
+++ b/include/linux/smp.h
@@ -103,6 +103,11 @@ void kick_all_cpus_sync(void);
103void wake_up_all_idle_cpus(void); 103void wake_up_all_idle_cpus(void);
104 104
105/* 105/*
106 * sends a 'pull timer' event to a remote CPU
107 */
108extern void smp_send_pull_timers(int cpu);
109
110/*
106 * Generic and arch helpers 111 * Generic and arch helpers
107 */ 112 */
108void __init call_function_init(void); 113void __init call_function_init(void);
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