diff options
Diffstat (limited to 'arch/alpha/oprofile/common.c')
-rw-r--r-- | arch/alpha/oprofile/common.c | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/arch/alpha/oprofile/common.c b/arch/alpha/oprofile/common.c new file mode 100644 index 000000000000..908eb4af8dec --- /dev/null +++ b/arch/alpha/oprofile/common.c | |||
@@ -0,0 +1,189 @@ | |||
1 | /** | ||
2 | * @file arch/alpha/oprofile/common.c | ||
3 | * | ||
4 | * @remark Copyright 2002 OProfile authors | ||
5 | * @remark Read the file COPYING | ||
6 | * | ||
7 | * @author Richard Henderson <rth@twiddle.net> | ||
8 | */ | ||
9 | |||
10 | #include <linux/oprofile.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/smp.h> | ||
13 | #include <linux/errno.h> | ||
14 | #include <asm/ptrace.h> | ||
15 | #include <asm/system.h> | ||
16 | |||
17 | #include "op_impl.h" | ||
18 | |||
19 | extern struct op_axp_model op_model_ev4 __attribute__((weak)); | ||
20 | extern struct op_axp_model op_model_ev5 __attribute__((weak)); | ||
21 | extern struct op_axp_model op_model_pca56 __attribute__((weak)); | ||
22 | extern struct op_axp_model op_model_ev6 __attribute__((weak)); | ||
23 | extern struct op_axp_model op_model_ev67 __attribute__((weak)); | ||
24 | |||
25 | static struct op_axp_model *model; | ||
26 | |||
27 | extern void (*perf_irq)(unsigned long, struct pt_regs *); | ||
28 | static void (*save_perf_irq)(unsigned long, struct pt_regs *); | ||
29 | |||
30 | static struct op_counter_config ctr[20]; | ||
31 | static struct op_system_config sys; | ||
32 | static struct op_register_config reg; | ||
33 | |||
34 | /* Called from do_entInt to handle the performance monitor interrupt. */ | ||
35 | |||
36 | static void | ||
37 | op_handle_interrupt(unsigned long which, struct pt_regs *regs) | ||
38 | { | ||
39 | model->handle_interrupt(which, regs, ctr); | ||
40 | |||
41 | /* If the user has selected an interrupt frequency that is | ||
42 | not exactly the width of the counter, write a new value | ||
43 | into the counter such that it'll overflow after N more | ||
44 | events. */ | ||
45 | if ((reg.need_reset >> which) & 1) | ||
46 | model->reset_ctr(®, which); | ||
47 | } | ||
48 | |||
49 | static int | ||
50 | op_axp_setup(void) | ||
51 | { | ||
52 | unsigned long i, e; | ||
53 | |||
54 | /* Install our interrupt handler into the existing hook. */ | ||
55 | save_perf_irq = perf_irq; | ||
56 | perf_irq = op_handle_interrupt; | ||
57 | |||
58 | /* Compute the mask of enabled counters. */ | ||
59 | for (i = e = 0; i < model->num_counters; ++i) | ||
60 | if (ctr[i].enabled) | ||
61 | e |= 1 << i; | ||
62 | reg.enable = e; | ||
63 | |||
64 | /* Pre-compute the values to stuff in the hardware registers. */ | ||
65 | model->reg_setup(®, ctr, &sys); | ||
66 | |||
67 | /* Configure the registers on all cpus. */ | ||
68 | smp_call_function(model->cpu_setup, ®, 0, 1); | ||
69 | model->cpu_setup(®); | ||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static void | ||
74 | op_axp_shutdown(void) | ||
75 | { | ||
76 | /* Remove our interrupt handler. We may be removing this module. */ | ||
77 | perf_irq = save_perf_irq; | ||
78 | } | ||
79 | |||
80 | static void | ||
81 | op_axp_cpu_start(void *dummy) | ||
82 | { | ||
83 | wrperfmon(1, reg.enable); | ||
84 | } | ||
85 | |||
86 | static int | ||
87 | op_axp_start(void) | ||
88 | { | ||
89 | smp_call_function(op_axp_cpu_start, NULL, 0, 1); | ||
90 | op_axp_cpu_start(NULL); | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static inline void | ||
95 | op_axp_cpu_stop(void *dummy) | ||
96 | { | ||
97 | /* Disable performance monitoring for all counters. */ | ||
98 | wrperfmon(0, -1); | ||
99 | } | ||
100 | |||
101 | static void | ||
102 | op_axp_stop(void) | ||
103 | { | ||
104 | smp_call_function(op_axp_cpu_stop, NULL, 0, 1); | ||
105 | op_axp_cpu_stop(NULL); | ||
106 | } | ||
107 | |||
108 | static int | ||
109 | op_axp_create_files(struct super_block * sb, struct dentry * root) | ||
110 | { | ||
111 | int i; | ||
112 | |||
113 | for (i = 0; i < model->num_counters; ++i) { | ||
114 | struct dentry *dir; | ||
115 | char buf[3]; | ||
116 | |||
117 | snprintf(buf, sizeof buf, "%d", i); | ||
118 | dir = oprofilefs_mkdir(sb, root, buf); | ||
119 | |||
120 | oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled); | ||
121 | oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event); | ||
122 | oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count); | ||
123 | /* Dummies. */ | ||
124 | oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel); | ||
125 | oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user); | ||
126 | oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask); | ||
127 | } | ||
128 | |||
129 | if (model->can_set_proc_mode) { | ||
130 | oprofilefs_create_ulong(sb, root, "enable_pal", | ||
131 | &sys.enable_pal); | ||
132 | oprofilefs_create_ulong(sb, root, "enable_kernel", | ||
133 | &sys.enable_kernel); | ||
134 | oprofilefs_create_ulong(sb, root, "enable_user", | ||
135 | &sys.enable_user); | ||
136 | } | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | int __init | ||
142 | oprofile_arch_init(struct oprofile_operations *ops) | ||
143 | { | ||
144 | struct op_axp_model *lmodel = NULL; | ||
145 | |||
146 | switch (implver()) { | ||
147 | case IMPLVER_EV4: | ||
148 | lmodel = &op_model_ev4; | ||
149 | break; | ||
150 | case IMPLVER_EV5: | ||
151 | /* 21164PC has a slightly different set of events. | ||
152 | Recognize the chip by the presence of the MAX insns. */ | ||
153 | if (!amask(AMASK_MAX)) | ||
154 | lmodel = &op_model_pca56; | ||
155 | else | ||
156 | lmodel = &op_model_ev5; | ||
157 | break; | ||
158 | case IMPLVER_EV6: | ||
159 | /* 21264A supports ProfileMe. | ||
160 | Recognize the chip by the presence of the CIX insns. */ | ||
161 | if (!amask(AMASK_CIX)) | ||
162 | lmodel = &op_model_ev67; | ||
163 | else | ||
164 | lmodel = &op_model_ev6; | ||
165 | break; | ||
166 | } | ||
167 | |||
168 | if (!lmodel) | ||
169 | return -ENODEV; | ||
170 | model = lmodel; | ||
171 | |||
172 | ops->create_files = op_axp_create_files; | ||
173 | ops->setup = op_axp_setup; | ||
174 | ops->shutdown = op_axp_shutdown; | ||
175 | ops->start = op_axp_start; | ||
176 | ops->stop = op_axp_stop; | ||
177 | ops->cpu_type = lmodel->cpu_type; | ||
178 | |||
179 | printk(KERN_INFO "oprofile: using %s performance monitoring.\n", | ||
180 | lmodel->cpu_type); | ||
181 | |||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | |||
186 | void | ||
187 | oprofile_arch_exit(void) | ||
188 | { | ||
189 | } | ||