Path: blob/master/arch/alpha/oprofile/op_model_ev67.c
10817 views
/**1* @file arch/alpha/oprofile/op_model_ev67.c2*3* @remark Copyright 2002 OProfile authors4* @remark Read the file COPYING5*6* @author Richard Henderson <[email protected]>7* @author Falk Hueffner <[email protected]>8*/910#include <linux/oprofile.h>11#include <linux/init.h>12#include <linux/smp.h>13#include <asm/ptrace.h>14#include <asm/system.h>1516#include "op_impl.h"171819/* Compute all of the registers in preparation for enabling profiling. */2021static void22ev67_reg_setup(struct op_register_config *reg,23struct op_counter_config *ctr,24struct op_system_config *sys)25{26unsigned long ctl, reset, need_reset, i;2728/* Select desired events. */29ctl = 1UL << 4; /* Enable ProfileMe mode. */3031/* The event numbers are chosen so we can use them directly if32PCTR1 is enabled. */33if (ctr[1].enabled) {34ctl |= (ctr[1].event & 3) << 2;35} else {36if (ctr[0].event == 0) /* cycles */37ctl |= 1UL << 2;38}39reg->mux_select = ctl;4041/* Select logging options. */42/* ??? Need to come up with some mechanism to trace only43selected processes. EV67 does not have a mechanism to44select kernel or user mode only. For now, enable always. */45reg->proc_mode = 0;4647/* EV67 cannot change the width of the counters as with the48other implementations. But fortunately, we can write to49the counters and set the value such that it will overflow50at the right time. */51reset = need_reset = 0;52for (i = 0; i < 2; ++i) {53unsigned long count = ctr[i].count;54if (!ctr[i].enabled)55continue;5657if (count > 0x100000)58count = 0x100000;59ctr[i].count = count;60reset |= (0x100000 - count) << (i ? 6 : 28);61if (count != 0x100000)62need_reset |= 1 << i;63}64reg->reset_values = reset;65reg->need_reset = need_reset;66}6768/* Program all of the registers in preparation for enabling profiling. */6970static void71ev67_cpu_setup (void *x)72{73struct op_register_config *reg = x;7475wrperfmon(2, reg->mux_select);76wrperfmon(3, reg->proc_mode);77wrperfmon(6, reg->reset_values | 3);78}7980/* CTR is a counter for which the user has requested an interrupt count81in between one of the widths selectable in hardware. Reset the count82for CTR to the value stored in REG->RESET_VALUES. */8384static void85ev67_reset_ctr(struct op_register_config *reg, unsigned long ctr)86{87wrperfmon(6, reg->reset_values | (1 << ctr));88}8990/* ProfileMe conditions which will show up as counters. We can also91detect the following, but it seems unlikely that anybody is92interested in counting them:93* Reset94* MT_FPCR (write to floating point control register)95* Arithmetic trap96* Dstream Fault97* Machine Check (ECC fault, etc.)98* OPCDEC (illegal opcode)99* Floating point disabled100* Differentiate between DTB single/double misses and 3 or 4 level101page tables102* Istream access violation103* Interrupt104* Icache Parity Error.105* Instruction killed (nop, trapb)106107Unfortunately, there seems to be no way to detect Dcache and Bcache108misses; the latter could be approximated by making the counter109count Bcache misses, but that is not precise.110111We model this as 20 counters:112* PCTR0113* PCTR1114* 9 ProfileMe events, induced by PCTR0115* 9 ProfileMe events, induced by PCTR1116*/117118enum profileme_counters {119PM_STALLED, /* Stalled for at least one cycle120between the fetch and map stages */121PM_TAKEN, /* Conditional branch taken */122PM_MISPREDICT, /* Branch caused mispredict trap */123PM_ITB_MISS, /* ITB miss */124PM_DTB_MISS, /* DTB miss */125PM_REPLAY, /* Replay trap */126PM_LOAD_STORE, /* Load-store order trap */127PM_ICACHE_MISS, /* Icache miss */128PM_UNALIGNED, /* Unaligned Load/Store */129PM_NUM_COUNTERS130};131132static inline void133op_add_pm(unsigned long pc, int kern, unsigned long counter,134struct op_counter_config *ctr, unsigned long event)135{136unsigned long fake_counter = 2 + event;137if (counter == 1)138fake_counter += PM_NUM_COUNTERS;139if (ctr[fake_counter].enabled)140oprofile_add_pc(pc, kern, fake_counter);141}142143static void144ev67_handle_interrupt(unsigned long which, struct pt_regs *regs,145struct op_counter_config *ctr)146{147unsigned long pmpc, pctr_ctl;148int kern = !user_mode(regs);149int mispredict = 0;150union {151unsigned long v;152struct {153unsigned reserved: 30; /* 0-29 */154unsigned overcount: 3; /* 30-32 */155unsigned icache_miss: 1; /* 33 */156unsigned trap_type: 4; /* 34-37 */157unsigned load_store: 1; /* 38 */158unsigned trap: 1; /* 39 */159unsigned mispredict: 1; /* 40 */160} fields;161} i_stat;162163enum trap_types {164TRAP_REPLAY,165TRAP_INVALID0,166TRAP_DTB_DOUBLE_MISS_3,167TRAP_DTB_DOUBLE_MISS_4,168TRAP_FP_DISABLED,169TRAP_UNALIGNED,170TRAP_DTB_SINGLE_MISS,171TRAP_DSTREAM_FAULT,172TRAP_OPCDEC,173TRAP_INVALID1,174TRAP_MACHINE_CHECK,175TRAP_INVALID2,176TRAP_ARITHMETIC,177TRAP_INVALID3,178TRAP_MT_FPCR,179TRAP_RESET180};181182pmpc = wrperfmon(9, 0);183/* ??? Don't know how to handle physical-mode PALcode address. */184if (pmpc & 1)185return;186pmpc &= ~2; /* clear reserved bit */187188i_stat.v = wrperfmon(8, 0);189if (i_stat.fields.trap) {190switch (i_stat.fields.trap_type) {191case TRAP_INVALID1:192case TRAP_INVALID2:193case TRAP_INVALID3:194/* Pipeline redirection occurred. PMPC points195to PALcode. Recognize ITB miss by PALcode196offset address, and get actual PC from197EXC_ADDR. */198oprofile_add_pc(regs->pc, kern, which);199if ((pmpc & ((1 << 15) - 1)) == 581)200op_add_pm(regs->pc, kern, which,201ctr, PM_ITB_MISS);202/* Most other bit and counter values will be203those for the first instruction in the204fault handler, so we're done. */205return;206case TRAP_REPLAY:207op_add_pm(pmpc, kern, which, ctr,208(i_stat.fields.load_store209? PM_LOAD_STORE : PM_REPLAY));210break;211case TRAP_DTB_DOUBLE_MISS_3:212case TRAP_DTB_DOUBLE_MISS_4:213case TRAP_DTB_SINGLE_MISS:214op_add_pm(pmpc, kern, which, ctr, PM_DTB_MISS);215break;216case TRAP_UNALIGNED:217op_add_pm(pmpc, kern, which, ctr, PM_UNALIGNED);218break;219case TRAP_INVALID0:220case TRAP_FP_DISABLED:221case TRAP_DSTREAM_FAULT:222case TRAP_OPCDEC:223case TRAP_MACHINE_CHECK:224case TRAP_ARITHMETIC:225case TRAP_MT_FPCR:226case TRAP_RESET:227break;228}229230/* ??? JSR/JMP/RET/COR or HW_JSR/HW_JMP/HW_RET/HW_COR231mispredicts do not set this bit but can be232recognized by the presence of one of these233instructions at the PMPC location with bit 39234set. */235if (i_stat.fields.mispredict) {236mispredict = 1;237op_add_pm(pmpc, kern, which, ctr, PM_MISPREDICT);238}239}240241oprofile_add_pc(pmpc, kern, which);242243pctr_ctl = wrperfmon(5, 0);244if (pctr_ctl & (1UL << 27))245op_add_pm(pmpc, kern, which, ctr, PM_STALLED);246247/* Unfortunately, TAK is undefined on mispredicted branches.248??? It is also undefined for non-cbranch insns, should249check that. */250if (!mispredict && pctr_ctl & (1UL << 0))251op_add_pm(pmpc, kern, which, ctr, PM_TAKEN);252}253254struct op_axp_model op_model_ev67 = {255.reg_setup = ev67_reg_setup,256.cpu_setup = ev67_cpu_setup,257.reset_ctr = ev67_reset_ctr,258.handle_interrupt = ev67_handle_interrupt,259.cpu_type = "alpha/ev67",260.num_counters = 20,261.can_set_proc_mode = 0,262};263264265