root/arch/mips/oprofile/op_model_loongson2.c

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

DEFINITIONS

This source file includes following definitions.
  1. reset_counters
  2. loongson2_reg_setup
  3. loongson2_cpu_setup
  4. loongson2_cpu_start
  5. loongson2_cpu_stop
  6. loongson2_perfcount_handler
  7. loongson2_init
  8. loongson2_exit

   1 /*
   2  * Loongson2 performance counter driver for oprofile
   3  *
   4  * Copyright (C) 2009 Lemote Inc.
   5  * Author: Yanhua <yanh@lemote.com>
   6  * Author: Wu Zhangjin <wuzhangjin@gmail.com>
   7  *
   8  * This file is subject to the terms and conditions of the GNU General Public
   9  * License.  See the file "COPYING" in the main directory of this archive
  10  * for more details.
  11  */
  12 #include <linux/init.h>
  13 #include <linux/oprofile.h>
  14 #include <linux/interrupt.h>
  15 
  16 #include <loongson.h>                   /* LOONGSON2_PERFCNT_IRQ */
  17 #include "op_impl.h"
  18 
  19 #define LOONGSON2_CPU_TYPE      "mips/loongson2"
  20 
  21 #define LOONGSON2_PERFCNT_OVERFLOW              (1ULL   << 31)
  22 
  23 #define LOONGSON2_PERFCTRL_EXL                  (1UL    <<  0)
  24 #define LOONGSON2_PERFCTRL_KERNEL               (1UL    <<  1)
  25 #define LOONGSON2_PERFCTRL_SUPERVISOR           (1UL    <<  2)
  26 #define LOONGSON2_PERFCTRL_USER                 (1UL    <<  3)
  27 #define LOONGSON2_PERFCTRL_ENABLE               (1UL    <<  4)
  28 #define LOONGSON2_PERFCTRL_EVENT(idx, event) \
  29         (((event) & 0x0f) << ((idx) ? 9 : 5))
  30 
  31 #define read_c0_perfctrl() __read_64bit_c0_register($24, 0)
  32 #define write_c0_perfctrl(val) __write_64bit_c0_register($24, 0, val)
  33 #define read_c0_perfcnt() __read_64bit_c0_register($25, 0)
  34 #define write_c0_perfcnt(val) __write_64bit_c0_register($25, 0, val)
  35 
  36 static struct loongson2_register_config {
  37         unsigned int ctrl;
  38         unsigned long long reset_counter1;
  39         unsigned long long reset_counter2;
  40         int cnt1_enabled, cnt2_enabled;
  41 } reg;
  42 
  43 static char *oprofid = "LoongsonPerf";
  44 static irqreturn_t loongson2_perfcount_handler(int irq, void *dev_id);
  45 
  46 static void reset_counters(void *arg)
  47 {
  48         write_c0_perfctrl(0);
  49         write_c0_perfcnt(0);
  50 }
  51 
  52 static void loongson2_reg_setup(struct op_counter_config *cfg)
  53 {
  54         unsigned int ctrl = 0;
  55 
  56         reg.reset_counter1 = 0;
  57         reg.reset_counter2 = 0;
  58 
  59         /*
  60          * Compute the performance counter ctrl word.
  61          * For now, count kernel and user mode.
  62          */
  63         if (cfg[0].enabled) {
  64                 ctrl |= LOONGSON2_PERFCTRL_EVENT(0, cfg[0].event);
  65                 reg.reset_counter1 = 0x80000000ULL - cfg[0].count;
  66         }
  67 
  68         if (cfg[1].enabled) {
  69                 ctrl |= LOONGSON2_PERFCTRL_EVENT(1, cfg[1].event);
  70                 reg.reset_counter2 = 0x80000000ULL - cfg[1].count;
  71         }
  72 
  73         if (cfg[0].enabled || cfg[1].enabled) {
  74                 ctrl |= LOONGSON2_PERFCTRL_EXL | LOONGSON2_PERFCTRL_ENABLE;
  75                 if (cfg[0].kernel || cfg[1].kernel)
  76                         ctrl |= LOONGSON2_PERFCTRL_KERNEL;
  77                 if (cfg[0].user || cfg[1].user)
  78                         ctrl |= LOONGSON2_PERFCTRL_USER;
  79         }
  80 
  81         reg.ctrl = ctrl;
  82 
  83         reg.cnt1_enabled = cfg[0].enabled;
  84         reg.cnt2_enabled = cfg[1].enabled;
  85 }
  86 
  87 static void loongson2_cpu_setup(void *args)
  88 {
  89         write_c0_perfcnt((reg.reset_counter2 << 32) | reg.reset_counter1);
  90 }
  91 
  92 static void loongson2_cpu_start(void *args)
  93 {
  94         /* Start all counters on current CPU */
  95         if (reg.cnt1_enabled || reg.cnt2_enabled)
  96                 write_c0_perfctrl(reg.ctrl);
  97 }
  98 
  99 static void loongson2_cpu_stop(void *args)
 100 {
 101         /* Stop all counters on current CPU */
 102         write_c0_perfctrl(0);
 103         memset(&reg, 0, sizeof(reg));
 104 }
 105 
 106 static irqreturn_t loongson2_perfcount_handler(int irq, void *dev_id)
 107 {
 108         uint64_t counter, counter1, counter2;
 109         struct pt_regs *regs = get_irq_regs();
 110         int enabled;
 111 
 112         /* Check whether the irq belongs to me */
 113         enabled = read_c0_perfctrl() & LOONGSON2_PERFCTRL_ENABLE;
 114         if (!enabled)
 115                 return IRQ_NONE;
 116         enabled = reg.cnt1_enabled | reg.cnt2_enabled;
 117         if (!enabled)
 118                 return IRQ_NONE;
 119 
 120         counter = read_c0_perfcnt();
 121         counter1 = counter & 0xffffffff;
 122         counter2 = counter >> 32;
 123 
 124         if (counter1 & LOONGSON2_PERFCNT_OVERFLOW) {
 125                 if (reg.cnt1_enabled)
 126                         oprofile_add_sample(regs, 0);
 127                 counter1 = reg.reset_counter1;
 128         }
 129         if (counter2 & LOONGSON2_PERFCNT_OVERFLOW) {
 130                 if (reg.cnt2_enabled)
 131                         oprofile_add_sample(regs, 1);
 132                 counter2 = reg.reset_counter2;
 133         }
 134 
 135         write_c0_perfcnt((counter2 << 32) | counter1);
 136 
 137         return IRQ_HANDLED;
 138 }
 139 
 140 static int __init loongson2_init(void)
 141 {
 142         return request_irq(LOONGSON2_PERFCNT_IRQ, loongson2_perfcount_handler,
 143                            IRQF_SHARED, "Perfcounter", oprofid);
 144 }
 145 
 146 static void loongson2_exit(void)
 147 {
 148         reset_counters(NULL);
 149         free_irq(LOONGSON2_PERFCNT_IRQ, oprofid);
 150 }
 151 
 152 struct op_mips_model op_model_loongson2_ops = {
 153         .reg_setup = loongson2_reg_setup,
 154         .cpu_setup = loongson2_cpu_setup,
 155         .init = loongson2_init,
 156         .exit = loongson2_exit,
 157         .cpu_start = loongson2_cpu_start,
 158         .cpu_stop = loongson2_cpu_stop,
 159         .cpu_type = LOONGSON2_CPU_TYPE,
 160         .num_counters = 2
 161 };

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