Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arm64: Support arch_irq_work_raise() via self IPIs

Support for arch_irq_work_raise() was missing from
arm64 (a prerequisite for FULL_NOHZ).

This patch is based on the arm32 patch ARM 7872/1.

commit bf18525fd793101df42a1344ecc48b49b62e48c9
Author: Stephen Boyd <sboyd@codeaurora.org>
Date: Tue Oct 29 20:32:56 2013 +0100

ARM: 7872/1: Support arch_irq_work_raise() via self IPIs

By default, IRQ work is run from the tick interrupt (see
irq_work_run() in update_process_times()). When we're in full
NOHZ mode, restarting the tick requires the use of IRQ work and
if the only place we run IRQ work is in the tick interrupt we
have an unbreakable cycle. Implement arch_irq_work_raise() via
self IPIs to break this cycle and get the tick started again.
Note that we implement this via IPIs which are only available on
SMP builds. This shouldn't be a problem because full NOHZ is only
supported on SMP builds anyway.

Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Reviewed-by: Kevin Hilman <khilman@linaro.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Signed-off-by: Larry Bassel <larry.bassel@linaro.org>
Reviewed-by: Kevin Hilman <khilman@linaro.org>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>

authored by

Larry Bassel and committed by
Catalin Marinas
eb631bb5 ebdc9447

+20 -1
+1 -1
arch/arm64/include/asm/hardirq.h
··· 20 20 #include <linux/threads.h> 21 21 #include <asm/irq.h> 22 22 23 - #define NR_IPI 5 23 + #define NR_IPI 6 24 24 25 25 typedef struct { 26 26 unsigned int __softirq_pending;
+19
arch/arm64/kernel/smp.c
··· 35 35 #include <linux/clockchips.h> 36 36 #include <linux/completion.h> 37 37 #include <linux/of.h> 38 + #include <linux/irq_work.h> 38 39 39 40 #include <asm/atomic.h> 40 41 #include <asm/cacheflush.h> ··· 63 62 IPI_CALL_FUNC_SINGLE, 64 63 IPI_CPU_STOP, 65 64 IPI_TIMER, 65 + IPI_IRQ_WORK, 66 66 }; 67 67 68 68 /* ··· 457 455 smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE); 458 456 } 459 457 458 + #ifdef CONFIG_IRQ_WORK 459 + void arch_irq_work_raise(void) 460 + { 461 + if (smp_cross_call) 462 + smp_cross_call(cpumask_of(smp_processor_id()), IPI_IRQ_WORK); 463 + } 464 + #endif 465 + 460 466 static const char *ipi_types[NR_IPI] = { 461 467 #define S(x,s) [x - IPI_RESCHEDULE] = s 462 468 S(IPI_RESCHEDULE, "Rescheduling interrupts"), ··· 472 462 S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"), 473 463 S(IPI_CPU_STOP, "CPU stop interrupts"), 474 464 S(IPI_TIMER, "Timer broadcast interrupts"), 465 + S(IPI_IRQ_WORK, "IRQ work interrupts"), 475 466 }; 476 467 477 468 void show_ipi_list(struct seq_file *p, int prec) ··· 561 550 case IPI_TIMER: 562 551 irq_enter(); 563 552 tick_receive_broadcast(); 553 + irq_exit(); 554 + break; 555 + #endif 556 + 557 + #ifdef CONFIG_IRQ_WORK 558 + case IPI_IRQ_WORK: 559 + irq_enter(); 560 + irq_work_run(); 564 561 irq_exit(); 565 562 break; 566 563 #endif