Release 4.14 arch/mips/oprofile/op_model_mipsxx.c
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2004, 05, 06 by Ralf Baechle
* Copyright (C) 2005 by MIPS Technologies, Inc.
*/
#include <linux/cpumask.h>
#include <linux/oprofile.h>
#include <linux/interrupt.h>
#include <linux/smp.h>
#include <asm/irq_regs.h>
#include <asm/time.h>
#include "op_impl.h"
#define M_PERFCTL_EVENT(event) (((event) << MIPS_PERFCTRL_EVENT_S) & \
MIPS_PERFCTRL_EVENT)
#define M_PERFCTL_VPEID(vpe) ((vpe) << MIPS_PERFCTRL_VPEID_S)
#define M_COUNTER_OVERFLOW (1UL << 31)
static int (*save_perf_irq)(void);
static int perfcount_irq;
/*
* XLR has only one set of counters per core. Designate the
* first hardware thread in the core for setup and init.
* Skip CPUs with non-zero hardware thread id (4 hwt per core)
*/
#if defined(CONFIG_CPU_XLR) && defined(CONFIG_SMP)
#define oprofile_skip_cpu(c) ((cpu_logical_map(c) & 0x3) != 0)
#else
#define oprofile_skip_cpu(c) 0
#endif
#ifdef CONFIG_MIPS_MT_SMP
static int cpu_has_mipsmt_pertccounters;
#define WHAT (MIPS_PERFCTRL_MT_EN_VPE | \
M_PERFCTL_VPEID(cpu_vpe_id(¤t_cpu_data)))
#define vpe_id() (cpu_has_mipsmt_pertccounters ? \
0 : cpu_vpe_id(¤t_cpu_data))
/*
* The number of bits to shift to convert between counters per core and
* counters per VPE. There is no reasonable interface atm to obtain the
* number of VPEs used by Linux and in the 34K this number is fixed to two
* anyways so we hardcore a few things here for the moment. The way it's
* done here will ensure that oprofile VSMP kernel will run right on a lesser
* core like a 24K also or with maxcpus=1.
*/
static inline unsigned int vpe_shift(void)
{
if (num_possible_cpus() > 1)
return 1;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ralf Bächle | 23 | 100.00% | 1 | 100.00% |
Total | 23 | 100.00% | 1 | 100.00% |
#else
#define WHAT 0
#define vpe_id() 0
static inline unsigned int vpe_shift(void)
{
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ralf Bächle | 13 | 100.00% | 1 | 100.00% |
Total | 13 | 100.00% | 1 | 100.00% |
#endif
static inline unsigned int counters_total_to_per_cpu(unsigned int counters)
{
return counters >> vpe_shift();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ralf Bächle | 18 | 100.00% | 1 | 100.00% |
Total | 18 | 100.00% | 1 | 100.00% |
static inline unsigned int counters_per_cpu_to_total(unsigned int counters)
{
return counters << vpe_shift();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ralf Bächle | 18 | 100.00% | 1 | 100.00% |
Total | 18 | 100.00% | 1 | 100.00% |
#define __define_perf_accessors(r, n, np) \
\
static inline unsigned int r_c0_ ## r ## n(void) \
{ \
unsigned int cpu = vpe_id(); \
\
switch (cpu) { \
case 0: \
return read_c0_ ## r ## n(); \
case 1: \
return read_c0_ ## r ## np(); \
default: \
BUG(); \
} \
return 0; \
} \
\
static inline void w_c0_ ## r ## n(unsigned int value) \
{ \
unsigned int cpu = vpe_id(); \
\
switch (cpu) { \
case 0: \
write_c0_ ## r ## n(value); \
return; \
case 1: \
write_c0_ ## r ## np(value); \
return; \
default: \
BUG(); \
} \
return; \
} \
__define_perf_accessors(perfcntr, 0, 2)
__define_perf_accessors(perfcntr, 1, 3)
__define_perf_accessors(perfcntr, 2, 0)
__define_perf_accessors(perfcntr, 3, 1)
__define_perf_accessors(perfctrl, 0, 2)
__define_perf_accessors(perfctrl, 1, 3)
__define_perf_accessors(perfctrl, 2, 0)
__define_perf_accessors(perfctrl, 3, 1)
struct op_mips_model op_model_mipsxx_ops;
static struct mipsxx_register_config {
unsigned int control[4];
unsigned int counter[4];
} reg;
/* Compute all of the registers in preparation for enabling profiling. */
static void mipsxx_reg_setup(struct op_counter_config *ctr)
{
unsigned int counters = op_model_mipsxx_ops.num_counters;
int i;
/* Compute the performance counter control word. */
for (i = 0; i < counters; i++) {
reg.control[i] = 0;
reg.counter[i] = 0;
if (!ctr[i].enabled)
continue;
reg.control[i] = M_PERFCTL_EVENT(ctr[i].event) |
MIPS_PERFCTRL_IE;
if (ctr[i].kernel)
reg.control[i] |= MIPS_PERFCTRL_K;
if (ctr[i].user)
reg.control[i] |= MIPS_PERFCTRL_U;
if (ctr[i].exl)
reg.control[i] |= MIPS_PERFCTRL_EXL;
if (boot_cpu_type() == CPU_XLR)
reg.control[i] |= XLR_PERFCTRL_ALLTHREADS;
reg.counter[i] = 0x80000000 - ctr[i].count;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ralf Bächle | 152 | 88.37% | 2 | 40.00% |
Madhusudan Bhat | 14 | 8.14% | 1 | 20.00% |
James Hogan | 5 | 2.91% | 1 | 20.00% |
Atsushi Nemoto | 1 | 0.58% | 1 | 20.00% |
Total | 172 | 100.00% | 5 | 100.00% |
/* Program all of the registers in preparation for enabling profiling. */
static void mipsxx_cpu_setup(void *args)
{
unsigned int counters = op_model_mipsxx_ops.num_counters;
if (oprofile_skip_cpu(smp_processor_id()))
return;
switch (counters) {
case 4:
w_c0_perfctrl3(0);
w_c0_perfcntr3(reg.counter[3]);
case 3:
w_c0_perfctrl2(0);
w_c0_perfcntr2(reg.counter[2]);
case 2:
w_c0_perfctrl1(0);
w_c0_perfcntr1(reg.counter[1]);
case 1:
w_c0_perfctrl0(0);
w_c0_perfcntr0(reg.counter[0]);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ralf Bächle | 95 | 90.48% | 2 | 50.00% |
Madhusudan Bhat | 9 | 8.57% | 1 | 25.00% |
Atsushi Nemoto | 1 | 0.95% | 1 | 25.00% |
Total | 105 | 100.00% | 4 | 100.00% |
/* Start all counters on current CPU */
static void mipsxx_cpu_start(void *args)
{
unsigned int counters = op_model_mipsxx_ops.num_counters;
if (oprofile_skip_cpu(smp_processor_id()))
return;
switch (counters) {
case 4:
w_c0_perfctrl3(WHAT | reg.control[3]);
case 3:
w_c0_perfctrl2(WHAT | reg.control[2]);
case 2:
w_c0_perfctrl1(WHAT | reg.control[1]);
case 1:
w_c0_perfctrl0(WHAT | reg.control[0]);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ralf Bächle | 83 | 89.25% | 2 | 50.00% |
Madhusudan Bhat | 9 | 9.68% | 1 | 25.00% |
Atsushi Nemoto | 1 | 1.08% | 1 | 25.00% |
Total | 93 | 100.00% | 4 | 100.00% |
/* Stop all counters on current CPU */
static void mipsxx_cpu_stop(void *args)
{
unsigned int counters = op_model_mipsxx_ops.num_counters;
if (oprofile_skip_cpu(smp_processor_id()))
return;
switch (counters) {
case 4:
w_c0_perfctrl3(0);
case 3:
w_c0_perfctrl2(0);
case 2:
w_c0_perfctrl1(0);
case 1:
w_c0_perfctrl0(0);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ralf Bächle | 55 | 84.62% | 2 | 50.00% |
Madhusudan Bhat | 9 | 13.85% | 1 | 25.00% |
Atsushi Nemoto | 1 | 1.54% | 1 | 25.00% |
Total | 65 | 100.00% | 4 | 100.00% |
static int mipsxx_perfcount_handler(void)
{
unsigned int counters = op_model_mipsxx_ops.num_counters;
unsigned int control;
unsigned int counter;
int handled = IRQ_NONE;
if (cpu_has_mips_r2 && !(read_c0_cause() & CAUSEF_PCI))
return handled;
switch (counters) {
#define HANDLE_COUNTER(n) \
case n + 1: \
control = r_c0_perfctrl ## n(); \
counter = r_c0_perfcntr ## n(); \
if ((control & MIPS_PERFCTRL_IE) && \
(counter & M_COUNTER_OVERFLOW)) { \
oprofile_add_sample(get_irq_regs(), n); \
w_c0_perfcntr ## n(reg.counter[n]); \
handled = IRQ_HANDLED; \
}
HANDLE_COUNTER(3)
HANDLE_COUNTER(2)
HANDLE_COUNTER(1)
HANDLE_COUNTER(0)
}
return handled;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ralf Bächle | 59 | 76.62% | 3 | 42.86% |
Chris Dearman | 15 | 19.48% | 1 | 14.29% |
James Hogan | 2 | 2.60% | 2 | 28.57% |
Atsushi Nemoto | 1 | 1.30% | 1 | 14.29% |
Total | 77 | 100.00% | 7 | 100.00% |
static inline int __n_counters(void)
{
if (!cpu_has_perf)
return 0;
if (!(read_c0_perfctrl0() & MIPS_PERFCTRL_M))
return 1;
if (!(read_c0_perfctrl1() & MIPS_PERFCTRL_M))
return 2;
if (!(read_c0_perfctrl2() & MIPS_PERFCTRL_M))
return 3;
return 4;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ralf Bächle | 55 | 93.22% | 3 | 60.00% |
James Hogan | 4 | 6.78% | 2 | 40.00% |
Total | 59 | 100.00% | 5 | 100.00% |
static inline int n_counters(void)
{
int counters;
switch (current_cpu_type()) {
case CPU_R10000:
counters = 2;
break;
case CPU_R12000:
case CPU_R14000:
case CPU_R16000:
counters = 4;
break;
default:
counters = __n_counters();
}
return counters;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ralf Bächle | 47 | 94.00% | 4 | 80.00% |
Joshua Kinard | 3 | 6.00% | 1 | 20.00% |
Total | 50 | 100.00% | 5 | 100.00% |
static void reset_counters(void *arg)
{
int counters = (int)(long)arg;
switch (counters) {
case 4:
w_c0_perfctrl3(0);
w_c0_perfcntr3(0);
case 3:
w_c0_perfctrl2(0);
w_c0_perfcntr2(0);
case 2:
w_c0_perfctrl1(0);
w_c0_perfcntr1(0);
case 1:
w_c0_perfctrl0(0);
w_c0_perfcntr0(0);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ralf Bächle | 76 | 96.20% | 3 | 75.00% |
Thiemo Seufer | 3 | 3.80% | 1 | 25.00% |
Total | 79 | 100.00% | 4 | 100.00% |
static irqreturn_t mipsxx_perfcount_int(int irq, void *dev_id)
{
return mipsxx_perfcount_handler();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Felix Fietkau | 17 | 100.00% | 1 | 100.00% |
Total | 17 | 100.00% | 1 | 100.00% |
static int __init mipsxx_init(void)
{
int counters;
counters = n_counters();
if (counters == 0) {
printk(KERN_ERR "Oprofile: CPU has no performance counters\n");
return -ENODEV;
}
#ifdef CONFIG_MIPS_MT_SMP
cpu_has_mipsmt_pertccounters = read_c0_config7() & (1<<19);
if (!cpu_has_mipsmt_pertccounters)
counters = counters_total_to_per_cpu(counters);
#endif
on_each_cpu(reset_counters, (void *)(long)counters, 1);
op_model_mipsxx_ops.num_counters = counters;
switch (current_cpu_type()) {
case CPU_M14KC:
op_model_mipsxx_ops.cpu_type = "mips/M14Kc";
break;
case CPU_M14KEC:
op_model_mipsxx_ops.cpu_type = "mips/M14KEc";
break;
case CPU_20KC:
op_model_mipsxx_ops.cpu_type = "mips/20K";
break;
case CPU_24K:
op_model_mipsxx_ops.cpu_type = "mips/24K";
break;
case CPU_25KF:
op_model_mipsxx_ops.cpu_type = "mips/25K";
break;
case CPU_1004K:
case CPU_34K:
op_model_mipsxx_ops.cpu_type = "mips/34K";
break;
case CPU_1074K:
case CPU_74K:
op_model_mipsxx_ops.cpu_type = "mips/74K";
break;
case CPU_INTERAPTIV:
op_model_mipsxx_ops.cpu_type = "mips/interAptiv";
break;
case CPU_PROAPTIV:
op_model_mipsxx_ops.cpu_type = "mips/proAptiv";
break;
case CPU_P5600:
op_model_mipsxx_ops.cpu_type = "mips/P5600";
break;
case CPU_I6400:
op_model_mipsxx_ops.cpu_type = "mips/I6400";
break;
case CPU_M5150:
op_model_mipsxx_ops.cpu_type = "mips/M5150";
break;
case CPU_5KC:
op_model_mipsxx_ops.cpu_type = "mips/5K";
break;
case CPU_R10000:
if ((current_cpu_data.processor_id & 0xff) == 0x20)
op_model_mipsxx_ops.cpu_type = "mips/r10000-v2.x";
else
op_model_mipsxx_ops.cpu_type = "mips/r10000";
break;
case CPU_R12000:
case CPU_R14000:
op_model_mipsxx_ops.cpu_type = "mips/r12000";
break;
case CPU_R16000:
op_model_mipsxx_ops.cpu_type = "mips/r16000";
break;
case CPU_SB1:
case CPU_SB1A:
op_model_mipsxx_ops.cpu_type = "mips/sb1";
break;
case CPU_LOONGSON1:
op_model_mipsxx_ops.cpu_type = "mips/loongson1";
break;
case CPU_XLR:
op_model_mipsxx_ops.cpu_type = "mips/xlr";
break;
default:
printk(KERN_ERR "Profiling unsupported for this CPU\n");
return -ENODEV;
}
save_perf_irq = perf_irq;
perf_irq = mipsxx_perfcount_handler;
if (get_c0_perfcount_int)
perfcount_irq = get_c0_perfcount_int();
else if (cp0_perfcount_irq >= 0)
perfcount_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
else
perfcount_irq = -1;
if (perfcount_irq >= 0)
return request_irq(perfcount_irq, mipsxx_perfcount_int,
IRQF_PERCPU | IRQF_NOBALANCING |
IRQF_NO_THREAD | IRQF_NO_SUSPEND |
IRQF_SHARED,
"Perfcounter", save_perf_irq);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ralf Bächle | 194 | 49.62% | 8 | 28.57% |
Leonid Yegoshin | 30 | 7.67% | 3 | 10.71% |
Andrew Bresticker | 29 | 7.42% | 1 | 3.57% |
Steven J. Hill | 23 | 5.88% | 3 | 10.71% |
James Hogan | 19 | 4.86% | 2 | 7.14% |
Felix Fietkau | 18 | 4.60% | 1 | 3.57% |
Mark Mason | 12 | 3.07% | 1 | 3.57% |
Chris Dearman | 11 | 2.81% | 2 | 7.14% |
Kelvin Cheung | 10 | 2.56% | 1 | 3.57% |
Joshua Kinard | 10 | 2.56% | 1 | 3.57% |
Markos Chandras | 10 | 2.56% | 1 | 3.57% |
Madhusudan Bhat | 10 | 2.56% | 1 | 3.57% |
Atsushi Nemoto | 8 | 2.05% | 1 | 3.57% |
Dmitri Vorobiev | 4 | 1.02% | 1 | 3.57% |
Thiemo Seufer | 3 | 0.77% | 1 | 3.57% |
Total | 391 | 100.00% | 28 | 100.00% |
static void mipsxx_exit(void)
{
int counters = op_model_mipsxx_ops.num_counters;
if (perfcount_irq >= 0)
free_irq(perfcount_irq, save_perf_irq);
counters = counters_per_cpu_to_total(counters);
on_each_cpu(reset_counters, (void *)(long)counters, 1);
perf_irq = save_perf_irq;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ralf Bächle | 29 | 52.73% | 3 | 33.33% |
Felix Fietkau | 11 | 20.00% | 1 | 11.11% |
Chris Dearman | 8 | 14.55% | 1 | 11.11% |
Thiemo Seufer | 3 | 5.45% | 1 | 11.11% |
Andrew Bresticker | 2 | 3.64% | 1 | 11.11% |
Dmitri Vorobiev | 1 | 1.82% | 1 | 11.11% |
Atsushi Nemoto | 1 | 1.82% | 1 | 11.11% |
Total | 55 | 100.00% | 9 | 100.00% |
struct op_mips_model op_model_mipsxx_ops = {
.reg_setup = mipsxx_reg_setup,
.cpu_setup = mipsxx_cpu_setup,
.init = mipsxx_init,
.exit = mipsxx_exit,
.cpu_start = mipsxx_cpu_start,
.cpu_stop = mipsxx_cpu_stop,
};
Overall Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ralf Bächle | 1107 | 74.70% | 16 | 38.10% |
Madhusudan Bhat | 71 | 4.79% | 1 | 2.38% |
Felix Fietkau | 46 | 3.10% | 1 | 2.38% |
Andrew Bresticker | 38 | 2.56% | 1 | 2.38% |
Chris Dearman | 38 | 2.56% | 3 | 7.14% |
James Hogan | 32 | 2.16% | 5 | 11.90% |
Leonid Yegoshin | 30 | 2.02% | 3 | 7.14% |
Steven J. Hill | 23 | 1.55% | 3 | 7.14% |
Atsushi Nemoto | 16 | 1.08% | 1 | 2.38% |
Dmitri Vorobiev | 15 | 1.01% | 1 | 2.38% |
Joshua Kinard | 13 | 0.88% | 1 | 2.38% |
Mark Mason | 12 | 0.81% | 1 | 2.38% |
Markos Chandras | 10 | 0.67% | 1 | 2.38% |
Kelvin Cheung | 10 | 0.67% | 1 | 2.38% |
Jayachandran C | 10 | 0.67% | 1 | 2.38% |
Thiemo Seufer | 9 | 0.61% | 1 | 2.38% |
Paul Burton | 2 | 0.13% | 1 | 2.38% |
Total | 1482 | 100.00% | 42 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.