2020-08-17 04:05:09

by Jiaxun Yang

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

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 <[email protected]>
---
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