Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -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();


+0 −2
Original line number Original line Diff line number Diff line
@@ -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 */
+2 −2
Original line number Original line Diff line number Diff line
@@ -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;
}
}
+0 −10
Original line number Original line Diff line number Diff line
@@ -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)
{
{
	/*
	/*
+1 −1
Original line number Original line Diff line number Diff line
@@ -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;
}
}


Loading