aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2013-09-04 05:55:17 -0400
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2013-12-16 12:17:35 -0500
commit1f85008e74768a88e1ddb96cc1fe45bb2378166c (patch)
tree7ef3e417c838d91b73ead8f7c0e2f83e6e79739b
parent60fc6942f6ac124503ed7f8506736a8f56b4ca7e (diff)
arm64: enable generic clockevent broadcast
On platforms with power management capabilities, timers that are shut down when a CPU enters deep C-states must be emulated using an always-on timer and a timer IPI to relay the timer IRQ to target CPUs on an SMP system. This patch enables the generic clockevents broadcast infrastructure for arm64, by providing the required Kconfig entries and adding the timer IPI infrastructure. Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
-rw-r--r--arch/arm64/Kconfig2
-rw-r--r--arch/arm64/include/asm/hardirq.h2
-rw-r--r--arch/arm64/kernel/smp.c17
3 files changed, 20 insertions, 1 deletions
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 6d4dd22ee4b7..baab4eb8bfe4 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -2,6 +2,7 @@ config ARM64
2 def_bool y 2 def_bool y
3 select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE 3 select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
4 select ARCH_USE_CMPXCHG_LOCKREF 4 select ARCH_USE_CMPXCHG_LOCKREF
5 select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
5 select ARCH_WANT_OPTIONAL_GPIOLIB 6 select ARCH_WANT_OPTIONAL_GPIOLIB
6 select ARCH_WANT_COMPAT_IPC_PARSE_VERSION 7 select ARCH_WANT_COMPAT_IPC_PARSE_VERSION
7 select ARCH_WANT_FRAME_POINTERS 8 select ARCH_WANT_FRAME_POINTERS
@@ -12,6 +13,7 @@ config ARM64
12 select CLONE_BACKWARDS 13 select CLONE_BACKWARDS
13 select COMMON_CLK 14 select COMMON_CLK
14 select GENERIC_CLOCKEVENTS 15 select GENERIC_CLOCKEVENTS
16 select GENERIC_CLOCKEVENTS_BROADCAST if SMP
15 select GENERIC_IOMAP 17 select GENERIC_IOMAP
16 select GENERIC_IRQ_PROBE 18 select GENERIC_IRQ_PROBE
17 select GENERIC_IRQ_SHOW 19 select GENERIC_IRQ_SHOW
diff --git a/arch/arm64/include/asm/hardirq.h b/arch/arm64/include/asm/hardirq.h
index 990c051e7829..ae4801d77514 100644
--- a/arch/arm64/include/asm/hardirq.h
+++ b/arch/arm64/include/asm/hardirq.h
@@ -20,7 +20,7 @@
20#include <linux/threads.h> 20#include <linux/threads.h>
21#include <asm/irq.h> 21#include <asm/irq.h>
22 22
23#define NR_IPI 4 23#define NR_IPI 5
24 24
25typedef struct { 25typedef struct {
26 unsigned int __softirq_pending; 26 unsigned int __softirq_pending;
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index a0c2ca602cf8..0b8c859e744f 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -61,6 +61,7 @@ enum ipi_msg_type {
61 IPI_CALL_FUNC, 61 IPI_CALL_FUNC,
62 IPI_CALL_FUNC_SINGLE, 62 IPI_CALL_FUNC_SINGLE,
63 IPI_CPU_STOP, 63 IPI_CPU_STOP,
64 IPI_TIMER,
64}; 65};
65 66
66/* 67/*
@@ -447,6 +448,7 @@ static const char *ipi_types[NR_IPI] = {
447 S(IPI_CALL_FUNC, "Function call interrupts"), 448 S(IPI_CALL_FUNC, "Function call interrupts"),
448 S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"), 449 S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"),
449 S(IPI_CPU_STOP, "CPU stop interrupts"), 450 S(IPI_CPU_STOP, "CPU stop interrupts"),
451 S(IPI_TIMER, "Timer broadcast interrupts"),
450}; 452};
451 453
452void show_ipi_list(struct seq_file *p, int prec) 454void show_ipi_list(struct seq_file *p, int prec)
@@ -532,6 +534,14 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
532 irq_exit(); 534 irq_exit();
533 break; 535 break;
534 536
537#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
538 case IPI_TIMER:
539 irq_enter();
540 tick_receive_broadcast();
541 irq_exit();
542 break;
543#endif
544
535 default: 545 default:
536 pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr); 546 pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr);
537 break; 547 break;
@@ -544,6 +554,13 @@ void smp_send_reschedule(int cpu)
544 smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE); 554 smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE);
545} 555}
546 556
557#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
558void tick_broadcast(const struct cpumask *mask)
559{
560 smp_cross_call(mask, IPI_TIMER);
561}
562#endif
563
547void smp_send_stop(void) 564void smp_send_stop(void)
548{ 565{
549 unsigned long timeout; 566 unsigned long timeout;