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