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