Re: riscv64: use sstc for clocks when available

Mark Kettenis <[email protected]> Mon, 27 Jul 2026 10:30:32 +0200
Newsgroups gmane.os.openbsd.tech
Message-ID <[email protected]>
> Date: Sun, 26 Jul 2026 19:33:58 +0200
> From: Jeremie Courreges-Anglas <[email protected]>
> 
> On Mon, Jul 13, 2026 at 09:18:20AM -0700, Nick Owens wrote:
> > hi,
> 
> Hi, sorry for the delay ;)
> 
> > this implements support for sstc extension. with sstc, we can write the
> > stimecmp csr directly instead of needing an sbi ecall to set the timer
> > comparison register.
> > 
> > both the k1 and k3 support it, and since it's a direct register write it
> > takes only ~10ns instead of several hundred ns for the ecall and
> > possible hypervisor emulation in the case of linux kvm.
> > 
> > i've tested on orangepi rv2 (k1) directly, and on the k3 under linux
> > kvm. fallback path tested on kvm by disabling sstc in the advertised
> > features of qemu kvm as well. without sstc, the k1 takes about 250ns and
> > the k3 + kvm takes about 600ns. with this change, both are around 10ns
> > per timer write.
> >
> > this also conveniently works around a bug in upstream kvm where timer
> > writes via sbi ecall can get lost if there's a context switch at the
> > wrong time, which makes kvm guest timers permanently stop firing. see
> > https://lore.kernel.org/all/[email protected]/
> 
> Getting rid of this overhead appears desirable, working around a bug
> in a hypervisor is just a bonus...
> 
> No visible regression on my k1 which exposes Sstc.  Please find a
> tweaked diff below: I'd rather have the check for the feature in a
> single place.  The "timer_set_timer" name is admittedly a bit
> redundant, suggestions welcome.

Maybe just timer_set()?

> 
> I'll commit this in a few days unless I hear objections.  Tests & oks
> welcome.

ok kettenis@

> Index: clock.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/riscv64/riscv64/clock.c,v
> diff -u -p -r1.14 clock.c
> --- clock.c	27 Jan 2024 12:05:40 -0000	1.14
> +++ clock.c	24 Jul 2026 14:54:28 -0000
> @@ -25,6 +25,7 @@
>  #include <sys/stdint.h>
>  #include <sys/timetc.h>
>  
> +#include <machine/elf.h>
>  #include <machine/cpufunc.h>
>  #include <machine/sbi.h>
>  
> @@ -60,6 +61,15 @@ static struct timecounter tb_timecounter
>  void	(*cpu_startclock_fcn)(void) = timer_startclock;
>  int	clock_intr(void *);
>  
> +static inline void
> +timer_set_timer(uint64_t nsecs)
> +{
> +	if (riscv_hwcap & HWCAP_ISA_SSTC)
> +		csr_write(stimecmp, nsecs);
> +	else
> +		sbi_set_timer(nsecs);
> +}
> +
>  void
>  timer_rearm(void *unused, uint64_t nsecs)
>  {
> @@ -68,13 +78,13 @@ timer_rearm(void *unused, uint64_t nsecs
>  	if (nsecs > timer_nsec_max)
>  		nsecs = timer_nsec_max;
>  	cycles = (nsecs * timer_nsec_cycle_ratio) >> 32;
> -	sbi_set_timer(rdtime() + cycles);
> +	timer_set_timer(rdtime() + cycles);
>  }
>  
>  void
>  timer_trigger(void *unused)
>  {
> -	sbi_set_timer(0);
> +	timer_set_timer(0);
>  }
>  
>  u_int
> @@ -125,7 +135,7 @@ clock_intr(void *frame)
>  	struct cpu_info *ci = curcpu();
>  	int s;
>  
> -	sbi_set_timer(UINT64_MAX);	/* clear timer interrupt */
> +	timer_set_timer(UINT64_MAX); /* clear timer interrupt */
>  
>  	/*
>  	 * If the clock interrupt is masked, defer all clock interrupt
> 
> 
> -- 
> jca
> 
>