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: 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>
This commit is contained in:
@@ -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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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 @@
|
|||||||
#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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user