Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.17 248 lines 5.4 kB view raw
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 by Ralf Baechle 7 * Copyright (C) 2005 by MIPS Technologies, Inc. 8 */ 9#include <linux/oprofile.h> 10#include <linux/interrupt.h> 11#include <linux/smp.h> 12 13#include "op_impl.h" 14 15#define M_PERFCTL_EXL (1UL << 0) 16#define M_PERFCTL_KERNEL (1UL << 1) 17#define M_PERFCTL_SUPERVISOR (1UL << 2) 18#define M_PERFCTL_USER (1UL << 3) 19#define M_PERFCTL_INTERRUPT_ENABLE (1UL << 4) 20#define M_PERFCTL_EVENT(event) ((event) << 5) 21#define M_PERFCTL_WIDE (1UL << 30) 22#define M_PERFCTL_MORE (1UL << 31) 23 24#define M_COUNTER_OVERFLOW (1UL << 31) 25 26struct op_mips_model op_model_mipsxx_ops; 27 28static struct mipsxx_register_config { 29 unsigned int control[4]; 30 unsigned int counter[4]; 31} reg; 32 33/* Compute all of the registers in preparation for enabling profiling. */ 34 35static void mipsxx_reg_setup(struct op_counter_config *ctr) 36{ 37 unsigned int counters = op_model_mipsxx_ops.num_counters; 38 int i; 39 40 /* Compute the performance counter control word. */ 41 /* For now count kernel and user mode */ 42 for (i = 0; i < counters; i++) { 43 reg.control[i] = 0; 44 reg.counter[i] = 0; 45 46 if (!ctr[i].enabled) 47 continue; 48 49 reg.control[i] = M_PERFCTL_EVENT(ctr[i].event) | 50 M_PERFCTL_INTERRUPT_ENABLE; 51 if (ctr[i].kernel) 52 reg.control[i] |= M_PERFCTL_KERNEL; 53 if (ctr[i].user) 54 reg.control[i] |= M_PERFCTL_USER; 55 if (ctr[i].exl) 56 reg.control[i] |= M_PERFCTL_EXL; 57 reg.counter[i] = 0x80000000 - ctr[i].count; 58 } 59} 60 61/* Program all of the registers in preparation for enabling profiling. */ 62 63static void mipsxx_cpu_setup (void *args) 64{ 65 unsigned int counters = op_model_mipsxx_ops.num_counters; 66 67 switch (counters) { 68 case 4: 69 write_c0_perfctrl3(0); 70 write_c0_perfcntr3(reg.counter[3]); 71 case 3: 72 write_c0_perfctrl2(0); 73 write_c0_perfcntr2(reg.counter[2]); 74 case 2: 75 write_c0_perfctrl1(0); 76 write_c0_perfcntr1(reg.counter[1]); 77 case 1: 78 write_c0_perfctrl0(0); 79 write_c0_perfcntr0(reg.counter[0]); 80 } 81} 82 83/* Start all counters on current CPU */ 84static void mipsxx_cpu_start(void *args) 85{ 86 unsigned int counters = op_model_mipsxx_ops.num_counters; 87 88 switch (counters) { 89 case 4: 90 write_c0_perfctrl3(reg.control[3]); 91 case 3: 92 write_c0_perfctrl2(reg.control[2]); 93 case 2: 94 write_c0_perfctrl1(reg.control[1]); 95 case 1: 96 write_c0_perfctrl0(reg.control[0]); 97 } 98} 99 100/* Stop all counters on current CPU */ 101static void mipsxx_cpu_stop(void *args) 102{ 103 unsigned int counters = op_model_mipsxx_ops.num_counters; 104 105 switch (counters) { 106 case 4: 107 write_c0_perfctrl3(0); 108 case 3: 109 write_c0_perfctrl2(0); 110 case 2: 111 write_c0_perfctrl1(0); 112 case 1: 113 write_c0_perfctrl0(0); 114 } 115} 116 117static int mipsxx_perfcount_handler(struct pt_regs *regs) 118{ 119 unsigned int counters = op_model_mipsxx_ops.num_counters; 120 unsigned int control; 121 unsigned int counter; 122 int handled = 0; 123 124 switch (counters) { 125#define HANDLE_COUNTER(n) \ 126 case n + 1: \ 127 control = read_c0_perfctrl ## n(); \ 128 counter = read_c0_perfcntr ## n(); \ 129 if ((control & M_PERFCTL_INTERRUPT_ENABLE) && \ 130 (counter & M_COUNTER_OVERFLOW)) { \ 131 oprofile_add_sample(regs, n); \ 132 write_c0_perfcntr ## n(reg.counter[n]); \ 133 handled = 1; \ 134 } 135 HANDLE_COUNTER(3) 136 HANDLE_COUNTER(2) 137 HANDLE_COUNTER(1) 138 HANDLE_COUNTER(0) 139 } 140 141 return handled; 142} 143 144#define M_CONFIG1_PC (1 << 4) 145 146static inline int n_counters(void) 147{ 148 if (!(read_c0_config1() & M_CONFIG1_PC)) 149 return 0; 150 if (!(read_c0_perfctrl0() & M_PERFCTL_MORE)) 151 return 1; 152 if (!(read_c0_perfctrl1() & M_PERFCTL_MORE)) 153 return 2; 154 if (!(read_c0_perfctrl2() & M_PERFCTL_MORE)) 155 return 3; 156 157 return 4; 158} 159 160static inline void reset_counters(int counters) 161{ 162 switch (counters) { 163 case 4: 164 write_c0_perfctrl3(0); 165 write_c0_perfcntr3(0); 166 case 3: 167 write_c0_perfctrl2(0); 168 write_c0_perfcntr2(0); 169 case 2: 170 write_c0_perfctrl1(0); 171 write_c0_perfcntr1(0); 172 case 1: 173 write_c0_perfctrl0(0); 174 write_c0_perfcntr0(0); 175 } 176} 177 178static int __init mipsxx_init(void) 179{ 180 int counters; 181 182 counters = n_counters(); 183 if (counters == 0) { 184 printk(KERN_ERR "Oprofile: CPU has no performance counters\n"); 185 return -ENODEV; 186 } 187 188 reset_counters(counters); 189 190 op_model_mipsxx_ops.num_counters = counters; 191 switch (current_cpu_data.cputype) { 192 case CPU_20KC: 193 op_model_mipsxx_ops.cpu_type = "mips/20K"; 194 break; 195 196 case CPU_24K: 197 op_model_mipsxx_ops.cpu_type = "mips/24K"; 198 break; 199 200 case CPU_25KF: 201 op_model_mipsxx_ops.cpu_type = "mips/25K"; 202 break; 203 204#ifndef CONFIG_SMP 205 case CPU_34K: 206 op_model_mipsxx_ops.cpu_type = "mips/34K"; 207 break; 208 209 case CPU_74K: 210 op_model_mipsxx_ops.cpu_type = "mips/74K"; 211 break; 212#endif 213 214 case CPU_5KC: 215 op_model_mipsxx_ops.cpu_type = "mips/5K"; 216 break; 217 218 case CPU_SB1: 219 case CPU_SB1A: 220 op_model_mipsxx_ops.cpu_type = "mips/sb1"; 221 break; 222 223 default: 224 printk(KERN_ERR "Profiling unsupported for this CPU\n"); 225 226 return -ENODEV; 227 } 228 229 perf_irq = mipsxx_perfcount_handler; 230 231 return 0; 232} 233 234static void mipsxx_exit(void) 235{ 236 reset_counters(op_model_mipsxx_ops.num_counters); 237 238 perf_irq = null_perf_irq; 239} 240 241struct op_mips_model op_model_mipsxx_ops = { 242 .reg_setup = mipsxx_reg_setup, 243 .cpu_setup = mipsxx_cpu_setup, 244 .init = mipsxx_init, 245 .exit = mipsxx_exit, 246 .cpu_start = mipsxx_cpu_start, 247 .cpu_stop = mipsxx_cpu_stop, 248};