diff options
Diffstat (limited to 'drivers/oprofile/timer_int.c')
-rw-r--r-- | drivers/oprofile/timer_int.c | 78 |
1 files changed, 69 insertions, 9 deletions
diff --git a/drivers/oprofile/timer_int.c b/drivers/oprofile/timer_int.c index 333f915568c7..dc0ae4d14dff 100644 --- a/drivers/oprofile/timer_int.c +++ b/drivers/oprofile/timer_int.c | |||
@@ -13,34 +13,94 @@ | |||
13 | #include <linux/oprofile.h> | 13 | #include <linux/oprofile.h> |
14 | #include <linux/profile.h> | 14 | #include <linux/profile.h> |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/cpu.h> | ||
17 | #include <linux/hrtimer.h> | ||
18 | #include <asm/irq_regs.h> | ||
16 | #include <asm/ptrace.h> | 19 | #include <asm/ptrace.h> |
17 | 20 | ||
18 | #include "oprof.h" | 21 | #include "oprof.h" |
19 | 22 | ||
20 | static int timer_notify(struct pt_regs *regs) | 23 | static DEFINE_PER_CPU(struct hrtimer, oprofile_hrtimer); |
24 | |||
25 | static enum hrtimer_restart oprofile_hrtimer_notify(struct hrtimer *hrtimer) | ||
26 | { | ||
27 | oprofile_add_sample(get_irq_regs(), 0); | ||
28 | hrtimer_forward_now(hrtimer, ns_to_ktime(TICK_NSEC)); | ||
29 | return HRTIMER_RESTART; | ||
30 | } | ||
31 | |||
32 | static void __oprofile_hrtimer_start(void *unused) | ||
33 | { | ||
34 | struct hrtimer *hrtimer = &__get_cpu_var(oprofile_hrtimer); | ||
35 | |||
36 | hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
37 | hrtimer->function = oprofile_hrtimer_notify; | ||
38 | |||
39 | hrtimer_start(hrtimer, ns_to_ktime(TICK_NSEC), | ||
40 | HRTIMER_MODE_REL_PINNED); | ||
41 | } | ||
42 | |||
43 | static int oprofile_hrtimer_start(void) | ||
21 | { | 44 | { |
22 | oprofile_add_sample(regs, 0); | 45 | on_each_cpu(__oprofile_hrtimer_start, NULL, 1); |
23 | return 0; | 46 | return 0; |
24 | } | 47 | } |
25 | 48 | ||
26 | static int timer_start(void) | 49 | static void __oprofile_hrtimer_stop(int cpu) |
27 | { | 50 | { |
28 | return register_timer_hook(timer_notify); | 51 | struct hrtimer *hrtimer = &per_cpu(oprofile_hrtimer, cpu); |
52 | |||
53 | hrtimer_cancel(hrtimer); | ||
29 | } | 54 | } |
30 | 55 | ||
56 | static void oprofile_hrtimer_stop(void) | ||
57 | { | ||
58 | int cpu; | ||
59 | |||
60 | for_each_online_cpu(cpu) | ||
61 | __oprofile_hrtimer_stop(cpu); | ||
62 | } | ||
31 | 63 | ||
32 | static void timer_stop(void) | 64 | static int __cpuinit oprofile_cpu_notify(struct notifier_block *self, |
65 | unsigned long action, void *hcpu) | ||
33 | { | 66 | { |
34 | unregister_timer_hook(timer_notify); | 67 | long cpu = (long) hcpu; |
68 | |||
69 | switch (action) { | ||
70 | case CPU_ONLINE: | ||
71 | case CPU_ONLINE_FROZEN: | ||
72 | smp_call_function_single(cpu, __oprofile_hrtimer_start, | ||
73 | NULL, 1); | ||
74 | break; | ||
75 | case CPU_DEAD: | ||
76 | case CPU_DEAD_FROZEN: | ||
77 | __oprofile_hrtimer_stop(cpu); | ||
78 | break; | ||
79 | } | ||
80 | return NOTIFY_OK; | ||
35 | } | 81 | } |
36 | 82 | ||
83 | static struct notifier_block __refdata oprofile_cpu_notifier = { | ||
84 | .notifier_call = oprofile_cpu_notify, | ||
85 | }; | ||
37 | 86 | ||
38 | void __init oprofile_timer_init(struct oprofile_operations *ops) | 87 | int __init oprofile_timer_init(struct oprofile_operations *ops) |
39 | { | 88 | { |
89 | int rc; | ||
90 | |||
91 | rc = register_hotcpu_notifier(&oprofile_cpu_notifier); | ||
92 | if (rc) | ||
93 | return rc; | ||
40 | ops->create_files = NULL; | 94 | ops->create_files = NULL; |
41 | ops->setup = NULL; | 95 | ops->setup = NULL; |
42 | ops->shutdown = NULL; | 96 | ops->shutdown = NULL; |
43 | ops->start = timer_start; | 97 | ops->start = oprofile_hrtimer_start; |
44 | ops->stop = timer_stop; | 98 | ops->stop = oprofile_hrtimer_stop; |
45 | ops->cpu_type = "timer"; | 99 | ops->cpu_type = "timer"; |
100 | return 0; | ||
101 | } | ||
102 | |||
103 | void __exit oprofile_timer_exit(void) | ||
104 | { | ||
105 | unregister_hotcpu_notifier(&oprofile_cpu_notifier); | ||
46 | } | 106 | } |