linux/arch/mips/oprofile/op_model_rm9000.c
<<
>>
Prefs
   1/*
   2 * This file is subject to the terms and conditions of the GNU General Public
   3 * License.  See the file "COPYING" in the main directory of this archive
   4 * for more details.
   5 *
   6 * Copyright (C) 2004 by Ralf Baechle
   7 */
   8#include <linux/init.h>
   9#include <linux/oprofile.h>
  10#include <linux/interrupt.h>
  11#include <linux/smp.h>
  12
  13#include "op_impl.h"
  14
  15#define RM9K_COUNTER1_EVENT(event)      ((event) << 0)
  16#define RM9K_COUNTER1_SUPERVISOR        (1ULL    <<  7)
  17#define RM9K_COUNTER1_KERNEL            (1ULL    <<  8)
  18#define RM9K_COUNTER1_USER              (1ULL    <<  9)
  19#define RM9K_COUNTER1_ENABLE            (1ULL    << 10)
  20#define RM9K_COUNTER1_OVERFLOW          (1ULL    << 15)
  21
  22#define RM9K_COUNTER2_EVENT(event)      ((event) << 16)
  23#define RM9K_COUNTER2_SUPERVISOR        (1ULL    << 23)
  24#define RM9K_COUNTER2_KERNEL            (1ULL    << 24)
  25#define RM9K_COUNTER2_USER              (1ULL    << 25)
  26#define RM9K_COUNTER2_ENABLE            (1ULL    << 26)
  27#define RM9K_COUNTER2_OVERFLOW          (1ULL    << 31)
  28
  29extern unsigned int rm9000_perfcount_irq;
  30
  31static struct rm9k_register_config {
  32        unsigned int control;
  33        unsigned int reset_counter1;
  34        unsigned int reset_counter2;
  35} reg;
  36
  37/* Compute all of the registers in preparation for enabling profiling.  */
  38
  39static void rm9000_reg_setup(struct op_counter_config *ctr)
  40{
  41        unsigned int control = 0;
  42
  43        /* Compute the performance counter control word.  */
  44        /* For now count kernel and user mode */
  45        if (ctr[0].enabled)
  46                control |= RM9K_COUNTER1_EVENT(ctr[0].event) |
  47                           RM9K_COUNTER1_KERNEL |
  48                           RM9K_COUNTER1_USER |
  49                           RM9K_COUNTER1_ENABLE;
  50        if (ctr[1].enabled)
  51                control |= RM9K_COUNTER2_EVENT(ctr[1].event) |
  52                           RM9K_COUNTER2_KERNEL |
  53                           RM9K_COUNTER2_USER |
  54                           RM9K_COUNTER2_ENABLE;
  55        reg.control = control;
  56
  57        reg.reset_counter1 = 0x80000000 - ctr[0].count;
  58        reg.reset_counter2 = 0x80000000 - ctr[1].count;
  59}
  60
  61/* Program all of the registers in preparation for enabling profiling.  */
  62
  63static void rm9000_cpu_setup(void *args)
  64{
  65        uint64_t perfcount;
  66
  67        perfcount = ((uint64_t) reg.reset_counter2 << 32) | reg.reset_counter1;
  68        write_c0_perfcount(perfcount);
  69}
  70
  71static void rm9000_cpu_start(void *args)
  72{
  73        /* Start all counters on current CPU */
  74        write_c0_perfcontrol(reg.control);
  75}
  76
  77static void rm9000_cpu_stop(void *args)
  78{
  79        /* Stop all counters on current CPU */
  80        write_c0_perfcontrol(0);
  81}
  82
  83static irqreturn_t rm9000_perfcount_handler(int irq, void *dev_id)
  84{
  85        unsigned int control = read_c0_perfcontrol();
  86        struct pt_regs *regs = get_irq_regs();
  87        uint32_t counter1, counter2;
  88        uint64_t counters;
  89
  90        /*
  91         * RM9000 combines two 32-bit performance counters into a single
  92         * 64-bit coprocessor zero register.  To avoid a race updating the
  93         * registers we need to stop the counters while we're messing with
  94         * them ...
  95         */
  96        write_c0_perfcontrol(0);
  97
  98        counters = read_c0_perfcount();
  99        counter1 = counters;
 100        counter2 = counters >> 32;
 101
 102        if (control & RM9K_COUNTER1_OVERFLOW) {
 103                oprofile_add_sample(regs, 0);
 104                counter1 = reg.reset_counter1;
 105        }
 106        if (control & RM9K_COUNTER2_OVERFLOW) {
 107                oprofile_add_sample(regs, 1);
 108                counter2 = reg.reset_counter2;
 109        }
 110
 111        counters = ((uint64_t)counter2 << 32) | counter1;
 112        write_c0_perfcount(counters);
 113        write_c0_perfcontrol(reg.control);
 114
 115        return IRQ_HANDLED;
 116}
 117
 118static int __init rm9000_init(void)
 119{
 120        return request_irq(rm9000_perfcount_irq, rm9000_perfcount_handler,
 121                           0, "Perfcounter", NULL);
 122}
 123
 124static void rm9000_exit(void)
 125{
 126        free_irq(rm9000_perfcount_irq, NULL);
 127}
 128
 129struct op_mips_model op_model_rm9000_ops = {
 130        .reg_setup      = rm9000_reg_setup,
 131        .cpu_setup      = rm9000_cpu_setup,
 132        .init           = rm9000_init,
 133        .exit           = rm9000_exit,
 134        .cpu_start      = rm9000_cpu_start,
 135        .cpu_stop       = rm9000_cpu_stop,
 136        .cpu_type       = "mips/rm9000",
 137        .num_counters   = 2
 138};
 139