MIPS: SMP: Don't increment irq_count multiple times for call function IPIs
authorAlex Smith <alex.smith@imgtec.com>
Fri, 24 Jul 2015 15:57:49 +0000 (16:57 +0100)
committerRalf Baechle <ralf@linux-mips.org>
Mon, 3 Aug 2015 07:25:12 +0000 (09:25 +0200)
The majority of SMP platforms handle their IPIs through do_IRQ()
which calls irq_{enter/exit}(). When a call function IPI is received,
smp_call_function_interrupt() is called which also calls
irq_{enter,exit}(), meaning irq_count is raised twice.

When tick broadcasting is used (which is implemented via a call
function IPI), this incorrectly causes all CPU idle time on the core
receiving broadcast ticks to be accounted as time spent servicing
IRQs, as account_process_tick() will account as such if irq_count is
greater than 1. This results in 100% CPU usage being reported on a
core which receives its ticks via broadcast.

This patch removes the SMP smp_call_function_interrupt() wrapper which
calls irq_{enter,exit}(). Platforms which handle their IPIs through
do_IRQ() now call generic_smp_call_function_interrupt() directly to
avoid incrementing irq_count a second time. Platforms which don't
(loongson, sgi-ip27, sibyte) call generic_smp_call_function_interrupt()
wrapped in irq_{enter,exit}().

Signed-off-by: Alex Smith <alex.smith@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/10770/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
14 files changed:
arch/mips/cavium-octeon/smp.c
arch/mips/include/asm/smp.h
arch/mips/kernel/smp-bmips.c
arch/mips/kernel/smp.c
arch/mips/lantiq/irq.c
arch/mips/loongson64/loongson-3/smp.c
arch/mips/mti-malta/malta-int.c
arch/mips/netlogic/common/smp.c
arch/mips/paravirt/paravirt-smp.c
arch/mips/pmcs-msp71xx/msp_smp.c
arch/mips/sgi-ip27/ip27-irq.c
arch/mips/sibyte/bcm1480/smp.c
arch/mips/sibyte/sb1250/smp.c
drivers/irqchip/irq-mips-gic.c

index 56f5d080ef9d6cb698ba70cf7027783167000284..b7fa9ae28c3659dbf457aecd7cd17255cd34f5da 100644 (file)
@@ -42,7 +42,7 @@ static irqreturn_t mailbox_interrupt(int irq, void *dev_id)
        cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), action);
 
        if (action & SMP_CALL_FUNCTION)
-               smp_call_function_interrupt();
+               generic_smp_call_function_interrupt();
        if (action & SMP_RESCHEDULE_YOURSELF)
                scheduler_ipi();
 
index 16f1ea9ab191234ee8dc5599803b91dcc2ccf745..03722d4326a1aad05935b58805ec8d881703201e 100644 (file)
@@ -83,8 +83,6 @@ static inline void __cpu_die(unsigned int cpu)
 extern void play_dead(void);
 #endif
 
-extern asmlinkage void smp_call_function_interrupt(void);
-
 static inline void arch_send_call_function_single_ipi(int cpu)
 {
        extern struct plat_smp_ops *mp_ops;     /* private */
index 336708ae5c5b4c74b75416058feabb4bef5e30b1..78cf8c2f1de0e8790923d25ab6e42a85e53a6fe9 100644 (file)
@@ -284,7 +284,7 @@ static irqreturn_t bmips5000_ipi_interrupt(int irq, void *dev_id)
        if (action == 0)
                scheduler_ipi();
        else
-               smp_call_function_interrupt();
+               generic_smp_call_function_interrupt();
 
        return IRQ_HANDLED;
 }
@@ -336,7 +336,7 @@ static irqreturn_t bmips43xx_ipi_interrupt(int irq, void *dev_id)
        if (action & SMP_RESCHEDULE_YOURSELF)
                scheduler_ipi();
        if (action & SMP_CALL_FUNCTION)
-               smp_call_function_interrupt();
+               generic_smp_call_function_interrupt();
 
        return IRQ_HANDLED;
 }
index d0744cc77ea7f7a02d94c96faf190787f7e88f64..a31896c33716d424bb30397c17b29af07c6728bb 100644 (file)
@@ -192,16 +192,6 @@ asmlinkage void start_secondary(void)
        cpu_startup_entry(CPUHP_ONLINE);
 }
 
-/*
- * Call into both interrupt handlers, as we share the IPI for them
- */
-void __irq_entry smp_call_function_interrupt(void)
-{
-       irq_enter();
-       generic_smp_call_function_interrupt();
-       irq_exit();
-}
-
 static void stop_this_cpu(void *dummy)
 {
        /*
index 6ab10573490de8a2d5a449e45c3585547c51f7c4..be18648cb8c8dcaf051d8e0d1896712ac921eea7 100644 (file)
@@ -293,7 +293,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
 
 static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
 {
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
        return IRQ_HANDLED;
 }
 
index 509877c6e9d908d7bac6110982c7208ab69204af..1a4738a8f2d3906ccffb58bdf8d9b35ee4b04ef3 100644 (file)
@@ -266,8 +266,11 @@ void loongson3_ipi_interrupt(struct pt_regs *regs)
        if (action & SMP_RESCHEDULE_YOURSELF)
                scheduler_ipi();
 
-       if (action & SMP_CALL_FUNCTION)
-               smp_call_function_interrupt();
+       if (action & SMP_CALL_FUNCTION) {
+               irq_enter();
+               generic_smp_call_function_interrupt();
+               irq_exit();
+       }
 
        if (action & SMP_ASK_C0COUNT) {
                BUG_ON(cpu != 0);
index d1392f8f5811f65ec72445026ac12c4fe15fe6b1..fa8f591f371361ba6fe3654617e6f44690a48a25 100644 (file)
@@ -222,7 +222,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
 
 static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
 {
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
 
        return IRQ_HANDLED;
 }
index dc3e327fbbac105e71c6b89a039e0f79f91e6f3d..f5fff228b347b6da07d68212fb11f4ae140548c8 100644 (file)
@@ -86,7 +86,7 @@ void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc)
 {
        clear_c0_eimr(irq);
        ack_c0_eirr(irq);
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
        set_c0_eimr(irq);
 }
 
index 42181c7105df70992892ead68933bcd5375ab74b..f8d3e081b2ebc77e6752dc10a61a69e9a8172b3d 100644 (file)
@@ -114,7 +114,7 @@ static irqreturn_t paravirt_reched_interrupt(int irq, void *dev_id)
 
 static irqreturn_t paravirt_function_interrupt(int irq, void *dev_id)
 {
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
        return IRQ_HANDLED;
 }
 
index 10170580a2def4501bb4f149c707d050a900246f..ffa0f7101a9773ec8e24813f37e3c270d912b5e2 100644 (file)
@@ -44,7 +44,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
 
 static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
 {
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
 
        return IRQ_HANDLED;
 }
index 3fbaef97a1b8d31791e8999bd222e3e1b01c3701..16ec4e12daa3fb7bed3355a5cd56cdb3c87946fc 100644 (file)
@@ -107,10 +107,14 @@ static void ip27_do_irq_mask0(void)
                scheduler_ipi();
        } else if (pend0 & (1UL << CPU_CALL_A_IRQ)) {
                LOCAL_HUB_CLR_INTR(CPU_CALL_A_IRQ);
-               smp_call_function_interrupt();
+               irq_enter();
+               generic_smp_call_function_interrupt();
+               irq_exit();
        } else if (pend0 & (1UL << CPU_CALL_B_IRQ)) {
                LOCAL_HUB_CLR_INTR(CPU_CALL_B_IRQ);
-               smp_call_function_interrupt();
+               irq_enter();
+               generic_smp_call_function_interrupt();
+               irq_exit();
        } else
 #endif
        {
index af7d44edd9a8f118b79944ecf21310634f308b56..4c71aea2566372c3f3af8627c79e91fb9aede4ea 100644 (file)
@@ -29,8 +29,6 @@
 #include <asm/sibyte/bcm1480_regs.h>
 #include <asm/sibyte/bcm1480_int.h>
 
-extern void smp_call_function_interrupt(void);
-
 /*
  * These are routines for dealing with the bcm1480 smp capabilities
  * independent of board/firmware
@@ -184,6 +182,9 @@ void bcm1480_mailbox_interrupt(void)
        if (action & SMP_RESCHEDULE_YOURSELF)
                scheduler_ipi();
 
-       if (action & SMP_CALL_FUNCTION)
-               smp_call_function_interrupt();
+       if (action & SMP_CALL_FUNCTION) {
+               irq_enter();
+               generic_smp_call_function_interrupt();
+               irq_exit();
+       }
 }
index c0c4b3f88a086f2c331cce0b311d9c547d3b5a6a..1cf66f5ff23d1a5afca26ffd9bc638566d8f68cb 100644 (file)
@@ -172,6 +172,9 @@ void sb1250_mailbox_interrupt(void)
        if (action & SMP_RESCHEDULE_YOURSELF)
                scheduler_ipi();
 
-       if (action & SMP_CALL_FUNCTION)
-               smp_call_function_interrupt();
+       if (action & SMP_CALL_FUNCTION) {
+               irq_enter();
+               generic_smp_call_function_interrupt();
+               irq_exit();
+       }
 }
index b7d54d428b5e55d1520d52e68b95202593cf4b53..ff4be0515a0dc7dbb206ae0a84968f922817101e 100644 (file)
@@ -538,7 +538,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
 
 static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
 {
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
 
        return IRQ_HANDLED;
 }