Commit 4ace6139 authored by Alex Smith's avatar Alex Smith Committed by Ralf Baechle

MIPS: SMP: Don't increment irq_count multiple times for call function IPIs

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: default avatarAlex Smith <alex.smith@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/10770/Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent 55fdcb2d
...@@ -42,7 +42,7 @@ static irqreturn_t mailbox_interrupt(int irq, void *dev_id) ...@@ -42,7 +42,7 @@ static irqreturn_t mailbox_interrupt(int irq, void *dev_id)
cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), action); cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), action);
if (action & SMP_CALL_FUNCTION) if (action & SMP_CALL_FUNCTION)
smp_call_function_interrupt(); generic_smp_call_function_interrupt();
if (action & SMP_RESCHEDULE_YOURSELF) if (action & SMP_RESCHEDULE_YOURSELF)
scheduler_ipi(); scheduler_ipi();
......
...@@ -83,8 +83,6 @@ static inline void __cpu_die(unsigned int cpu) ...@@ -83,8 +83,6 @@ static inline void __cpu_die(unsigned int cpu)
extern void play_dead(void); extern void play_dead(void);
#endif #endif
extern asmlinkage void smp_call_function_interrupt(void);
static inline void arch_send_call_function_single_ipi(int cpu) static inline void arch_send_call_function_single_ipi(int cpu)
{ {
extern struct plat_smp_ops *mp_ops; /* private */ extern struct plat_smp_ops *mp_ops; /* private */
......
...@@ -284,7 +284,7 @@ static irqreturn_t bmips5000_ipi_interrupt(int irq, void *dev_id) ...@@ -284,7 +284,7 @@ static irqreturn_t bmips5000_ipi_interrupt(int irq, void *dev_id)
if (action == 0) if (action == 0)
scheduler_ipi(); scheduler_ipi();
else else
smp_call_function_interrupt(); generic_smp_call_function_interrupt();
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -336,7 +336,7 @@ static irqreturn_t bmips43xx_ipi_interrupt(int irq, void *dev_id) ...@@ -336,7 +336,7 @@ static irqreturn_t bmips43xx_ipi_interrupt(int irq, void *dev_id)
if (action & SMP_RESCHEDULE_YOURSELF) if (action & SMP_RESCHEDULE_YOURSELF)
scheduler_ipi(); scheduler_ipi();
if (action & SMP_CALL_FUNCTION) if (action & SMP_CALL_FUNCTION)
smp_call_function_interrupt(); generic_smp_call_function_interrupt();
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
...@@ -192,16 +192,6 @@ asmlinkage void start_secondary(void) ...@@ -192,16 +192,6 @@ asmlinkage void start_secondary(void)
cpu_startup_entry(CPUHP_ONLINE); 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) static void stop_this_cpu(void *dummy)
{ {
/* /*
......
...@@ -293,7 +293,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) ...@@ -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) static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
{ {
smp_call_function_interrupt(); generic_smp_call_function_interrupt();
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
...@@ -266,8 +266,11 @@ void loongson3_ipi_interrupt(struct pt_regs *regs) ...@@ -266,8 +266,11 @@ void loongson3_ipi_interrupt(struct pt_regs *regs)
if (action & SMP_RESCHEDULE_YOURSELF) if (action & SMP_RESCHEDULE_YOURSELF)
scheduler_ipi(); scheduler_ipi();
if (action & SMP_CALL_FUNCTION) if (action & SMP_CALL_FUNCTION) {
smp_call_function_interrupt(); irq_enter();
generic_smp_call_function_interrupt();
irq_exit();
}
if (action & SMP_ASK_C0COUNT) { if (action & SMP_ASK_C0COUNT) {
BUG_ON(cpu != 0); BUG_ON(cpu != 0);
......
...@@ -222,7 +222,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) ...@@ -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) static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
{ {
smp_call_function_interrupt(); generic_smp_call_function_interrupt();
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
...@@ -86,7 +86,7 @@ void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc) ...@@ -86,7 +86,7 @@ void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc)
{ {
clear_c0_eimr(irq); clear_c0_eimr(irq);
ack_c0_eirr(irq); ack_c0_eirr(irq);
smp_call_function_interrupt(); generic_smp_call_function_interrupt();
set_c0_eimr(irq); set_c0_eimr(irq);
} }
......
...@@ -114,7 +114,7 @@ static irqreturn_t paravirt_reched_interrupt(int irq, void *dev_id) ...@@ -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) static irqreturn_t paravirt_function_interrupt(int irq, void *dev_id)
{ {
smp_call_function_interrupt(); generic_smp_call_function_interrupt();
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
...@@ -44,7 +44,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) ...@@ -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) static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
{ {
smp_call_function_interrupt(); generic_smp_call_function_interrupt();
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
...@@ -107,10 +107,14 @@ static void ip27_do_irq_mask0(void) ...@@ -107,10 +107,14 @@ static void ip27_do_irq_mask0(void)
scheduler_ipi(); scheduler_ipi();
} else if (pend0 & (1UL << CPU_CALL_A_IRQ)) { } else if (pend0 & (1UL << CPU_CALL_A_IRQ)) {
LOCAL_HUB_CLR_INTR(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)) { } else if (pend0 & (1UL << CPU_CALL_B_IRQ)) {
LOCAL_HUB_CLR_INTR(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 } else
#endif #endif
{ {
......
...@@ -29,8 +29,6 @@ ...@@ -29,8 +29,6 @@
#include <asm/sibyte/bcm1480_regs.h> #include <asm/sibyte/bcm1480_regs.h>
#include <asm/sibyte/bcm1480_int.h> #include <asm/sibyte/bcm1480_int.h>
extern void smp_call_function_interrupt(void);
/* /*
* These are routines for dealing with the bcm1480 smp capabilities * These are routines for dealing with the bcm1480 smp capabilities
* independent of board/firmware * independent of board/firmware
...@@ -184,6 +182,9 @@ void bcm1480_mailbox_interrupt(void) ...@@ -184,6 +182,9 @@ void bcm1480_mailbox_interrupt(void)
if (action & SMP_RESCHEDULE_YOURSELF) if (action & SMP_RESCHEDULE_YOURSELF)
scheduler_ipi(); scheduler_ipi();
if (action & SMP_CALL_FUNCTION) if (action & SMP_CALL_FUNCTION) {
smp_call_function_interrupt(); irq_enter();
generic_smp_call_function_interrupt();
irq_exit();
}
} }
...@@ -172,6 +172,9 @@ void sb1250_mailbox_interrupt(void) ...@@ -172,6 +172,9 @@ void sb1250_mailbox_interrupt(void)
if (action & SMP_RESCHEDULE_YOURSELF) if (action & SMP_RESCHEDULE_YOURSELF)
scheduler_ipi(); scheduler_ipi();
if (action & SMP_CALL_FUNCTION) if (action & SMP_CALL_FUNCTION) {
smp_call_function_interrupt(); irq_enter();
generic_smp_call_function_interrupt();
irq_exit();
}
} }
...@@ -538,7 +538,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) ...@@ -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) static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
{ {
smp_call_function_interrupt(); generic_smp_call_function_interrupt();
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment