xref: /OK3568_Linux_fs/kernel/arch/alpha/oprofile/op_model_ev6.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /**
2*4882a593Smuzhiyun  * @file arch/alpha/oprofile/op_model_ev6.c
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * @remark Copyright 2002 OProfile authors
5*4882a593Smuzhiyun  * @remark Read the file COPYING
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * @author Richard Henderson <rth@twiddle.net>
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/oprofile.h>
11*4882a593Smuzhiyun #include <linux/smp.h>
12*4882a593Smuzhiyun #include <asm/ptrace.h>
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #include "op_impl.h"
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun /* Compute all of the registers in preparation for enabling profiling.  */
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun static void
ev6_reg_setup(struct op_register_config * reg,struct op_counter_config * ctr,struct op_system_config * sys)20*4882a593Smuzhiyun ev6_reg_setup(struct op_register_config *reg,
21*4882a593Smuzhiyun 	      struct op_counter_config *ctr,
22*4882a593Smuzhiyun 	      struct op_system_config *sys)
23*4882a593Smuzhiyun {
24*4882a593Smuzhiyun 	unsigned long ctl, reset, need_reset, i;
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun 	/* Select desired events.  We've mapped the event numbers
27*4882a593Smuzhiyun 	   such that they fit directly into the event selection fields.  */
28*4882a593Smuzhiyun 	ctl = 0;
29*4882a593Smuzhiyun 	if (ctr[0].enabled && ctr[0].event)
30*4882a593Smuzhiyun 		ctl |= (ctr[0].event & 1) << 4;
31*4882a593Smuzhiyun 	if (ctr[1].enabled)
32*4882a593Smuzhiyun 		ctl |= (ctr[1].event - 2) & 15;
33*4882a593Smuzhiyun 	reg->mux_select = ctl;
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun 	/* Select logging options.  */
36*4882a593Smuzhiyun 	/* ??? Need to come up with some mechanism to trace only
37*4882a593Smuzhiyun 	   selected processes.  EV6 does not have a mechanism to
38*4882a593Smuzhiyun 	   select kernel or user mode only.  For now, enable always.  */
39*4882a593Smuzhiyun 	reg->proc_mode = 0;
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 	/* EV6 cannot change the width of the counters as with the
42*4882a593Smuzhiyun 	   other implementations.  But fortunately, we can write to
43*4882a593Smuzhiyun 	   the counters and set the value such that it will overflow
44*4882a593Smuzhiyun 	   at the right time.  */
45*4882a593Smuzhiyun 	reset = need_reset = 0;
46*4882a593Smuzhiyun 	for (i = 0; i < 2; ++i) {
47*4882a593Smuzhiyun 		unsigned long count = ctr[i].count;
48*4882a593Smuzhiyun 		if (!ctr[i].enabled)
49*4882a593Smuzhiyun 			continue;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 		if (count > 0x100000)
52*4882a593Smuzhiyun 			count = 0x100000;
53*4882a593Smuzhiyun 		ctr[i].count = count;
54*4882a593Smuzhiyun 		reset |= (0x100000 - count) << (i ? 6 : 28);
55*4882a593Smuzhiyun 		if (count != 0x100000)
56*4882a593Smuzhiyun 			need_reset |= 1 << i;
57*4882a593Smuzhiyun 	}
58*4882a593Smuzhiyun 	reg->reset_values = reset;
59*4882a593Smuzhiyun 	reg->need_reset = need_reset;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun /* Program all of the registers in preparation for enabling profiling.  */
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun static void
ev6_cpu_setup(void * x)65*4882a593Smuzhiyun ev6_cpu_setup (void *x)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun 	struct op_register_config *reg = x;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	wrperfmon(2, reg->mux_select);
70*4882a593Smuzhiyun 	wrperfmon(3, reg->proc_mode);
71*4882a593Smuzhiyun 	wrperfmon(6, reg->reset_values | 3);
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun /* CTR is a counter for which the user has requested an interrupt count
75*4882a593Smuzhiyun    in between one of the widths selectable in hardware.  Reset the count
76*4882a593Smuzhiyun    for CTR to the value stored in REG->RESET_VALUES.  */
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun static void
ev6_reset_ctr(struct op_register_config * reg,unsigned long ctr)79*4882a593Smuzhiyun ev6_reset_ctr(struct op_register_config *reg, unsigned long ctr)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun 	wrperfmon(6, reg->reset_values | (1 << ctr));
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun static void
ev6_handle_interrupt(unsigned long which,struct pt_regs * regs,struct op_counter_config * ctr)85*4882a593Smuzhiyun ev6_handle_interrupt(unsigned long which, struct pt_regs *regs,
86*4882a593Smuzhiyun 		     struct op_counter_config *ctr)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	/* Record the sample.  */
89*4882a593Smuzhiyun 	oprofile_add_sample(regs, which);
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun struct op_axp_model op_model_ev6 = {
94*4882a593Smuzhiyun 	.reg_setup		= ev6_reg_setup,
95*4882a593Smuzhiyun 	.cpu_setup		= ev6_cpu_setup,
96*4882a593Smuzhiyun 	.reset_ctr		= ev6_reset_ctr,
97*4882a593Smuzhiyun 	.handle_interrupt	= ev6_handle_interrupt,
98*4882a593Smuzhiyun 	.cpu_type		= "alpha/ev6",
99*4882a593Smuzhiyun 	.num_counters		= 2,
100*4882a593Smuzhiyun 	.can_set_proc_mode	= 0,
101*4882a593Smuzhiyun };
102