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