root/arch/alpha/oprofile/op_model_ev67.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ev67_reg_setup
  2. ev67_cpu_setup
  3. ev67_reset_ctr
  4. op_add_pm
  5. ev67_handle_interrupt

   1 /**
   2  * @file arch/alpha/oprofile/op_model_ev67.c
   3  *
   4  * @remark Copyright 2002 OProfile authors
   5  * @remark Read the file COPYING
   6  *
   7  * @author Richard Henderson <rth@twiddle.net>
   8  * @author Falk Hueffner <falk@debian.org>
   9  */
  10 
  11 #include <linux/oprofile.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 static void
  21 ev67_reg_setup(struct op_register_config *reg,
  22                struct op_counter_config *ctr,
  23                struct op_system_config *sys)
  24 {
  25         unsigned long ctl, reset, need_reset, i;
  26 
  27         /* Select desired events.  */
  28         ctl = 1UL << 4;         /* Enable ProfileMe mode. */
  29 
  30         /* The event numbers are chosen so we can use them directly if
  31            PCTR1 is enabled.  */
  32         if (ctr[1].enabled) {
  33                 ctl |= (ctr[1].event & 3) << 2;
  34         } else {
  35                 if (ctr[0].event == 0) /* cycles */
  36                         ctl |= 1UL << 2;
  37         }
  38         reg->mux_select = ctl;
  39 
  40         /* Select logging options.  */
  41         /* ??? Need to come up with some mechanism to trace only
  42            selected processes.  EV67 does not have a mechanism to
  43            select kernel or user mode only.  For now, enable always.  */
  44         reg->proc_mode = 0;
  45 
  46         /* EV67 cannot change the width of the counters as with the
  47            other implementations.  But fortunately, we can write to
  48            the counters and set the value such that it will overflow
  49            at the right time.  */
  50         reset = need_reset = 0;
  51         for (i = 0; i < 2; ++i) {
  52                 unsigned long count = ctr[i].count;
  53                 if (!ctr[i].enabled)
  54                         continue;
  55 
  56                 if (count > 0x100000)
  57                         count = 0x100000;
  58                 ctr[i].count = count;
  59                 reset |= (0x100000 - count) << (i ? 6 : 28);
  60                 if (count != 0x100000)
  61                         need_reset |= 1 << i;
  62         }
  63         reg->reset_values = reset;
  64         reg->need_reset = need_reset;
  65 }
  66 
  67 /* Program all of the registers in preparation for enabling profiling.  */
  68 
  69 static void
  70 ev67_cpu_setup (void *x)
  71 {
  72         struct op_register_config *reg = x;
  73 
  74         wrperfmon(2, reg->mux_select);
  75         wrperfmon(3, reg->proc_mode);
  76         wrperfmon(6, reg->reset_values | 3);
  77 }
  78 
  79 /* CTR is a counter for which the user has requested an interrupt count
  80    in between one of the widths selectable in hardware.  Reset the count
  81    for CTR to the value stored in REG->RESET_VALUES.  */
  82 
  83 static void
  84 ev67_reset_ctr(struct op_register_config *reg, unsigned long ctr)
  85 {
  86         wrperfmon(6, reg->reset_values | (1 << ctr));
  87 }
  88 
  89 /* ProfileMe conditions which will show up as counters. We can also
  90    detect the following, but it seems unlikely that anybody is
  91    interested in counting them:
  92     * Reset
  93     * MT_FPCR (write to floating point control register)
  94     * Arithmetic trap
  95     * Dstream Fault
  96     * Machine Check (ECC fault, etc.)
  97     * OPCDEC (illegal opcode)
  98     * Floating point disabled
  99     * Differentiate between DTB single/double misses and 3 or 4 level
 100       page tables
 101     * Istream access violation
 102     * Interrupt
 103     * Icache Parity Error.
 104     * Instruction killed (nop, trapb)
 105 
 106    Unfortunately, there seems to be no way to detect Dcache and Bcache
 107    misses; the latter could be approximated by making the counter
 108    count Bcache misses, but that is not precise.
 109 
 110    We model this as 20 counters:
 111     * PCTR0
 112     * PCTR1
 113     * 9 ProfileMe events, induced by PCTR0
 114     * 9 ProfileMe events, induced by PCTR1
 115 */
 116 
 117 enum profileme_counters {
 118         PM_STALLED,             /* Stalled for at least one cycle
 119                                    between the fetch and map stages  */
 120         PM_TAKEN,               /* Conditional branch taken */
 121         PM_MISPREDICT,          /* Branch caused mispredict trap */
 122         PM_ITB_MISS,            /* ITB miss */
 123         PM_DTB_MISS,            /* DTB miss */
 124         PM_REPLAY,              /* Replay trap */
 125         PM_LOAD_STORE,          /* Load-store order trap */
 126         PM_ICACHE_MISS,         /* Icache miss */
 127         PM_UNALIGNED,           /* Unaligned Load/Store */
 128         PM_NUM_COUNTERS
 129 };
 130 
 131 static inline void
 132 op_add_pm(unsigned long pc, int kern, unsigned long counter,
 133           struct op_counter_config *ctr, unsigned long event)
 134 {
 135         unsigned long fake_counter = 2 + event;
 136         if (counter == 1)
 137                 fake_counter += PM_NUM_COUNTERS;
 138         if (ctr[fake_counter].enabled)
 139                 oprofile_add_pc(pc, kern, fake_counter);
 140 }
 141 
 142 static void
 143 ev67_handle_interrupt(unsigned long which, struct pt_regs *regs,
 144                       struct op_counter_config *ctr)
 145 {
 146         unsigned long pmpc, pctr_ctl;
 147         int kern = !user_mode(regs);
 148         int mispredict = 0;
 149         union {
 150                 unsigned long v;
 151                 struct {
 152                         unsigned reserved:      30; /*  0-29 */
 153                         unsigned overcount:      3; /* 30-32 */
 154                         unsigned icache_miss:    1; /*    33 */
 155                         unsigned trap_type:      4; /* 34-37 */
 156                         unsigned load_store:     1; /*    38 */
 157                         unsigned trap:           1; /*    39 */
 158                         unsigned mispredict:     1; /*    40 */
 159                 } fields;
 160         } i_stat;
 161 
 162         enum trap_types {
 163                 TRAP_REPLAY,
 164                 TRAP_INVALID0,
 165                 TRAP_DTB_DOUBLE_MISS_3,
 166                 TRAP_DTB_DOUBLE_MISS_4,
 167                 TRAP_FP_DISABLED,
 168                 TRAP_UNALIGNED,
 169                 TRAP_DTB_SINGLE_MISS,
 170                 TRAP_DSTREAM_FAULT,
 171                 TRAP_OPCDEC,
 172                 TRAP_INVALID1,
 173                 TRAP_MACHINE_CHECK,
 174                 TRAP_INVALID2,
 175                 TRAP_ARITHMETIC,
 176                 TRAP_INVALID3,
 177                 TRAP_MT_FPCR,
 178                 TRAP_RESET
 179         };
 180 
 181         pmpc = wrperfmon(9, 0);
 182         /* ??? Don't know how to handle physical-mode PALcode address.  */
 183         if (pmpc & 1)
 184                 return;
 185         pmpc &= ~2;             /* clear reserved bit */
 186 
 187         i_stat.v = wrperfmon(8, 0);
 188         if (i_stat.fields.trap) {
 189                 switch (i_stat.fields.trap_type) {
 190                 case TRAP_INVALID1:
 191                 case TRAP_INVALID2:
 192                 case TRAP_INVALID3:
 193                         /* Pipeline redirection occurred. PMPC points
 194                            to PALcode. Recognize ITB miss by PALcode
 195                            offset address, and get actual PC from
 196                            EXC_ADDR.  */
 197                         oprofile_add_pc(regs->pc, kern, which);
 198                         if ((pmpc & ((1 << 15) - 1)) ==  581)
 199                                 op_add_pm(regs->pc, kern, which,
 200                                           ctr, PM_ITB_MISS);
 201                         /* Most other bit and counter values will be
 202                            those for the first instruction in the
 203                            fault handler, so we're done.  */
 204                         return;
 205                 case TRAP_REPLAY:
 206                         op_add_pm(pmpc, kern, which, ctr,
 207                                   (i_stat.fields.load_store
 208                                    ? PM_LOAD_STORE : PM_REPLAY));
 209                         break;
 210                 case TRAP_DTB_DOUBLE_MISS_3:
 211                 case TRAP_DTB_DOUBLE_MISS_4:
 212                 case TRAP_DTB_SINGLE_MISS:
 213                         op_add_pm(pmpc, kern, which, ctr, PM_DTB_MISS);
 214                         break;
 215                 case TRAP_UNALIGNED:
 216                         op_add_pm(pmpc, kern, which, ctr, PM_UNALIGNED);
 217                         break;
 218                 case TRAP_INVALID0:
 219                 case TRAP_FP_DISABLED:
 220                 case TRAP_DSTREAM_FAULT:
 221                 case TRAP_OPCDEC:
 222                 case TRAP_MACHINE_CHECK:
 223                 case TRAP_ARITHMETIC:
 224                 case TRAP_MT_FPCR:
 225                 case TRAP_RESET:
 226                         break;
 227                 }
 228 
 229                 /* ??? JSR/JMP/RET/COR or HW_JSR/HW_JMP/HW_RET/HW_COR
 230                    mispredicts do not set this bit but can be
 231                    recognized by the presence of one of these
 232                    instructions at the PMPC location with bit 39
 233                    set.  */
 234                 if (i_stat.fields.mispredict) {
 235                         mispredict = 1;
 236                         op_add_pm(pmpc, kern, which, ctr, PM_MISPREDICT);
 237                 }
 238         }
 239 
 240         oprofile_add_pc(pmpc, kern, which);
 241 
 242         pctr_ctl = wrperfmon(5, 0);
 243         if (pctr_ctl & (1UL << 27))
 244                 op_add_pm(pmpc, kern, which, ctr, PM_STALLED);
 245 
 246         /* Unfortunately, TAK is undefined on mispredicted branches.
 247            ??? It is also undefined for non-cbranch insns, should
 248            check that.  */
 249         if (!mispredict && pctr_ctl & (1UL << 0))
 250                 op_add_pm(pmpc, kern, which, ctr, PM_TAKEN);
 251 }
 252 
 253 struct op_axp_model op_model_ev67 = {
 254         .reg_setup              = ev67_reg_setup,
 255         .cpu_setup              = ev67_cpu_setup,
 256         .reset_ctr              = ev67_reset_ctr,
 257         .handle_interrupt       = ev67_handle_interrupt,
 258         .cpu_type               = "alpha/ev67",
 259         .num_counters           = 20,
 260         .can_set_proc_mode      = 0,
 261 };

/* [<][>][^][v][top][bottom][index][help] */