18c2ecf20Sopenharmony_ci/** 28c2ecf20Sopenharmony_ci * @file arch/alpha/oprofile/common.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * @remark Copyright 2002 OProfile authors 58c2ecf20Sopenharmony_ci * @remark Read the file COPYING 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * @author Richard Henderson <rth@twiddle.net> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/oprofile.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/smp.h> 138c2ecf20Sopenharmony_ci#include <linux/errno.h> 148c2ecf20Sopenharmony_ci#include <asm/ptrace.h> 158c2ecf20Sopenharmony_ci#include <asm/special_insns.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "op_impl.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ciextern struct op_axp_model op_model_ev4 __attribute__((weak)); 208c2ecf20Sopenharmony_ciextern struct op_axp_model op_model_ev5 __attribute__((weak)); 218c2ecf20Sopenharmony_ciextern struct op_axp_model op_model_pca56 __attribute__((weak)); 228c2ecf20Sopenharmony_ciextern struct op_axp_model op_model_ev6 __attribute__((weak)); 238c2ecf20Sopenharmony_ciextern struct op_axp_model op_model_ev67 __attribute__((weak)); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic struct op_axp_model *model; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ciextern void (*perf_irq)(unsigned long, struct pt_regs *); 288c2ecf20Sopenharmony_cistatic void (*save_perf_irq)(unsigned long, struct pt_regs *); 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic struct op_counter_config ctr[20]; 318c2ecf20Sopenharmony_cistatic struct op_system_config sys; 328c2ecf20Sopenharmony_cistatic struct op_register_config reg; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* Called from do_entInt to handle the performance monitor interrupt. */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic void 378c2ecf20Sopenharmony_ciop_handle_interrupt(unsigned long which, struct pt_regs *regs) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci model->handle_interrupt(which, regs, ctr); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci /* If the user has selected an interrupt frequency that is 428c2ecf20Sopenharmony_ci not exactly the width of the counter, write a new value 438c2ecf20Sopenharmony_ci into the counter such that it'll overflow after N more 448c2ecf20Sopenharmony_ci events. */ 458c2ecf20Sopenharmony_ci if ((reg.need_reset >> which) & 1) 468c2ecf20Sopenharmony_ci model->reset_ctr(®, which); 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic int 508c2ecf20Sopenharmony_ciop_axp_setup(void) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci unsigned long i, e; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci /* Install our interrupt handler into the existing hook. */ 558c2ecf20Sopenharmony_ci save_perf_irq = perf_irq; 568c2ecf20Sopenharmony_ci perf_irq = op_handle_interrupt; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci /* Compute the mask of enabled counters. */ 598c2ecf20Sopenharmony_ci for (i = e = 0; i < model->num_counters; ++i) 608c2ecf20Sopenharmony_ci if (ctr[i].enabled) 618c2ecf20Sopenharmony_ci e |= 1 << i; 628c2ecf20Sopenharmony_ci reg.enable = e; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci /* Pre-compute the values to stuff in the hardware registers. */ 658c2ecf20Sopenharmony_ci model->reg_setup(®, ctr, &sys); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci /* Configure the registers on all cpus. */ 688c2ecf20Sopenharmony_ci smp_call_function(model->cpu_setup, ®, 1); 698c2ecf20Sopenharmony_ci model->cpu_setup(®); 708c2ecf20Sopenharmony_ci return 0; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic void 748c2ecf20Sopenharmony_ciop_axp_shutdown(void) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci /* Remove our interrupt handler. We may be removing this module. */ 778c2ecf20Sopenharmony_ci perf_irq = save_perf_irq; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic void 818c2ecf20Sopenharmony_ciop_axp_cpu_start(void *dummy) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci wrperfmon(1, reg.enable); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic int 878c2ecf20Sopenharmony_ciop_axp_start(void) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci smp_call_function(op_axp_cpu_start, NULL, 1); 908c2ecf20Sopenharmony_ci op_axp_cpu_start(NULL); 918c2ecf20Sopenharmony_ci return 0; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic inline void 958c2ecf20Sopenharmony_ciop_axp_cpu_stop(void *dummy) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci /* Disable performance monitoring for all counters. */ 988c2ecf20Sopenharmony_ci wrperfmon(0, -1); 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic void 1028c2ecf20Sopenharmony_ciop_axp_stop(void) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci smp_call_function(op_axp_cpu_stop, NULL, 1); 1058c2ecf20Sopenharmony_ci op_axp_cpu_stop(NULL); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic int 1098c2ecf20Sopenharmony_ciop_axp_create_files(struct dentry *root) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci int i; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci for (i = 0; i < model->num_counters; ++i) { 1148c2ecf20Sopenharmony_ci struct dentry *dir; 1158c2ecf20Sopenharmony_ci char buf[4]; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci snprintf(buf, sizeof buf, "%d", i); 1188c2ecf20Sopenharmony_ci dir = oprofilefs_mkdir(root, buf); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci oprofilefs_create_ulong(dir, "enabled", &ctr[i].enabled); 1218c2ecf20Sopenharmony_ci oprofilefs_create_ulong(dir, "event", &ctr[i].event); 1228c2ecf20Sopenharmony_ci oprofilefs_create_ulong(dir, "count", &ctr[i].count); 1238c2ecf20Sopenharmony_ci /* Dummies. */ 1248c2ecf20Sopenharmony_ci oprofilefs_create_ulong(dir, "kernel", &ctr[i].kernel); 1258c2ecf20Sopenharmony_ci oprofilefs_create_ulong(dir, "user", &ctr[i].user); 1268c2ecf20Sopenharmony_ci oprofilefs_create_ulong(dir, "unit_mask", &ctr[i].unit_mask); 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if (model->can_set_proc_mode) { 1308c2ecf20Sopenharmony_ci oprofilefs_create_ulong(root, "enable_pal", 1318c2ecf20Sopenharmony_ci &sys.enable_pal); 1328c2ecf20Sopenharmony_ci oprofilefs_create_ulong(root, "enable_kernel", 1338c2ecf20Sopenharmony_ci &sys.enable_kernel); 1348c2ecf20Sopenharmony_ci oprofilefs_create_ulong(root, "enable_user", 1358c2ecf20Sopenharmony_ci &sys.enable_user); 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci return 0; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ciint __init 1428c2ecf20Sopenharmony_cioprofile_arch_init(struct oprofile_operations *ops) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci struct op_axp_model *lmodel = NULL; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci switch (implver()) { 1478c2ecf20Sopenharmony_ci case IMPLVER_EV4: 1488c2ecf20Sopenharmony_ci lmodel = &op_model_ev4; 1498c2ecf20Sopenharmony_ci break; 1508c2ecf20Sopenharmony_ci case IMPLVER_EV5: 1518c2ecf20Sopenharmony_ci /* 21164PC has a slightly different set of events. 1528c2ecf20Sopenharmony_ci Recognize the chip by the presence of the MAX insns. */ 1538c2ecf20Sopenharmony_ci if (!amask(AMASK_MAX)) 1548c2ecf20Sopenharmony_ci lmodel = &op_model_pca56; 1558c2ecf20Sopenharmony_ci else 1568c2ecf20Sopenharmony_ci lmodel = &op_model_ev5; 1578c2ecf20Sopenharmony_ci break; 1588c2ecf20Sopenharmony_ci case IMPLVER_EV6: 1598c2ecf20Sopenharmony_ci /* 21264A supports ProfileMe. 1608c2ecf20Sopenharmony_ci Recognize the chip by the presence of the CIX insns. */ 1618c2ecf20Sopenharmony_ci if (!amask(AMASK_CIX)) 1628c2ecf20Sopenharmony_ci lmodel = &op_model_ev67; 1638c2ecf20Sopenharmony_ci else 1648c2ecf20Sopenharmony_ci lmodel = &op_model_ev6; 1658c2ecf20Sopenharmony_ci break; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (!lmodel) 1698c2ecf20Sopenharmony_ci return -ENODEV; 1708c2ecf20Sopenharmony_ci model = lmodel; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci ops->create_files = op_axp_create_files; 1738c2ecf20Sopenharmony_ci ops->setup = op_axp_setup; 1748c2ecf20Sopenharmony_ci ops->shutdown = op_axp_shutdown; 1758c2ecf20Sopenharmony_ci ops->start = op_axp_start; 1768c2ecf20Sopenharmony_ci ops->stop = op_axp_stop; 1778c2ecf20Sopenharmony_ci ops->cpu_type = lmodel->cpu_type; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci printk(KERN_INFO "oprofile: using %s performance monitoring.\n", 1808c2ecf20Sopenharmony_ci lmodel->cpu_type); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci return 0; 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_civoid 1878c2ecf20Sopenharmony_cioprofile_arch_exit(void) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci} 190