Re: [PATCH] clocksource: Loongson constant timer support

From: Jiaxun Yang
Date: Fri Sep 10 2021 - 03:35:04 EST



在 2021/9/10 15:18, zhengd 写道:
Loongson constant timer is found in Loongson-3A4000 processor.
It has a counter which is globally accessiable via rdhwr instruction,
also each core has a clock event generator connected to this clock
source sharing interrupt with MIPS cont & comapre cevt.

We add cevt, csrc, vdso, sched_clock support for this timer.

Signed-off-by: Jiaxun Yang<jiaxun.yang@xxxxxxxxxxx>
Signed-off-by: Huacai Chen<chenhuacai@xxxxxxxxxxxx>
Signed-off-by: zhengd<zhengd@xxxxxxxxxx>

Hi Zheng D

(I think you should provide your full name for sign-off purpose)

It seems like you are repasting my patch, it's appreciated as I don't have capacity to care it presently.

I noticed that you had squashed my patches together, it is discoraged as it will makes reviewing much more harder.

Also, I do have a personal request, could you please mark your modifications from my original set so I can ensure all concerns around the original issue are addressed?

Thanks.

- Jiaxun


---
arch/mips/include/asm/cpu-features.h | 4 +
arch/mips/include/asm/cpu.h | 1 +
.../include/asm/mach-loongson64/loongson.h | 9 +
.../asm/mach-loongson64/loongson_regs.h | 7 +
arch/mips/include/asm/mipsregs.h | 2 +
arch/mips/include/asm/time.h | 3 +
arch/mips/include/asm/vdso/clocksource.h | 3 +-
arch/mips/include/asm/vdso/gettimeofday.h | 25 +-
arch/mips/kernel/cevt-r4k.c | 25 ++
arch/mips/kernel/cpu-probe.c | 6 +-
arch/mips/kernel/csrc-r4k.c | 5 +-
arch/mips/kernel/time.c | 3 +
drivers/clocksource/Kconfig | 10 +
drivers/clocksource/Makefile | 1 +
drivers/clocksource/loongson_const_timer.c | 249 ++++++++++++++++++
include/linux/cpuhotplug.h | 1 +
16 files changed, 348 insertions(+), 6 deletions(-)
create mode 100644 drivers/clocksource/loongson_const_timer.c

diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h
index 3d71081afc55..787bd53be900 100644
--- a/arch/mips/include/asm/cpu-features.h
+++ b/arch/mips/include/asm/cpu-features.h
@@ -573,6 +573,10 @@
# define cpu_has_gsexcex __opt(MIPS_CPU_GSEXCEX)
#endif
+#ifndef cpu_has_extimer
+# define cpu_has_extimer __opt(MIPS_CPU_EXTIMER)
+#endif
+
#ifdef CONFIG_SMP
/*
* Some systems share FTLB RAMs between threads within a core (siblings in
diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h
index d45a52f65b7a..8d221b4c3fa3 100644
--- a/arch/mips/include/asm/cpu.h
+++ b/arch/mips/include/asm/cpu.h
@@ -428,6 +428,7 @@ enum cpu_type_enum {
#define MIPS_CPU_MAC_2008_ONLY BIT_ULL(60) /* CPU Only support MAC2008 Fused multiply-add instruction */
#define MIPS_CPU_FTLBPAREX BIT_ULL(61) /* CPU has FTLB parity exception */
#define MIPS_CPU_GSEXCEX BIT_ULL(62) /* CPU has GSExc exception */
+#define MIPS_CPU_EXTIMER BIT_ULL(63) /* CPU has External Timer (Loongson) */
/*
* CPU ASE encodings
diff --git a/arch/mips/include/asm/mach-loongson64/loongson.h b/arch/mips/include/asm/mach-loongson64/loongson.h
index f7c3ab6d724e..8c7a85bce539 100644
--- a/arch/mips/include/asm/mach-loongson64/loongson.h
+++ b/arch/mips/include/asm/mach-loongson64/loongson.h
@@ -56,6 +56,15 @@ extern void *loongson_fdt_blob;
extern void mach_irq_dispatch(unsigned int pending);
extern int mach_i8259_irq(void);
+#ifdef CONFIG_LOONGSON_CONST_TIMER
+extern int __init constant_timer_init(void);
+#else
+static inline int constant_timer_init(void)
+{
+ return -ENODEV;
+}
+#endif
+
/* We need this in some places... */
#define delay() ({ \
int x; \
diff --git a/arch/mips/include/asm/mach-loongson64/loongson_regs.h b/arch/mips/include/asm/mach-loongson64/loongson_regs.h
index 165993514762..229465060be2 100644
--- a/arch/mips/include/asm/mach-loongson64/loongson_regs.h
+++ b/arch/mips/include/asm/mach-loongson64/loongson_regs.h
@@ -88,6 +88,7 @@ static inline u32 read_cpucfg(u32 reg)
#define LOONGSON_CFG2_LGFTP BIT(19)
#define LOONGSON_CFG2_LGFTPREV GENMASK(22, 20)
#define LOONGSON_CFG2_LLFTP BIT(23)
+#define LOONGSON_CFG2_LLFTPREVB 24
#define LOONGSON_CFG2_LLFTPREV GENMASK(26, 24)
#define LOONGSON_CFG2_LCSRP BIT(27)
#define LOONGSON_CFG2_LDISBLIKELY BIT(28)
@@ -237,6 +238,12 @@ static inline void csr_writeq(u64 val, u32 reg)
#define CSR_MAIL_SEND_BUF_SHIFT 32
#define CSR_MAIL_SEND_H32_MASK 0xFFFFFFFF00000000ULL
+#define LOONGSON_CSR_TIMER_CFG 0x1060
+#define LOONGSON_CSR_TIMER_TICK 0x1070
+#define CONSTANT_TIMER_CFG_PERIODIC (_ULCAST_(1) << 62)
+#define CONSTANT_TIMER_CFG_EN (_ULCAST_(1) << 61)
+#define CONSTANT_TIMER_INITVAL_RESET (_ULCAST_(0xffff) << 48)
+
static inline u64 drdtime(void)
{
int rID = 0;
diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h
index acdf8c69220b..c16580a15336 100644
--- a/arch/mips/include/asm/mipsregs.h
+++ b/arch/mips/include/asm/mipsregs.h
@@ -699,6 +699,8 @@
/* Config6 feature bits for proAptiv/P5600 */
+#define LOONGSON_CONF6_INTIMER (_ULCAST_(1) << 6)
+#define LOONGSON_CONF6_EXTIMER (_ULCAST_(1) << 7)
/* Jump register cache prediction disable */
#define MTI_CONF6_JRCD (_ULCAST_(1) << 0)
/* MIPSr6 extensions enable */
diff --git a/arch/mips/include/asm/time.h b/arch/mips/include/asm/time.h
index e855a3611d92..e235b8a27768 100644
--- a/arch/mips/include/asm/time.h
+++ b/arch/mips/include/asm/time.h
@@ -28,6 +28,9 @@ extern void plat_time_init(void);
*/
extern unsigned int mips_hpt_frequency;
+/* True if platform registered sched_clock by itself */
+extern bool plat_have_sched_clock __initdata;
+
/*
* The performance counter IRQ on MIPS is a close relative to the timer IRQ
* so it lives here.
diff --git a/arch/mips/include/asm/vdso/clocksource.h b/arch/mips/include/asm/vdso/clocksource.h
index 510e1671d898..7fd43ca06eb1 100644
--- a/arch/mips/include/asm/vdso/clocksource.h
+++ b/arch/mips/include/asm/vdso/clocksource.h
@@ -4,6 +4,7 @@
#define VDSO_ARCH_CLOCKMODES \
VDSO_CLOCKMODE_R4K, \
- VDSO_CLOCKMODE_GIC
+ VDSO_CLOCKMODE_GIC, \
+ VDSO_CLOCKMODE_CONST
#endif /* __ASM_VDSOCLOCKSOURCE_H */
diff --git a/arch/mips/include/asm/vdso/gettimeofday.h b/arch/mips/include/asm/vdso/gettimeofday.h
index 44a45f3fa4b0..2f860c1e3aa5 100644
--- a/arch/mips/include/asm/vdso/gettimeofday.h
+++ b/arch/mips/include/asm/vdso/gettimeofday.h
@@ -183,6 +183,24 @@ static __always_inline u64 read_gic_count(const struct vdso_data *data)
#endif
+#ifdef CONFIG_LOONGSON_CONST_TIMER
+
+static __always_inline u64 read_const_timer(void)
+{
+ u64 count;
+
+ __asm__ __volatile__(
+ " .set push\n"
+ " .set mips32r2\n"
+ " rdhwr %0, $30\n"
+ " .set pop\n"
+ : "=r" (count));
+
+ return count;
+}
+
+#endif
+
static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
const struct vdso_data *vd)
{
@@ -193,6 +211,10 @@ static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
#ifdef CONFIG_CLKSRC_MIPS_GIC
if (clock_mode == VDSO_CLOCKMODE_GIC)
return read_gic_count(vd);
+#endif
+#ifdef CONFIG_LOONGSON_CONST_TIMER
+ if (clock_mode == VDSO_CLOCKMODE_CONST)
+ return read_const_timer();
#endif
/*
* Core checks mode already. So this raced against a concurrent
@@ -205,7 +227,8 @@ static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
static inline bool mips_vdso_hres_capable(void)
{
return IS_ENABLED(CONFIG_CSRC_R4K) ||
- IS_ENABLED(CONFIG_CLKSRC_MIPS_GIC);
+ IS_ENABLED(CONFIG_CLKSRC_MIPS_GIC) ||
+ IS_ENABLED(CONFIG_LOONGSON_CONST_TIMER);
}
#define __arch_vdso_hres_capable mips_vdso_hres_capable
diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c
index 32ec67c9ab67..91fc62001149 100644
--- a/arch/mips/kernel/cevt-r4k.c
+++ b/arch/mips/kernel/cevt-r4k.c
@@ -15,6 +15,8 @@
#include <asm/time.h>
#include <asm/cevt-r4k.h>
+#include <asm/cpu-features.h>
+#include <asm/mipsregs.h>
static int mips_next_event(unsigned long delta,
struct clock_event_device *evt)
@@ -290,6 +292,24 @@ core_initcall(r4k_register_cpufreq_notifier);
#endif /* !CONFIG_CPU_FREQ */
+#ifdef CONFIG_CPU_LOONGSON64
+static int c0_compare_int_enable(struct clock_event_device *cd)
+{
+ if (cpu_has_extimer)
+ set_c0_config6(LOONGSON_CONF6_INTIMER);
+
+ return 0;
+}
+
+static int c0_compare_int_disable(struct clock_event_device *cd)
+{
+ if (cpu_has_extimer)
+ clear_c0_config6(LOONGSON_CONF6_INTIMER);
+
+ return 0;
+}
+#endif
+
int r4k_clockevent_init(void)
{
unsigned long flags = IRQF_PERCPU | IRQF_TIMER | IRQF_SHARED;
@@ -325,6 +345,11 @@ int r4k_clockevent_init(void)
cd->set_next_event = mips_next_event;
cd->event_handler = mips_event_handler;
+#ifdef CONFIG_CPU_LOONGSON64
+ cd->set_state_oneshot = c0_compare_int_enable;
+ cd->set_state_shutdown = c0_compare_int_disable;
+#endif
+
clockevents_config_and_register(cd, mips_hpt_frequency, min_delta, 0x7fffffff);
if (cp0_timer_irq_installed)
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 630fcb4cb30e..8a9b028a1df7 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -1723,6 +1723,9 @@ static inline void decode_cpucfg(struct cpuinfo_mips *c)
if (cfg2 & LOONGSON_CFG2_LEXT2)
c->ases |= MIPS_ASE_LOONGSON_EXT2;
+ if (cfg2 & LOONGSON_CFG2_LLFTP)
+ c->options |= MIPS_CPU_EXTIMER;
+
if (cfg2 & LOONGSON_CFG2_LSPW) {
c->options |= MIPS_CPU_LDPTE;
c->guest.options |= MIPS_CPU_LDPTE;
@@ -1780,7 +1783,8 @@ static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu)
* Also some early Loongson-3A2000 had wrong TLB type in Config
* register, we correct it here.
*/
- c->options |= MIPS_CPU_FTLB | MIPS_CPU_TLBINV | MIPS_CPU_LDPTE;
+ c->options |= MIPS_CPU_FTLB | MIPS_CPU_TLBINV | MIPS_CPU_LDPTE |
+ MIPS_CPU_EXTIMER;
c->ases |= (MIPS_ASE_LOONGSON_MMI | MIPS_ASE_LOONGSON_CAM |
MIPS_ASE_LOONGSON_EXT | MIPS_ASE_LOONGSON_EXT2);
c->ases &= ~MIPS_ASE_VZ; /* VZ of Loongson-3A2000/3000 is incomplete */
diff --git a/arch/mips/kernel/csrc-r4k.c b/arch/mips/kernel/csrc-r4k.c
index edc4afc080fa..b50a24da6528 100644
--- a/arch/mips/kernel/csrc-r4k.c
+++ b/arch/mips/kernel/csrc-r4k.c
@@ -122,9 +122,8 @@ int __init init_r4k_clocksource(void)
clocksource_register_hz(&clocksource_mips, mips_hpt_frequency);
-#ifndef CONFIG_CPU_FREQ
- sched_clock_register(r4k_read_sched_clock, 32, mips_hpt_frequency);
-#endif
+ if (!IS_ENABLED(CONFIG_CPU_FREQ) && !plat_have_sched_clock)
+ sched_clock_register(r4k_read_sched_clock, 32, mips_hpt_frequency);
return 0;
}
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index caa01457dce6..baf33da8c79d 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -123,6 +123,9 @@ EXPORT_SYMBOL(perf_irq);
unsigned int mips_hpt_frequency;
EXPORT_SYMBOL_GPL(mips_hpt_frequency);
+/* True if platform registered sched_clock by itself */
+bool plat_have_sched_clock __initdata;
+
static __init int cpu_has_mfc0_count_bug(void)
{
switch (current_cpu_type()) {
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 0f5e3983951a..d12e3e4bedd1 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -708,4 +708,14 @@ config MICROCHIP_PIT64B
modes and high resolution. It is used as a clocksource
and a clockevent.
+config LOONGSON_CONST_TIMER
+ bool "Loongson Constant Timer"
+ depends on MACH_LOONGSON64
+ default MACH_LOONGSON64
+ help
+ This option enables Loongson constant timer for Loongson64
+ systems. It supports the oneshot, the periodic modes and high
+ resolution. It is used as a clocksource and a clockevent, it is
+ also accessible in VDSO.
+
endmenu
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index c17ee32a7151..f717a1e06900 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -88,3 +88,4 @@ obj-$(CONFIG_CSKY_MP_TIMER) += timer-mp-csky.o
obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o
obj-$(CONFIG_HYPERV_TIMER) += hyperv_timer.o
obj-$(CONFIG_MICROCHIP_PIT64B) += timer-microchip-pit64b.o
+obj-$(CONFIG_LOONGSON_CONST_TIMER) += loongson_const_timer.o
diff --git a/drivers/clocksource/loongson_const_timer.c b/drivers/clocksource/loongson_const_timer.c
new file mode 100644
index 000000000000..3921b8c37092
--- /dev/null
+++ b/drivers/clocksource/loongson_const_timer.c
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Loongson64 constant timer driver
+ *
+ * Copyright (C) 2020 Huacai Chen<chenhuacai@xxxxxxxxxxxx>
+ * Copyright (C) 2020 Jiaxun Yang<jiaxun.yang@xxxxxxxxxxxx>
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/clockchips.h>
+#include <linux/cpuhotplug.h>
+#include <linux/sched_clock.h>
+#include <asm/time.h>
+#include <asm/mipsregs.h>
+#include <asm/cevt-r4k.h>
+#include <loongson.h>
+#include <loongson_regs.h>
+
+static unsigned int constant_timer_irq = -1;
+
+static DEFINE_PER_CPU(struct clock_event_device, constant_clockevent_device);
+
+static inline unsigned int calc_const_freq(void)
+{
+ unsigned int res;
+ unsigned int base_freq;
+ unsigned int cfm, cfd;
+
+ res = read_cpucfg(LOONGSON_CFG2);
+ if (!(res & LOONGSON_CFG2_LLFTP))
+ return 0;
+
+ res = read_cpucfg(LOONGSON_CFG5);
+ cfm = res & 0xffff;
+ cfd = (res >> 16) & 0xffff;
+ base_freq = read_cpucfg(LOONGSON_CFG4);
+
+ if (!base_freq || !cfm || !cfd)
+ return 0;
+ else
+ return (base_freq * cfm / cfd);
+}
+
+static irqreturn_t handle_constant_timer(int irq, void *data)
+{
+ int cpu = smp_processor_id();
+ struct clock_event_device *cd;
+
+ if ((cp0_perfcount_irq < 0) && perf_irq() == IRQ_HANDLED)
+ return IRQ_HANDLED;
+
+ cd = &per_cpu(mips_clockevent_device, cpu);
+
+
+ if (clockevent_state_detached(cd) || clockevent_state_shutdown(cd))
+ return IRQ_NONE;
+
+ if (read_c0_cause() & CAUSEF_TI) {
+ /* Clear Count/Compare Interrupt */
+ write_c0_compare(read_c0_compare());
+ cd = &per_cpu(constant_clockevent_device, cpu);
+ cd->event_handler(cd);
+
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int constant_set_state_oneshot(struct clock_event_device *evt)
+{
+ u64 cfg;
+
+ cfg = csr_readq(LOONGSON_CSR_TIMER_CFG);
+
+ cfg |= CONSTANT_TIMER_CFG_EN;
+ cfg &= ~CONSTANT_TIMER_CFG_PERIODIC;
+
+ csr_writeq(cfg, LOONGSON_CSR_TIMER_CFG);
+
+ set_c0_config6(LOONGSON_CONF6_EXTIMER);
+
+ return 0;
+}
+
+static int constant_set_state_periodic(struct clock_event_device *evt)
+{
+ unsigned int period;
+ u64 cfg;
+
+ cfg = csr_readq(LOONGSON_CSR_TIMER_CFG);
+
+ cfg &= CONSTANT_TIMER_INITVAL_RESET;
+ cfg |= (CONSTANT_TIMER_CFG_PERIODIC | CONSTANT_TIMER_CFG_EN);
+
+ period = calc_const_freq() / HZ;
+
+ csr_writeq(cfg | period, LOONGSON_CSR_TIMER_CFG);
+
+ set_c0_config6(LOONGSON_CONF6_EXTIMER);
+
+ return 0;
+}
+
+static int constant_set_state_shutdown(struct clock_event_device *evt)
+{
+ u64 cfg;
+
+ clear_c0_config6(LOONGSON_CONF6_EXTIMER);
+ cfg = csr_readq(LOONGSON_CSR_TIMER_CFG);
+ cfg &= ~CONSTANT_TIMER_CFG_EN;
+ csr_writeq(cfg, LOONGSON_CSR_TIMER_CFG);
+
+ return 0;
+}
+
+static int constant_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ csr_writeq(delta | CONSTANT_TIMER_CFG_EN, LOONGSON_CSR_TIMER_CFG);
+ return 0;
+}
+
+static int constant_init_percpu(unsigned int cpu)
+{
+ unsigned int const_freq;
+ struct clock_event_device *cd;
+ unsigned long min_delta = 0x600;
+ unsigned long max_delta = (1UL << 48) - 1;
+
+ cd = &per_cpu(constant_clockevent_device, cpu);
+
+ const_freq = calc_const_freq();
+
+ cd->name = "constant";
+ cd->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC |
+ CLOCK_EVT_FEAT_PERCPU;
+
+ cd->rating = 500; /* Higher than cevt-r4k */
+ cd->irq = constant_timer_irq;
+ cd->cpumask = cpumask_of(cpu);
+ cd->set_state_oneshot = constant_set_state_oneshot;
+ cd->set_state_periodic = constant_set_state_periodic;
+ cd->set_state_shutdown = constant_set_state_shutdown;
+ cd->set_next_event = constant_next_event;
+
+ clockevents_config_and_register(cd, const_freq, min_delta, max_delta);
+
+ return 0;
+}
+
+static int __init constant_clockevent_init(void)
+{
+ unsigned long long flags = IRQF_PERCPU | IRQF_TIMER | IRQF_SHARED;
+
+ constant_timer_irq = get_c0_compare_int();
+ if (constant_timer_irq <= 0)
+ return -ENXIO;
+
+ /* Init on CPU0 firstly to keep away from IRQ storm */
+ constant_init_percpu(0);
+
+ if (request_irq(constant_timer_irq, handle_constant_timer, flags,
+ "constant_timer", handle_constant_timer)) {
+ pr_err("Failed to request irq %d (constant_timer)\n", constant_timer_irq);
+ return -ENXIO;
+ }
+
+ cpuhp_setup_state_nocalls(CPUHP_AP_MIPS_CONST_TIMER_STARTING,
+ "clockevents/mips/constant/timer:starting",
+ constant_init_percpu, NULL);
+
+ return 0;
+}
+
+static u64 read_const_counter(void)
+{
+ u64 count;
+
+ __asm__ __volatile__(
+ " .set push\n"
+ " .set mips64r2\n"
+ " rdhwr %0, $30\n"
+ " .set pop\n"
+ : "=r" (count));
+
+ return count;
+}
+
+static u64 csrc_read_const_counter(struct clocksource *clk)
+{
+ return read_const_counter();
+}
+
+static struct clocksource clocksource_const = {
+ .name = "constant",
+ .rating = 8000,
+ .read = csrc_read_const_counter,
+ .mask = CLOCKSOURCE_MASK(64),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .vdso_clock_mode = VDSO_CLOCKMODE_CONST,
+ .mult = 0,
+ .shift = 10,
+};
+
+static int __init constant_clocksource_init(unsigned long freq)
+{
+
+ clocksource_const.mult =
+ clocksource_hz2mult(freq, clocksource_const.shift);
+
+ return clocksource_register_hz(&clocksource_const, freq);
+}
+
+static void __init constant_sched_clock_init(unsigned long freq)
+{
+ plat_have_sched_clock = true;
+ sched_clock_register(read_const_counter, 64, freq);
+}
+
+int __init constant_timer_init(void)
+{
+ u32 ver;
+ unsigned long freq;
+
+ if (!cpu_has_extimer)
+ return -ENODEV;
+
+ if (!cpu_has_csr())
+ return -ENODEV;
+
+ ver = read_cpucfg(LOONGSON_CFG2);
+ ver &= LOONGSON_CFG2_LLFTPREV;
+ ver >>= LOONGSON_CFG2_LLFTPREVB;
+
+ if (ver < 2)
+ return -ENODEV;
+
+ freq = calc_const_freq();
+ if (!freq)
+ return -ENODEV;
+
+ constant_clockevent_init();
+ constant_clocksource_init(freq);
+ constant_sched_clock_init(freq);
+
+ return 0;
+}
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index ef3f48def8be..0230d13481c8 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -136,6 +136,7 @@ enum cpuhp_state {
CPUHP_AP_ARMADA_TIMER_STARTING,
CPUHP_AP_MARCO_TIMER_STARTING,
CPUHP_AP_MIPS_GIC_TIMER_STARTING,
+ CPUHP_AP_MIPS_CONST_TIMER_STARTING,
CPUHP_AP_ARC_TIMER_STARTING,
CPUHP_AP_RISCV_TIMER_STARTING,
CPUHP_AP_CLINT_TIMER_STARTING,