[RFC PATCH 2/3] clocksource/drivers/arm_arch_timer: Extend and export arch_timer_mem_register()

Yicong Yang yangyicong at huawei.com
Tue Oct 10 05:30:32 PDT 2023


From: Yicong Yang <yangyicong at hisilicon.com>

Currently the memory-mapped timer will be probed by the GTDT table on
ACPI based systems, and the timer interrupt can only be the GSI (SPI
interrupt for arm64) per ACPI spec. However the generic timer
specification doesn't restrict the interrupt type and per BSA Spec
section 3.8.1 (DEN0094C 1.0C) the timer interrupt can also be a LPI
interrupt.

So this patch extends and exports the arch_timer_mem_register() function
to allow other drivers registers a generic timer using LPI interrupt
and probed by other means rather than GTDT. Note that the GTDT timer
still has a higher priority, if a GTDT timer is registered, we'll block
later registration of other timers.

Signed-off-by: Yicong Yang <yangyicong at hisilicon.com>
---
 drivers/clocksource/arm_arch_timer.c | 26 +++++++++++++++++---------
 include/clocksource/arm_arch_timer.h |  2 ++
 2 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 2e20a8ec50ca..6e9445192ca4 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -66,7 +66,7 @@ struct arch_timer {
 	struct clock_event_device evt;
 };
 
-static struct arch_timer *arch_timer_mem __ro_after_init;
+static struct arch_timer *arch_timer_mem;
 
 #define to_arch_timer(e) container_of(e, struct arch_timer, evt)
 
@@ -888,15 +888,16 @@ static void __arch_timer_setup_cp15(struct clock_event_device *clk)
 	clockevents_config_and_register(clk, arch_timer_rate, 0xf, max_delta);
 }
 
-static void __arch_timer_setup_mem(struct clock_event_device *clk)
+static void __arch_timer_setup_mem(struct clock_event_device *clk,
+				   bool irq_virtual, const char *name)
 {
 	u64 max_delta;
 
 	clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ;
-	clk->name = "arch_mem_timer";
+	clk->name = name;
 	clk->rating = 400;
 	clk->cpumask = cpu_possible_mask;
-	if (arch_timer_mem_use_virtual) {
+	if (irq_virtual) {
 		clk->set_state_shutdown = arch_timer_shutdown_virt_mem;
 		clk->set_state_oneshot_stopped = arch_timer_shutdown_virt_mem;
 		clk->set_next_event =
@@ -1286,25 +1287,30 @@ static int __init arch_timer_register(void)
 	return err;
 }
 
-static int __init arch_timer_mem_register(void __iomem *base, unsigned int irq)
+int arch_timer_mem_register(void __iomem *base, unsigned int irq,
+			    bool irq_virtual, const char *name)
 {
 	int ret;
 	irq_handler_t func;
 
+	/* If we've already register a memory timer, fail the registration */
+	if (arch_timer_mem)
+		return -EEXIST;
+
 	arch_timer_mem = kzalloc(sizeof(*arch_timer_mem), GFP_KERNEL);
 	if (!arch_timer_mem)
 		return -ENOMEM;
 
 	arch_timer_mem->base = base;
 	arch_timer_mem->evt.irq = irq;
-	__arch_timer_setup_mem(&arch_timer_mem->evt);
+	__arch_timer_setup_mem(&arch_timer_mem->evt, irq_virtual, name);
 
-	if (arch_timer_mem_use_virtual)
+	if (irq_virtual)
 		func = arch_timer_handler_virt_mem;
 	else
 		func = arch_timer_handler_phys_mem;
 
-	ret = request_irq(irq, func, IRQF_TIMER, "arch_mem_timer", &arch_timer_mem->evt);
+	ret = request_irq(irq, func, IRQF_TIMER, name, &arch_timer_mem->evt);
 	if (ret) {
 		pr_err("Failed to request mem timer irq\n");
 		kfree(arch_timer_mem);
@@ -1313,6 +1319,7 @@ static int __init arch_timer_mem_register(void __iomem *base, unsigned int irq)
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(arch_timer_mem_register);
 
 static const struct of_device_id arch_timer_of_match[] __initconst = {
 	{ .compatible   = "arm,armv7-timer",    },
@@ -1560,7 +1567,8 @@ arch_timer_mem_frame_register(struct arch_timer_mem_frame *frame)
 		return -ENXIO;
 	}
 
-	ret = arch_timer_mem_register(base, irq);
+	ret = arch_timer_mem_register(base, irq, arch_timer_mem_use_virtual,
+				      "arch_mem_timer");
 	if (ret) {
 		iounmap(base);
 		return ret;
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h
index cbbc9a6dc571..d0fa2065586c 100644
--- a/include/clocksource/arm_arch_timer.h
+++ b/include/clocksource/arm_arch_timer.h
@@ -89,6 +89,8 @@ extern u32 arch_timer_get_rate(void);
 extern u64 (*arch_timer_read_counter)(void);
 extern struct arch_timer_kvm_info *arch_timer_get_kvm_info(void);
 extern bool arch_timer_evtstrm_available(void);
+extern int arch_timer_mem_register(void __iomem *base, unsigned int irq,
+				   bool irq_virtual, const char *name);
 
 #else
 
-- 
2.24.0




More information about the linux-arm-kernel mailing list