From cf16fb19e8b4462fd639c032a6431fe0afd81aff Mon Sep 17 00:00:00 2001 From: hujun5 Date: Mon, 9 Sep 2024 12:33:44 +0800 Subject: [PATCH] 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 --- arch/arm/src/armv7-a/arm_timer.c | 73 +++++++++++++++++--------------- arch/arm/src/armv7-r/arm_timer.c | 73 +++++++++++++++++--------------- 2 files changed, 80 insertions(+), 66 deletions(-) diff --git a/arch/arm/src/armv7-a/arm_timer.c b/arch/arm/src/armv7-a/arm_timer.c index c15c2119e935e..454e8875363d1 100644 --- a/arch/arm/src/armv7-a/arm_timer.c +++ b/arch/arm/src/armv7-a/arm_timer.c @@ -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; diff --git a/arch/arm/src/armv7-r/arm_timer.c b/arch/arm/src/armv7-r/arm_timer.c index 06d89079d176c..81c305add2206 100644 --- a/arch/arm/src/armv7-r/arm_timer.c +++ b/arch/arm/src/armv7-r/arm_timer.c @@ -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;