18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 38c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 48c2ecf20Sopenharmony_ci * for more details. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2004, 05, 06 by Ralf Baechle 78c2ecf20Sopenharmony_ci * Copyright (C) 2005 by MIPS Technologies, Inc. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci#include <linux/cpumask.h> 108c2ecf20Sopenharmony_ci#include <linux/oprofile.h> 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/smp.h> 138c2ecf20Sopenharmony_ci#include <asm/irq_regs.h> 148c2ecf20Sopenharmony_ci#include <asm/time.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "op_impl.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define M_PERFCTL_EVENT(event) (((event) << MIPS_PERFCTRL_EVENT_S) & \ 198c2ecf20Sopenharmony_ci MIPS_PERFCTRL_EVENT) 208c2ecf20Sopenharmony_ci#define M_PERFCTL_VPEID(vpe) ((vpe) << MIPS_PERFCTRL_VPEID_S) 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define M_COUNTER_OVERFLOW (1UL << 31) 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic int (*save_perf_irq)(void); 258c2ecf20Sopenharmony_cistatic int perfcount_irq; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* 288c2ecf20Sopenharmony_ci * XLR has only one set of counters per core. Designate the 298c2ecf20Sopenharmony_ci * first hardware thread in the core for setup and init. 308c2ecf20Sopenharmony_ci * Skip CPUs with non-zero hardware thread id (4 hwt per core) 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci#if defined(CONFIG_CPU_XLR) && defined(CONFIG_SMP) 338c2ecf20Sopenharmony_ci#define oprofile_skip_cpu(c) ((cpu_logical_map(c) & 0x3) != 0) 348c2ecf20Sopenharmony_ci#else 358c2ecf20Sopenharmony_ci#define oprofile_skip_cpu(c) 0 368c2ecf20Sopenharmony_ci#endif 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#ifdef CONFIG_MIPS_MT_SMP 398c2ecf20Sopenharmony_ci#define WHAT (MIPS_PERFCTRL_MT_EN_VPE | \ 408c2ecf20Sopenharmony_ci M_PERFCTL_VPEID(cpu_vpe_id(¤t_cpu_data))) 418c2ecf20Sopenharmony_ci#define vpe_id() (cpu_has_mipsmt_pertccounters ? \ 428c2ecf20Sopenharmony_ci 0 : cpu_vpe_id(¤t_cpu_data)) 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/* 458c2ecf20Sopenharmony_ci * The number of bits to shift to convert between counters per core and 468c2ecf20Sopenharmony_ci * counters per VPE. There is no reasonable interface atm to obtain the 478c2ecf20Sopenharmony_ci * number of VPEs used by Linux and in the 34K this number is fixed to two 488c2ecf20Sopenharmony_ci * anyways so we hardcore a few things here for the moment. The way it's 498c2ecf20Sopenharmony_ci * done here will ensure that oprofile VSMP kernel will run right on a lesser 508c2ecf20Sopenharmony_ci * core like a 24K also or with maxcpus=1. 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_cistatic inline unsigned int vpe_shift(void) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci if (num_possible_cpus() > 1) 558c2ecf20Sopenharmony_ci return 1; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci return 0; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#else 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define WHAT 0 638c2ecf20Sopenharmony_ci#define vpe_id() 0 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic inline unsigned int vpe_shift(void) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci return 0; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#endif 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic inline unsigned int counters_total_to_per_cpu(unsigned int counters) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci return counters >> vpe_shift(); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic inline unsigned int counters_per_cpu_to_total(unsigned int counters) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci return counters << vpe_shift(); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#define __define_perf_accessors(r, n, np) \ 838c2ecf20Sopenharmony_ci \ 848c2ecf20Sopenharmony_cistatic inline unsigned int r_c0_ ## r ## n(void) \ 858c2ecf20Sopenharmony_ci{ \ 868c2ecf20Sopenharmony_ci unsigned int cpu = vpe_id(); \ 878c2ecf20Sopenharmony_ci \ 888c2ecf20Sopenharmony_ci switch (cpu) { \ 898c2ecf20Sopenharmony_ci case 0: \ 908c2ecf20Sopenharmony_ci return read_c0_ ## r ## n(); \ 918c2ecf20Sopenharmony_ci case 1: \ 928c2ecf20Sopenharmony_ci return read_c0_ ## r ## np(); \ 938c2ecf20Sopenharmony_ci default: \ 948c2ecf20Sopenharmony_ci BUG(); \ 958c2ecf20Sopenharmony_ci } \ 968c2ecf20Sopenharmony_ci return 0; \ 978c2ecf20Sopenharmony_ci} \ 988c2ecf20Sopenharmony_ci \ 998c2ecf20Sopenharmony_cistatic inline void w_c0_ ## r ## n(unsigned int value) \ 1008c2ecf20Sopenharmony_ci{ \ 1018c2ecf20Sopenharmony_ci unsigned int cpu = vpe_id(); \ 1028c2ecf20Sopenharmony_ci \ 1038c2ecf20Sopenharmony_ci switch (cpu) { \ 1048c2ecf20Sopenharmony_ci case 0: \ 1058c2ecf20Sopenharmony_ci write_c0_ ## r ## n(value); \ 1068c2ecf20Sopenharmony_ci return; \ 1078c2ecf20Sopenharmony_ci case 1: \ 1088c2ecf20Sopenharmony_ci write_c0_ ## r ## np(value); \ 1098c2ecf20Sopenharmony_ci return; \ 1108c2ecf20Sopenharmony_ci default: \ 1118c2ecf20Sopenharmony_ci BUG(); \ 1128c2ecf20Sopenharmony_ci } \ 1138c2ecf20Sopenharmony_ci return; \ 1148c2ecf20Sopenharmony_ci} \ 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci__define_perf_accessors(perfcntr, 0, 2) 1178c2ecf20Sopenharmony_ci__define_perf_accessors(perfcntr, 1, 3) 1188c2ecf20Sopenharmony_ci__define_perf_accessors(perfcntr, 2, 0) 1198c2ecf20Sopenharmony_ci__define_perf_accessors(perfcntr, 3, 1) 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci__define_perf_accessors(perfctrl, 0, 2) 1228c2ecf20Sopenharmony_ci__define_perf_accessors(perfctrl, 1, 3) 1238c2ecf20Sopenharmony_ci__define_perf_accessors(perfctrl, 2, 0) 1248c2ecf20Sopenharmony_ci__define_perf_accessors(perfctrl, 3, 1) 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistruct op_mips_model op_model_mipsxx_ops; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic struct mipsxx_register_config { 1298c2ecf20Sopenharmony_ci unsigned int control[4]; 1308c2ecf20Sopenharmony_ci unsigned int counter[4]; 1318c2ecf20Sopenharmony_ci} reg; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/* Compute all of the registers in preparation for enabling profiling. */ 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic void mipsxx_reg_setup(struct op_counter_config *ctr) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci unsigned int counters = op_model_mipsxx_ops.num_counters; 1388c2ecf20Sopenharmony_ci int i; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci /* Compute the performance counter control word. */ 1418c2ecf20Sopenharmony_ci for (i = 0; i < counters; i++) { 1428c2ecf20Sopenharmony_ci reg.control[i] = 0; 1438c2ecf20Sopenharmony_ci reg.counter[i] = 0; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (!ctr[i].enabled) 1468c2ecf20Sopenharmony_ci continue; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci reg.control[i] = M_PERFCTL_EVENT(ctr[i].event) | 1498c2ecf20Sopenharmony_ci MIPS_PERFCTRL_IE; 1508c2ecf20Sopenharmony_ci if (ctr[i].kernel) 1518c2ecf20Sopenharmony_ci reg.control[i] |= MIPS_PERFCTRL_K; 1528c2ecf20Sopenharmony_ci if (ctr[i].user) 1538c2ecf20Sopenharmony_ci reg.control[i] |= MIPS_PERFCTRL_U; 1548c2ecf20Sopenharmony_ci if (ctr[i].exl) 1558c2ecf20Sopenharmony_ci reg.control[i] |= MIPS_PERFCTRL_EXL; 1568c2ecf20Sopenharmony_ci if (boot_cpu_type() == CPU_XLR) 1578c2ecf20Sopenharmony_ci reg.control[i] |= XLR_PERFCTRL_ALLTHREADS; 1588c2ecf20Sopenharmony_ci reg.counter[i] = 0x80000000 - ctr[i].count; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci/* Program all of the registers in preparation for enabling profiling. */ 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic void mipsxx_cpu_setup(void *args) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci unsigned int counters = op_model_mipsxx_ops.num_counters; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (oprofile_skip_cpu(smp_processor_id())) 1698c2ecf20Sopenharmony_ci return; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci switch (counters) { 1728c2ecf20Sopenharmony_ci case 4: 1738c2ecf20Sopenharmony_ci w_c0_perfctrl3(0); 1748c2ecf20Sopenharmony_ci w_c0_perfcntr3(reg.counter[3]); 1758c2ecf20Sopenharmony_ci fallthrough; 1768c2ecf20Sopenharmony_ci case 3: 1778c2ecf20Sopenharmony_ci w_c0_perfctrl2(0); 1788c2ecf20Sopenharmony_ci w_c0_perfcntr2(reg.counter[2]); 1798c2ecf20Sopenharmony_ci fallthrough; 1808c2ecf20Sopenharmony_ci case 2: 1818c2ecf20Sopenharmony_ci w_c0_perfctrl1(0); 1828c2ecf20Sopenharmony_ci w_c0_perfcntr1(reg.counter[1]); 1838c2ecf20Sopenharmony_ci fallthrough; 1848c2ecf20Sopenharmony_ci case 1: 1858c2ecf20Sopenharmony_ci w_c0_perfctrl0(0); 1868c2ecf20Sopenharmony_ci w_c0_perfcntr0(reg.counter[0]); 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci/* Start all counters on current CPU */ 1918c2ecf20Sopenharmony_cistatic void mipsxx_cpu_start(void *args) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci unsigned int counters = op_model_mipsxx_ops.num_counters; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (oprofile_skip_cpu(smp_processor_id())) 1968c2ecf20Sopenharmony_ci return; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci switch (counters) { 1998c2ecf20Sopenharmony_ci case 4: 2008c2ecf20Sopenharmony_ci w_c0_perfctrl3(WHAT | reg.control[3]); 2018c2ecf20Sopenharmony_ci fallthrough; 2028c2ecf20Sopenharmony_ci case 3: 2038c2ecf20Sopenharmony_ci w_c0_perfctrl2(WHAT | reg.control[2]); 2048c2ecf20Sopenharmony_ci fallthrough; 2058c2ecf20Sopenharmony_ci case 2: 2068c2ecf20Sopenharmony_ci w_c0_perfctrl1(WHAT | reg.control[1]); 2078c2ecf20Sopenharmony_ci fallthrough; 2088c2ecf20Sopenharmony_ci case 1: 2098c2ecf20Sopenharmony_ci w_c0_perfctrl0(WHAT | reg.control[0]); 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci/* Stop all counters on current CPU */ 2148c2ecf20Sopenharmony_cistatic void mipsxx_cpu_stop(void *args) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci unsigned int counters = op_model_mipsxx_ops.num_counters; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (oprofile_skip_cpu(smp_processor_id())) 2198c2ecf20Sopenharmony_ci return; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci switch (counters) { 2228c2ecf20Sopenharmony_ci case 4: 2238c2ecf20Sopenharmony_ci w_c0_perfctrl3(0); 2248c2ecf20Sopenharmony_ci fallthrough; 2258c2ecf20Sopenharmony_ci case 3: 2268c2ecf20Sopenharmony_ci w_c0_perfctrl2(0); 2278c2ecf20Sopenharmony_ci fallthrough; 2288c2ecf20Sopenharmony_ci case 2: 2298c2ecf20Sopenharmony_ci w_c0_perfctrl1(0); 2308c2ecf20Sopenharmony_ci fallthrough; 2318c2ecf20Sopenharmony_ci case 1: 2328c2ecf20Sopenharmony_ci w_c0_perfctrl0(0); 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic int mipsxx_perfcount_handler(void) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci unsigned int counters = op_model_mipsxx_ops.num_counters; 2398c2ecf20Sopenharmony_ci unsigned int control; 2408c2ecf20Sopenharmony_ci unsigned int counter; 2418c2ecf20Sopenharmony_ci int handled = IRQ_NONE; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (cpu_has_mips_r2 && !(read_c0_cause() & CAUSEF_PCI)) 2448c2ecf20Sopenharmony_ci return handled; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci switch (counters) { 2478c2ecf20Sopenharmony_ci#define HANDLE_COUNTER(n) \ 2488c2ecf20Sopenharmony_ci case n + 1: \ 2498c2ecf20Sopenharmony_ci control = r_c0_perfctrl ## n(); \ 2508c2ecf20Sopenharmony_ci counter = r_c0_perfcntr ## n(); \ 2518c2ecf20Sopenharmony_ci if ((control & MIPS_PERFCTRL_IE) && \ 2528c2ecf20Sopenharmony_ci (counter & M_COUNTER_OVERFLOW)) { \ 2538c2ecf20Sopenharmony_ci oprofile_add_sample(get_irq_regs(), n); \ 2548c2ecf20Sopenharmony_ci w_c0_perfcntr ## n(reg.counter[n]); \ 2558c2ecf20Sopenharmony_ci handled = IRQ_HANDLED; \ 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci HANDLE_COUNTER(3) 2588c2ecf20Sopenharmony_ci fallthrough; 2598c2ecf20Sopenharmony_ci HANDLE_COUNTER(2) 2608c2ecf20Sopenharmony_ci fallthrough; 2618c2ecf20Sopenharmony_ci HANDLE_COUNTER(1) 2628c2ecf20Sopenharmony_ci fallthrough; 2638c2ecf20Sopenharmony_ci HANDLE_COUNTER(0) 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci return handled; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic inline int __n_counters(void) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci if (!cpu_has_perf) 2728c2ecf20Sopenharmony_ci return 0; 2738c2ecf20Sopenharmony_ci if (!(read_c0_perfctrl0() & MIPS_PERFCTRL_M)) 2748c2ecf20Sopenharmony_ci return 1; 2758c2ecf20Sopenharmony_ci if (!(read_c0_perfctrl1() & MIPS_PERFCTRL_M)) 2768c2ecf20Sopenharmony_ci return 2; 2778c2ecf20Sopenharmony_ci if (!(read_c0_perfctrl2() & MIPS_PERFCTRL_M)) 2788c2ecf20Sopenharmony_ci return 3; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci return 4; 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic inline int n_counters(void) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci int counters; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci switch (current_cpu_type()) { 2888c2ecf20Sopenharmony_ci case CPU_R10000: 2898c2ecf20Sopenharmony_ci counters = 2; 2908c2ecf20Sopenharmony_ci break; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci case CPU_R12000: 2938c2ecf20Sopenharmony_ci case CPU_R14000: 2948c2ecf20Sopenharmony_ci case CPU_R16000: 2958c2ecf20Sopenharmony_ci counters = 4; 2968c2ecf20Sopenharmony_ci break; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci default: 2998c2ecf20Sopenharmony_ci counters = __n_counters(); 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return counters; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic void reset_counters(void *arg) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci int counters = (int)(long)arg; 3088c2ecf20Sopenharmony_ci switch (counters) { 3098c2ecf20Sopenharmony_ci case 4: 3108c2ecf20Sopenharmony_ci w_c0_perfctrl3(0); 3118c2ecf20Sopenharmony_ci w_c0_perfcntr3(0); 3128c2ecf20Sopenharmony_ci fallthrough; 3138c2ecf20Sopenharmony_ci case 3: 3148c2ecf20Sopenharmony_ci w_c0_perfctrl2(0); 3158c2ecf20Sopenharmony_ci w_c0_perfcntr2(0); 3168c2ecf20Sopenharmony_ci fallthrough; 3178c2ecf20Sopenharmony_ci case 2: 3188c2ecf20Sopenharmony_ci w_c0_perfctrl1(0); 3198c2ecf20Sopenharmony_ci w_c0_perfcntr1(0); 3208c2ecf20Sopenharmony_ci fallthrough; 3218c2ecf20Sopenharmony_ci case 1: 3228c2ecf20Sopenharmony_ci w_c0_perfctrl0(0); 3238c2ecf20Sopenharmony_ci w_c0_perfcntr0(0); 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic irqreturn_t mipsxx_perfcount_int(int irq, void *dev_id) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci return mipsxx_perfcount_handler(); 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic int __init mipsxx_init(void) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci int counters; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci counters = n_counters(); 3378c2ecf20Sopenharmony_ci if (counters == 0) { 3388c2ecf20Sopenharmony_ci printk(KERN_ERR "Oprofile: CPU has no performance counters\n"); 3398c2ecf20Sopenharmony_ci return -ENODEV; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci#ifdef CONFIG_MIPS_MT_SMP 3438c2ecf20Sopenharmony_ci if (!cpu_has_mipsmt_pertccounters) 3448c2ecf20Sopenharmony_ci counters = counters_total_to_per_cpu(counters); 3458c2ecf20Sopenharmony_ci#endif 3468c2ecf20Sopenharmony_ci on_each_cpu(reset_counters, (void *)(long)counters, 1); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci op_model_mipsxx_ops.num_counters = counters; 3498c2ecf20Sopenharmony_ci switch (current_cpu_type()) { 3508c2ecf20Sopenharmony_ci case CPU_M14KC: 3518c2ecf20Sopenharmony_ci op_model_mipsxx_ops.cpu_type = "mips/M14Kc"; 3528c2ecf20Sopenharmony_ci break; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci case CPU_M14KEC: 3558c2ecf20Sopenharmony_ci op_model_mipsxx_ops.cpu_type = "mips/M14KEc"; 3568c2ecf20Sopenharmony_ci break; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci case CPU_20KC: 3598c2ecf20Sopenharmony_ci op_model_mipsxx_ops.cpu_type = "mips/20K"; 3608c2ecf20Sopenharmony_ci break; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci case CPU_24K: 3638c2ecf20Sopenharmony_ci op_model_mipsxx_ops.cpu_type = "mips/24K"; 3648c2ecf20Sopenharmony_ci break; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci case CPU_25KF: 3678c2ecf20Sopenharmony_ci op_model_mipsxx_ops.cpu_type = "mips/25K"; 3688c2ecf20Sopenharmony_ci break; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci case CPU_1004K: 3718c2ecf20Sopenharmony_ci case CPU_34K: 3728c2ecf20Sopenharmony_ci op_model_mipsxx_ops.cpu_type = "mips/34K"; 3738c2ecf20Sopenharmony_ci break; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci case CPU_1074K: 3768c2ecf20Sopenharmony_ci case CPU_74K: 3778c2ecf20Sopenharmony_ci op_model_mipsxx_ops.cpu_type = "mips/74K"; 3788c2ecf20Sopenharmony_ci break; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci case CPU_INTERAPTIV: 3818c2ecf20Sopenharmony_ci op_model_mipsxx_ops.cpu_type = "mips/interAptiv"; 3828c2ecf20Sopenharmony_ci break; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci case CPU_PROAPTIV: 3858c2ecf20Sopenharmony_ci op_model_mipsxx_ops.cpu_type = "mips/proAptiv"; 3868c2ecf20Sopenharmony_ci break; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci case CPU_P5600: 3898c2ecf20Sopenharmony_ci op_model_mipsxx_ops.cpu_type = "mips/P5600"; 3908c2ecf20Sopenharmony_ci break; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci case CPU_I6400: 3938c2ecf20Sopenharmony_ci op_model_mipsxx_ops.cpu_type = "mips/I6400"; 3948c2ecf20Sopenharmony_ci break; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci case CPU_M5150: 3978c2ecf20Sopenharmony_ci op_model_mipsxx_ops.cpu_type = "mips/M5150"; 3988c2ecf20Sopenharmony_ci break; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci case CPU_5KC: 4018c2ecf20Sopenharmony_ci op_model_mipsxx_ops.cpu_type = "mips/5K"; 4028c2ecf20Sopenharmony_ci break; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci case CPU_R10000: 4058c2ecf20Sopenharmony_ci if ((current_cpu_data.processor_id & 0xff) == 0x20) 4068c2ecf20Sopenharmony_ci op_model_mipsxx_ops.cpu_type = "mips/r10000-v2.x"; 4078c2ecf20Sopenharmony_ci else 4088c2ecf20Sopenharmony_ci op_model_mipsxx_ops.cpu_type = "mips/r10000"; 4098c2ecf20Sopenharmony_ci break; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci case CPU_R12000: 4128c2ecf20Sopenharmony_ci case CPU_R14000: 4138c2ecf20Sopenharmony_ci op_model_mipsxx_ops.cpu_type = "mips/r12000"; 4148c2ecf20Sopenharmony_ci break; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci case CPU_R16000: 4178c2ecf20Sopenharmony_ci op_model_mipsxx_ops.cpu_type = "mips/r16000"; 4188c2ecf20Sopenharmony_ci break; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci case CPU_SB1: 4218c2ecf20Sopenharmony_ci case CPU_SB1A: 4228c2ecf20Sopenharmony_ci op_model_mipsxx_ops.cpu_type = "mips/sb1"; 4238c2ecf20Sopenharmony_ci break; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci case CPU_LOONGSON32: 4268c2ecf20Sopenharmony_ci op_model_mipsxx_ops.cpu_type = "mips/loongson1"; 4278c2ecf20Sopenharmony_ci break; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci case CPU_XLR: 4308c2ecf20Sopenharmony_ci op_model_mipsxx_ops.cpu_type = "mips/xlr"; 4318c2ecf20Sopenharmony_ci break; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci default: 4348c2ecf20Sopenharmony_ci printk(KERN_ERR "Profiling unsupported for this CPU\n"); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci return -ENODEV; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci save_perf_irq = perf_irq; 4408c2ecf20Sopenharmony_ci perf_irq = mipsxx_perfcount_handler; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci if (get_c0_perfcount_int) 4438c2ecf20Sopenharmony_ci perfcount_irq = get_c0_perfcount_int(); 4448c2ecf20Sopenharmony_ci else if (cp0_perfcount_irq >= 0) 4458c2ecf20Sopenharmony_ci perfcount_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; 4468c2ecf20Sopenharmony_ci else 4478c2ecf20Sopenharmony_ci perfcount_irq = -1; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if (perfcount_irq >= 0) 4508c2ecf20Sopenharmony_ci return request_irq(perfcount_irq, mipsxx_perfcount_int, 4518c2ecf20Sopenharmony_ci IRQF_PERCPU | IRQF_NOBALANCING | 4528c2ecf20Sopenharmony_ci IRQF_NO_THREAD | IRQF_NO_SUSPEND | 4538c2ecf20Sopenharmony_ci IRQF_SHARED, 4548c2ecf20Sopenharmony_ci "Perfcounter", save_perf_irq); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci return 0; 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic void mipsxx_exit(void) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci int counters = op_model_mipsxx_ops.num_counters; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (perfcount_irq >= 0) 4648c2ecf20Sopenharmony_ci free_irq(perfcount_irq, save_perf_irq); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci counters = counters_per_cpu_to_total(counters); 4678c2ecf20Sopenharmony_ci on_each_cpu(reset_counters, (void *)(long)counters, 1); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci perf_irq = save_perf_irq; 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistruct op_mips_model op_model_mipsxx_ops = { 4738c2ecf20Sopenharmony_ci .reg_setup = mipsxx_reg_setup, 4748c2ecf20Sopenharmony_ci .cpu_setup = mipsxx_cpu_setup, 4758c2ecf20Sopenharmony_ci .init = mipsxx_init, 4768c2ecf20Sopenharmony_ci .exit = mipsxx_exit, 4778c2ecf20Sopenharmony_ci .cpu_start = mipsxx_cpu_start, 4788c2ecf20Sopenharmony_ci .cpu_stop = mipsxx_cpu_stop, 4798c2ecf20Sopenharmony_ci}; 480