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/46fa3d88219a
branches: trunk
changeset: 835922:46fa3d88219a
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 a444de1acfec -r 46fa3d88219a 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 = >mr_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(>mr_cntv_tval_write_ev, EVCNT_TYPE_MISC, NULL,
- device_xname(self), "CNTV_TVAL write retry max");
-#ifdef DIAGNOSTIC
- evcnt_attach_dynamic(>mr_cntv_cval_read_ev, EVCNT_TYPE_MISC, NULL,
- device_xname(self), "CNTV_CVAL read retry max");
-#endif
- evcnt_attach_dynamic(>mr_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 a444de1acfec -r 46fa3d88219a 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 a444de1acfec -r 46fa3d88219a 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