linux/arch/alpha/oprofile/op_model_ev5.c
<<
>>
Prefs
   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