Source-Changes-HG archive

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

[src/trunk]: src/sys/arch Add support for physical timers and sprinkle isb wh...



details:   https://anonhg.NetBSD.org/src/rev/fdf21deed9ca
branches:  trunk
changeset: 458842:fdf21deed9ca
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Mon Aug 12 23:31:48 2019 +0000

description:
Add support for physical timers and sprinkle isb where needed.

diffstat:

 sys/arch/aarch64/include/armreg.h |   45 +++++++++++++-
 sys/arch/arm/cortex/gtmr.c        |  126 ++++++++++++++++++++++++++++---------
 sys/arch/arm/cortex/gtmr_var.h    |    3 +-
 sys/arch/arm/include/armreg.h     |   50 ++++++++++++++-
 4 files changed, 190 insertions(+), 34 deletions(-)

diffs (truncated from 420 to 300 lines):

diff -r 08abd2098364 -r fdf21deed9ca sys/arch/aarch64/include/armreg.h
--- a/sys/arch/aarch64/include/armreg.h Mon Aug 12 15:47:02 2019 +0000
+++ b/sys/arch/aarch64/include/armreg.h Mon Aug 12 23:31:48 2019 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: armreg.h,v 1.25 2019/06/16 15:16:15 skrll Exp $ */
+/* $NetBSD: armreg.h,v 1.26 2019/08/12 23:31:48 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -1138,6 +1138,16 @@
        reg_cntv_ctl_el0_write(val);
 }
 
+/*
+ * Counter-timer Physical Timer Control register
+ */
+static __inline uint32_t
+gtmr_cntp_ctl_read(void)
+{
+
+       return reg_cntp_ctl_el0_read();
+}
+
 static __inline void
 gtmr_cntp_ctl_write(uint32_t val)
 {
@@ -1146,6 +1156,23 @@
 }
 
 /*
+ * Counter-timer Physical Timer TimerValue register
+ */
+static __inline uint32_t
+gtmr_cntp_tval_read(void)
+{
+
+       return reg_cntp_tval_el0_read();
+}
+
+static __inline void
+gtmr_cntp_tval_write(uint32_t val)
+{
+
+       reg_cntp_tval_el0_write(val);
+}
+
+/*
  * Counter-timer Virtual Timer TimerValue register
  */
 static __inline uint32_t
@@ -1162,6 +1189,22 @@
        reg_cntv_tval_el0_write(val);
 }
 
+/*
+ * Counter-timer Physical Timer CompareValue register
+ */
+static __inline uint64_t
+gtmr_cntp_cval_read(void)
+{
+
+       return reg_cntp_cval_el0_read();
+}
+
+static __inline void
+gtmr_cntp_cval_write(uint64_t val)
+{
+
+       reg_cntp_cval_el0_write(val);
+}
 
 /*
  * Counter-timer Virtual Timer CompareValue register
diff -r 08abd2098364 -r fdf21deed9ca sys/arch/arm/cortex/gtmr.c
--- a/sys/arch/arm/cortex/gtmr.c        Mon Aug 12 15:47:02 2019 +0000
+++ b/sys/arch/arm/cortex/gtmr.c        Mon Aug 12 23:31:48 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: gtmr.c,v 1.40 2019/06/16 10:57:59 jmcneill Exp $       */
+/*     $NetBSD: gtmr.c,v 1.41 2019/08/12 23:31:48 jmcneill Exp $       */
 
 /*-
  * Copyright (c) 2012 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gtmr.c,v 1.40 2019/06/16 10:57:59 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gtmr.c,v 1.41 2019/08/12 23:31:48 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -55,6 +55,12 @@
 
 static u_int gtmr_get_timecount(struct timecounter *);
 
+static uint64_t gtmr_read_cntct(struct gtmr_softc *);
+static uint32_t gtmr_read_ctl(struct gtmr_softc *);
+static void gtmr_write_ctl(struct gtmr_softc *, uint32_t);
+static void gtmr_write_tval(struct gtmr_softc *, uint32_t);
+static void gtmr_write_cval(struct gtmr_softc *, uint64_t);
+
 static struct gtmr_softc gtmr_sc;
 
 struct gtmr_percpu {
@@ -99,6 +105,7 @@
        struct mpcore_attach_args * const mpcaa = aux;
        struct gtmr_softc *sc = &gtmr_sc;
        prop_dictionary_t dict = device_properties(self);
+       prop_dictionary_t pdict = device_properties(device_parent(self));
        char freqbuf[sizeof("X.XXX SHz")];
        bool flag;
 
@@ -108,12 +115,16 @@
        if (!prop_dictionary_get_uint32(dict, "frequency", &sc->sc_freq))
                sc->sc_freq = gtmr_cntfrq_read();
 
+       if (!prop_dictionary_get_bool(dict, "physical", &sc->sc_physical))
+           prop_dictionary_get_bool(pdict, "physical", &sc->sc_physical);
+
        KASSERT(sc->sc_freq != 0);
 
        humanize_number(freqbuf, sizeof(freqbuf), sc->sc_freq, "Hz", 1000);
 
        aprint_naive("\n");
-       aprint_normal(": ARM Generic Timer (%s)\n", freqbuf);
+       aprint_normal(": Generic Timer (%s, %s)\n", freqbuf,
+           sc->sc_physical ? "physical" : "virtual");
 
        if (prop_dictionary_get_bool(dict, "sun50i-a64-unstable-timer", &flag) && flag) {
                sc->sc_flags |= GTMR_FLAG_SUN50I_A64_UNSTABLE_TIMER;
@@ -155,12 +166,14 @@
        tc_init(&gtmr_timecounter);
 
        /* Disable the timer until we are ready */
-       gtmr_cntv_ctl_write(0);
+       gtmr_write_ctl(sc, 0);
 }
 
 static uint64_t
-gtmr_read_cntvct(struct gtmr_softc *sc)
+gtmr_read_cntct(struct gtmr_softc *sc)
 {
+       arm_isb();
+
        if (ISSET(sc->sc_flags, GTMR_FLAG_SUN50I_A64_UNSTABLE_TIMER)) {
                /*
                 * The Allwinner A64 SoC has an unstable architectural timer.
@@ -170,19 +183,63 @@
                uint64_t val;
                u_int bits;
                do {
-                       val = gtmr_cntvct_read();
+                       val = sc->sc_physical ? gtmr_cntpct_read() : gtmr_cntvct_read();
                        bits = val & __BITS(9,0);
                } while (bits == 0 || bits == __BITS(9,0));
                return val;
        }
 
-       return gtmr_cntvct_read();
+       return sc->sc_physical ? gtmr_cntpct_read() : gtmr_cntvct_read();
+}
+
+static uint32_t
+gtmr_read_ctl(struct gtmr_softc *sc)
+{
+       if (sc->sc_physical)
+               return gtmr_cntp_ctl_read();
+       else
+               return gtmr_cntv_ctl_read();
+}
+
+static void
+gtmr_write_ctl(struct gtmr_softc *sc, uint32_t val)
+{
+       if (sc->sc_physical)
+               gtmr_cntp_ctl_write(val);
+       else
+               gtmr_cntv_ctl_write(val);
+
+       arm_isb();
 }
 
+static void
+gtmr_write_tval(struct gtmr_softc *sc, uint32_t val)
+{
+       if (sc->sc_physical)
+               gtmr_cntp_tval_write(val);
+       else
+               gtmr_cntv_tval_write(val);
+
+       arm_isb();
+}
+
+static void
+gtmr_write_cval(struct gtmr_softc *sc, uint64_t val)
+{
+       if (sc->sc_physical)
+               gtmr_cntp_cval_write(val);
+       else
+               gtmr_cntv_cval_write(val);
+
+       arm_isb();
+}
+
+
 void
 gtmr_init_cpu_clock(struct cpu_info *ci)
 {
        struct gtmr_softc * const sc = &gtmr_sc;
+       uint32_t val;
 
        KASSERT(ci == curcpu());
 
@@ -192,22 +249,30 @@
         * Allow the virtual and physical counters to be accessed from
         * usermode. (PL0)
         */
-       gtmr_cntk_ctl_write(gtmr_cntk_ctl_read() |
-           CNTKCTL_PL0VCTEN | CNTKCTL_PL0PCTEN);
+       val = gtmr_cntk_ctl_read();
+       val &= ~(CNTKCTL_PL0PTEN | CNTKCTL_PL0VTEN | CNTKCTL_EVNTEN);
+       if (sc->sc_physical) {
+               val |= CNTKCTL_PL0PCTEN;
+               val &= ~CNTKCTL_PL0VCTEN;
+       } else {
+               val |= CNTKCTL_PL0VCTEN;
+               val &= ~CNTKCTL_PL0PCTEN;
+       }
+       gtmr_cntk_ctl_write(val);
+       arm_isb();
 
        /*
         * enable timer and stop masking the timer.
         */
-       gtmr_cntv_ctl_write(CNTCTL_ENABLE);
+       gtmr_write_ctl(sc, CNTCTL_ENABLE);
 
        /*
         * Get now and update the compare timer.
         */
-       arm_isb();
-       ci->ci_lastintr = gtmr_read_cntvct(sc);
-       gtmr_cntv_tval_write(sc->sc_autoinc);
+       ci->ci_lastintr = gtmr_read_cntct(sc);
+       gtmr_write_tval(sc, sc->sc_autoinc);
        splx(s);
-       KASSERT(gtmr_read_cntvct(sc) != 0);
+       KASSERT(gtmr_read_cntct(sc) != 0);
 }
 
 void
@@ -236,12 +301,10 @@
        const unsigned int incr_per_us = howmany(freq, 1000000);
        int64_t ticks = (int64_t)n * incr_per_us;
 
-       arm_isb();
-       uint64_t last = gtmr_read_cntvct(sc);
+       uint64_t last = gtmr_read_cntct(sc);
 
        while (ticks > 0) {
-               arm_isb();
-               uint64_t curr = gtmr_read_cntvct(sc);
+               uint64_t curr = gtmr_read_cntct(sc);
                if (curr >= last)
                        ticks -= (curr - last);
                else
@@ -261,23 +324,22 @@
        struct cpu_info * const ci = curcpu();
        struct clockframe * const cf = arg;
        struct gtmr_softc * const sc = &gtmr_sc;
+       uint32_t ctl;
 
-       arm_isb();
-
-       const uint32_t ctl = gtmr_cntv_ctl_read();
+       ctl = gtmr_read_ctl(sc);
        if ((ctl & CNTCTL_ISTATUS) == 0)
                return 0;
 
-       arm_isb();
-       gtmr_cntv_ctl_write(0);
+       ctl |= CNTCTL_IMASK;
+       gtmr_write_ctl(sc, ctl);
 
-       const uint64_t now = gtmr_read_cntvct(sc);
+       const uint64_t now = gtmr_read_cntct(sc);
        uint64_t delta = now - ci->ci_lastintr;
 
 #ifdef DIAGNOSTIC
        struct gtmr_percpu *pc = NULL;
        if (!ISSET(sc->sc_flags, GTMR_FLAG_SUN50I_A64_UNSTABLE_TIMER)) {
-               const uint64_t then = gtmr_cntv_cval_read();
+               const uint64_t then = sc->sc_physical ? gtmr_cntp_cval_read() : gtmr_cntv_cval_read();
                pc = percpu_getref(sc->sc_percpu);
                KASSERTMSG(then <= now, "%"PRId64, now - then);
                KASSERTMSG(then + pc->pc_delta >= ci->ci_lastintr + sc->sc_autoinc,
@@ -304,13 +366,15 @@
 
        arm_isb();
        if (ISSET(sc->sc_flags, GTMR_FLAG_SUN50I_A64_UNSTABLE_TIMER)) {



Home | Main Index | Thread Index | Old Index