1 /**
2  * @file arch/alpha/oprofile/op_model_ev5.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 <asm/ptrace.h>
14 
15 #include "op_impl.h"
16 
17 
18 /* Compute all of the registers in preparation for enabling profiling.
19 
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.  */
24 
25 static void
common_reg_setup(struct op_register_config * reg,struct op_counter_config * ctr,struct op_system_config * sys,int cbox1_ofs,int cbox2_ofs)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)
30 {
31 	int i, ctl, reset, need_reset;
32 
33 	/* Select desired events.  The event numbers are selected such
34 	   that they map directly into the event selection fields:
35 
36 		PCSEL0:	0, 1
37 		PCSEL1:	24-39
38 		 CBOX1: 40-47
39 		PCSEL2: 48-63
40 		 CBOX2: 64-71
41 
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.  */
45 
46 	ctl = 0;
47 	for (i = 0; i < 3; ++i) {
48 		unsigned long event = ctr[i].event;
49 		if (!ctr[i].enabled)
50 			continue;
51 
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;
58 		}
59 
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;
73 	}
74 	reg->mux_select = ctl;
75 
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;
84 
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.  */
89 
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;
95 
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;
103 		}
104 		ctr[i].count = count;
105 
106 		ctl |= hilo << (8 - i*2);
107 		reset |= (max - count) << (48 - 16*i);
108 		if (count != max)
109 			need_reset |= 1 << i;
110 	}
111 	reg->freq = ctl;
112 	reg->reset_values = reset;
113 	reg->need_reset = need_reset;
114 }
115 
116 static void
ev5_reg_setup(struct op_register_config * reg,struct op_counter_config * ctr,struct op_system_config * sys)117 ev5_reg_setup(struct op_register_config *reg,
118 	      struct op_counter_config *ctr,
119 	      struct op_system_config *sys)
120 {
121 	common_reg_setup(reg, ctr, sys, 19, 22);
122 }
123 
124 static void
pca56_reg_setup(struct op_register_config * reg,struct op_counter_config * ctr,struct op_system_config * sys)125 pca56_reg_setup(struct op_register_config *reg,
126 	        struct op_counter_config *ctr,
127 	        struct op_system_config *sys)
128 {
129 	common_reg_setup(reg, ctr, sys, 8, 11);
130 }
131 
132 /* Program all of the registers in preparation for enabling profiling.  */
133 
134 static void
ev5_cpu_setup(void * x)135 ev5_cpu_setup (void *x)
136 {
137 	struct op_register_config *reg = x;
138 
139 	wrperfmon(2, reg->mux_select);
140 	wrperfmon(3, reg->proc_mode);
141 	wrperfmon(4, reg->freq);
142 	wrperfmon(6, reg->reset_values);
143 }
144 
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.
148 
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.
152 
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).  */
156 
157 static void
ev5_reset_ctr(struct op_register_config * reg,unsigned long ctr)158 ev5_reset_ctr(struct op_register_config *reg, unsigned long ctr)
159 {
160 	unsigned long values, mask, not_pk, reset_values;
161 
162 	mask = (ctr == 0 ? 0xfffful << 48
163 	        : ctr == 1 ? 0xfffful << 32
164 		: 0x3fff << 16);
165 
166 	not_pk = 1 << 9 | 1 << 8;
167 
168 	reset_values = reg->reset_values;
169 
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);
180 	}
181 }
182 
183 static void
ev5_handle_interrupt(unsigned long which,struct pt_regs * regs,struct op_counter_config * ctr)184 ev5_handle_interrupt(unsigned long which, struct pt_regs *regs,
185 		     struct op_counter_config *ctr)
186 {
187 	/* Record the sample.  */
188 	oprofile_add_sample(regs, which);
189 }
190 
191 
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,
200 };
201 
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,
210 };
211