Path: blob/master/arch/alpha/oprofile/op_model_ev5.c
10817 views
/**1* @file arch/alpha/oprofile/op_model_ev5.c2*3* @remark Copyright 2002 OProfile authors4* @remark Read the file COPYING5*6* @author Richard Henderson <[email protected]>7*/89#include <linux/oprofile.h>10#include <linux/init.h>11#include <linux/smp.h>12#include <asm/ptrace.h>13#include <asm/system.h>1415#include "op_impl.h"161718/* Compute all of the registers in preparation for enabling profiling.1920The 21164 (EV5) and 21164PC (PCA65) vary in the bit placement and21meaning of the "CBOX" events. Given that we don't care about meaning22at this point, arrange for the difference in bit placement to be23handled by common code. */2425static void26common_reg_setup(struct op_register_config *reg,27struct op_counter_config *ctr,28struct op_system_config *sys,29int cbox1_ofs, int cbox2_ofs)30{31int i, ctl, reset, need_reset;3233/* Select desired events. The event numbers are selected such34that they map directly into the event selection fields:3536PCSEL0: 0, 137PCSEL1: 24-3938CBOX1: 40-4739PCSEL2: 48-6340CBOX2: 64-714142There are two special cases, in that CYCLES can be measured43on PCSEL[02], and SCACHE_WRITE can be measured on CBOX[12].44These event numbers are canonicalizes to their first appearance. */4546ctl = 0;47for (i = 0; i < 3; ++i) {48unsigned long event = ctr[i].event;49if (!ctr[i].enabled)50continue;5152/* Remap the duplicate events, as described above. */53if (i == 2) {54if (event == 0)55event = 12+48;56else if (event == 2+41)57event = 4+65;58}5960/* Convert the event numbers onto mux_select bit mask. */61if (event < 2)62ctl |= event << 31;63else if (event < 24)64/* error */;65else if (event < 40)66ctl |= (event - 24) << 4;67else if (event < 48)68ctl |= (event - 40) << cbox1_ofs | 15 << 4;69else if (event < 64)70ctl |= event - 48;71else if (event < 72)72ctl |= (event - 64) << cbox2_ofs | 15;73}74reg->mux_select = ctl;7576/* Select processor mode. */77/* ??? Need to come up with some mechanism to trace only selected78processes. For now select from pal, kernel and user mode. */79ctl = 0;80ctl |= !sys->enable_pal << 9;81ctl |= !sys->enable_kernel << 8;82ctl |= !sys->enable_user << 30;83reg->proc_mode = ctl;8485/* Select interrupt frequencies. Take the interrupt count selected86by the user, and map it onto one of the possible counter widths.87If the user value is in between, compute a value to which the88counter is reset at each interrupt. */8990ctl = reset = need_reset = 0;91for (i = 0; i < 3; ++i) {92unsigned long max, hilo, count = ctr[i].count;93if (!ctr[i].enabled)94continue;9596if (count <= 256)97count = 256, hilo = 3, max = 256;98else {99max = (i == 2 ? 16384 : 65536);100hilo = 2;101if (count > max)102count = max;103}104ctr[i].count = count;105106ctl |= hilo << (8 - i*2);107reset |= (max - count) << (48 - 16*i);108if (count != max)109need_reset |= 1 << i;110}111reg->freq = ctl;112reg->reset_values = reset;113reg->need_reset = need_reset;114}115116static void117ev5_reg_setup(struct op_register_config *reg,118struct op_counter_config *ctr,119struct op_system_config *sys)120{121common_reg_setup(reg, ctr, sys, 19, 22);122}123124static void125pca56_reg_setup(struct op_register_config *reg,126struct op_counter_config *ctr,127struct op_system_config *sys)128{129common_reg_setup(reg, ctr, sys, 8, 11);130}131132/* Program all of the registers in preparation for enabling profiling. */133134static void135ev5_cpu_setup (void *x)136{137struct op_register_config *reg = x;138139wrperfmon(2, reg->mux_select);140wrperfmon(3, reg->proc_mode);141wrperfmon(4, reg->freq);142wrperfmon(6, reg->reset_values);143}144145/* CTR is a counter for which the user has requested an interrupt count146in between one of the widths selectable in hardware. Reset the count147for CTR to the value stored in REG->RESET_VALUES.148149For EV5, this means disabling profiling, reading the current values,150masking in the value for the desired register, writing, then turning151profiling back on.152153This can be streamlined if profiling is only enabled for user mode.154In that case we know that the counters are not currently incrementing155(due to being in kernel mode). */156157static void158ev5_reset_ctr(struct op_register_config *reg, unsigned long ctr)159{160unsigned long values, mask, not_pk, reset_values;161162mask = (ctr == 0 ? 0xfffful << 48163: ctr == 1 ? 0xfffful << 32164: 0x3fff << 16);165166not_pk = 1 << 9 | 1 << 8;167168reset_values = reg->reset_values;169170if ((reg->proc_mode & not_pk) == not_pk) {171values = wrperfmon(5, 0);172values = (reset_values & mask) | (values & ~mask & -2);173wrperfmon(6, values);174} else {175wrperfmon(0, -1);176values = wrperfmon(5, 0);177values = (reset_values & mask) | (values & ~mask & -2);178wrperfmon(6, values);179wrperfmon(1, reg->enable);180}181}182183static void184ev5_handle_interrupt(unsigned long which, struct pt_regs *regs,185struct op_counter_config *ctr)186{187/* Record the sample. */188oprofile_add_sample(regs, which);189}190191192struct 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};201202struct 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};211212213