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