armv7a/r: fix use arch-timer in SMP

reason:
Only one timer will be effective at a time.In the current
implementation of NuttX's timer handling, only a single global timer is necessary.
Having an excessive number of timers can lead to additional performance
overhead and logical errors, especially when operating in SMP
(Symmetric Multi-Processing) tickless mode.

Signed-off-by: hujun5 <hujun5@xiaomi.com>
This commit is contained in:
hujun5 2024-09-09 12:33:44 +08:00 committed by Xiang Xiao
parent 23a4a23397
commit f49d5f4451
2 changed files with 80 additions and 66 deletions

View file

@ -56,6 +56,11 @@ struct arm_timer_lowerhalf_s
uint32_t freq; /* Timer working clock frequency(Hz) */
oneshot_callback_t callback; /* Current user interrupt callback */
void *arg; /* Argument passed to upper half callback */
bool init[CONFIG_SMP_NCPUS]; /* True: timer is init */
/* which cpu timer is running, -1 indicate timer stoppd */
int running;
};
/****************************************************************************
@ -156,10 +161,7 @@ static inline uint64_t sec_to_count(uint32_t sec, uint32_t freq)
static int arm_timer_maxdelay(struct oneshot_lowerhalf_s *lower_,
struct timespec *ts)
{
struct arm_timer_lowerhalf_s *lower =
(struct arm_timer_lowerhalf_s *)lower_;
uint64_t maxnsec = nsec_from_count(UINT64_MAX, lower->freq);
uint64_t maxnsec = nsec_from_count(UINT64_MAX, arm_timer_get_freq());
ts->tv_sec = maxnsec / NSEC_PER_SEC;
ts->tv_nsec = maxnsec % NSEC_PER_SEC;
@ -182,8 +184,31 @@ static int arm_timer_start(struct oneshot_lowerhalf_s *lower_,
lower->callback = callback;
lower->arg = arg;
count = sec_to_count(ts->tv_sec, lower->freq) +
nsec_to_count(ts->tv_nsec, lower->freq);
if (!lower->init[this_cpu()])
{
if (lower->freq)
{
arm_timer_set_freq(lower->freq);
}
/* Enable timer */
ctrl = arm_timer_get_ctrl();
ctrl |= ARM_TIMER_CTRL_ENABLE | ARM_TIMER_CTRL_INT_MASK;
arm_timer_set_ctrl(ctrl);
#if defined(CONFIG_ARCH_TRUSTZONE_SECURE)
up_enable_irq(GIC_IRQ_STM);
#else
up_enable_irq(GIC_IRQ_PTM);
#endif
lower->init[this_cpu()] = true;
}
lower->running = this_cpu();
count = sec_to_count(ts->tv_sec, arm_timer_get_freq()) +
nsec_to_count(ts->tv_nsec, arm_timer_get_freq());
arm_timer_set_cval(arm_timer_get_count() + count);
ctrl = arm_timer_get_ctrl();
@ -205,8 +230,9 @@ static int arm_timer_cancel(struct oneshot_lowerhalf_s *lower_,
flags = up_irq_save();
lower->callback = NULL;
lower->arg = NULL;
lower->callback = NULL;
lower->arg = NULL;
lower->running = -1;
ctrl = arm_timer_get_ctrl();
ctrl |= ARM_TIMER_CTRL_INT_MASK;
@ -220,10 +246,8 @@ static int arm_timer_cancel(struct oneshot_lowerhalf_s *lower_,
static int arm_timer_current(struct oneshot_lowerhalf_s *lower_,
struct timespec *ts)
{
struct arm_timer_lowerhalf_s *lower =
(struct arm_timer_lowerhalf_s *)lower_;
uint64_t nsec = nsec_from_count(arm_timer_get_count(), lower->freq);
uint64_t nsec = nsec_from_count(arm_timer_get_count(),
arm_timer_get_freq());
ts->tv_sec = nsec / NSEC_PER_SEC;
ts->tv_nsec = nsec % NSEC_PER_SEC;
@ -241,7 +265,7 @@ static int arm_timer_interrupt(int irq, void *context, void *arg)
arm_timer_set_ctrl(arm_timer_get_ctrl() | ARM_TIMER_CTRL_INT_MASK);
if (lower->callback != NULL)
if (lower->callback != NULL && lower->running == this_cpu())
{
callback = lower->callback;
cbarg = lower->arg;
@ -269,7 +293,6 @@ uint32_t arm_timer_get_freq(void)
struct oneshot_lowerhalf_s *arm_timer_initialize(unsigned int freq)
{
struct arm_timer_lowerhalf_s *lower;
uint32_t ctrl;
lower = kmm_zalloc(sizeof(*lower));
if (lower == NULL)
@ -277,30 +300,14 @@ struct oneshot_lowerhalf_s *arm_timer_initialize(unsigned int freq)
return NULL;
}
if (freq == 0)
{
freq = arm_timer_get_freq();
}
else
{
arm_timer_set_freq(freq);
}
lower->lh.ops = &g_arm_timer_ops;
lower->freq = freq;
/* Enable timer, but disable interrupt */
ctrl = arm_timer_get_ctrl();
ctrl |= ARM_TIMER_CTRL_ENABLE | ARM_TIMER_CTRL_INT_MASK;
arm_timer_set_ctrl(ctrl);
lower->lh.ops = &g_arm_timer_ops;
lower->freq = freq;
lower->running = -1;
#if defined(CONFIG_ARCH_TRUSTZONE_SECURE)
irq_attach(GIC_IRQ_STM, arm_timer_interrupt, lower);
up_enable_irq(GIC_IRQ_STM);
#else
irq_attach(GIC_IRQ_PTM, arm_timer_interrupt, lower);
up_enable_irq(GIC_IRQ_PTM);
#endif
return (struct oneshot_lowerhalf_s *)lower;

View file

@ -54,6 +54,11 @@ struct arm_timer_lowerhalf_s
uint32_t freq; /* Timer working clock frequency(Hz) */
oneshot_callback_t callback; /* Current user interrupt callback */
void *arg; /* Argument passed to upper half callback */
bool init[CONFIG_SMP_NCPUS]; /* True: timer is init */
/* which cpu timer is running, -1 indicate timer stoppd */
int running;
};
/****************************************************************************
@ -154,10 +159,7 @@ static inline uint64_t sec_to_count(uint32_t sec, uint32_t freq)
static int arm_timer_maxdelay(struct oneshot_lowerhalf_s *lower_,
struct timespec *ts)
{
struct arm_timer_lowerhalf_s *lower =
(struct arm_timer_lowerhalf_s *)lower_;
uint64_t maxnsec = nsec_from_count(UINT64_MAX, lower->freq);
uint64_t maxnsec = nsec_from_count(UINT64_MAX, arm_timer_get_freq());
ts->tv_sec = maxnsec / NSEC_PER_SEC;
ts->tv_nsec = maxnsec % NSEC_PER_SEC;
@ -180,8 +182,31 @@ static int arm_timer_start(struct oneshot_lowerhalf_s *lower_,
lower->callback = callback;
lower->arg = arg;
count = sec_to_count(ts->tv_sec, lower->freq) +
nsec_to_count(ts->tv_nsec, lower->freq);
if (!lower->init[this_cpu()])
{
if (lower->freq)
{
arm_timer_set_freq(lower->freq);
}
/* Enable timer */
ctrl = arm_timer_get_ctrl();
ctrl |= ARM_TIMER_CTRL_ENABLE | ARM_TIMER_CTRL_INT_MASK;
arm_timer_set_ctrl(ctrl);
#if defined(CONFIG_ARCH_TRUSTZONE_SECURE)
up_enable_irq(GIC_IRQ_STM);
#else
up_enable_irq(GIC_IRQ_PTM);
#endif
lower->init[this_cpu()] = true;
}
lower->running = this_cpu();
count = sec_to_count(ts->tv_sec, arm_timer_get_freq()) +
nsec_to_count(ts->tv_nsec, arm_timer_get_freq());
arm_timer_set_cval(arm_timer_get_count() + count);
ctrl = arm_timer_get_ctrl();
@ -203,8 +228,9 @@ static int arm_timer_cancel(struct oneshot_lowerhalf_s *lower_,
flags = up_irq_save();
lower->callback = NULL;
lower->arg = NULL;
lower->callback = NULL;
lower->arg = NULL;
lower->running = -1;
ctrl = arm_timer_get_ctrl();
ctrl |= ARM_TIMER_CTRL_INT_MASK;
@ -218,10 +244,8 @@ static int arm_timer_cancel(struct oneshot_lowerhalf_s *lower_,
static int arm_timer_current(struct oneshot_lowerhalf_s *lower_,
struct timespec *ts)
{
struct arm_timer_lowerhalf_s *lower =
(struct arm_timer_lowerhalf_s *)lower_;
uint64_t nsec = nsec_from_count(arm_timer_get_count(), lower->freq);
uint64_t nsec = nsec_from_count(arm_timer_get_count(),
arm_timer_get_freq());
ts->tv_sec = nsec / NSEC_PER_SEC;
ts->tv_nsec = nsec % NSEC_PER_SEC;
@ -239,7 +263,7 @@ static int arm_timer_interrupt(int irq, void *context, void *arg)
arm_timer_set_ctrl(arm_timer_get_ctrl() | ARM_TIMER_CTRL_INT_MASK);
if (lower->callback != NULL)
if (lower->callback != NULL && lower->running == this_cpu())
{
callback = lower->callback;
cbarg = lower->arg;
@ -267,7 +291,6 @@ uint32_t arm_timer_get_freq(void)
struct oneshot_lowerhalf_s *arm_timer_initialize(unsigned int freq)
{
struct arm_timer_lowerhalf_s *lower;
uint32_t ctrl;
lower = kmm_zalloc(sizeof(*lower));
if (lower == NULL)
@ -275,30 +298,14 @@ struct oneshot_lowerhalf_s *arm_timer_initialize(unsigned int freq)
return NULL;
}
if (freq == 0)
{
freq = arm_timer_get_freq();
}
else
{
arm_timer_set_freq(freq);
}
lower->lh.ops = &g_arm_timer_ops;
lower->freq = freq;
/* Enable timer, but disable interrupt */
ctrl = arm_timer_get_ctrl();
ctrl |= ARM_TIMER_CTRL_ENABLE | ARM_TIMER_CTRL_INT_MASK;
arm_timer_set_ctrl(ctrl);
lower->lh.ops = &g_arm_timer_ops;
lower->freq = freq;
lower->running = -1;
#if defined(CONFIG_ARCH_TRUSTZONE_SECURE)
irq_attach(GIC_IRQ_STM, arm_timer_interrupt, lower);
up_enable_irq(GIC_IRQ_STM);
#else
irq_attach(GIC_IRQ_PTM, arm_timer_interrupt, lower);
up_enable_irq(GIC_IRQ_PTM);
#endif
return (struct oneshot_lowerhalf_s *)lower;