[PATCH 2/7] MIPS: time: Use CPUHUP to handle r4k timer

From: Jiaxun Yang
Date: Sun Aug 16 2020 - 23:48:23 EST


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