#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64) || \
defined(CONFIG_CPU_R10000) || defined(CONFIG_CPU_SB1)
#define M_CONFIG1_PC (1 << 4)
#define M_PERFCTL_EXL (1UL << 0)
#define M_PERFCTL_KERNEL (1UL << 1)
#define M_PERFCTL_SUPERVISOR (1UL << 2)
#define M_PERFCTL_USER (1UL << 3)
#define M_PERFCTL_INTERRUPT_ENABLE (1UL << 4)
#define M_PERFCTL_EVENT(event) (((event) & 0x3ff) << 5)
#define M_PERFCTL_VPEID(vpe) ((vpe) << 16)
#define M_PERFCTL_MT_EN(filter) ((filter) << 20)
#define M_TC_EN_ALL M_PERFCTL_MT_EN(0)
#define M_TC_EN_VPE M_PERFCTL_MT_EN(1)
#define M_TC_EN_TC M_PERFCTL_MT_EN(2)
#define M_PERFCTL_TCID(tcid) ((tcid) << 22)
#define M_PERFCTL_WIDE (1UL << 30)
#define M_PERFCTL_MORE (1UL << 31)
#define M_PERFCTL_COUNT_EVENT_WHENEVER (M_PERFCTL_EXL | \
M_PERFCTL_KERNEL | \
M_PERFCTL_USER | \
M_PERFCTL_SUPERVISOR | \
M_PERFCTL_INTERRUPT_ENABLE)
#ifdef CONFIG_MIPS_MT_SMP
#define M_PERFCTL_CONFIG_MASK 0x3fff801f
#else
#define M_PERFCTL_CONFIG_MASK 0x1f
#endif
#define M_PERFCTL_EVENT_MASK 0xfe0
#define M_COUNTER_OVERFLOW (1UL << 31)
#ifdef CONFIG_MIPS_MT_SMP
static int cpu_has_mipsmt_pertccounters;
/*
* FIXME: For VSMP, vpe_id() is redefined for Perf-events, because
* cpu_data[cpuid].vpe_id reports 0 for _both_ CPUs.
*/
#if defined(CONFIG_HW_PERF_EVENTS)
#define vpe_id() (cpu_has_mipsmt_pertccounters ? \
0 : smp_processor_id())
#else
#define vpe_id() (cpu_has_mipsmt_pertccounters ? \
0 : cpu_data[smp_processor_id()].vpe_id)
#endif
/* Copied from op_model_mipsxx.c */
static inline unsigned int vpe_shift(void)
{
if (num_possible_cpus() > 1)
return 1;
return 0;
}
#else /* !CONFIG_MIPS_MT_SMP */
#define vpe_id() 0
static inline unsigned int vpe_shift(void)
{
return 0;
}
#endif /* CONFIG_MIPS_MT_SMP */
static inline unsigned int
counters_total_to_per_cpu(unsigned int counters)
{
return counters >> vpe_shift();
}
static inline unsigned int
counters_per_cpu_to_total(unsigned int counters)
{
return counters << vpe_shift();
}
#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)
static inline int __n_counters(void)
{
if (!(read_c0_config1() & M_CONFIG1_PC))
return 0;
if (!(read_c0_perfctrl0() & M_PERFCTL_MORE))
return 1;
if (!(read_c0_perfctrl1() & M_PERFCTL_MORE))
return 2;
if (!(read_c0_perfctrl2() & M_PERFCTL_MORE))
return 3;
return 4;
}
static inline int n_counters(void)
{
int counters;
switch (current_cpu_type()) {
case CPU_R10000:
counters = 2;
break;
case CPU_R12000:
case CPU_R14000:
counters = 4;
break;
default:
counters = __n_counters();
}
return counters;
}
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);
}
}
static inline u64
mipsxx_pmu_read_counter(unsigned int idx)
{
switch (idx) {
case 0:
return r_c0_perfcntr0();
case 1:
return r_c0_perfcntr1();
case 2:
return r_c0_perfcntr2();
case 3:
return r_c0_perfcntr3();
default:
WARN_ONCE(1, "Invalid performance counter number (%d)\n", idx);
return 0;
}
}
static inline void
mipsxx_pmu_write_counter(unsigned int idx, u64 val)
{
switch (idx) {
case 0:
w_c0_perfcntr0(val);
return;
case 1:
w_c0_perfcntr1(val);
return;
case 2:
w_c0_perfcntr2(val);
return;
case 3:
w_c0_perfcntr3(val);
return;
}
}