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