acpihpet(4): add acpihpet_delay(), another delay(9) implementation
authorcheloha <cheloha@openbsd.org>
Thu, 25 Aug 2022 17:54:33 +0000 (17:54 +0000)
committercheloha <cheloha@openbsd.org>
Thu, 25 Aug 2022 17:54:33 +0000 (17:54 +0000)
When lapic_delay() is removed from the tree in the near future, older
machines without a constant/invariant TSC will need a delay(9)
implementation better than i8254_delay().

This patch adds acpihpet_delay(), a delay(9) implementation based on
the ACPI HPET timer.  It is preferable to i8254_delay() (0) and
acpitimer_delay() (1000), so set its quality to 2000.

On newer machines, the HPET is slower to read than the PMT on newer
machines for reasons unknown, so _technically_ this quality hierarchy
is not always accurate.  However, we expect these newer machines to
have a constant/invariant TSC available, so the inaccuracy is harmless
because tsc_delay() will be available, which is better than both the
PMT and the HPET.

In general, on real hardware that predates wide availability of the
constant/invariant TSC, the HPET is preferable to the PMT.

With input from jsg@.

Link: https://marc.info/?l=openbsd-tech&m=166053729104923&w=2
ok mlarkin@ jsg@

sys/dev/acpi/acpihpet.c

index b917edb..87eaf02 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpihpet.c,v 1.26 2022/04/06 18:59:27 naddy Exp $ */
+/* $OpenBSD: acpihpet.c,v 1.27 2022/08/25 17:54:33 cheloha Exp $ */
 /*
  * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
  *
 #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,6 +268,9 @@ acpihpet_attach(struct device *parent, struct device *self, void *aux)
        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);
@@ -273,6 +278,18 @@ acpihpet_attach(struct device *parent, struct device *self, void *aux)
        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
 acpihpet_gettime(struct timecounter *tc)
 {