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_M5150: 95 case CPU_LOONGSON1: 96 case CPU_SB1: 97 case CPU_SB1A: 98 case CPU_R10000: 99 case CPU_R12000: 100 case CPU_R14000: 101 case CPU_R16000: 102 case CPU_XLR: 103 lmodel = &op_model_mipsxx_ops; 104 break; 105 106 case CPU_LOONGSON2: 107 lmodel = &op_model_loongson2_ops; 108 break; 109 case CPU_LOONGSON3: 110 lmodel = &op_model_loongson3_ops; 111 break; 112 }; 113 114 /* 115 * Always set the backtrace. This allows unsupported CPU types to still 116 * use timer-based oprofile. 117 */ 118 ops->backtrace = op_mips_backtrace; 119 120 if (!lmodel) 121 return -ENODEV; 122 123 res = lmodel->init(); 124 if (res) 125 return res; 126 127 model = lmodel; 128 129 ops->create_files = op_mips_create_files; 130 ops->setup = op_mips_setup; 131 //ops->shutdown = op_mips_shutdown; 132 ops->start = op_mips_start; 133 ops->stop = op_mips_stop; 134 ops->cpu_type = lmodel->cpu_type; 135 136 printk(KERN_INFO "oprofile: using %s performance monitoring.\n", 137 lmodel->cpu_type); 138 139 return 0; 140} 141 142void oprofile_arch_exit(void) 143{ 144 if (model) 145 model->exit(); 146} 147