diff options
-rw-r--r-- | arch/x86/kernel/smp_32.c | 3 | ||||
-rw-r--r-- | include/linux/hrtimer.h | 15 | ||||
-rw-r--r-- | kernel/hrtimer.c | 68 |
3 files changed, 86 insertions, 0 deletions
diff --git a/arch/x86/kernel/smp_32.c b/arch/x86/kernel/smp_32.c index 3d16decc15cf..8d28cee0dec0 100644 --- a/arch/x86/kernel/smp_32.c +++ b/arch/x86/kernel/smp_32.c | |||
@@ -656,10 +656,13 @@ fastcall void smp_reschedule_interrupt(struct pt_regs *regs) | |||
656 | TS_SEND_RESCHED_END; | 656 | TS_SEND_RESCHED_END; |
657 | } | 657 | } |
658 | 658 | ||
659 | extern void hrtimer_pull(void); | ||
660 | |||
659 | fastcall void smp_pull_timers_interrupt(struct pt_regs *regs) | 661 | fastcall void smp_pull_timers_interrupt(struct pt_regs *regs) |
660 | { | 662 | { |
661 | ack_APIC_irq(); | 663 | ack_APIC_irq(); |
662 | TRACE("pull timers interrupt\n"); | 664 | TRACE("pull timers interrupt\n"); |
665 | hrtimer_pull(); | ||
663 | } | 666 | } |
664 | 667 | ||
665 | fastcall void smp_call_function_interrupt(struct pt_regs *regs) | 668 | fastcall void smp_call_function_interrupt(struct pt_regs *regs) |
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 7a9398e19704..32d456e01da0 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h | |||
@@ -200,6 +200,18 @@ struct hrtimer_cpu_base { | |||
200 | struct list_head cb_pending; | 200 | struct list_head cb_pending; |
201 | unsigned long nr_events; | 201 | unsigned long nr_events; |
202 | #endif | 202 | #endif |
203 | struct list_head to_pull; | ||
204 | }; | ||
205 | |||
206 | #define HRTIMER_START_ON_INACTIVE 0 | ||
207 | #define HRTIMER_START_ON_QUEUED 1 | ||
208 | |||
209 | struct hrtimer_start_on_info { | ||
210 | struct list_head list; | ||
211 | struct hrtimer* timer; | ||
212 | ktime_t time; | ||
213 | enum hrtimer_mode mode; | ||
214 | atomic_t state; | ||
203 | }; | 215 | }; |
204 | 216 | ||
205 | #ifdef CONFIG_HIGH_RES_TIMERS | 217 | #ifdef CONFIG_HIGH_RES_TIMERS |
@@ -262,6 +274,9 @@ extern void hrtimer_init(struct hrtimer *timer, clockid_t which_clock, | |||
262 | /* Basic timer operations: */ | 274 | /* Basic timer operations: */ |
263 | extern int hrtimer_start(struct hrtimer *timer, ktime_t tim, | 275 | extern int hrtimer_start(struct hrtimer *timer, ktime_t tim, |
264 | const enum hrtimer_mode mode); | 276 | const enum hrtimer_mode mode); |
277 | extern int hrtimer_start_on(int cpu, struct hrtimer_start_on_info* info, | ||
278 | struct hrtimer *timer, ktime_t time, | ||
279 | const enum hrtimer_mode mode); | ||
265 | extern int hrtimer_cancel(struct hrtimer *timer); | 280 | extern int hrtimer_cancel(struct hrtimer *timer); |
266 | extern int hrtimer_try_to_cancel(struct hrtimer *timer); | 281 | extern int hrtimer_try_to_cancel(struct hrtimer *timer); |
267 | 282 | ||
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index f994bb8065e6..3165b4810106 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c | |||
@@ -46,6 +46,9 @@ | |||
46 | 46 | ||
47 | #include <asm/uaccess.h> | 47 | #include <asm/uaccess.h> |
48 | 48 | ||
49 | #include <litmus/litmus.h> | ||
50 | |||
51 | |||
49 | /** | 52 | /** |
50 | * ktime_get - get the monotonic time in ktime_t format | 53 | * ktime_get - get the monotonic time in ktime_t format |
51 | * | 54 | * |
@@ -813,6 +816,70 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base) | |||
813 | return 0; | 816 | return 0; |
814 | } | 817 | } |
815 | 818 | ||
819 | void hrtimer_pull(void) | ||
820 | { | ||
821 | struct hrtimer_cpu_base* base = &__get_cpu_var(hrtimer_bases); | ||
822 | struct hrtimer_start_on_info* info; | ||
823 | struct list_head *pos, *safe, list; | ||
824 | |||
825 | spin_lock(&base->lock); | ||
826 | list_replace_init(&base->to_pull, &list); | ||
827 | spin_unlock(&base->lock); | ||
828 | |||
829 | list_for_each_safe(pos, safe, &list) { | ||
830 | info = list_entry(pos, struct hrtimer_start_on_info, list); | ||
831 | TRACE("pulled timer 0x%x\n", info->timer); | ||
832 | list_del(pos); | ||
833 | hrtimer_start(info->timer, info->time, info->mode); | ||
834 | } | ||
835 | } | ||
836 | |||
837 | int hrtimer_start_on(int cpu, struct hrtimer_start_on_info* info, | ||
838 | struct hrtimer *timer, ktime_t time, | ||
839 | const enum hrtimer_mode mode) | ||
840 | { | ||
841 | unsigned long flags; | ||
842 | struct hrtimer_cpu_base* base; | ||
843 | int in_use = 0, was_empty; | ||
844 | |||
845 | /* serialize access to info through the timer base */ | ||
846 | lock_hrtimer_base(timer, &flags); | ||
847 | |||
848 | in_use = atomic_read(&info->state) != HRTIMER_START_ON_INACTIVE; | ||
849 | if (!in_use) { | ||
850 | INIT_LIST_HEAD(&info->list); | ||
851 | info->timer = timer; | ||
852 | info->time = time; | ||
853 | info->mode = mode; | ||
854 | /* mark as in use */ | ||
855 | atomic_set(&info->state, HRTIMER_START_ON_QUEUED); | ||
856 | } | ||
857 | |||
858 | unlock_hrtimer_base(timer, &flags); | ||
859 | |||
860 | if (!in_use) { | ||
861 | /* initiate pull */ | ||
862 | preempt_disable(); | ||
863 | if (cpu == smp_processor_id()) { | ||
864 | /* start timer locally */ | ||
865 | hrtimer_start(info->timer, info->time, info->mode); | ||
866 | } else { | ||
867 | base = &per_cpu(hrtimer_bases, cpu); | ||
868 | spin_lock_irqsave(&base->lock, flags); | ||
869 | was_empty = list_empty(&base->to_pull); | ||
870 | list_add(&info->list, &base->to_pull); | ||
871 | spin_unlock_irqrestore(&base->lock, flags); | ||
872 | if (was_empty) | ||
873 | /* only send IPI if other no else | ||
874 | * has done so already | ||
875 | */ | ||
876 | smp_send_pull_timers(cpu); | ||
877 | } | ||
878 | preempt_enable(); | ||
879 | } | ||
880 | return in_use; | ||
881 | } | ||
882 | |||
816 | /** | 883 | /** |
817 | * hrtimer_start - (re)start an relative timer on the current CPU | 884 | * hrtimer_start - (re)start an relative timer on the current CPU |
818 | * @timer: the timer to be added | 885 | * @timer: the timer to be added |
@@ -1390,6 +1457,7 @@ static void __cpuinit init_hrtimers_cpu(int cpu) | |||
1390 | cpu_base->clock_base[i].cpu_base = cpu_base; | 1457 | cpu_base->clock_base[i].cpu_base = cpu_base; |
1391 | 1458 | ||
1392 | hrtimer_init_hres(cpu_base); | 1459 | hrtimer_init_hres(cpu_base); |
1460 | INIT_LIST_HEAD(&cpu_base->to_pull); | ||
1393 | } | 1461 | } |
1394 | 1462 | ||
1395 | #ifdef CONFIG_HOTPLUG_CPU | 1463 | #ifdef CONFIG_HOTPLUG_CPU |