[PATCH 3/3] lib: sbi_timer: Add support for timer events

Nicholas Piggin npiggin at gmail.com
Thu Apr 23 18:09:16 PDT 2026


On Thu, Apr 23, 2026 at 01:55:59PM +0530, Anup Patel wrote:
> On Thu, Apr 23, 2026 at 12:24 PM Nicholas Piggin <npiggin at gmail.com> wrote:
> >
> > On Wed, Apr 15, 2026 at 04:30:02PM +0530, Anup Patel wrote:

> > > +void sbi_timer_event_start(struct sbi_timer_event *ev, u64 next_event)
> > > +{
> > > +     struct sbi_timer_event *tev, *next_ev = NULL;
> > > +     struct timer_state *tstate;
> > > +
> > > +     if (!ev)
> > > +             return;
> > > +
> > > +     /* Ensure that event is not on the per-HART event list */
> > > +     if (ev->hart_index > -1) {
> >
> > It is a bit worrying to permit sbi_timer_event_start() if the timer is
> > already on a list. Is that necessary, or could you return an error in
> > this case?
> >
> > I'm thinking problems like this -
> >
> > HART0                         HART1
> > sbi_timer_event_start()       sbi_timer_process()
> >
> >   if (hart_index > -1) {
> >                                 __sbi_timer_event_stop(ev)
> >                                 if (ev->callback) {
> >                                   spin_unlock();
> >     spin_lock();
> >     __sbi_timer_event_stop(ev)
> >     spin_unlock();
> >                                   callback_fn()
> >                                     sbi_timer_event_start(); /* re-add periodic timer */
> 
> It is generally good to have ability to stop a running timer
> event from any CPU but I agree the problem you are highlighting.
> I think the real problem in this patch is the spin_unlock()/spin_lock()
> dance around the callback function called by sbi_timer_process().
> 
> To avoid the spin_unlock()/spin_lock() dance in sbi_timer_process(),
> I think it is better to call the callback function with lock held and callback
> function can optionally return next_time_stamp if it wants to re-add
> periodic timer. Suggestions ?

Yes, if the timer callbacks are fine with it, then the simpler the better.

Returning next_time_stamp if a reschedule is needed seems reasonable to
me. sbi_timer_event_start_from_callback() would be okay too.

> > > +             tstate = sbi_scratch_offset_ptr(sbi_hartindex_to_scratch(ev->hart_index),
> > > +                                             timer_state_off);
> > > +             spin_lock(&tstate->event_list_lock);
> > > +             __sbi_timer_event_stop(ev);
> > > +             spin_unlock(&tstate->event_list_lock);
> > > +     }
> > > +
> > > +     tstate = sbi_scratch_thishart_offset_ptr(timer_state_off);
> > > +     spin_lock(&tstate->event_list_lock);
> > > +
> > > +     /* Find where to insert the event in per-HART event list */
> > > +     sbi_list_for_each_entry(tev, &tstate->event_list, head) {
> > > +             if (next_event < tev->time_stamp) {
> > > +                     next_ev = tev;
> > > +                     break;
> > > +             }
> > > +     }
> > > +
> > > +     /* Insert the event in per-HART event list */
> > > +     ev->hart_index = current_hartindex();
> > > +     ev->time_stamp = next_event;
> > > +     if (next_ev)
> > > +             sbi_list_add(&ev->head, &next_ev->head);
> > > +     else
> > > +             sbi_list_add_tail(&ev->head, &tstate->event_list);
> > > +
> > > +     __sbi_timer_update_device(tstate);
> > > +
> > > +     spin_unlock(&tstate->event_list_lock);
> > > +}
> > > +
> > > +void sbi_timer_event_stop(struct sbi_timer_event *ev)
> > > +{
> > > +     struct timer_state *tstate;
> > > +
> > > +     if (!ev)
> > > +             return;
> > > +
> > > +     /* Ensure that event is not on the per-HART event list */
> > > +     if (ev->hart_index > -1) {
> > > +             tstate = sbi_scratch_offset_ptr(sbi_hartindex_to_scratch(ev->hart_index),
> > > +                                             timer_state_off);
> > > +             spin_lock(&tstate->event_list_lock);
> > > +             __sbi_timer_event_stop(ev);
> > > +             spin_unlock(&tstate->event_list_lock);
> >
> > Similar concern here, timer could be in the middle of running. Maybe it
> > is benign. I think it would be nice to make this a "sync" stop though,
> > so it can wait for potential running timers.
> >
> > timer event could have a 'running' state which is updated inside the
> > lock, then sbi_timer_event_stop() (and sbi_timer_exit()) could wait for
> > it to clear.
> 
> We might have to waste a lot of CPU cycles in the busy-loop.

That's true but I would expect it to not be common. Having the simpler
sync API as the first / default one would be good, add something more
complex if you find the need.

In any case, I think keeping the lock held over the callback should
make this a synchronous delete.

Thanks,
Nick



More information about the opensbi mailing list