Commit 2f100585 authored by Guo Ren's avatar Guo Ren Committed by Palmer Dabbelt

riscv: Enable generic clockevent broadcast

When percpu-timers are stopped by deep power saving mode, we
need system timer help to broadcast IPI_TIMER.

This is first introduced by broken x86 hardware, where the local apic
timer stops in C3 state. But many other architectures(powerpc, mips,
arm, hexagon, openrisc, sh) have supported the infrastructure to
deal with Power Management issues.
Signed-off-by: default avatarGuo Ren <guoren@linux.alibaba.com>
Reviewed-by: default avatarAnup Patel <anup@brainfault.org>
Signed-off-by: default avatarPalmer Dabbelt <palmerdabbelt@google.com>
parent 95301414
...@@ -29,6 +29,7 @@ config RISCV ...@@ -29,6 +29,7 @@ config RISCV
select ARCH_HAS_SET_DIRECT_MAP select ARCH_HAS_SET_DIRECT_MAP
select ARCH_HAS_SET_MEMORY select ARCH_HAS_SET_MEMORY
select ARCH_HAS_STRICT_KERNEL_RWX if MMU select ARCH_HAS_STRICT_KERNEL_RWX if MMU
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
select ARCH_OPTIONAL_KERNEL_RWX if ARCH_HAS_STRICT_KERNEL_RWX select ARCH_OPTIONAL_KERNEL_RWX if ARCH_HAS_STRICT_KERNEL_RWX
select ARCH_OPTIONAL_KERNEL_RWX_DEFAULT select ARCH_OPTIONAL_KERNEL_RWX_DEFAULT
select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU
...@@ -40,6 +41,7 @@ config RISCV ...@@ -40,6 +41,7 @@ config RISCV
select EDAC_SUPPORT select EDAC_SUPPORT
select GENERIC_ARCH_TOPOLOGY if SMP select GENERIC_ARCH_TOPOLOGY if SMP
select GENERIC_ATOMIC64 if !64BIT select GENERIC_ATOMIC64 if !64BIT
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
select GENERIC_EARLY_IOREMAP select GENERIC_EARLY_IOREMAP
select GENERIC_GETTIMEOFDAY if HAVE_GENERIC_VDSO select GENERIC_GETTIMEOFDAY if HAVE_GENERIC_VDSO
select GENERIC_IOREMAP select GENERIC_IOREMAP
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
*/ */
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/clockchips.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/profile.h> #include <linux/profile.h>
...@@ -27,6 +28,7 @@ enum ipi_message_type { ...@@ -27,6 +28,7 @@ enum ipi_message_type {
IPI_CALL_FUNC, IPI_CALL_FUNC,
IPI_CPU_STOP, IPI_CPU_STOP,
IPI_IRQ_WORK, IPI_IRQ_WORK,
IPI_TIMER,
IPI_MAX IPI_MAX
}; };
...@@ -176,6 +178,12 @@ void handle_IPI(struct pt_regs *regs) ...@@ -176,6 +178,12 @@ void handle_IPI(struct pt_regs *regs)
irq_work_run(); irq_work_run();
} }
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
if (ops & (1 << IPI_TIMER)) {
stats[IPI_TIMER]++;
tick_receive_broadcast();
}
#endif
BUG_ON((ops >> IPI_MAX) != 0); BUG_ON((ops >> IPI_MAX) != 0);
/* Order data access and bit testing. */ /* Order data access and bit testing. */
...@@ -192,6 +200,7 @@ static const char * const ipi_names[] = { ...@@ -192,6 +200,7 @@ static const char * const ipi_names[] = {
[IPI_CALL_FUNC] = "Function call interrupts", [IPI_CALL_FUNC] = "Function call interrupts",
[IPI_CPU_STOP] = "CPU stop interrupts", [IPI_CPU_STOP] = "CPU stop interrupts",
[IPI_IRQ_WORK] = "IRQ work interrupts", [IPI_IRQ_WORK] = "IRQ work interrupts",
[IPI_TIMER] = "Timer broadcast interrupts",
}; };
void show_ipi_stats(struct seq_file *p, int prec) void show_ipi_stats(struct seq_file *p, int prec)
...@@ -217,6 +226,13 @@ void arch_send_call_function_single_ipi(int cpu) ...@@ -217,6 +226,13 @@ void arch_send_call_function_single_ipi(int cpu)
send_ipi_single(cpu, IPI_CALL_FUNC); send_ipi_single(cpu, IPI_CALL_FUNC);
} }
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
void tick_broadcast(const struct cpumask *mask)
{
send_ipi_mask(mask, IPI_TIMER);
}
#endif
void smp_send_stop(void) void smp_send_stop(void)
{ {
unsigned long timeout; unsigned long timeout;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment