There is no need to hijack initialization procudre to take care of r4k timer we have CPUHP framework to deal with the CPU plug sequence. Signed-off-by: Jiaxun Yang <jiaxun.yang@xxxxxxxxxxx> --- arch/mips/include/asm/time.h | 28 +++++++++++++++------------- arch/mips/kernel/cevt-r4k.c | 30 ++++++++++++++++++++++-------- arch/mips/kernel/smp.c | 3 --- arch/mips/kernel/time.c | 22 ++++++++++++++++++++-- include/linux/cpuhotplug.h | 1 + 5 files changed, 58 insertions(+), 26 deletions(-) diff --git a/arch/mips/include/asm/time.h b/arch/mips/include/asm/time.h index e855a3611d92..d00a5b05a420 100644 --- a/arch/mips/include/asm/time.h +++ b/arch/mips/include/asm/time.h @@ -39,30 +39,32 @@ extern int __weak get_c0_perfcount_int(void); * Initialize the calling CPU's compare interrupt as clockevent device */ extern unsigned int get_c0_compare_int(void); -extern int r4k_clockevent_init(void); -static inline int mips_clockevent_init(void) -{ #ifdef CONFIG_CEVT_R4K - return r4k_clockevent_init(); +extern int r4k_clockevent_init(void); +extern int r4k_clockevent_percpu_init(int cpu); #else - return -ENXIO; -#endif +static inline int r4k_clockevent_init(void) +{ + return -ENODEV; +} +static inline int r4k_clockevent_percpu_init(int cpu) +{ + return -ENODEV; } +#endif /* * Initialize the count register as a clocksource */ -extern int init_r4k_clocksource(void); - -static inline int init_mips_clocksource(void) -{ #ifdef CONFIG_CSRC_R4K - return init_r4k_clocksource(); +extern int init_r4k_clocksource(void); #else - return 0; -#endif +static inline int init_r4k_clocksource(void) +{ + return -ENODEV; } +#endif static inline void clockevent_set_clock(struct clock_event_device *cd, unsigned int clock) diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c index 995ad9e69ded..f0c52d751d0a 100644 --- a/arch/mips/kernel/cevt-r4k.c +++ b/arch/mips/kernel/cevt-r4k.c @@ -294,10 +294,8 @@ core_initcall(r4k_register_cpufreq_notifier); #endif /* !CONFIG_CPU_FREQ */ -int r4k_clockevent_init(void) +int r4k_clockevent_percpu_init(int cpu) { - unsigned long flags = IRQF_PERCPU | IRQF_TIMER | IRQF_SHARED; - unsigned int cpu = smp_processor_id(); struct clock_event_device *cd; unsigned int irq, min_delta; @@ -307,11 +305,6 @@ int r4k_clockevent_init(void) if (!c0_compare_int_usable()) return -ENXIO; - /* - * With vectored interrupts things are getting platform specific. - * get_c0_compare_int is a hook to allow a platform to return the - * interrupt number of its liking. - */ irq = get_c0_compare_int(); cd = &per_cpu(mips_clockevent_device, cpu); @@ -331,9 +324,30 @@ int r4k_clockevent_init(void) clockevents_config_and_register(cd, mips_hpt_frequency, min_delta, 0x7fffffff); + return 0; +} + +int r4k_clockevent_init(void) +{ + int ret; + unsigned int irq; + unsigned long flags = IRQF_PERCPU | IRQF_TIMER | IRQF_SHARED; + + ret = r4k_clockevent_percpu_init(0); + if (ret) + return ret; + + if (cp0_timer_irq_installed) return 0; + /* + * With vectored interrupts things are getting platform specific. + * get_c0_compare_int is a hook to allow a platform to return the + * interrupt number of its liking. + */ + irq = get_c0_compare_int(); + cp0_timer_irq_installed = 1; if (request_irq(irq, c0_compare_interrupt, flags, "timer", diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index ead9ac883241..0ca4f7cf6402 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -337,7 +337,6 @@ asmlinkage void start_secondary(void) cpu_probe(); per_cpu_trap_init(false); - mips_clockevent_init(); mp_ops->init_secondary(); cpu_report(); maar_init(); @@ -358,8 +357,6 @@ asmlinkage void start_secondary(void) /* Notify boot CPU that we're starting & ready to sync counters */ complete(&cpu_starting); - synchronise_count_slave(cpu); - /* The CPU is running and counters synchronised, now mark it online */ set_cpu_online(cpu, true); diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index caa01457dce6..9b16e60aaa30 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -8,6 +8,7 @@ */ #include <linux/bug.h> #include <linux/clockchips.h> +#include <linux/cpuhotplug.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/init.h> @@ -24,6 +25,7 @@ #include <asm/cpu-features.h> #include <asm/cpu-type.h> #include <asm/div64.h> +#include <asm/r4k-timer.h> #include <asm/time.h> #ifdef CONFIG_CPU_FREQ @@ -155,6 +157,16 @@ static __init int cpu_has_mfc0_count_bug(void) return 0; } +#if defined(CONFIG_CEVT_R4K) || defined(CONFIG_CSRC_R4K) +static int mips_r4k_timer_starting_cpu(unsigned int cpu) +{ + synchronise_count_slave(cpu); + r4k_clockevent_percpu_init(cpu); + + return 0; +} +#endif + void __init time_init(void) { plat_time_init(); @@ -167,6 +179,12 @@ void __init time_init(void) * timer interrupt isn't reliable; the interference doesn't * matter then, because we don't use the interrupt. */ - if (mips_clockevent_init() != 0 || !cpu_has_mfc0_count_bug()) - init_mips_clocksource(); + if (r4k_clockevent_init() != 0 || !cpu_has_mfc0_count_bug()) + init_r4k_clocksource(); + +#if defined(CONFIG_CEVT_R4K) || defined(CONFIG_CSRC_R4K) + cpuhp_setup_state_nocalls(CPUHP_AP_MIPS_R4K_TIMER_STARTING, + "clockevents/mips/r4k/timer:starting", + mips_r4k_timer_starting_cpu, NULL); +#endif } diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index 191772d4a4d7..163288803cd4 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -129,6 +129,7 @@ enum cpuhp_state { CPUHP_AP_TEGRA_TIMER_STARTING, CPUHP_AP_ARMADA_TIMER_STARTING, CPUHP_AP_MARCO_TIMER_STARTING, + CPUHP_AP_MIPS_R4K_TIMER_STARTING, CPUHP_AP_MIPS_GIC_TIMER_STARTING, CPUHP_AP_ARC_TIMER_STARTING, CPUHP_AP_RISCV_TIMER_STARTING, -- 2.28.0.rc1