1/** 2 * @file arch/alpha/oprofile/common.c 3 * 4 * @remark Copyright 2002 OProfile authors 5 * @remark Read the file COPYING 6 * 7 * @author Richard Henderson <rth@twiddle.net> 8 */ 9 10#include <linux/oprofile.h> 11#include <linux/init.h> 12#include <linux/smp.h> 13#include <linux/errno.h> 14#include <asm/ptrace.h> 15#include <asm/special_insns.h> 16 17#include "op_impl.h" 18 19extern struct op_axp_model op_model_ev4 __attribute__((weak)); 20extern struct op_axp_model op_model_ev5 __attribute__((weak)); 21extern struct op_axp_model op_model_pca56 __attribute__((weak)); 22extern struct op_axp_model op_model_ev6 __attribute__((weak)); 23extern struct op_axp_model op_model_ev67 __attribute__((weak)); 24 25static struct op_axp_model *model; 26 27extern void (*perf_irq)(unsigned long, struct pt_regs *); 28static void (*save_perf_irq)(unsigned long, struct pt_regs *); 29 30static struct op_counter_config ctr[20]; 31static struct op_system_config sys; 32static struct op_register_config reg; 33 34/* Called from do_entInt to handle the performance monitor interrupt. */ 35 36static void 37op_handle_interrupt(unsigned long which, struct pt_regs *regs) 38{ 39 model->handle_interrupt(which, regs, ctr); 40 41 /* If the user has selected an interrupt frequency that is 42 not exactly the width of the counter, write a new value 43 into the counter such that it'll overflow after N more 44 events. */ 45 if ((reg.need_reset >> which) & 1) 46 model->reset_ctr(®, which); 47} 48 49static int 50op_axp_setup(void) 51{ 52 unsigned long i, e; 53 54 /* Install our interrupt handler into the existing hook. */ 55 save_perf_irq = perf_irq; 56 perf_irq = op_handle_interrupt; 57 58 /* Compute the mask of enabled counters. */ 59 for (i = e = 0; i < model->num_counters; ++i) 60 if (ctr[i].enabled) 61 e |= 1 << i; 62 reg.enable = e; 63 64 /* Pre-compute the values to stuff in the hardware registers. */ 65 model->reg_setup(®, ctr, &sys); 66 67 /* Configure the registers on all cpus. */ 68 (void)smp_call_function(model->cpu_setup, ®, 1); 69 model->cpu_setup(®); 70 return 0; 71} 72 73static void 74op_axp_shutdown(void) 75{ 76 /* Remove our interrupt handler. We may be removing this module. */ 77 perf_irq = save_perf_irq; 78} 79 80static void 81op_axp_cpu_start(void *dummy) 82{ 83 wrperfmon(1, reg.enable); 84} 85 86static int 87op_axp_start(void) 88{ 89 (void)smp_call_function(op_axp_cpu_start, NULL, 1); 90 op_axp_cpu_start(NULL); 91 return 0; 92} 93 94static inline void 95op_axp_cpu_stop(void *dummy) 96{ 97 /* Disable performance monitoring for all counters. */ 98 wrperfmon(0, -1); 99} 100 101static void 102op_axp_stop(void) 103{ 104 (void)smp_call_function(op_axp_cpu_stop, NULL, 1); 105 op_axp_cpu_stop(NULL); 106} 107 108static int 109op_axp_create_files(struct dentry *root) 110{ 111 int i; 112 113 for (i = 0; i < model->num_counters; ++i) { 114 struct dentry *dir; 115 char buf[4]; 116 117 snprintf(buf, sizeof buf, "%d", i); 118 dir = oprofilefs_mkdir(root, buf); 119 120 oprofilefs_create_ulong(dir, "enabled", &ctr[i].enabled); 121 oprofilefs_create_ulong(dir, "event", &ctr[i].event); 122 oprofilefs_create_ulong(dir, "count", &ctr[i].count); 123 /* Dummies. */ 124 oprofilefs_create_ulong(dir, "kernel", &ctr[i].kernel); 125 oprofilefs_create_ulong(dir, "user", &ctr[i].user); 126 oprofilefs_create_ulong(dir, "unit_mask", &ctr[i].unit_mask); 127 } 128 129 if (model->can_set_proc_mode) { 130 oprofilefs_create_ulong(root, "enable_pal", 131 &sys.enable_pal); 132 oprofilefs_create_ulong(root, "enable_kernel", 133 &sys.enable_kernel); 134 oprofilefs_create_ulong(root, "enable_user", 135 &sys.enable_user); 136 } 137 138 return 0; 139} 140 141int __init 142oprofile_arch_init(struct oprofile_operations *ops) 143{ 144 struct op_axp_model *lmodel = NULL; 145 146 switch (implver()) { 147 case IMPLVER_EV4: 148 lmodel = &op_model_ev4; 149 break; 150 case IMPLVER_EV5: 151 /* 21164PC has a slightly different set of events. 152 Recognize the chip by the presence of the MAX insns. */ 153 if (!amask(AMASK_MAX)) 154 lmodel = &op_model_pca56; 155 else 156 lmodel = &op_model_ev5; 157 break; 158 case IMPLVER_EV6: 159 /* 21264A supports ProfileMe. 160 Recognize the chip by the presence of the CIX insns. */ 161 if (!amask(AMASK_CIX)) 162 lmodel = &op_model_ev67; 163 else 164 lmodel = &op_model_ev6; 165 break; 166 } 167 168 if (!lmodel) 169 return -ENODEV; 170 model = lmodel; 171 172 ops->create_files = op_axp_create_files; 173 ops->setup = op_axp_setup; 174 ops->shutdown = op_axp_shutdown; 175 ops->start = op_axp_start; 176 ops->stop = op_axp_stop; 177 ops->cpu_type = lmodel->cpu_type; 178 179 printk(KERN_INFO "oprofile: using %s performance monitoring.\n", 180 lmodel->cpu_type); 181 182 return 0; 183} 184 185 186void 187oprofile_arch_exit(void) 188{ 189} 190