[linux-yocto] [PATCH 11/12] MIPS: Add support for OCTEON III perf events.

Chandrakala Chavva cchavva.cavm at gmail.com
Thu Jan 29 07:32:10 PST 2015


From: Abhishek Paliwal <abhishek.paliwal at aricent.com>

From: David Daney <david.daney at cavium.com>

They are mostly the same as previous OCTEON models, but we need to
enable them for the OCTEON III CPUs.

Signed-off-by: David Daney <david.daney at cavium.com>
Signed-off-by: Abhishek Paliwal <abhishek.paliwal at aricent.com>
---
 arch/mips/cavium-octeon/setup.c      | 38 ++++++++++++++++++++++++++++++++++++
 arch/mips/include/asm/perf_event.h   | 10 +++++++++-
 arch/mips/kernel/perf_event_mipsxx.c | 35 +++++++++++++++++++++++++--------
 3 files changed, 74 insertions(+), 9 deletions(-)

diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c
index eb67381..2b152c1 100644
--- a/arch/mips/cavium-octeon/setup.c
+++ b/arch/mips/cavium-octeon/setup.c
@@ -37,6 +37,7 @@
 #include <asm/bootinfo.h>
 #include <asm/sections.h>
 #include <asm/time.h>
+#include <asm/perf_event.h>
 
 #include <asm/octeon/octeon.h>
 #include <asm/octeon/pci-octeon.h>
@@ -926,6 +927,43 @@ void __init prom_init(void)
 	octeon_setup_smp();
 }
 
+#ifdef CONFIG_HW_PERF_EVENTS
+static int octeon_mipspmu_notifier(struct notifier_block *nb,
+				   unsigned long action, void *data)
+{
+	u64 cvmctl_orig = read_c0_cvmctl();
+	u64 cvmctl_new = cvmctl_orig;
+	u64 mask = (1ull << 15) | (1ull << 17);
+
+	switch (action) {
+	case MIPSPMU_ACTIVE:
+		cvmctl_new = cvmctl_orig | mask;
+		/*
+		 * Set CvmCtl[DCICLK,DISCE] for more accurate profiling at
+		 * the expense of power consumption.
+		 */
+		break;
+	case MIPSPMU_INACTIVE:
+		cvmctl_new = cvmctl_orig & ~mask;
+		break;
+	default:
+		break;
+	}
+	if (cvmctl_new != cvmctl_orig)
+		write_c0_cvmctl(cvmctl_new);
+	return NOTIFY_OK;
+}
+static struct notifier_block octeon_mipspmu_nb = {
+	.notifier_call = octeon_mipspmu_notifier
+};
+
+static int __init octeon_setup_mipspmu_notifiers(void)
+{
+	return mipspmu_notifier_register(&octeon_mipspmu_nb);
+}
+late_initcall(octeon_setup_mipspmu_notifiers);
+#endif
+
 /* Exclude a single page from the regions obtained in plat_mem_setup. */
 #ifndef CONFIG_CRASH_DUMP
 static __init void memory_exclude_page(u64 addr, u64 *mem, u64 *size)
diff --git a/arch/mips/include/asm/perf_event.h b/arch/mips/include/asm/perf_event.h
index d0c7749..bfd8f0a 100644
--- a/arch/mips/include/asm/perf_event.h
+++ b/arch/mips/include/asm/perf_event.h
@@ -11,5 +11,13 @@
 
 #ifndef __MIPS_PERF_EVENT_H__
 #define __MIPS_PERF_EVENT_H__
-/* Leave it empty here. The file is required by linux/perf_event.h */
+
+#include <linux/notifier.h>
+
+/* Allow CPU specific actions on PMU state changes. */
+int mipspmu_notifier_register(struct notifier_block *nb);
+int mipspmu_notifier_unregister(struct notifier_block *nb);
+#define MIPSPMU_ACTIVE 0
+#define MIPSPMU_INACTIVE 1
+
 #endif /* __MIPS_PERF_EVENT_H__ */
diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c
index 24cdf64..3aae869 100644
--- a/arch/mips/kernel/perf_event_mipsxx.c
+++ b/arch/mips/kernel/perf_event_mipsxx.c
@@ -77,6 +77,17 @@ struct mips_perf_event {
 #endif
 };
 
+static ATOMIC_NOTIFIER_HEAD(mipsxx_pmu_chain);
+int mipspmu_notifier_register(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&mipsxx_pmu_chain, nb);
+}
+
+int mipspmu_notifier_unregister(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&mipsxx_pmu_chain, nb);
+}
+
 static struct mips_perf_event raw_event;
 static DEFINE_MUTEX(raw_event_mutex);
 
@@ -175,7 +186,7 @@ static unsigned int counters_total_to_per_cpu(unsigned int counters)
 
 #endif /* CONFIG_MIPS_PERF_SHARED_TC_COUNTERS */
 
-static void resume_local_counters(void);
+static int resume_local_counters(void);
 static void pause_local_counters(void);
 static irqreturn_t mipsxx_pmu_handle_irq(int, void *);
 static int mipsxx_pmu_handle_shared_irq(void);
@@ -522,10 +533,12 @@ static void mipspmu_read(struct perf_event *event)
 
 static void mipspmu_enable(struct pmu *pmu)
 {
+	int i;
 #ifdef CONFIG_MIPS_PERF_SHARED_TC_COUNTERS
 	write_unlock(&pmuint_rwlock);
 #endif
-	resume_local_counters();
+	i = resume_local_counters();
+	atomic_notifier_call_chain(&mipsxx_pmu_chain, i ? MIPSPMU_ACTIVE : MIPSPMU_INACTIVE, NULL);
 }
 
 /*
@@ -803,6 +816,7 @@ static void reset_counters(void *arg)
 		mipsxx_pmu_write_control(0, 0);
 		mipspmu.write_counter(0, 0);
 	}
+	atomic_notifier_call_chain(&mipsxx_pmu_chain, MIPSPMU_INACTIVE, NULL);
 }
 
 /* 24K/34K/1004K cores can share the same event map. */
@@ -1284,15 +1298,19 @@ static void pause_local_counters(void)
 	local_irq_restore(flags);
 }
 
-static void resume_local_counters(void)
+static int resume_local_counters(void)
 {
+	int r = 0;
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 	int ctr = mipspmu.num_counters;
 
 	do {
 		ctr--;
 		mipsxx_pmu_write_control(ctr, cpuc->saved_ctrl[ctr]);
+		r += (cpuc->saved_ctrl[ctr] & M_PERFCTL_INTERRUPT_ENABLE) != 0;
 	} while (ctr > 0);
+
+	return r;
 }
 
 static int mipsxx_pmu_handle_shared_irq(void)
@@ -1479,14 +1497,15 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config)
 
 static const struct mips_perf_event *octeon_pmu_map_raw_event(u64 config)
 {
-	unsigned int raw_id = config & 0xff;
-	unsigned int base_id = raw_id & 0x7f;
-
+	unsigned int base_id = config & 0x7f;
 
 	raw_event.cntr_mask = CNTR_ALL;
 	raw_event.event_id = base_id;
 
-	if (current_cpu_type() == CPU_CAVIUM_OCTEON2) {
+	if (current_cpu_type() == CPU_CAVIUM_OCTEON3) {
+		if (base_id > 0x5f)
+			return ERR_PTR(-EOPNOTSUPP);
+	} else if (current_cpu_type() == CPU_CAVIUM_OCTEON2) {
 		if (base_id > 0x42)
 			return ERR_PTR(-EOPNOTSUPP);
 	} else {
@@ -1501,7 +1520,6 @@ static const struct mips_perf_event *octeon_pmu_map_raw_event(u64 config)
 	case 0x1f:
 	case 0x2f:
 	case 0x34:
-	case 0x3b ... 0x3f:
 		return ERR_PTR(-EOPNOTSUPP);
 	default:
 		break;
@@ -1592,6 +1610,7 @@ init_hw_perf_events(void)
 	case CPU_CAVIUM_OCTEON:
 	case CPU_CAVIUM_OCTEON_PLUS:
 	case CPU_CAVIUM_OCTEON2:
+	case CPU_CAVIUM_OCTEON3:
 		mipspmu.name = "octeon";
 		mipspmu.general_event_map = &octeon_event_map;
 		mipspmu.cache_event_map = &octeon_cache_map;
-- 
1.8.1.4



More information about the linux-yocto mailing list