Since commit a1ec0e188330 ("MIPS: perf: Allow sharing IRQ with timer")
we have supported registering our performance counter overflow IRQ
handler using the IRQF_SHARED flag when cp0_perfcount_irq >= 0 or
get_c0_perfcount_int() is implemented & returns a valid interrupt. This
was made unconditional for MIPSr2 & beyond by commit 4a91d8fb61e2
("MIPS: Allow shared IRQ for timer & perf counter") which removed a
special case that set cp0_perfcount_irq to -1 if the performance counter
overflow & timer interrupts share a CPU interrupt pin, however for
pre-r2 systems we retained a fallback wherein we don't register the perf
IRQ handler & instead set a perf_irq function pointer which is called by
the timer driver.

Commit 4a91d8fb61e2 ("MIPS: Allow shared IRQ for timer & perf counter")
seems to suggest that this is necessary because the we can't decode
which interrupt happened on pre-r2 systems, but this is not true - in
this case __handle_irq_event_percpu() will simply invoke both the timer
driver & perf interrupt handlers which is exactly what we want, and
they'll simply both perform their work as they do now.

As such we can set cp0_perfcount_irq = cp0_compare_irq for pre-r2
systems and remove the perf_irq fallback in favor of always relying on
more standard interrupt sharing using IRQF_SHARED & multiple handlers.

A natural cleanup that ties in with no longer using perf_irq is that we
can remove mipsxx_pmu_handle_shared_irq() which we previously pointed
perf_irq at, and effectively inline it in mipsxx_pmu_handle_irq().

In the the loongson3 oprofile case the driver had exclusively relied
upon perf_irq, and we switch instead to calling request_irq() to
register the shared handler just like the mipsxx perf & oprofile code.

Signed-off-by: Paul Burton <paul.bur...@imgtec.com>
Cc: James Hogan <james.ho...@imgtec.com>
Cc: Jason Cooper <ja...@lakedaemon.net>
Cc: Marc Zyngier <marc.zyng...@arm.com>
Cc: Ralf Baechle <r...@linux-mips.org>
Cc: Thomas Gleixner <t...@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Cc: linux-m...@linux-mips.org
---

 arch/mips/kernel/perf_event_mipsxx.c    | 59 +++++++++++----------------------
 arch/mips/kernel/traps.c                |  2 +-
 arch/mips/oprofile/op_model_loongson3.c | 39 +++++++++++-----------
 arch/mips/oprofile/op_model_mipsxx.c    | 10 ++----
 4 files changed, 42 insertions(+), 68 deletions(-)

diff --git a/arch/mips/kernel/perf_event_mipsxx.c 
b/arch/mips/kernel/perf_event_mipsxx.c
index 9e6c74bf66c4..cae36ca400e9 100644
--- a/arch/mips/kernel/perf_event_mipsxx.c
+++ b/arch/mips/kernel/perf_event_mipsxx.c
@@ -25,7 +25,7 @@
 #include <asm/irq.h>
 #include <asm/irq_regs.h>
 #include <asm/stacktrace.h>
-#include <asm/time.h> /* For perf_irq */
+#include <asm/time.h>
 
 #define MIPS_MAX_HWEVENTS 4
 #define MIPS_TCS_PER_COUNTER 2
@@ -167,7 +167,6 @@ static unsigned int counters_total_to_per_cpu(unsigned int 
counters)
 static void 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);
 
 static unsigned int mipsxx_pmu_swizzle_perf_idx(unsigned int idx)
 {
@@ -538,44 +537,25 @@ static void mipspmu_disable(struct pmu *pmu)
 
 static atomic_t active_events = ATOMIC_INIT(0);
 static DEFINE_MUTEX(pmu_reserve_mutex);
-static int (*save_perf_irq)(void);
 
 static int mipspmu_get_irq(void)
 {
        int err;
 
-       if (mipspmu.irq >= 0) {
-               /* Request my own irq handler. */
-               err = request_irq(mipspmu.irq, mipsxx_pmu_handle_irq,
-                                 IRQF_PERCPU | IRQF_NOBALANCING |
-                                 IRQF_NO_THREAD | IRQF_NO_SUSPEND |
-                                 IRQF_SHARED,
-                                 "mips_perf_pmu", &mipspmu);
-               if (err) {
-                       pr_warn("Unable to request IRQ%d for MIPS performance 
counters!\n",
-                               mipspmu.irq);
-               }
-       } else if (cp0_perfcount_irq < 0) {
-               /*
-                * We are sharing the irq number with the timer interrupt.
-                */
-               save_perf_irq = perf_irq;
-               perf_irq = mipsxx_pmu_handle_shared_irq;
-               err = 0;
-       } else {
-               pr_warn("The platform hasn't properly defined its interrupt 
controller\n");
-               err = -ENOENT;
-       }
-
+       err = request_irq(mipspmu.irq, mipsxx_pmu_handle_irq,
+                         IRQF_PERCPU | IRQF_NOBALANCING |
+                         IRQF_NO_THREAD | IRQF_NO_SUSPEND |
+                         IRQF_SHARED,
+                         "mips_perf_pmu", &mipspmu);
+       if (err)
+               pr_warn("Unable to request IRQ%d for MIPS performance 
counters!\n",
+                       mipspmu.irq);
        return err;
 }
 
 static void mipspmu_free_irq(void)
 {
-       if (mipspmu.irq >= 0)
-               free_irq(mipspmu.irq, &mipspmu);
-       else if (cp0_perfcount_irq < 0)
-               perf_irq = save_perf_irq;
+       free_irq(mipspmu.irq, &mipspmu);
 }
 
 /*
@@ -1403,13 +1383,13 @@ static void resume_local_counters(void)
        } while (ctr > 0);
 }
 
-static int mipsxx_pmu_handle_shared_irq(void)
+static irqreturn_t mipsxx_pmu_handle_irq(int irq, void *dev)
 {
        struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
        struct perf_sample_data data;
        unsigned int counters = mipspmu.num_counters;
        u64 counter;
-       int handled = IRQ_NONE;
+       irqreturn_t handled = IRQ_NONE;
        struct pt_regs *regs;
 
        if (cpu_has_perf_cntr_intr_bit && !(read_c0_cause() & CAUSEF_PCI))
@@ -1462,11 +1442,6 @@ static int mipsxx_pmu_handle_shared_irq(void)
        return handled;
 }
 
-static irqreturn_t mipsxx_pmu_handle_irq(int irq, void *dev)
-{
-       return mipsxx_pmu_handle_shared_irq();
-}
-
 /* 24K */
 #define IS_BOTH_COUNTERS_24K_EVENT(b)                                  \
        ((b) == 0 || (b) == 1 || (b) == 11)
@@ -1736,6 +1711,11 @@ init_hw_perf_events(void)
        else
                irq = -1;
 
+       if (irq < 0) {
+               pr_warn("The platform hasn't properly defined its interrupt 
controller\n");
+               return -ENOENT;
+       }
+
        mipspmu.map_raw_event = mipsxx_pmu_map_raw_event;
 
        switch (current_cpu_type()) {
@@ -1850,9 +1830,8 @@ init_hw_perf_events(void)
 
        on_each_cpu(reset_counters, (void *)(long)counters, 1);
 
-       pr_cont("%s PMU enabled, %d %d-bit counters available to each "
-               "CPU, irq %d%s\n", mipspmu.name, counters, counter_bits, irq,
-               irq < 0 ? " (share with timer interrupt)" : "");
+       pr_cont("%s PMU enabled, %d %d-bit counters available to each CPU, irq 
%d",
+               mipspmu.name, counters, counter_bits, irq);
 
        perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
 
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 5669d3b8bd38..0fe19103e882 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -2227,7 +2227,7 @@ void per_cpu_trap_init(bool is_boot_cpu)
        } else {
                cp0_compare_irq = CP0_LEGACY_COMPARE_IRQ;
                cp0_compare_irq_shift = CP0_LEGACY_PERFCNT_IRQ;
-               cp0_perfcount_irq = -1;
+               cp0_perfcount_irq = cp0_compare_irq;
                cp0_fdc_irq = -1;
        }
 
diff --git a/arch/mips/oprofile/op_model_loongson3.c 
b/arch/mips/oprofile/op_model_loongson3.c
index 436b1fc99f2c..e6954ebff4a1 100644
--- a/arch/mips/oprofile/op_model_loongson3.c
+++ b/arch/mips/oprofile/op_model_loongson3.c
@@ -40,8 +40,6 @@
 #define read_c0_perfhi2() __read_64bit_c0_register($25, 3)
 #define write_c0_perfhi2(val) __write_64bit_c0_register($25, 3, val)
 
-static int (*save_perf_irq)(void);
-
 static struct loongson3_register_config {
        unsigned int control1;
        unsigned int control2;
@@ -130,12 +128,13 @@ static void loongson3_cpu_stop(void *args)
        memset(&reg, 0, sizeof(reg));
 }
 
-static int loongson3_perfcount_handler(void)
+static irqreturn_t loongson3_perfcount_handler(int irq, void *dev_id)
 {
        unsigned long flags;
        uint64_t counter1, counter2;
-       uint32_t cause, handled = IRQ_NONE;
+       uint32_t cause;
        struct pt_regs *regs = get_irq_regs();
+       irqreturn_t handled = IRQ_NONE;
 
        cause = read_c0_cause();
        if (!(cause & CAUSEF_PCI))
@@ -182,32 +181,34 @@ static int loongson3_dying_cpu(unsigned int cpu)
        return 0;
 }
 
+struct op_mips_model op_model_loongson3_ops = {
+       .reg_setup      = loongson3_reg_setup,
+       .cpu_setup      = loongson3_cpu_setup,
+       .init           = loongson3_init,
+       .exit           = loongson3_exit,
+       .cpu_start      = loongson3_cpu_start,
+       .cpu_stop       = loongson3_cpu_stop,
+       .cpu_type       = "mips/loongson3",
+       .num_counters   = 2
+};
+
 static int __init loongson3_init(void)
 {
        on_each_cpu(reset_counters, NULL, 1);
        cpuhp_setup_state_nocalls(CPUHP_AP_MIPS_OP_LOONGSON3_STARTING,
                                  "mips/oprofile/loongson3:starting",
                                  loongson3_starting_cpu, loongson3_dying_cpu);
-       save_perf_irq = perf_irq;
-       perf_irq = loongson3_perfcount_handler;
 
-       return 0;
+       return request_irq(cp0_compare_irq, loongson3_perfcount_handler,
+                          IRQF_PERCPU | IRQF_NOBALANCING |
+                          IRQF_NO_THREAD | IRQF_NO_SUSPEND |
+                          IRQF_SHARED,
+                          "Perfcounter", &op_model_loongson3_ops);
 }
 
 static void loongson3_exit(void)
 {
+       free_irq(cp0_compare_irq, &op_model_loongson3_ops);
        on_each_cpu(reset_counters, NULL, 1);
        cpuhp_remove_state_nocalls(CPUHP_AP_MIPS_OP_LOONGSON3_STARTING);
-       perf_irq = save_perf_irq;
 }
-
-struct op_mips_model op_model_loongson3_ops = {
-       .reg_setup      = loongson3_reg_setup,
-       .cpu_setup      = loongson3_cpu_setup,
-       .init           = loongson3_init,
-       .exit           = loongson3_exit,
-       .cpu_start      = loongson3_cpu_start,
-       .cpu_stop       = loongson3_cpu_stop,
-       .cpu_type       = "mips/loongson3",
-       .num_counters   = 2
-};
diff --git a/arch/mips/oprofile/op_model_mipsxx.c 
b/arch/mips/oprofile/op_model_mipsxx.c
index c3e4c18ef8d4..09cbb226c7da 100644
--- a/arch/mips/oprofile/op_model_mipsxx.c
+++ b/arch/mips/oprofile/op_model_mipsxx.c
@@ -21,7 +21,6 @@
 
 #define M_COUNTER_OVERFLOW             (1UL      << 31)
 
-static int (*save_perf_irq)(void);
 static int perfcount_irq;
 
 /*
@@ -423,9 +422,6 @@ static int __init mipsxx_init(void)
                return -ENODEV;
        }
 
-       save_perf_irq = perf_irq;
-       perf_irq = mipsxx_perfcount_handler;
-
        if (get_c0_perfcount_int)
                perfcount_irq = get_c0_perfcount_int();
        else if (cp0_perfcount_irq >= 0)
@@ -438,7 +434,7 @@ static int __init mipsxx_init(void)
                                   IRQF_PERCPU | IRQF_NOBALANCING |
                                   IRQF_NO_THREAD | IRQF_NO_SUSPEND |
                                   IRQF_SHARED,
-                                  "Perfcounter", save_perf_irq);
+                                  "Perfcounter", &op_model_mipsxx_ops);
 
        return 0;
 }
@@ -448,12 +444,10 @@ static void mipsxx_exit(void)
        int counters = op_model_mipsxx_ops.num_counters;
 
        if (perfcount_irq >= 0)
-               free_irq(perfcount_irq, save_perf_irq);
+               free_irq(perfcount_irq, &op_model_mipsxx_ops);
 
        counters = counters_per_cpu_to_total(counters);
        on_each_cpu(reset_counters, (void *)(long)counters, 1);
-
-       perf_irq = save_perf_irq;
 }
 
 struct op_mips_model op_model_mipsxx_ops = {
-- 
2.14.1

Reply via email to