On Wed, Aug 24, 2022 at 05:51:14PM +1000, Jonathan Gray wrote:
> On Tue, Aug 23, 2022 at 12:20:39PM -0500, Scott Cheloha wrote:
> > > Hyper-V generation 1 VMs are bios boot with emulation of the usual
> > > devices. 32-bit and 64-bit guests.
> > >
> > > Hyper-V generation 2 VMs are 64-bit uefi with paravirtualised devices.
> > > 64-bit guests only.
> > >
> > > There is no 8254 in generation 2.
> > > No HPET in either generation.
> > >
> > > hv_delay uses the "Partition Reference Counter MSR" described in
> > > https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/timers
> > > It seems it is available in both generations and could be used from i386?
> > >
> > > From reading that page hv_delay() should be preferred over lapic_delay()
> >
> > Alright, I have nudged hv_delay's quality up over lapic_delay's
> > quality.
>
> Before these changes, tsc is probed before pvbus. Do the tsc sanity
> checks result in it not being considered an option on hyper-v? I think
> the tsc_delay and hv_delay numbers should be swapped in a later commit.
> It is unclear if that would change the final delay_func setting.
Why would we prefer hv_delay() to tsc_delay() if we had a
constant/invariant TSC available in our Hyper-V guest?
When patrick@ emailed me last year about issues with delay(9) on
Hyper-V, he started by saying that the root of the problem was that
the OpenBSD guest was not opting to use tsc_delay() because the host
wasn't reporting a constant/invariant TSC. So the guest was trying to
use i8254_delay(), which was impossible because Hyper-V Gen2 guests
don't have an i8254. Hence, hv_delay() was added to the tree.
So, my understanding is that the addition of hv_delay() does not mean
tsc_delay() is worse than hv_delay(). hv_delay() was added because
tsc_delay() isn't always an option and (to our surprise) neither is
i8254_delay().
> It would be a good idea to have different commits for the places new
> delay callbacks are introduced.
>
> - add delay_init()
> - use delay_init() in lapic, tsc, hv_delay
> - commit acpihpet
> - commit acpitimer
I had planned to do separate commits. This ordering seems right.
> - swap tsc and hv_delay numbers
See above.
> > How are we looking now?
>
> some minor suggestions inline
>
> have you built a release with this?
Just finished building a release and upgrading with it from physical
media. I think we are good to go. I incorporated your suggestions
below and I'm going to do the first four suggested commits tomorrow
unless I hear otherwise.
Current combined patch is attached.
> > Index: sys/arch/amd64/amd64/lapic.c
> > ===================================================================
> > RCS file: /cvs/src/sys/arch/amd64/amd64/lapic.c,v
> > retrieving revision 1.60
> > diff -u -p -r1.60 lapic.c
> > --- sys/arch/amd64/amd64/lapic.c 15 Aug 2022 04:17:50 -0000 1.60
> > +++ sys/arch/amd64/amd64/lapic.c 23 Aug 2022 17:18:30 -0000
> > @@ -486,8 +486,6 @@ wait_next_cycle(void)
> > }
> > }
> >
> > -extern void tsc_delay(int);
> > -
>
> this cleanup is unrelated and should be a different diff/commit
Ack, will do it separately.
> > /*
> > * Calibrate the local apic count-down timer (which is running at
> > * bus-clock speed) vs. the i8254 counter/timer (which is running at
> > @@ -592,8 +590,7 @@ skip_calibration:
> > * Now that the timer's calibrated, use the apic timer routines
> > * for all our timing needs..
> > */
> > - if (delay_func == i8254_delay)
> > - delay_func = lapic_delay;
> > + delay_init(lapic_delay, 3000);
> > initclock_func = lapic_initclocks;
> > }
> > }
> > Index: sys/arch/amd64/amd64/machdep.c
> > ===================================================================
> > RCS file: /cvs/src/sys/arch/amd64/amd64/machdep.c,v
> > retrieving revision 1.279
> > diff -u -p -r1.279 machdep.c
> > --- sys/arch/amd64/amd64/machdep.c 7 Aug 2022 23:56:06 -0000 1.279
> > +++ sys/arch/amd64/amd64/machdep.c 23 Aug 2022 17:18:31 -0000
> > @@ -2069,3 +2069,13 @@ check_context(const struct reg *regs, st
> >
> > return 0;
> > }
> > +
> > +void
> > +delay_init(void(*fn)(int), int fn_quality)
> > +{
> > + static int cur_quality = 0;
> > + if (fn_quality > cur_quality) {
> > + delay_func = fn;
> > + cur_quality = fn_quality;
> > + }
> > +}
> > Index: sys/arch/amd64/amd64/tsc.c
> > ===================================================================
> > RCS file: /cvs/src/sys/arch/amd64/amd64/tsc.c,v
> > retrieving revision 1.25
> > diff -u -p -r1.25 tsc.c
> > --- sys/arch/amd64/amd64/tsc.c 12 Aug 2022 02:20:36 -0000 1.25
> > +++ sys/arch/amd64/amd64/tsc.c 23 Aug 2022 17:18:31 -0000
> > @@ -109,7 +109,7 @@ tsc_identify(struct cpu_info *ci)
> >
> > tsc_frequency = tsc_freq_cpuid(ci);
> > if (tsc_frequency > 0)
> > - delay_func = tsc_delay;
> > + delay_init(tsc_delay, 5000);
> > }
> >
> > static inline int
> > Index: sys/arch/amd64/include/cpu.h
> > ===================================================================
> > RCS file: /cvs/src/sys/arch/amd64/include/cpu.h,v
> > retrieving revision 1.148
> > diff -u -p -r1.148 cpu.h
> > --- sys/arch/amd64/include/cpu.h 22 Aug 2022 08:57:54 -0000 1.148
> > +++ sys/arch/amd64/include/cpu.h 23 Aug 2022 17:18:31 -0000
> > @@ -359,6 +359,7 @@ void signotify(struct proc *);
> > * We need a machine-independent name for this.
> > */
> > extern void (*delay_func)(int);
> > +void delay_init(void (*)(int), int);
> > struct timeval;
> >
> > #define DELAY(x) (*delay_func)(x)
> > Index: sys/arch/i386/i386/lapic.c
> > ===================================================================
> > RCS file: /cvs/src/sys/arch/i386/i386/lapic.c,v
> > retrieving revision 1.49
> > diff -u -p -r1.49 lapic.c
> > --- sys/arch/i386/i386/lapic.c 15 Aug 2022 04:17:50 -0000 1.49
> > +++ sys/arch/i386/i386/lapic.c 23 Aug 2022 17:18:31 -0000
> > @@ -395,7 +395,7 @@ lapic_calibrate_timer(struct cpu_info *c
> > * Now that the timer's calibrated, use the apic timer routines
> > * for all our timing needs..
> > */
> > - delay_func = lapic_delay;
> > + delay_init(lapic_delay, 3000);
> > initclock_func = lapic_initclocks;
> > }
> > }
> > Index: sys/arch/i386/i386/machdep.c
> > ===================================================================
> > RCS file: /cvs/src/sys/arch/i386/i386/machdep.c,v
> > retrieving revision 1.655
> > diff -u -p -r1.655 machdep.c
> > --- sys/arch/i386/i386/machdep.c 22 Aug 2022 08:53:55 -0000 1.655
> > +++ sys/arch/i386/i386/machdep.c 23 Aug 2022 17:18:33 -0000
> > @@ -3974,3 +3974,13 @@ cpu_rnd_messybits(void)
> > nanotime(&ts);
> > return (ts.tv_nsec ^ (ts.tv_sec << 20));
> > }
> > +
> > +void
> > +delay_init(void(*fn)(int), int fn_quality)
> > +{
> > + static int cur_quality = 0;
> > + if (fn_quality > cur_quality) {
> > + delay_func = fn;
> > + cur_quality = fn_quality;
> > + }
> > +}
> > Index: sys/arch/i386/include/cpu.h
> > ===================================================================
> > RCS file: /cvs/src/sys/arch/i386/include/cpu.h,v
> > retrieving revision 1.177
> > diff -u -p -r1.177 cpu.h
> > --- sys/arch/i386/include/cpu.h 22 Aug 2022 08:53:55 -0000 1.177
> > +++ sys/arch/i386/include/cpu.h 23 Aug 2022 17:18:33 -0000
> > @@ -302,6 +302,7 @@ void signotify(struct proc *);
> > * We need a machine-independent name for this.
> > */
> > extern void (*delay_func)(int);
> > +void delay_init(void(*)(int), int);
> > struct timeval;
> >
> > #define DELAY(x) (*delay_func)(x)
> > Index: sys/dev/acpi/acpitimer.c
> > ===================================================================
> > RCS file: /cvs/src/sys/dev/acpi/acpitimer.c,v
> > retrieving revision 1.15
> > diff -u -p -r1.15 acpitimer.c
> > --- sys/dev/acpi/acpitimer.c 6 Apr 2022 18:59:27 -0000 1.15
> > +++ sys/dev/acpi/acpitimer.c 23 Aug 2022 17:18:33 -0000
> > @@ -18,17 +18,22 @@
> > #include <sys/param.h>
> > #include <sys/systm.h>
> > #include <sys/device.h>
> > +#include <sys/stdint.h>
> > #include <sys/timetc.h>
> >
> > #include <machine/bus.h>
> > +#include <machine/cpu.h>
> >
> > #include <dev/acpi/acpireg.h>
> > #include <dev/acpi/acpivar.h>
> >
> > +struct acpitimer_softc;
>
> move acpitimer_softc here instead
Done.
> > +
> > int acpitimermatch(struct device *, void *, void *);
> > void acpitimerattach(struct device *, struct device *, void *);
> > -
> > +void acpitimer_delay(int);
> > u_int acpi_get_timecount(struct timecounter *tc);
> > +uint32_t acpitimer_read(struct acpitimer_softc *);
> >
> > static struct timecounter acpi_timecounter = {
> > .tc_get_timecount = acpi_get_timecount,
> > @@ -98,18 +103,43 @@ acpitimerattach(struct device *parent, s
> > acpi_timecounter.tc_priv = sc;
> > acpi_timecounter.tc_name = sc->sc_dev.dv_xname;
> > tc_init(&acpi_timecounter);
> > +
> > + delay_init(acpitimer_delay, 1000);
> > +
> > #if defined(__amd64__)
> > extern void cpu_recalibrate_tsc(struct timecounter *);
> > cpu_recalibrate_tsc(&acpi_timecounter);
> > #endif
> > }
> >
> > +void
> > +acpitimer_delay(int usecs)
> > +{
> > + uint64_t count = 0, cycles;
> > + struct acpitimer_softc *sc = acpi_timecounter.tc_priv;
> > + uint32_t mask = acpi_timecounter.tc_counter_mask;
> > + uint32_t val1, val2;
> > +
> > + val2 = acpitimer_read(sc);
> > + cycles = usecs * acpi_timecounter.tc_frequency / 1000000;
> > + while (count < cycles) {
> > + CPU_BUSY_CYCLE();
> > + val1 = val2;
> > + val2 = acpitimer_read(sc);
> > + count += (val2 - val1) & mask;
> > + }
> > +}
> >
> > u_int
> > acpi_get_timecount(struct timecounter *tc)
> > {
> > - struct acpitimer_softc *sc = tc->tc_priv;
> > - u_int u1, u2, u3;
> > + return acpitimer_read(tc->tc_priv);
> > +}
> > +
> > +uint32_t
> > +acpitimer_read(struct acpitimer_softc *sc)
> > +{
> > + uint32_t u1, u2, u3;
> >
> > u2 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 0);
> > u3 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 0);
> > Index: sys/dev/acpi/acpihpet.c
> > ===================================================================
> > RCS file: /cvs/src/sys/dev/acpi/acpihpet.c,v
> > retrieving revision 1.26
> > diff -u -p -r1.26 acpihpet.c
> > --- sys/dev/acpi/acpihpet.c 6 Apr 2022 18:59:27 -0000 1.26
> > +++ sys/dev/acpi/acpihpet.c 23 Aug 2022 17:18:33 -0000
> > @@ -18,9 +18,11 @@
> > #include <sys/param.h>
> > #include <sys/systm.h>
> > #include <sys/device.h>
> > +#include <sys/stdint.h>
> > #include <sys/timetc.h>
> >
> > #include <machine/bus.h>
> > +#include <machine/cpu.h>
> >
> > #include <dev/acpi/acpireg.h>
> > #include <dev/acpi/acpivar.h>
> > @@ -31,7 +33,7 @@ int acpihpet_attached;
> > int acpihpet_match(struct device *, void *, void *);
> > void acpihpet_attach(struct device *, struct device *, void *);
> > int acpihpet_activate(struct device *, int);
> > -
> > +void acpihpet_delay(int);
> > u_int acpihpet_gettime(struct timecounter *tc);
> >
> > uint64_t acpihpet_r(bus_space_tag_t _iot, bus_space_handle_t _ioh,
> > @@ -262,15 +264,30 @@ acpihpet_attach(struct device *parent, s
> > freq = 1000000000000000ull / period;
> > printf(": %lld Hz\n", freq);
> >
> > - hpet_timecounter.tc_frequency = (uint32_t)freq;
> > + hpet_timecounter.tc_frequency = freq;
>
> this is unrelated and should be a different diff/commit
Ack, will do it separately.
--
Index: sys/arch/amd64/amd64/lapic.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/lapic.c,v
retrieving revision 1.60
diff -u -p -r1.60 lapic.c
--- sys/arch/amd64/amd64/lapic.c 15 Aug 2022 04:17:50 -0000 1.60
+++ sys/arch/amd64/amd64/lapic.c 25 Aug 2022 03:56:47 -0000
@@ -592,8 +592,7 @@ skip_calibration:
* Now that the timer's calibrated, use the apic timer routines
* for all our timing needs..
*/
- if (delay_func == i8254_delay)
- delay_func = lapic_delay;
+ delay_init(lapic_delay, 3000);
initclock_func = lapic_initclocks;
}
}
Index: sys/arch/amd64/amd64/machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/machdep.c,v
retrieving revision 1.279
diff -u -p -r1.279 machdep.c
--- sys/arch/amd64/amd64/machdep.c 7 Aug 2022 23:56:06 -0000 1.279
+++ sys/arch/amd64/amd64/machdep.c 25 Aug 2022 03:56:47 -0000
@@ -2069,3 +2069,13 @@ check_context(const struct reg *regs, st
return 0;
}
+
+void
+delay_init(void(*fn)(int), int fn_quality)
+{
+ static int cur_quality = 0;
+ if (fn_quality > cur_quality) {
+ delay_func = fn;
+ cur_quality = fn_quality;
+ }
+}
Index: sys/arch/amd64/amd64/tsc.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/tsc.c,v
retrieving revision 1.25
diff -u -p -r1.25 tsc.c
--- sys/arch/amd64/amd64/tsc.c 12 Aug 2022 02:20:36 -0000 1.25
+++ sys/arch/amd64/amd64/tsc.c 25 Aug 2022 03:56:48 -0000
@@ -109,7 +109,7 @@ tsc_identify(struct cpu_info *ci)
tsc_frequency = tsc_freq_cpuid(ci);
if (tsc_frequency > 0)
- delay_func = tsc_delay;
+ delay_init(tsc_delay, 5000);
}
static inline int
Index: sys/arch/amd64/include/cpu.h
===================================================================
RCS file: /cvs/src/sys/arch/amd64/include/cpu.h,v
retrieving revision 1.148
diff -u -p -r1.148 cpu.h
--- sys/arch/amd64/include/cpu.h 22 Aug 2022 08:57:54 -0000 1.148
+++ sys/arch/amd64/include/cpu.h 25 Aug 2022 03:56:48 -0000
@@ -359,6 +359,7 @@ void signotify(struct proc *);
* We need a machine-independent name for this.
*/
extern void (*delay_func)(int);
+void delay_init(void (*)(int), int);
struct timeval;
#define DELAY(x) (*delay_func)(x)
Index: sys/arch/i386/i386/lapic.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/i386/lapic.c,v
retrieving revision 1.49
diff -u -p -r1.49 lapic.c
--- sys/arch/i386/i386/lapic.c 15 Aug 2022 04:17:50 -0000 1.49
+++ sys/arch/i386/i386/lapic.c 25 Aug 2022 03:56:48 -0000
@@ -395,7 +395,7 @@ lapic_calibrate_timer(struct cpu_info *c
* Now that the timer's calibrated, use the apic timer routines
* for all our timing needs..
*/
- delay_func = lapic_delay;
+ delay_init(lapic_delay, 3000);
initclock_func = lapic_initclocks;
}
}
Index: sys/arch/i386/i386/machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/i386/machdep.c,v
retrieving revision 1.655
diff -u -p -r1.655 machdep.c
--- sys/arch/i386/i386/machdep.c 22 Aug 2022 08:53:55 -0000 1.655
+++ sys/arch/i386/i386/machdep.c 25 Aug 2022 03:56:49 -0000
@@ -3974,3 +3974,13 @@ cpu_rnd_messybits(void)
nanotime(&ts);
return (ts.tv_nsec ^ (ts.tv_sec << 20));
}
+
+void
+delay_init(void(*fn)(int), int fn_quality)
+{
+ static int cur_quality = 0;
+ if (fn_quality > cur_quality) {
+ delay_func = fn;
+ cur_quality = fn_quality;
+ }
+}
Index: sys/arch/i386/include/cpu.h
===================================================================
RCS file: /cvs/src/sys/arch/i386/include/cpu.h,v
retrieving revision 1.177
diff -u -p -r1.177 cpu.h
--- sys/arch/i386/include/cpu.h 22 Aug 2022 08:53:55 -0000 1.177
+++ sys/arch/i386/include/cpu.h 25 Aug 2022 03:56:49 -0000
@@ -302,6 +302,7 @@ void signotify(struct proc *);
* We need a machine-independent name for this.
*/
extern void (*delay_func)(int);
+void delay_init(void(*)(int), int);
struct timeval;
#define DELAY(x) (*delay_func)(x)
Index: sys/dev/acpi/acpitimer.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/acpitimer.c,v
retrieving revision 1.15
diff -u -p -r1.15 acpitimer.c
--- sys/dev/acpi/acpitimer.c 6 Apr 2022 18:59:27 -0000 1.15
+++ sys/dev/acpi/acpitimer.c 25 Aug 2022 03:56:49 -0000
@@ -18,17 +18,27 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
+#include <sys/stdint.h>
#include <sys/timetc.h>
#include <machine/bus.h>
+#include <machine/cpu.h>
#include <dev/acpi/acpireg.h>
#include <dev/acpi/acpivar.h>
+struct acpitimer_softc {
+ struct device sc_dev;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+};
+
int acpitimermatch(struct device *, void *, void *);
void acpitimerattach(struct device *, struct device *, void *);
-
+void acpitimer_delay(int);
u_int acpi_get_timecount(struct timecounter *tc);
+uint32_t acpitimer_read(struct acpitimer_softc *);
static struct timecounter acpi_timecounter = {
.tc_get_timecount = acpi_get_timecount,
@@ -41,13 +51,6 @@ static struct timecounter acpi_timecount
.tc_user = 0,
};
-struct acpitimer_softc {
- struct device sc_dev;
-
- bus_space_tag_t sc_iot;
- bus_space_handle_t sc_ioh;
-};
-
const struct cfattach acpitimer_ca = {
sizeof(struct acpitimer_softc), acpitimermatch, acpitimerattach
};
@@ -98,18 +101,43 @@ acpitimerattach(struct device *parent, s
acpi_timecounter.tc_priv = sc;
acpi_timecounter.tc_name = sc->sc_dev.dv_xname;
tc_init(&acpi_timecounter);
+
+ delay_init(acpitimer_delay, 1000);
+
#if defined(__amd64__)
extern void cpu_recalibrate_tsc(struct timecounter *);
cpu_recalibrate_tsc(&acpi_timecounter);
#endif
}
+void
+acpitimer_delay(int usecs)
+{
+ uint64_t count = 0, cycles;
+ struct acpitimer_softc *sc = acpi_timecounter.tc_priv;
+ uint32_t mask = acpi_timecounter.tc_counter_mask;
+ uint32_t val1, val2;
+
+ val2 = acpitimer_read(sc);
+ cycles = usecs * acpi_timecounter.tc_frequency / 1000000;
+ while (count < cycles) {
+ CPU_BUSY_CYCLE();
+ val1 = val2;
+ val2 = acpitimer_read(sc);
+ count += (val2 - val1) & mask;
+ }
+}
u_int
acpi_get_timecount(struct timecounter *tc)
{
- struct acpitimer_softc *sc = tc->tc_priv;
- u_int u1, u2, u3;
+ return acpitimer_read(tc->tc_priv);
+}
+
+uint32_t
+acpitimer_read(struct acpitimer_softc *sc)
+{
+ uint32_t u1, u2, u3;
u2 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 0);
u3 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 0);
Index: sys/dev/acpi/acpihpet.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/acpihpet.c,v
retrieving revision 1.26
diff -u -p -r1.26 acpihpet.c
--- sys/dev/acpi/acpihpet.c 6 Apr 2022 18:59:27 -0000 1.26
+++ sys/dev/acpi/acpihpet.c 25 Aug 2022 03:56:49 -0000
@@ -18,9 +18,11 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
+#include <sys/stdint.h>
#include <sys/timetc.h>
#include <machine/bus.h>
+#include <machine/cpu.h>
#include <dev/acpi/acpireg.h>
#include <dev/acpi/acpivar.h>
@@ -31,7 +33,7 @@ int acpihpet_attached;
int acpihpet_match(struct device *, void *, void *);
void acpihpet_attach(struct device *, struct device *, void *);
int acpihpet_activate(struct device *, int);
-
+void acpihpet_delay(int);
u_int acpihpet_gettime(struct timecounter *tc);
uint64_t acpihpet_r(bus_space_tag_t _iot, bus_space_handle_t _ioh,
@@ -266,11 +268,26 @@ acpihpet_attach(struct device *parent, s
hpet_timecounter.tc_priv = sc;
hpet_timecounter.tc_name = sc->sc_dev.dv_xname;
tc_init(&hpet_timecounter);
+
+ delay_init(acpihpet_delay, 2000);
+
#if defined(__amd64__)
extern void cpu_recalibrate_tsc(struct timecounter *);
cpu_recalibrate_tsc(&hpet_timecounter);
#endif
acpihpet_attached++;
+}
+
+void
+acpihpet_delay(int usecs)
+{
+ uint64_t c, s;
+ struct acpihpet_softc *sc = hpet_timecounter.tc_priv;
+
+ s = acpihpet_r(sc->sc_iot, sc->sc_ioh, HPET_MAIN_COUNTER);
+ c = usecs * hpet_timecounter.tc_frequency / 1000000;
+ while (acpihpet_r(sc->sc_iot, sc->sc_ioh, HPET_MAIN_COUNTER) - s < c)
+ CPU_BUSY_CYCLE();
}
u_int
Index: sys/dev/pv/pvbus.c
===================================================================
RCS file: /cvs/src/sys/dev/pv/pvbus.c,v
retrieving revision 1.24
diff -u -p -r1.24 pvbus.c
--- sys/dev/pv/pvbus.c 5 Nov 2021 11:38:29 -0000 1.24
+++ sys/dev/pv/pvbus.c 25 Aug 2022 03:56:49 -0000
@@ -319,9 +319,8 @@ pvbus_hyperv(struct pvbus_hv *hv)
HYPERV_VERSION_EBX_MINOR_S;
#if NHYPERV > 0
- if (hv->hv_features & CPUID_HV_MSR_TIME_REFCNT &&
- delay_func == i8254_delay)
- delay_func = hv_delay;
+ if (hv->hv_features & CPUID_HV_MSR_TIME_REFCNT)
+ delay_init(hv_delay, 4000);
#endif
}