Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
op_model_ev5.c
Go to the documentation of this file.
1 
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
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
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
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
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
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
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 
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 
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 };