Back to home page

LXR

 
 

    


0001 /**
0002  * @file arch/alpha/oprofile/common.c
0003  *
0004  * @remark Copyright 2002 OProfile authors
0005  * @remark Read the file COPYING
0006  *
0007  * @author Richard Henderson <rth@twiddle.net>
0008  */
0009 
0010 #include <linux/oprofile.h>
0011 #include <linux/init.h>
0012 #include <linux/smp.h>
0013 #include <linux/errno.h>
0014 #include <asm/ptrace.h>
0015 #include <asm/special_insns.h>
0016 
0017 #include "op_impl.h"
0018 
0019 extern struct op_axp_model op_model_ev4 __attribute__((weak));
0020 extern struct op_axp_model op_model_ev5 __attribute__((weak));
0021 extern struct op_axp_model op_model_pca56 __attribute__((weak));
0022 extern struct op_axp_model op_model_ev6 __attribute__((weak));
0023 extern struct op_axp_model op_model_ev67 __attribute__((weak));
0024 
0025 static struct op_axp_model *model;
0026 
0027 extern void (*perf_irq)(unsigned long, struct pt_regs *);
0028 static void (*save_perf_irq)(unsigned long, struct pt_regs *);
0029 
0030 static struct op_counter_config ctr[20];
0031 static struct op_system_config sys;
0032 static struct op_register_config reg;
0033 
0034 /* Called from do_entInt to handle the performance monitor interrupt.  */
0035 
0036 static void
0037 op_handle_interrupt(unsigned long which, struct pt_regs *regs)
0038 {
0039     model->handle_interrupt(which, regs, ctr);
0040 
0041     /* If the user has selected an interrupt frequency that is
0042        not exactly the width of the counter, write a new value
0043        into the counter such that it'll overflow after N more
0044        events.  */
0045     if ((reg.need_reset >> which) & 1)
0046         model->reset_ctr(&reg, which);
0047 }
0048  
0049 static int
0050 op_axp_setup(void)
0051 {
0052     unsigned long i, e;
0053 
0054     /* Install our interrupt handler into the existing hook.  */
0055     save_perf_irq = perf_irq;
0056     perf_irq = op_handle_interrupt;
0057 
0058     /* Compute the mask of enabled counters.  */
0059     for (i = e = 0; i < model->num_counters; ++i)
0060         if (ctr[i].enabled)
0061             e |= 1 << i;
0062     reg.enable = e;
0063 
0064     /* Pre-compute the values to stuff in the hardware registers.  */
0065     model->reg_setup(&reg, ctr, &sys);
0066 
0067     /* Configure the registers on all cpus.  */
0068     (void)smp_call_function(model->cpu_setup, &reg, 1);
0069     model->cpu_setup(&reg);
0070     return 0;
0071 }
0072 
0073 static void
0074 op_axp_shutdown(void)
0075 {
0076     /* Remove our interrupt handler.  We may be removing this module.  */
0077     perf_irq = save_perf_irq;
0078 }
0079 
0080 static void
0081 op_axp_cpu_start(void *dummy)
0082 {
0083     wrperfmon(1, reg.enable);
0084 }
0085 
0086 static int
0087 op_axp_start(void)
0088 {
0089     (void)smp_call_function(op_axp_cpu_start, NULL, 1);
0090     op_axp_cpu_start(NULL);
0091     return 0;
0092 }
0093 
0094 static inline void
0095 op_axp_cpu_stop(void *dummy)
0096 {
0097     /* Disable performance monitoring for all counters.  */
0098     wrperfmon(0, -1);
0099 }
0100 
0101 static void
0102 op_axp_stop(void)
0103 {
0104     (void)smp_call_function(op_axp_cpu_stop, NULL, 1);
0105     op_axp_cpu_stop(NULL);
0106 }
0107 
0108 static int
0109 op_axp_create_files(struct dentry *root)
0110 {
0111     int i;
0112 
0113     for (i = 0; i < model->num_counters; ++i) {
0114         struct dentry *dir;
0115         char buf[4];
0116 
0117         snprintf(buf, sizeof buf, "%d", i);
0118         dir = oprofilefs_mkdir(root, buf);
0119 
0120         oprofilefs_create_ulong(dir, "enabled", &ctr[i].enabled);
0121                 oprofilefs_create_ulong(dir, "event", &ctr[i].event);
0122         oprofilefs_create_ulong(dir, "count", &ctr[i].count);
0123         /* Dummies.  */
0124         oprofilefs_create_ulong(dir, "kernel", &ctr[i].kernel);
0125         oprofilefs_create_ulong(dir, "user", &ctr[i].user);
0126         oprofilefs_create_ulong(dir, "unit_mask", &ctr[i].unit_mask);
0127     }
0128 
0129     if (model->can_set_proc_mode) {
0130         oprofilefs_create_ulong(root, "enable_pal",
0131                     &sys.enable_pal);
0132         oprofilefs_create_ulong(root, "enable_kernel",
0133                     &sys.enable_kernel);
0134         oprofilefs_create_ulong(root, "enable_user",
0135                     &sys.enable_user);
0136     }
0137 
0138     return 0;
0139 }
0140 
0141 int __init
0142 oprofile_arch_init(struct oprofile_operations *ops)
0143 {
0144     struct op_axp_model *lmodel = NULL;
0145 
0146     switch (implver()) {
0147     case IMPLVER_EV4:
0148         lmodel = &op_model_ev4;
0149         break;
0150     case IMPLVER_EV5:
0151         /* 21164PC has a slightly different set of events.
0152            Recognize the chip by the presence of the MAX insns.  */
0153         if (!amask(AMASK_MAX))
0154             lmodel = &op_model_pca56;
0155         else
0156             lmodel = &op_model_ev5;
0157         break;
0158     case IMPLVER_EV6:
0159         /* 21264A supports ProfileMe.
0160            Recognize the chip by the presence of the CIX insns.  */
0161         if (!amask(AMASK_CIX))
0162             lmodel = &op_model_ev67;
0163         else
0164             lmodel = &op_model_ev6;
0165         break;
0166     }
0167 
0168     if (!lmodel)
0169         return -ENODEV;
0170     model = lmodel;
0171 
0172     ops->create_files = op_axp_create_files;
0173     ops->setup = op_axp_setup;
0174     ops->shutdown = op_axp_shutdown;
0175     ops->start = op_axp_start;
0176     ops->stop = op_axp_stop;
0177     ops->cpu_type = lmodel->cpu_type;
0178 
0179     printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
0180            lmodel->cpu_type);
0181 
0182     return 0;
0183 }
0184 
0185 
0186 void
0187 oprofile_arch_exit(void)
0188 {
0189 }