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