drivers: arcv2_timer0: add support for smp

* use global free running counter as global wall clock (clock source)
* use arc internal timer 0 as local time event (clock event)

Signed-off-by: Wayne Ren <wei.ren@synopsys.com>
This commit is contained in:
Wayne Ren 2019-07-10 16:51:27 +08:00 committed by Carles Cufí
parent 1f4232ad7e
commit 31a0371a0a

View file

@ -35,10 +35,16 @@
static struct k_spinlock lock;
#ifdef CONFIG_SMP
volatile static u64_t last_time;
volatile static u64_t start_time;
#else
static u32_t last_load;
static u32_t cycle_count;
#endif
/**
*
@ -106,6 +112,7 @@ static ALWAYS_INLINE void timer0_limit_register_set(u32_t count)
z_arc_v2_aux_reg_write(_ARC_V2_TMR0_LIMIT, count);
}
#ifndef CONFIG_SMP
static u32_t elapsed(void)
{
u32_t val, ov, ctrl;
@ -118,6 +125,7 @@ static u32_t elapsed(void)
ov = (ctrl & _ARC_V2_TMR_CTRL_IP) ? last_load : 0;
return val + ov;
}
#endif
/**
*
@ -137,10 +145,25 @@ static void timer_int_handler(void *unused)
/* clear the interrupt by writing 0 to IP bit of the control register */
timer0_control_register_set(_ARC_V2_TMR_CTRL_NH | _ARC_V2_TMR_CTRL_IE);
#ifdef CONFIG_SMP
u64_t curr_time;
k_spinlock_key_t key;
key = k_spin_lock(&lock);
/* gfrc is the wall clock */
curr_time = z_arc_connect_gfrc_read();
dticks = (curr_time - last_time) / CYC_PER_TICK;
last_time = curr_time;
k_spin_unlock(&lock, key);
z_clock_announce(dticks);
#else
cycle_count += last_load;
dticks = last_load / CYC_PER_TICK;
z_clock_announce(TICKLESS ? dticks : 1);
#endif
}
@ -161,6 +184,14 @@ int z_clock_driver_init(struct device *device)
/* ensure that the timer will not generate interrupts */
timer0_control_register_set(0);
#ifdef CONFIG_SMP
IRQ_CONNECT(IRQ_TIMER0, CONFIG_ARCV2_TIMER_IRQ_PRIORITY,
timer_int_handler, NULL, 0);
timer0_limit_register_set(CYC_PER_TICK - 1);
last_time = z_arc_connect_gfrc_read();
start_time = last_time;
#else
last_load = CYC_PER_TICK;
IRQ_CONNECT(IRQ_TIMER0, CONFIG_ARCV2_TIMER_IRQ_PRIORITY,
@ -169,6 +200,7 @@ int z_clock_driver_init(struct device *device)
timer0_limit_register_set(last_load - 1);
#ifdef CONFIG_BOOT_TIME_MEASUREMENT
cycle_count = timer0_count_register_get();
#endif
#endif
timer0_count_register_set(0);
timer0_control_register_set(_ARC_V2_TMR_CTRL_NH | _ARC_V2_TMR_CTRL_IE);
@ -186,6 +218,33 @@ void z_clock_set_timeout(s32_t ticks, bool idle)
* then shut off the counter. (Note: we can assume if idle==true
* that interrupts are already disabled)
*/
#ifdef CONFIG_SMP
if (IS_ENABLED(CONFIG_TICKLESS_IDLE) && idle && ticks == K_FOREVER) {
timer0_control_register_set(0);
timer0_count_register_set(0);
timer0_limit_register_set(0);
return;
}
#if defined(CONFIG_TICKLESS_KERNEL)
u32_t delay;
u32_t key;
ticks = MIN(MAX_TICKS, MAX(ticks - 1, 0));
/* Desired delay in the future */
delay = (ticks == 0) ? CYC_PER_TICK : ticks * CYC_PER_TICK;
key = z_arch_irq_lock();
timer0_limit_register_set(delay - 1);
timer0_count_register_set(0);
timer0_control_register_set(_ARC_V2_TMR_CTRL_NH |
_ARC_V2_TMR_CTRL_IE);
z_arch_irq_unlock(key);
#endif
#else
if (IS_ENABLED(CONFIG_TICKLESS_IDLE) && idle && ticks == K_FOREVER) {
timer0_control_register_set(0);
timer0_count_register_set(0);
@ -221,6 +280,7 @@ void z_clock_set_timeout(s32_t ticks, bool idle)
k_spin_unlock(&lock, key);
#endif
#endif
}
u32_t z_clock_elapsed(void)
@ -229,20 +289,31 @@ u32_t z_clock_elapsed(void)
return 0;
}
u32_t cyc;
k_spinlock_key_t key = k_spin_lock(&lock);
u32_t cyc = elapsed();
#ifdef CONFIG_SMP
cyc = (z_arc_connect_gfrc_read() - last_time) / CYC_PER_TICK;
#else
cyc = elapsed() / CYC_PER_TICK;
#endif
k_spin_unlock(&lock, key);
return cyc / CYC_PER_TICK;
return cyc;
}
u32_t z_timer_cycle_get_32(void)
{
#ifdef CONFIG_SMP
return z_arc_connect_gfrc_read() - start_time;
#else
k_spinlock_key_t key = k_spin_lock(&lock);
u32_t ret = elapsed() + cycle_count;
k_spin_unlock(&lock, key);
return ret;
#endif
}
/**
@ -272,3 +343,18 @@ void sys_clock_disable(void)
irq_disable(IRQ_TIMER0);
}
#ifdef CONFIG_SMP
void smp_timer_init(void)
{
/* set the initial status of timer0 of each slave core
*/
timer0_control_register_set(0);
timer0_count_register_set(0);
timer0_limit_register_set(0);
z_irq_priority_set(IRQ_TIMER0, CONFIG_ARCV2_TIMER_IRQ_PRIORITY, 0);
irq_enable(IRQ_TIMER0);
}
#endif