> Date: Sun, 23 Aug 2020 18:11:12 -0500
> From: Scott Cheloha <[email protected]>
>
> Hi,
>
> Other BSDs use the TSC to implement delay(9) if the TSC is constant
> and invariant. Here's a patch to add something similar to our kernel.
If the TSC is fine as a timecounter it should be absolutely fine for
use as delay(). And we could even use if the TSC isn't synchronized
between CPUs.
>
> This patch (or something equivalent) is a prerequisite to running the
> lapic timer in oneshot or TSC deadline mode. Using the lapic timer to
> implement delay(9) when it isn't running in periodic mode is too
> complicated. However, using the i8254 for delay(9) is too slow. We
> need an alternative.
Hmm, but what are we going to use on machines where the TSC isn't
constant/invariant?
In what respect is the i8254 too slow? Does it take more than a
microsecond to read it?
We could use the HPET I suppose, whic may be a bit better.
> As for the patch, it works for me here, though I'd appreciate a few
> tests. I admit that comparing function pointers is ugly, but I think
> this is as simple as it can be without implementing some sort of
> framework for "registering" delay(9) implementations and comparing
> them and selecting the "best" implementation.
What about:
if (delay_func == NULL)
delay_func = lapic_delay;
> I'm not sure I put the prototypes in the right headers. We don't have
> a tsc.h but cpuvar.h looks sorta-correct for tsc_delay().
I think cpuvar.h is fine since it has other TSC-related stuff.
However, with my suggestion above you can drop that.
> FreeBSD's x86/delay.c may be of note:
>
> https://github.com/freebsd/freebsd/blob/ed96335a07b688c39e16db8856232e5840bc22ac/sys/x86/x86/delay.c
>
> Thoughts?
>
> Index: amd64/tsc.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/amd64/amd64/tsc.c,v
> retrieving revision 1.20
> diff -u -p -r1.20 tsc.c
> --- amd64/tsc.c 23 Aug 2020 21:38:47 -0000 1.20
> +++ amd64/tsc.c 23 Aug 2020 22:59:25 -0000
> @@ -26,6 +26,7 @@
>
> #include <machine/cpu.h>
> #include <machine/cpufunc.h>
> +#include <machine/cpuvar.h>
>
> #define RECALIBRATE_MAX_RETRIES 5
> #define RECALIBRATE_SMI_THRESHOLD 50000
> @@ -252,7 +253,8 @@ tsc_timecounter_init(struct cpu_info *ci
> tsc_timecounter.tc_quality = -1000;
> tsc_timecounter.tc_user = 0;
> tsc_is_invariant = 0;
> - }
> + } else
> + delay_func = tsc_delay;
>
> tc_init(&tsc_timecounter);
> }
> @@ -342,4 +344,15 @@ tsc_sync_ap(struct cpu_info *ci)
> {
> tsc_post_ap(ci);
> tsc_post_ap(ci);
> +}
> +
> +void
> +tsc_delay(int usecs)
> +{
> + uint64_t interval, start;
> +
> + interval = (uint64_t)usecs * tsc_frequency / 1000000;
> + start = rdtsc_lfence();
> + while (rdtsc_lfence() - start < interval)
> + CPU_BUSY_CYCLE();
> }
> Index: amd64/lapic.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/amd64/amd64/lapic.c,v
> retrieving revision 1.55
> diff -u -p -r1.55 lapic.c
> --- amd64/lapic.c 3 Aug 2019 14:57:51 -0000 1.55
> +++ amd64/lapic.c 23 Aug 2020 22:59:25 -0000
> @@ -41,6 +41,7 @@
> #include <machine/codepatch.h>
> #include <machine/cpu.h>
> #include <machine/cpufunc.h>
> +#include <machine/cpuvar.h>
> #include <machine/pmap.h>
> #include <machine/mpbiosvar.h>
> #include <machine/specialreg.h>
> @@ -569,7 +570,8 @@ skip_calibration:
> * Now that the timer's calibrated, use the apic timer routines
> * for all our timing needs..
> */
> - delay_func = lapic_delay;
> + if (delay_func != tsc_delay)
> + delay_func = lapic_delay;
> initclock_func = lapic_initclocks;
> }
> }
> Index: include/cpuvar.h
> ===================================================================
> RCS file: /cvs/src/sys/arch/amd64/include/cpuvar.h,v
> retrieving revision 1.10
> diff -u -p -r1.10 cpuvar.h
> --- include/cpuvar.h 9 Aug 2019 15:20:05 -0000 1.10
> +++ include/cpuvar.h 23 Aug 2020 22:59:25 -0000
> @@ -102,4 +102,6 @@ void tsc_sync_drift(int64_t);
> void tsc_sync_bp(struct cpu_info *);
> void tsc_sync_ap(struct cpu_info *);
>
> +void tsc_delay(int);
> +
> #endif
> Index: include/i82489var.h
> ===================================================================
> RCS file: /cvs/src/sys/arch/amd64/include/i82489var.h,v
> retrieving revision 1.18
> diff -u -p -r1.18 i82489var.h
> --- include/i82489var.h 4 Oct 2018 05:00:40 -0000 1.18
> +++ include/i82489var.h 23 Aug 2020 22:59:26 -0000
> @@ -128,4 +128,6 @@ extern void lapic_calibrate_timer(struct
> extern void lapic_startclock(void);
> extern void lapic_initclocks(void);
>
> +extern void lapic_delay(int);
> +
> #endif
>
>