Skip to content

Commit

Permalink
armv7a/r: fix use arch-timer in SMP
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
hujun260 committed Sep 27, 2024
1 parent 4195851 commit cf16fb1
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 66 deletions.
73 changes: 40 additions & 33 deletions arch/arm/src/armv7-a/arm_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

/****************************************************************************
Expand Down Expand Up @@ -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;
Expand All @@ -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();
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -269,38 +293,21 @@ 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)
{
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;
Expand Down
73 changes: 40 additions & 33 deletions arch/arm/src/armv7-r/arm_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

/****************************************************************************
Expand Down Expand Up @@ -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;
Expand All @@ -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();
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -267,38 +291,21 @@ 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)
{
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;
Expand Down

0 comments on commit cf16fb1

Please sign in to comment.