MIPS: Add hook to get C0 performance counter interrupt
authorAndrew Bresticker <abrestic@chromium.org>
Thu, 18 Sep 2014 21:47:12 +0000 (14:47 -0700)
committerRalf Baechle <ralf@linux-mips.org>
Mon, 24 Nov 2014 06:44:53 +0000 (07:44 +0100)
The hardware perf event driver and oprofile interpret the global
cp0_perfcount_irq differently: in the hardware perf event driver
it is an offset from MIPS_CPU_IRQ_BASE and in oprofile it is the
actual IRQ number.  This still works most of the time since
MIPS_CPU_IRQ_BASE is usually 0, but is clearly wrong.  Since the
performance counter interrupt may vary from platform to platform
like the C0 timer interrupt, add the optional get_c0_perfcount_int
hook which returns the IRQ number of the performance counter.
The hook should return < 0 if the performance counter interrupt is
shared with the timer.  If the hook is not present, the CPU vector
reported in C0_IntCtl (cp0_perfcount_irq) is used.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
Reviewed-by: Qais Yousef <qais.yousef@imgtec.com>
Tested-by: Qais Yousef <qais.yousef@imgtec.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Andrew Bresticker <abrestic@chromium.org>
Cc: Jeffrey Deans <jeffrey.deans@imgtec.com>
Cc: Markos Chandras <markos.chandras@imgtec.com>
Cc: Paul Burton <paul.burton@imgtec.com>
Cc: Qais Yousef <qais.yousef@imgtec.com>
Cc: Jonas Gorski <jogo@openwrt.org>
Cc: John Crispin <blogic@openwrt.org>
Cc: David Daney <ddaney.cavm@gmail.com>
Cc: linux-mips@linux-mips.org
Cc: linux-kernel@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/7805/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/ath79/irq.c
arch/mips/ath79/setup.c
arch/mips/include/asm/time.h
arch/mips/kernel/perf_event_mipsxx.c
arch/mips/lantiq/irq.c
arch/mips/mti-malta/malta-time.c
arch/mips/mti-sead3/sead3-time.c
arch/mips/oprofile/op_model_mipsxx.c
arch/mips/ralink/irq.c

index 9c0e1761773f73d824accbfad15461da9793f8c1..6adae366f11a9c4936a3546be33766871bf0b261 100644 (file)
@@ -359,7 +359,6 @@ void __init arch_init_irq(void)
                BUG();
        }
 
-       cp0_perfcount_irq = ATH79_MISC_IRQ(5);
        mips_cpu_irq_init();
        ath79_misc_irq_init();
 
index 64807a4809d0a4b6f367ad52f15fe2fcbfc6a843..a73c93c3d44a1069149945cf2732aeed26c918bd 100644 (file)
@@ -182,6 +182,11 @@ const char *get_system_type(void)
        return ath79_sys_type;
 }
 
+int get_c0_perfcount_int(void)
+{
+       return ATH79_MISC_IRQ(5);
+}
+
 unsigned int get_c0_compare_int(void)
 {
        return CP0_LEGACY_COMPARE_IRQ;
index 8f3047d611ee89556eb4c41d1b8337136b5ea710..7969933ba89a6587c0ca3a5bac386ce869d92d2c 100644 (file)
@@ -46,6 +46,7 @@ extern unsigned int mips_hpt_frequency;
  * so it lives here.
  */
 extern int (*perf_irq)(void);
+extern int __weak get_c0_perfcount_int(void);
 
 /*
  * Initialize the calling CPU's compare interrupt as clockevent device
index 7633d30550e9bd1e6022a24b6bcbafd5b9477479..9466184d0039d1b40e85db2fc0447ce9cafcee2b 100644 (file)
@@ -1613,22 +1613,13 @@ init_hw_perf_events(void)
                counters = counters_total_to_per_cpu(counters);
 #endif
 
-#ifdef MSC01E_INT_BASE
-       if (cpu_has_veic) {
-               /*
-                * Using platform specific interrupt controller defines.
-                */
-               irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR;
-       } else {
-#endif
-               if ((cp0_perfcount_irq >= 0) &&
-                               (cp0_compare_irq != cp0_perfcount_irq))
-                       irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
-               else
-                       irq = -1;
-#ifdef MSC01E_INT_BASE
-       }
-#endif
+       if (get_c0_perfcount_int)
+               irq = get_c0_perfcount_int();
+       else if ((cp0_perfcount_irq >= 0) &&
+                (cp0_compare_irq != cp0_perfcount_irq))
+               irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
+       else
+               irq = -1;
 
        mipspmu.map_raw_event = mipsxx_pmu_map_raw_event;
 
index 030568a70ac49418b38cbdfb278a429ae06c4927..21c38eee0a81eba5d214392daf5d2e92631f42e5 100644 (file)
@@ -70,6 +70,7 @@ static struct resource ltq_eiu_irq[MAX_EIU];
 static void __iomem *ltq_icu_membase[MAX_IM];
 static void __iomem *ltq_eiu_membase;
 static struct irq_domain *ltq_domain;
+static int ltq_perfcount_irq;
 
 int ltq_eiu_get_irq(int exin)
 {
@@ -449,7 +450,7 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
 #endif
 
        /* tell oprofile which irq to use */
-       cp0_perfcount_irq = irq_create_mapping(ltq_domain, LTQ_PERF_IRQ);
+       ltq_perfcount_irq = irq_create_mapping(ltq_domain, LTQ_PERF_IRQ);
 
        /*
         * if the timer irq is not one of the mips irqs we need to
@@ -461,6 +462,11 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
        return 0;
 }
 
+int get_c0_perfcount_int(void)
+{
+       return ltq_perfcount_irq;
+}
+
 unsigned int get_c0_compare_int(void)
 {
        return MIPS_CPU_TIMER_IRQ;
index 3778a359f3ad98279fe32f952b725ea521eb6e0a..a4e035c8acf6543a9200ff90efd275856aaba36c 100644 (file)
@@ -121,22 +121,20 @@ void read_persistent_clock(struct timespec *ts)
        ts->tv_nsec = 0;
 }
 
-static void __init plat_perf_setup(void)
+int get_c0_perfcount_int(void)
 {
-#ifdef MSC01E_INT_BASE
        if (cpu_has_veic) {
                set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch);
                mips_cpu_perf_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR;
-       } else
-#endif
-       if (cp0_perfcount_irq >= 0) {
+       } else if (cp0_perfcount_irq >= 0) {
                if (cpu_has_vint)
                        set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch);
                mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
-#ifdef CONFIG_SMP
-               irq_set_handler(mips_cpu_perf_irq, handle_percpu_irq);
-#endif
+       } else {
+               mips_cpu_perf_irq = -1;
        }
+
+       return mips_cpu_perf_irq;
 }
 
 unsigned int get_c0_compare_int(void)
@@ -201,6 +199,4 @@ void __init plat_time_init(void)
 #endif
        }
 #endif
-
-       plat_perf_setup();
 }
index 678d03d53c60cc80e399e1b79a44dfbb4f64ab84..f090c5177719bf2b84daa215f015285175a70877 100644 (file)
@@ -81,13 +81,16 @@ void read_persistent_clock(struct timespec *ts)
        ts->tv_nsec = 0;
 }
 
-static void __init plat_perf_setup(void)
+int get_c0_perfcount_int(void)
 {
        if (cp0_perfcount_irq >= 0) {
                if (cpu_has_vint)
                        set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch);
                mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
+       } else {
+               mips_cpu_perf_irq = -1;
        }
+       return mips_cpu_perf_irq;
 }
 
 unsigned int get_c0_compare_int(void)
@@ -108,6 +111,4 @@ void __init plat_time_init(void)
                (est_freq % 1000000) * 100 / 1000000);
 
        mips_scroll_message();
-
-       plat_perf_setup();
 }
index 42821ae2d77e586155eb2554232af87481423731..01f721a85c5b390a42553403c27875a4ee4e8cec 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/interrupt.h>
 #include <linux/smp.h>
 #include <asm/irq_regs.h>
+#include <asm/time.h>
 
 #include "op_impl.h"
 
@@ -35,6 +36,7 @@
 #define M_PERFCTL_COUNT_ALL_THREADS    (1UL      << 13)
 
 static int (*save_perf_irq)(void);
+static int perfcount_irq;
 
 /*
  * XLR has only one set of counters per core. Designate the
@@ -431,8 +433,16 @@ 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,
+       if (get_c0_perfcount_int)
+               perfcount_irq = get_c0_perfcount_int();
+       else if ((cp0_perfcount_irq >= 0) &&
+                (cp0_compare_irq != cp0_perfcount_irq))
+               perfcount_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
+       else
+               perfcount_irq = -1;
+
+       if (perfcount_irq >= 0)
+               return request_irq(perfcount_irq, mipsxx_perfcount_int,
                        0, "Perfcounter", save_perf_irq);
 
        return 0;
@@ -442,8 +452,8 @@ 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);
+       if (perfcount_irq >= 0)
+               free_irq(perfcount_irq, save_perf_irq);
 
        counters = counters_per_cpu_to_total(counters);
        on_each_cpu(reset_counters, (void *)(long)counters, 1);
index 0495011a19df52d8d60c890bb69e80c75a7836e5..7634dcd887663b24f47e76e2fbf4000cde6ffab7 100644 (file)
@@ -45,6 +45,7 @@
 #define RALINK_INTC_IRQ_PERFC   (RALINK_INTC_IRQ_BASE + 9)
 
 static void __iomem *rt_intc_membase;
+static int rt_perfcount_irq;
 
 static inline void rt_intc_w32(u32 val, unsigned reg)
 {
@@ -73,6 +74,11 @@ static struct irq_chip ralink_intc_irq_chip = {
        .irq_mask_ack   = ralink_intc_irq_mask,
 };
 
+int get_c0_perfcount_int(void)
+{
+       return rt_perfcount_irq;
+}
+
 unsigned int get_c0_compare_int(void)
 {
        return CP0_LEGACY_COMPARE_IRQ;
@@ -167,7 +173,7 @@ static int __init intc_of_init(struct device_node *node,
        irq_set_handler_data(irq, domain);
 
        /* tell the kernel which irq is used for performance monitoring */
-       cp0_perfcount_irq = irq_create_mapping(domain, 9);
+       rt_perfcount_irq = irq_create_mapping(domain, 9);
 
        return 0;
 }