]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
arm64: enable generic clockevent broadcast
authorLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Wed, 4 Sep 2013 09:55:17 +0000 (10:55 +0100)
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Mon, 16 Dec 2013 17:17:35 +0000 (17:17 +0000)
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>
arch/arm64/Kconfig
arch/arm64/include/asm/hardirq.h
arch/arm64/kernel/smp.c

index 6d4dd22ee4b7bc70622f3fe95538bcba0ff6b99e..baab4eb8bfe463613ccdc25e9a248d5ed04ce4a4 100644 (file)
@@ -2,6 +2,7 @@ config ARM64
        def_bool y
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
        select ARCH_USE_CMPXCHG_LOCKREF
+       select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select ARCH_WANT_COMPAT_IPC_PARSE_VERSION
        select ARCH_WANT_FRAME_POINTERS
@@ -12,6 +13,7 @@ config ARM64
        select CLONE_BACKWARDS
        select COMMON_CLK
        select GENERIC_CLOCKEVENTS
+       select GENERIC_CLOCKEVENTS_BROADCAST if SMP
        select GENERIC_IOMAP
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
index 990c051e7829a6ff5df031f5d7e89946383bb840..ae4801d77514ed7ab1e96b9bd1436fac60462a5c 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/threads.h>
 #include <asm/irq.h>
 
-#define NR_IPI 4
+#define NR_IPI 5
 
 typedef struct {
        unsigned int __softirq_pending;
index a0c2ca602cf85bebc6e7996454adb9e47fe9456d..0b8c859e744fb0257148beb7ac26650db280a4d0 100644 (file)
@@ -61,6 +61,7 @@ enum ipi_msg_type {
        IPI_CALL_FUNC,
        IPI_CALL_FUNC_SINGLE,
        IPI_CPU_STOP,
+       IPI_TIMER,
 };
 
 /*
@@ -447,6 +448,7 @@ static const char *ipi_types[NR_IPI] = {
        S(IPI_CALL_FUNC, "Function call interrupts"),
        S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"),
        S(IPI_CPU_STOP, "CPU stop interrupts"),
+       S(IPI_TIMER, "Timer broadcast interrupts"),
 };
 
 void show_ipi_list(struct seq_file *p, int prec)
@@ -532,6 +534,14 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
                irq_exit();
                break;
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
+       case IPI_TIMER:
+               irq_enter();
+               tick_receive_broadcast();
+               irq_exit();
+               break;
+#endif
+
        default:
                pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr);
                break;
@@ -544,6 +554,13 @@ void smp_send_reschedule(int cpu)
        smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE);
 }
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
+void tick_broadcast(const struct cpumask *mask)
+{
+       smp_cross_call(mask, IPI_TIMER);
+}
+#endif
+
 void smp_send_stop(void)
 {
        unsigned long timeout;