acpihpet(4): acpihpet_delay: only use lower 32 bits of counter
authorcheloha <cheloha@openbsd.org>
Mon, 12 Sep 2022 10:58:05 +0000 (10:58 +0000)
committercheloha <cheloha@openbsd.org>
Mon, 12 Sep 2022 10:58:05 +0000 (10:58 +0000)
We can't use acpihpet_r() to implement acpihpet_delay().  Even if we
made acpihpet_r() atomic on amd64, i386 would still be incapable of
doing atomic 8-byte reads.  As-is, the code does a split read on all
platforms, which may or may not already be causing problems with TSC
calibration:

https://marc.info/?l=openbsd-tech&m=166220561709496&w=2

Switch from acpihpet_r() to bus_space_read_4() and only use the lower
32 bits of the counter.  This makes acpihpet_delay() slightly larger,
but unless we want two acpihpet_delay() implementations we have no
choice.

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

sys/dev/acpi/acpihpet.c

index bb1e6c5..7b7898f 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpihpet.c,v 1.28 2022/08/25 18:01:54 cheloha Exp $ */
+/* $OpenBSD: acpihpet.c,v 1.29 2022/09/12 10:58:05 cheloha Exp $ */
 /*
  * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
  *
@@ -281,13 +281,19 @@ acpihpet_attach(struct device *parent, struct device *self, void *aux)
 void
 acpihpet_delay(int usecs)
 {
-       uint64_t cs;
+       uint64_t count = 0, cycles;
        struct acpihpet_softc *sc = hpet_timecounter.tc_priv;
+       uint32_t val1, val2;
 
-       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)
+       val2 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, HPET_MAIN_COUNTER);
+       cycles = usecs * hpet_timecounter.tc_frequency / 1000000;
+       while (count < cycles) {
                CPU_BUSY_CYCLE();
+               val1 = val2;
+               val2 = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+                   HPET_MAIN_COUNTER);
+               count += val2 - val1;
+       }
 }
 
 u_int