Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target...
[linux-2.6.git] / arch / alpha / oprofile / op_model_ev5.c
blobc32f8a0ad92543a0d6e6767e698f51da0972c17e
1 /**
2 * @file arch/alpha/oprofile/op_model_ev5.c
4 * @remark Copyright 2002 OProfile authors
5 * @remark Read the file COPYING
7 * @author Richard Henderson <rth@twiddle.net>
8 */
10 #include <linux/oprofile.h>
11 #include <linux/init.h>
12 #include <linux/smp.h>
13 #include <asm/ptrace.h>
15 #include "op_impl.h"
18 /* Compute all of the registers in preparation for enabling profiling.
20 The 21164 (EV5) and 21164PC (PCA65) vary in the bit placement and
21 meaning of the "CBOX" events. Given that we don't care about meaning
22 at this point, arrange for the difference in bit placement to be
23 handled by common code. */
25 static void
26 common_reg_setup(struct op_register_config *reg,
27 struct op_counter_config *ctr,
28 struct op_system_config *sys,
29 int cbox1_ofs, int cbox2_ofs)
31 int i, ctl, reset, need_reset;
33 /* Select desired events. The event numbers are selected such
34 that they map directly into the event selection fields:
36 PCSEL0: 0, 1
37 PCSEL1: 24-39
38 CBOX1: 40-47
39 PCSEL2: 48-63
40 CBOX2: 64-71
42 There are two special cases, in that CYCLES can be measured
43 on PCSEL[02], and SCACHE_WRITE can be measured on CBOX[12].
44 These event numbers are canonicalizes to their first appearance. */
46 ctl = 0;
47 for (i = 0; i < 3; ++i) {
48 unsigned long event = ctr[i].event;
49 if (!ctr[i].enabled)
50 continue;
52 /* Remap the duplicate events, as described above. */
53 if (i == 2) {
54 if (event == 0)
55 event = 12+48;
56 else if (event == 2+41)
57 event = 4+65;
60 /* Convert the event numbers onto mux_select bit mask. */
61 if (event < 2)
62 ctl |= event << 31;
63 else if (event < 24)
64 /* error */;
65 else if (event < 40)
66 ctl |= (event - 24) << 4;
67 else if (event < 48)
68 ctl |= (event - 40) << cbox1_ofs | 15 << 4;
69 else if (event < 64)
70 ctl |= event - 48;
71 else if (event < 72)
72 ctl |= (event - 64) << cbox2_ofs | 15;
74 reg->mux_select = ctl;
76 /* Select processor mode. */
77 /* ??? Need to come up with some mechanism to trace only selected
78 processes. For now select from pal, kernel and user mode. */
79 ctl = 0;
80 ctl |= !sys->enable_pal << 9;
81 ctl |= !sys->enable_kernel << 8;
82 ctl |= !sys->enable_user << 30;
83 reg->proc_mode = ctl;
85 /* Select interrupt frequencies. Take the interrupt count selected
86 by the user, and map it onto one of the possible counter widths.
87 If the user value is in between, compute a value to which the
88 counter is reset at each interrupt. */
90 ctl = reset = need_reset = 0;
91 for (i = 0; i < 3; ++i) {
92 unsigned long max, hilo, count = ctr[i].count;
93 if (!ctr[i].enabled)
94 continue;
96 if (count <= 256)
97 count = 256, hilo = 3, max = 256;
98 else {
99 max = (i == 2 ? 16384 : 65536);
100 hilo = 2;
101 if (count > max)
102 count = max;
104 ctr[i].count = count;
106 ctl |= hilo << (8 - i*2);
107 reset |= (max - count) << (48 - 16*i);
108 if (count != max)
109 need_reset |= 1 << i;
111 reg->freq = ctl;
112 reg->reset_values = reset;
113 reg->need_reset = need_reset;
116 static void
117 ev5_reg_setup(struct op_register_config *reg,
118 struct op_counter_config *ctr,
119 struct op_system_config *sys)
121 common_reg_setup(reg, ctr, sys, 19, 22);
124 static void
125 pca56_reg_setup(struct op_register_config *reg,
126 struct op_counter_config *ctr,
127 struct op_system_config *sys)
129 common_reg_setup(reg, ctr, sys, 8, 11);
132 /* Program all of the registers in preparation for enabling profiling. */
134 static void
135 ev5_cpu_setup (void *x)
137 struct op_register_config *reg = x;
139 wrperfmon(2, reg->mux_select);
140 wrperfmon(3, reg->proc_mode);
141 wrperfmon(4, reg->freq);
142 wrperfmon(6, reg->reset_values);
145 /* CTR is a counter for which the user has requested an interrupt count
146 in between one of the widths selectable in hardware. Reset the count
147 for CTR to the value stored in REG->RESET_VALUES.
149 For EV5, this means disabling profiling, reading the current values,
150 masking in the value for the desired register, writing, then turning
151 profiling back on.
153 This can be streamlined if profiling is only enabled for user mode.
154 In that case we know that the counters are not currently incrementing
155 (due to being in kernel mode). */
157 static void
158 ev5_reset_ctr(struct op_register_config *reg, unsigned long ctr)
160 unsigned long values, mask, not_pk, reset_values;
162 mask = (ctr == 0 ? 0xfffful << 48
163 : ctr == 1 ? 0xfffful << 32
164 : 0x3fff << 16);
166 not_pk = 1 << 9 | 1 << 8;
168 reset_values = reg->reset_values;
170 if ((reg->proc_mode & not_pk) == not_pk) {
171 values = wrperfmon(5, 0);
172 values = (reset_values & mask) | (values & ~mask & -2);
173 wrperfmon(6, values);
174 } else {
175 wrperfmon(0, -1);
176 values = wrperfmon(5, 0);
177 values = (reset_values & mask) | (values & ~mask & -2);
178 wrperfmon(6, values);
179 wrperfmon(1, reg->enable);
183 static void
184 ev5_handle_interrupt(unsigned long which, struct pt_regs *regs,
185 struct op_counter_config *ctr)
187 /* Record the sample. */
188 oprofile_add_sample(regs, which);
192 struct op_axp_model op_model_ev5 = {
193 .reg_setup = ev5_reg_setup,
194 .cpu_setup = ev5_cpu_setup,
195 .reset_ctr = ev5_reset_ctr,
196 .handle_interrupt = ev5_handle_interrupt,
197 .cpu_type = "alpha/ev5",
198 .num_counters = 3,
199 .can_set_proc_mode = 1,
202 struct op_axp_model op_model_pca56 = {
203 .reg_setup = pca56_reg_setup,
204 .cpu_setup = ev5_cpu_setup,
205 .reset_ctr = ev5_reset_ctr,
206 .handle_interrupt = ev5_handle_interrupt,
207 .cpu_type = "alpha/pca56",
208 .num_counters = 3,
209 .can_set_proc_mode = 1,