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, 2005 Ralf Baechle 7 * Copyright (C) 2005 MIPS Technologies, Inc. 8 */ 9#include <linux/compiler.h> 10#include <linux/errno.h> 11#include <linux/init.h> 12#include <linux/oprofile.h> 13#include <linux/smp.h> 14#include <asm/cpu-info.h> 15#include <asm/cpu-type.h> 16 17#include "op_impl.h" 18 19extern struct op_mips_model op_model_mipsxx_ops __weak; 20extern struct op_mips_model op_model_loongson2_ops __weak; 21extern struct op_mips_model op_model_loongson3_ops __weak; 22 23static struct op_mips_model *model; 24 25static struct op_counter_config ctr[20]; 26 27static int op_mips_setup(void) 28{ 29 /* Pre-compute the values to stuff in the hardware registers. */ 30 model->reg_setup(ctr); 31 32 /* Configure the registers on all cpus. */ 33 on_each_cpu(model->cpu_setup, NULL, 1); 34 35 return 0; 36} 37 38static int op_mips_create_files(struct dentry *root) 39{ 40 int i; 41 42 for (i = 0; i < model->num_counters; ++i) { 43 struct dentry *dir; 44 char buf[4]; 45 46 snprintf(buf, sizeof buf, "%d", i); 47 dir = oprofilefs_mkdir(root, buf); 48 49 oprofilefs_create_ulong(dir, "enabled", &ctr[i].enabled); 50 oprofilefs_create_ulong(dir, "event", &ctr[i].event); 51 oprofilefs_create_ulong(dir, "count", &ctr[i].count); 52 oprofilefs_create_ulong(dir, "kernel", &ctr[i].kernel); 53 oprofilefs_create_ulong(dir, "user", &ctr[i].user); 54 oprofilefs_create_ulong(dir, "exl", &ctr[i].exl); 55 /* Dummy. */ 56 oprofilefs_create_ulong(dir, "unit_mask", &ctr[i].unit_mask); 57 } 58 59 return 0; 60} 61 62static int op_mips_start(void) 63{ 64 on_each_cpu(model->cpu_start, NULL, 1); 65 66 return 0; 67} 68 69static void op_mips_stop(void) 70{ 71 /* Disable performance monitoring for all counters. */ 72 on_each_cpu(model->cpu_stop, NULL, 1); 73} 74 75int __init oprofile_arch_init(struct oprofile_operations *ops) 76{ 77 struct op_mips_model *lmodel = NULL; 78 int res; 79 80 switch (current_cpu_type()) { 81 case CPU_5KC: 82 case CPU_M14KC: 83 case CPU_M14KEC: 84 case CPU_20KC: 85 case CPU_24K: 86 case CPU_25KF: 87 case CPU_34K: 88 case CPU_1004K: 89 case CPU_74K: 90 case CPU_1074K: 91 case CPU_INTERAPTIV: 92 case CPU_PROAPTIV: 93 case CPU_P5600: 94 case CPU_I6400: 95 case CPU_M5150: 96 case CPU_LOONGSON1: 97 case CPU_SB1: 98 case CPU_SB1A: 99 case CPU_R10000: 100 case CPU_R12000: 101 case CPU_R14000: 102 case CPU_R16000: 103 case CPU_XLR: 104 lmodel = &op_model_mipsxx_ops; 105 break; 106 107 case CPU_LOONGSON2: 108 lmodel = &op_model_loongson2_ops; 109 break; 110 case CPU_LOONGSON3: 111 lmodel = &op_model_loongson3_ops; 112 break; 113 }; 114 115 /* 116 * Always set the backtrace. This allows unsupported CPU types to still 117 * use timer-based oprofile. 118 */ 119 ops->backtrace = op_mips_backtrace; 120 121 if (!lmodel) 122 return -ENODEV; 123 124 res = lmodel->init(); 125 if (res) 126 return res; 127 128 model = lmodel; 129 130 ops->create_files = op_mips_create_files; 131 ops->setup = op_mips_setup; 132 //ops->shutdown = op_mips_shutdown; 133 ops->start = op_mips_start; 134 ops->stop = op_mips_stop; 135 ops->cpu_type = lmodel->cpu_type; 136 137 printk(KERN_INFO "oprofile: using %s performance monitoring.\n", 138 lmodel->cpu_type); 139 140 return 0; 141} 142 143void oprofile_arch_exit(void) 144{ 145 if (model) 146 model->exit(); 147} 148