Skip to content
Permalink
Browse files

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>
  • Loading branch information...
vonhust authored and carlescufi committed Jul 10, 2019
1 parent 1f4232a commit 31a0371a0ab8eb0d941d59f3405b53243b49c71c
Showing with 90 additions and 4 deletions.
  1. +90 −4 drivers/timer/arcv2_timer0.c
@@ -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

0 comments on commit 31a0371

Please sign in to comment.
You can’t perform that action at this time.