Source-Changes-HG archive

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

[src/trunk]: src/sys/arch/arm port-evbarm/53308: evbarm-earmv7hf performance ...



details:   https://anonhg.NetBSD.org/src/rev/9c5519ea1656
branches:  trunk
changeset: 433483:9c5519ea1656
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Sun Sep 16 13:21:36 2018 +0000

description:
port-evbarm/53308: evbarm-earmv7hf performance regression under qemu

Revert gtmr.c r1.27 and apply a workaround for Allwinner A64 SoCs based
on analysis of the issue from LKML: https://lkml.org/lkml/2018/5/10/774

Since this bug is specific to the Allwinner A64 SoC, only apply the
workaround when the root ("/") node of the device tree is compatible
with "allwinner,sun50i-a64".

diffstat:

 sys/arch/arm/cortex/gtmr.c          |  100 +++++++++++++----------------------
 sys/arch/arm/cortex/gtmr_var.h      |    4 +-
 sys/arch/arm/sunxi/sunxi_platform.c |   15 ++++-
 3 files changed, 54 insertions(+), 65 deletions(-)

diffs (243 lines):

diff -r f0e8b1eb5e82 -r 9c5519ea1656 sys/arch/arm/cortex/gtmr.c
--- a/sys/arch/arm/cortex/gtmr.c        Sun Sep 16 13:14:12 2018 +0000
+++ b/sys/arch/arm/cortex/gtmr.c        Sun Sep 16 13:21:36 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: gtmr.c,v 1.34 2018/09/10 10:55:02 skrll Exp $  */
+/*     $NetBSD: gtmr.c,v 1.35 2018/09/16 13:21:36 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.34 2018/09/10 10:55:02 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gtmr.c,v 1.35 2018/09/16 13:21:36 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -50,48 +50,6 @@
 #include <arm/cortex/gtmr_var.h>
 #include <arm/cortex/mpcore_var.h>
 
-#define stable_write(reg) \
-static struct evcnt reg ## _write_ev; \
-static void \
-reg ## _stable_write(struct gtmr_softc *sc, uint64_t val) \
-{ \
-       int retry; \
-       reg ## _write(val); \
-       retry = 0; \
-       while (reg ## _read() != (val) && retry++ < 200) \
-               reg ## _write(val); \
-       if (retry > reg ## _write_ev.ev_count) { \
-               reg ## _write_ev.ev_count = retry; \
-       } \
-}
-
-stable_write(gtmr_cntv_tval);
-
-#define stable_read(reg) \
-static struct evcnt reg ## _read_ev; \
-static uint64_t \
-reg ## _stable_read(struct gtmr_softc *sc) \
-{ \
-       uint64_t oval, val; \
-       int retry = 0; \
-       val = reg ## _read(); \
-       while (++retry < 200) { \
-               oval = val; \
-               val = reg ## _read(); \
-               if (val == oval) \
-                       break; \
-       } \
-       if (retry > reg ## _read_ev.ev_count) { \
-               reg ## _read_ev.ev_count = retry; \
-       } \
-       return val; \
-}
-
-#ifdef DIAGNOSTIC
-stable_read(gtmr_cntv_cval);
-#endif
-stable_read(gtmr_cntvct);
-
 static int gtmr_match(device_t, cfdata_t, void *);
 static void gtmr_attach(device_t, device_t, void *);
 
@@ -142,6 +100,7 @@
        struct gtmr_softc *sc = &gtmr_sc;
        prop_dictionary_t dict = device_properties(self);
        char freqbuf[sizeof("X.XXX SHz")];
+       bool flag;
 
        /*
         * This runs at a fixed frequency of 1 to 50MHz.
@@ -156,6 +115,11 @@
        aprint_naive("\n");
        aprint_normal(": ARM Generic Timer (%s)\n", freqbuf);
 
+       if (prop_dictionary_get_bool(dict, "sun50i-a64-unstable-timer", &flag) && flag) {
+               sc->sc_flags |= GTMR_FLAG_SUN50I_A64_UNSTABLE_TIMER;
+               aprint_debug_dev(self, "enabling Allwinner A64 timer workaround\n");
+       }
+
        /*
         * Enable the virtual counter to be accessed from usermode.
         */
@@ -172,15 +136,6 @@
        evcnt_attach_dynamic(&sc->sc_ev_missing_ticks, EVCNT_TYPE_MISC, NULL,
            device_xname(self), "missing interrupts");
 
-       evcnt_attach_dynamic(&gtmr_cntv_tval_write_ev, EVCNT_TYPE_MISC, NULL,
-           device_xname(self), "CNTV_TVAL write retry max");
-#ifdef DIAGNOSTIC
-       evcnt_attach_dynamic(&gtmr_cntv_cval_read_ev, EVCNT_TYPE_MISC, NULL,
-           device_xname(self), "CNTV_CVAL read retry max");
-#endif
-       evcnt_attach_dynamic(&gtmr_cntvct_read_ev, EVCNT_TYPE_MISC, NULL,
-           device_xname(self), "CNTVCT read retry max");
-
        if (mpcaa->mpcaa_irq != -1) {
                sc->sc_global_ih = intr_establish(mpcaa->mpcaa_irq, IPL_CLOCK,
                    IST_LEVEL | IST_MPSAFE, gtmr_intr, NULL);
@@ -209,6 +164,27 @@
        gtmr_cntv_ctl_write(0);
 }
 
+static uint64_t
+gtmr_read_cntvct(struct gtmr_softc *sc)
+{
+       if (ISSET(sc->sc_flags, GTMR_FLAG_SUN50I_A64_UNSTABLE_TIMER)) {
+               /*
+                * The Allwinner A64 SoC has an unstable architectural timer.
+                * To workaround this problem, ignore reads where the lower
+                * 11 bits are all 0s or 1s.
+                */
+               uint64_t val;
+               u_int bits;
+               do {
+                       val = gtmr_cntvct_read();
+                       bits = val & __BITS(10,0);
+               } while (bits == 0 || bits == __BITS(10,0));
+               return val;
+       }
+
+       return gtmr_cntvct_read();
+}
+
 void
 gtmr_init_cpu_clock(struct cpu_info *ci)
 {
@@ -227,10 +203,10 @@
         * Get now and update the compare timer.
         */
        arm_isb();
-       ci->ci_lastintr = gtmr_cntvct_stable_read(sc);
-       gtmr_cntv_tval_stable_write(sc, sc->sc_autoinc);
+       ci->ci_lastintr = gtmr_read_cntvct(sc);
+       gtmr_cntv_tval_write(sc->sc_autoinc);
        splx(s);
-       KASSERT(gtmr_cntvct_read() != 0);
+       KASSERT(gtmr_read_cntvct(sc) != 0);
 }
 
 void
@@ -260,11 +236,11 @@
        int64_t ticks = (int64_t)n * incr_per_us;
 
        arm_isb();
-       uint64_t last = gtmr_cntvct_stable_read(sc);
+       uint64_t last = gtmr_read_cntvct(sc);
 
        while (ticks > 0) {
                arm_isb();
-               uint64_t curr = gtmr_cntvct_stable_read(sc);
+               uint64_t curr = gtmr_read_cntvct(sc);
                if (curr >= last)
                        ticks -= (curr - last);
                else
@@ -291,11 +267,11 @@
        if ((ctl & CNTCTL_ISTATUS) == 0)
                return 0;
 
-       const uint64_t now = gtmr_cntvct_stable_read(sc);
+       const uint64_t now = gtmr_read_cntvct(sc);
        uint64_t delta = now - ci->ci_lastintr;
 
 #ifdef DIAGNOSTIC
-       const uint64_t then = gtmr_cntv_cval_stable_read(sc);
+       const uint64_t then = gtmr_cntv_cval_read();
        struct gtmr_percpu * const pc = percpu_getref(sc->sc_percpu);
        KASSERTMSG(then <= now, "%"PRId64, now - then);
        KASSERTMSG(then + pc->pc_delta >= ci->ci_lastintr + sc->sc_autoinc,
@@ -316,7 +292,7 @@
        } else {
                delta = 0;
        }
-       gtmr_cntv_tval_stable_write(sc, sc->sc_autoinc - delta);
+       gtmr_cntv_tval_write(sc->sc_autoinc - delta);
 
        ci->ci_lastintr = now;
 
@@ -343,5 +319,5 @@
 {
        struct gtmr_softc * const sc = tc->tc_priv;
        arm_isb();      // we want the time NOW, not some instructions later.
-       return (u_int) gtmr_cntvct_stable_read(sc);
+       return (u_int) gtmr_read_cntvct(sc);
 }
diff -r f0e8b1eb5e82 -r 9c5519ea1656 sys/arch/arm/cortex/gtmr_var.h
--- a/sys/arch/arm/cortex/gtmr_var.h    Sun Sep 16 13:14:12 2018 +0000
+++ b/sys/arch/arm/cortex/gtmr_var.h    Sun Sep 16 13:21:36 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: gtmr_var.h,v 1.10 2018/05/14 17:09:41 joerg Exp $ */
+/* $NetBSD: gtmr_var.h,v 1.11 2018/09/16 13:21:36 jmcneill Exp $ */
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -37,6 +37,8 @@
        device_t sc_dev;
        struct evcnt sc_ev_missing_ticks;
        uint32_t sc_freq;
+       uint32_t sc_flags;
+#define        GTMR_FLAG_SUN50I_A64_UNSTABLE_TIMER     __BIT(0)
        u_long sc_autoinc;
        void *sc_global_ih;
 #ifdef DIAGNOSTIC
diff -r f0e8b1eb5e82 -r 9c5519ea1656 sys/arch/arm/sunxi/sunxi_platform.c
--- a/sys/arch/arm/sunxi/sunxi_platform.c       Sun Sep 16 13:14:12 2018 +0000
+++ b/sys/arch/arm/sunxi/sunxi_platform.c       Sun Sep 16 13:21:36 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: sunxi_platform.c,v 1.26 2018/09/10 11:05:12 ryo Exp $ */
+/* $NetBSD: sunxi_platform.c,v 1.27 2018/09/16 13:21:36 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2017 Jared McNeill <jmcneill%invisible.ca@localhost>
@@ -31,7 +31,7 @@
 #include "opt_fdt_arm.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sunxi_platform.c,v 1.26 2018/09/10 11:05:12 ryo Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sunxi_platform.c,v 1.27 2018/09/16 13:21:36 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -165,6 +165,17 @@
                        prop_dictionary_set_bool(prop, "no-rx-delay", true);
                }
        }
+
+       if (device_is_a(self, "armgtmr")) {
+               /* Allwinner A64 has an unstable architectural timer */
+               const char * compat[] = {
+                       "allwinner,sun50i-a64",
+                       NULL
+               };
+               if (of_match_compatible(OF_finddevice("/"), compat)) {
+                       prop_dictionary_set_bool(prop, "sun50i-a64-unstable-timer", true);
+               }
+       }
 }
 
 static u_int



Home | Main Index | Thread Index | Old Index