aboutsummaryrefslogtreecommitdiff
path: root/arch/mips/oprofile/op_model_mipsxx.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/oprofile/op_model_mipsxx.c')
-rw-r--r--arch/mips/oprofile/op_model_mipsxx.c108
1 files changed, 86 insertions, 22 deletions
diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c
index 54759f1669d..42821ae2d77 100644
--- a/arch/mips/oprofile/op_model_mipsxx.c
+++ b/arch/mips/oprofile/op_model_mipsxx.c
@@ -14,25 +14,39 @@
#include "op_impl.h"
-#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_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_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_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_COUNTER_OVERFLOW (1UL << 31)
+#define M_COUNTER_OVERFLOW (1UL << 31)
+
+/* Netlogic XLR specific, count events in all threads in a core */
+#define M_PERFCTL_COUNT_ALL_THREADS (1UL << 13)
static int (*save_perf_irq)(void);
+/*
+ * 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 (M_TC_EN_VPE | \
@@ -129,7 +143,7 @@ static struct mipsxx_register_config {
unsigned int counter[4];
} reg;
-/* Compute all of the registers in preparation for enabling profiling. */
+/* Compute all of the registers in preparation for enabling profiling. */
static void mipsxx_reg_setup(struct op_counter_config *ctr)
{
@@ -145,23 +159,28 @@ static void mipsxx_reg_setup(struct op_counter_config *ctr)
continue;
reg.control[i] = M_PERFCTL_EVENT(ctr[i].event) |
- M_PERFCTL_INTERRUPT_ENABLE;
+ M_PERFCTL_INTERRUPT_ENABLE;
if (ctr[i].kernel)
reg.control[i] |= M_PERFCTL_KERNEL;
if (ctr[i].user)
reg.control[i] |= M_PERFCTL_USER;
if (ctr[i].exl)
reg.control[i] |= M_PERFCTL_EXL;
+ if (boot_cpu_type() == CPU_XLR)
+ reg.control[i] |= M_PERFCTL_COUNT_ALL_THREADS;
reg.counter[i] = 0x80000000 - ctr[i].count;
}
}
-/* Program all of the registers in preparation for enabling profiling. */
+/* 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);
@@ -183,6 +202,9 @@ 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]);
@@ -200,6 +222,9 @@ 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);
@@ -298,6 +323,11 @@ static void reset_counters(void *arg)
}
}
+static irqreturn_t mipsxx_perfcount_int(int irq, void *dev_id)
+{
+ return mipsxx_perfcount_handler();
+}
+
static int __init mipsxx_init(void)
{
int counters;
@@ -317,6 +347,14 @@ static int __init mipsxx_init(void)
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;
@@ -330,20 +368,31 @@ static int __init mipsxx_init(void)
break;
case CPU_1004K:
-#if 0
- /* FIXME: report as 34K for now */
- op_model_mipsxx_ops.cpu_type = "mips/1004K";
- break;
-#endif
-
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_M5150:
+ op_model_mipsxx_ops.cpu_type = "mips/M5150";
+ break;
+
case CPU_5KC:
op_model_mipsxx_ops.cpu_type = "mips/5K";
break;
@@ -365,6 +414,14 @@ static int __init mipsxx_init(void)
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");
@@ -374,6 +431,10 @@ static int __init mipsxx_init(void)
save_perf_irq = perf_irq;
perf_irq = mipsxx_perfcount_handler;
+ if ((cp0_perfcount_irq >= 0) && (cp0_compare_irq != cp0_perfcount_irq))
+ return request_irq(cp0_perfcount_irq, mipsxx_perfcount_int,
+ 0, "Perfcounter", save_perf_irq);
+
return 0;
}
@@ -381,6 +442,9 @@ static void mipsxx_exit(void)
{
int counters = op_model_mipsxx_ops.num_counters;
+ if ((cp0_perfcount_irq >= 0) && (cp0_compare_irq != cp0_perfcount_irq))
+ free_irq(cp0_perfcount_irq, save_perf_irq);
+
counters = counters_per_cpu_to_total(counters);
on_each_cpu(reset_counters, (void *)(long)counters, 1);