From ac8ee8dcb7e4b5370e0c1be9f11e20c0f0a2014b Mon Sep 17 00:00:00 2001
From: Luis Gerhorst <privat@luisgerhorst.de>
Date: Wed, 30 Dec 2020 10:28:20 +0100
Subject: [PATCH] per-cpu arm_arch_timer lock and last_cycle

---
 drivers/timer/arm_arch_timer.c | 51 +++++++++++++++++++++-------------
 1 file changed, 32 insertions(+), 19 deletions(-)

diff --git a/drivers/timer/arm_arch_timer.c b/drivers/timer/arm_arch_timer.c
index 871c4e659f9..bdc8b6f4cb9 100644
--- a/drivers/timer/arm_arch_timer.c
+++ b/drivers/timer/arm_arch_timer.c
@@ -15,8 +15,11 @@
 #define MAX_TICKS	INT32_MAX
 #define MIN_DELAY	(1000)
 
-static struct k_spinlock lock;
-static volatile uint64_t last_cycle;
+struct arm_arch_timer {
+	struct k_spinlock lock;
+	volatile uint64_t last_cycle;
+};
+static struct arm_arch_timer timer[CONFIG_MP_NUM_CPUS];
 
 static void arm_arch_timer_compare_isr(const void *arg)
 {
@@ -24,15 +27,18 @@ static void arm_arch_timer_compare_isr(const void *arg)
 
 	printk("%s on cpu%d\n", __func__, arch_curr_cpu()->id);
 
-	k_spinlock_key_t key = k_spin_lock(&lock);
+	int cpu = arch_curr_cpu()->id;
+	struct arm_arch_timer *cpu_timer = &timer[cpu];
+
+	k_spinlock_key_t key = k_spin_lock(&cpu_timer->lock);
 
 	uint64_t curr_cycle = arm_arch_timer_count();
-	uint32_t delta_ticks = (uint32_t)((curr_cycle - last_cycle) / CYC_PER_TICK);
+	uint32_t delta_ticks = (uint32_t)((curr_cycle - cpu_timer->last_cycle) / CYC_PER_TICK);
 
-	last_cycle += delta_ticks * CYC_PER_TICK;
+	cpu_timer->last_cycle += delta_ticks * CYC_PER_TICK;
 
 	if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
-		uint64_t next_cycle = last_cycle + CYC_PER_TICK;
+		uint64_t next_cycle = cpu_timer->last_cycle + CYC_PER_TICK;
 
 		if ((uint64_t)(next_cycle - curr_cycle) < MIN_DELAY) {
 			next_cycle += CYC_PER_TICK;
@@ -40,7 +46,7 @@ static void arm_arch_timer_compare_isr(const void *arg)
 		arm_arch_timer_set_compare(next_cycle);
 	}
 
-	k_spin_unlock(&lock, key);
+	k_spin_unlock(&cpu_timer->lock, key);
 
 	z_clock_announce(IS_ENABLED(CONFIG_TICKLESS_KERNEL) ? delta_ticks : 1);
 }
@@ -71,21 +77,24 @@ void z_clock_set_timeout(int32_t ticks, bool idle)
 	ticks = (ticks == K_TICKS_FOREVER) ? MAX_TICKS : \
 		MIN(MAX_TICKS,  MAX(ticks - 1,  0));
 
-	k_spinlock_key_t key = k_spin_lock(&lock);
+	int cpu = arch_curr_cpu()->id;
+	struct arm_arch_timer *cpu_timer = &timer[cpu];
+
+	k_spinlock_key_t key = k_spin_lock(&cpu_timer->lock);
 	uint64_t curr_cycle = arm_arch_timer_count();
 	uint64_t req_cycle = ticks * CYC_PER_TICK;
 
 	/* Round up to next tick boundary */
-	req_cycle += (curr_cycle - last_cycle) + (CYC_PER_TICK - 1);
+	req_cycle += (curr_cycle - cpu_timer->last_cycle) + (CYC_PER_TICK - 1);
 
 	req_cycle = (req_cycle / CYC_PER_TICK) * CYC_PER_TICK;
 
-	if ((req_cycle + last_cycle - curr_cycle) < MIN_DELAY) {
+	if ((req_cycle + cpu_timer->last_cycle - curr_cycle) < MIN_DELAY) {
 		req_cycle += CYC_PER_TICK;
 	}
 
-	arm_arch_timer_set_compare(req_cycle + last_cycle);
-	k_spin_unlock(&lock, key);
+	arm_arch_timer_set_compare(req_cycle + cpu_timer->last_cycle);
+	k_spin_unlock(&cpu_timer->lock, key);
 
 #endif
 }
@@ -96,11 +105,15 @@ uint32_t z_clock_elapsed(void)
 		return 0;
 	}
 
-	k_spinlock_key_t key = k_spin_lock(&lock);
-	uint32_t ret = (uint32_t)((arm_arch_timer_count() - last_cycle)
+	/* TODO: irq_lock? */
+	int cpu = arch_curr_cpu()->id;
+	struct arm_arch_timer *cpu_timer = &timer[cpu];
+
+	k_spinlock_key_t key = k_spin_lock(&cpu_timer->lock);
+	uint32_t ret = (uint32_t)((arm_arch_timer_count() - cpu_timer->last_cycle)
 		    / CYC_PER_TICK);
 
-	k_spin_unlock(&lock, key);
+	k_spin_unlock(&cpu_timer->lock, key);
 	return ret;
 }
 
@@ -112,9 +125,9 @@ uint32_t z_timer_cycle_get_32(void)
 #if defined(CONFIG_SMP) && CONFIG_MP_NUM_CPUS > 1
 void smp_timer_init(void)
 {
-	printk("%s()\n", __func__);
-	/* arm_arch_timer_set_compare(arm_arch_timer_count() + CYC_PER_TICK); */
-	/* arm_arch_timer_enable(true); */
-	/* irq_enable(ARM_ARCH_TIMER_IRQ); */
+	printk("%s() on cpu%d\n", __func__, arch_curr_cpu()->id);
+	arm_arch_timer_set_compare(arm_arch_timer_count() + CYC_PER_TICK);
+	arm_arch_timer_enable(true);
+	irq_enable(ARM_ARCH_TIMER_IRQ);
 }
 #endif
-- 
GitLab