Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/ic Implement a HPET based DELAY().



details:   https://anonhg.NetBSD.org/src/rev/3dd389368fbf
branches:  trunk
changeset: 1009460:3dd389368fbf
user:      ad <ad%NetBSD.org@localhost>
date:      Thu Apr 23 20:33:57 2020 +0000

description:
Implement a HPET based DELAY().

diffstat:

 sys/dev/ic/hpet.c    |  52 +++++++++++++++++++++++++++++++++++++++++++++++-----
 sys/dev/ic/hpetvar.h |   7 ++++++-
 2 files changed, 53 insertions(+), 6 deletions(-)

diffs (150 lines):

diff -r 71fecea164d5 -r 3dd389368fbf sys/dev/ic/hpet.c
--- a/sys/dev/ic/hpet.c Thu Apr 23 19:24:53 2020 +0000
+++ b/sys/dev/ic/hpet.c Thu Apr 23 20:33:57 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: hpet.c,v 1.13 2011/10/31 12:47:15 yamt Exp $ */
+/* $NetBSD: hpet.c,v 1.14 2020/04/23 20:33:57 ad Exp $ */
 
 /*
  * Copyright (c) 2006 Nicolas Joly
@@ -33,7 +33,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: hpet.c,v 1.13 2011/10/31 12:47:15 yamt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: hpet.c,v 1.14 2020/04/23 20:33:57 ad Exp $");
 
 #include <sys/systm.h>
 #include <sys/device.h>
@@ -43,6 +43,7 @@
 #include <sys/timetc.h>
 
 #include <sys/bus.h>
+#include <sys/lock.h>
 
 #include <dev/ic/hpetreg.h>
 #include <dev/ic/hpetvar.h>
@@ -50,9 +51,12 @@
 static u_int   hpet_get_timecount(struct timecounter *);
 static bool    hpet_resume(device_t, const pmf_qual_t *);
 
+static struct hpet_softc *hpet0 __read_mostly;
+
 int
 hpet_detach(device_t dv, int flags)
 {
+#if 0 /* XXX DELAY() is based off this, detaching is not a good idea. */
        struct hpet_softc *sc = device_private(dv);
        int rc;
 
@@ -64,6 +68,9 @@
        bus_space_write_4(sc->sc_memt, sc->sc_memh, HPET_CONFIG, sc->sc_config);
 
        return 0;
+#else
+       return EBUSY;
+#endif
 }
 
 void
@@ -84,8 +91,8 @@
        tc->tc_counter_mask = 0xffffffff;
 
        /* Get frequency */
-       val = bus_space_read_4(sc->sc_memt, sc->sc_memh, HPET_PERIOD);
-       if (val == 0 || val > HPET_PERIOD_MAX) {
+       sc->sc_period = bus_space_read_4(sc->sc_memt, sc->sc_memh, HPET_PERIOD);
+       if (sc->sc_period == 0 || sc->sc_period > HPET_PERIOD_MAX) {
                aprint_error_dev(dv, "invalid timer period\n");
                return;
        }
@@ -104,7 +111,7 @@
                }
        }
 
-       tmp = (1000000000000000ULL * 2) / val;
+       tmp = (1000000000000000ULL * 2) / sc->sc_period;
        tc->tc_frequency = (tmp / 2) + (tmp & 1);
 
        /* Enable timer */
@@ -120,6 +127,9 @@
 
        if (!pmf_device_register(dv, NULL, hpet_resume))
                aprint_error_dev(dv, "couldn't establish power handler\n");
+
+       if (device_unit(dv) == 0)
+               hpet0 = sc;
 }
 
 static u_int
@@ -143,6 +153,38 @@
        return true;
 }
 
+bool
+hpet_delay_p(void)
+{
+
+       return hpet0 != NULL;
+}
+
+void
+hpet_delay(unsigned int us)
+{
+       struct hpet_softc *sc;
+       uint32_t ntick, otick;
+       int64_t delta;
+
+       /*
+        * Read timer before slow division.  Assume that each read of the
+        * HPET costs ~500ns.  Aim for the middle and subtract 750ns for
+        * overhead.
+        */
+       sc = hpet0;
+       otick = bus_space_read_4(sc->sc_memt, sc->sc_memh, HPET_MCOUNT_LO);
+       delta = (((int64_t)us * 1000000000) - 750000000) / sc->sc_period;
+
+       while (delta > 0) {
+               SPINLOCK_BACKOFF_HOOK;
+               ntick = bus_space_read_4(sc->sc_memt, sc->sc_memh,
+                   HPET_MCOUNT_LO);
+               delta -= (uint32_t)(ntick - otick);
+               otick = ntick;
+       }
+}
+
 MODULE(MODULE_CLASS_DRIVER, hpet, NULL);
 
 #ifdef _MODULE
diff -r 71fecea164d5 -r 3dd389368fbf sys/dev/ic/hpetvar.h
--- a/sys/dev/ic/hpetvar.h      Thu Apr 23 19:24:53 2020 +0000
+++ b/sys/dev/ic/hpetvar.h      Thu Apr 23 20:33:57 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: hpetvar.h,v 1.4 2011/06/14 16:33:51 jruoho Exp $ */
+/* $NetBSD: hpetvar.h,v 1.5 2020/04/23 20:33:57 ad Exp $ */
 
 /*
  * Copyright (c) 2006 Nicolas Joly
@@ -31,6 +31,8 @@
 #ifndef _DEV_IC_HPETVAR_H_
 #define _DEV_IC_HPETVAR_H_
 
+#include <sys/timetc.h>
+
 struct hpet_softc {
        bus_size_t              sc_mems;
        bus_space_tag_t         sc_memt;
@@ -38,10 +40,13 @@
 
        bool                    sc_mapped;
        uint32_t                sc_config;
+       int32_t                 sc_period;
        struct                  timecounter sc_tc;
 };
 
 void   hpet_attach_subr(device_t);
 int    hpet_detach(device_t, int flags);
+void   hpet_delay(unsigned int);
+bool   hpet_delay_p(void);
 
 #endif /* _DEV_IC_HPETVAR_H_ */



Home | Main Index | Thread Index | Old Index