From: Abhishek Paliwal <abhishek.pali...@aricent.com>

From: David Daney <david.da...@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.da...@cavium.com>
Signed-off-by: Abhishek Paliwal <abhishek.pali...@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

-- 
_______________________________________________
linux-yocto mailing list
linux-yocto@yoctoproject.org
https://lists.yoctoproject.org/listinfo/linux-yocto

Reply via email to