aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Boyd <sboyd@codeaurora.org>2013-10-29 15:32:56 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2013-11-06 19:21:26 -0500
commitbf18525fd793101df42a1344ecc48b49b62e48c9 (patch)
treef21c8dab2f929ff4b5410ef8355bfba10c34aa45
parent8d451442549a2696880288ba6325f9681451231b (diff)
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>
-rw-r--r--arch/arm/include/asm/hardirq.h2
-rw-r--r--arch/arm/kernel/smp.c18
2 files changed, 19 insertions, 1 deletions
diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h
index 2740c2a2df63..3d7351c844aa 100644
--- a/arch/arm/include/asm/hardirq.h
+++ b/arch/arm/include/asm/hardirq.h
@@ -5,7 +5,7 @@
5#include <linux/threads.h> 5#include <linux/threads.h>
6#include <asm/irq.h> 6#include <asm/irq.h>
7 7
8#define NR_IPI 6 8#define NR_IPI 7
9 9
10typedef struct { 10typedef struct {
11 unsigned int __softirq_pending; 11 unsigned int __softirq_pending;
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 72024ea8a3a6..bf9a0d6d91dc 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -25,6 +25,7 @@
25#include <linux/clockchips.h> 25#include <linux/clockchips.h>
26#include <linux/completion.h> 26#include <linux/completion.h>
27#include <linux/cpufreq.h> 27#include <linux/cpufreq.h>
28#include <linux/irq_work.h>
28 29
29#include <linux/atomic.h> 30#include <linux/atomic.h>
30#include <asm/smp.h> 31#include <asm/smp.h>
@@ -66,6 +67,7 @@ enum ipi_msg_type {
66 IPI_CALL_FUNC, 67 IPI_CALL_FUNC,
67 IPI_CALL_FUNC_SINGLE, 68 IPI_CALL_FUNC_SINGLE,
68 IPI_CPU_STOP, 69 IPI_CPU_STOP,
70 IPI_IRQ_WORK,
69}; 71};
70 72
71static DECLARE_COMPLETION(cpu_running); 73static DECLARE_COMPLETION(cpu_running);
@@ -448,6 +450,13 @@ void arch_send_call_function_single_ipi(int cpu)
448 smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE); 450 smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
449} 451}
450 452
453#ifdef CONFIG_IRQ_WORK
454void arch_irq_work_raise(void)
455{
456 smp_cross_call(cpumask_of(smp_processor_id()), IPI_IRQ_WORK);
457}
458#endif
459
451static const char *ipi_types[NR_IPI] = { 460static const char *ipi_types[NR_IPI] = {
452#define S(x,s) [x] = s 461#define S(x,s) [x] = s
453 S(IPI_WAKEUP, "CPU wakeup interrupts"), 462 S(IPI_WAKEUP, "CPU wakeup interrupts"),
@@ -456,6 +465,7 @@ static const char *ipi_types[NR_IPI] = {
456 S(IPI_CALL_FUNC, "Function call interrupts"), 465 S(IPI_CALL_FUNC, "Function call interrupts"),
457 S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"), 466 S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"),
458 S(IPI_CPU_STOP, "CPU stop interrupts"), 467 S(IPI_CPU_STOP, "CPU stop interrupts"),
468 S(IPI_IRQ_WORK, "IRQ work interrupts"),
459}; 469};
460 470
461void show_ipi_list(struct seq_file *p, int prec) 471void show_ipi_list(struct seq_file *p, int prec)
@@ -565,6 +575,14 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
565 irq_exit(); 575 irq_exit();
566 break; 576 break;
567 577
578#ifdef CONFIG_IRQ_WORK
579 case IPI_IRQ_WORK:
580 irq_enter();
581 irq_work_run();
582 irq_exit();
583 break;
584#endif
585
568 default: 586 default:
569 printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n", 587 printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
570 cpu, ipinr); 588 cpu, ipinr);