Module Name:    src
Committed By:   jmcneill
Date:           Sun Sep 16 13:21:36 UTC 2018

Modified Files:
        src/sys/arch/arm/cortex: gtmr.c gtmr_var.h
        src/sys/arch/arm/sunxi: sunxi_platform.c

Log Message:
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".


To generate a diff of this commit:
cvs rdiff -u -r1.34 -r1.35 src/sys/arch/arm/cortex/gtmr.c
cvs rdiff -u -r1.10 -r1.11 src/sys/arch/arm/cortex/gtmr_var.h
cvs rdiff -u -r1.26 -r1.27 src/sys/arch/arm/sunxi/sunxi_platform.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/arm/cortex/gtmr.c
diff -u src/sys/arch/arm/cortex/gtmr.c:1.34 src/sys/arch/arm/cortex/gtmr.c:1.35
--- src/sys/arch/arm/cortex/gtmr.c:1.34	Mon Sep 10 10:55:02 2018
+++ src/sys/arch/arm/cortex/gtmr.c	Sun Sep 16 13:21:36 2018
@@ -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 @@ __KERNEL_RCSID(0, "$NetBSD: gtmr.c,v 1.3
 #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 @@ gtmr_attach(device_t parent, device_t se
 	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 @@ gtmr_attach(device_t parent, device_t se
 	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 @@ gtmr_attach(device_t parent, device_t se
 	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_attach(device_t parent, device_t se
 	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 @@ gtmr_init_cpu_clock(struct cpu_info *ci)
 	 * 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 @@ gtmr_delay(unsigned int n)
 	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 @@ gtmr_intr(void *arg)
 	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 @@ gtmr_intr(void *arg)
 	} 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 @@ gtmr_get_timecount(struct timecounter *t
 {
 	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);
 }

Index: src/sys/arch/arm/cortex/gtmr_var.h
diff -u src/sys/arch/arm/cortex/gtmr_var.h:1.10 src/sys/arch/arm/cortex/gtmr_var.h:1.11
--- src/sys/arch/arm/cortex/gtmr_var.h:1.10	Mon May 14 17:09:41 2018
+++ src/sys/arch/arm/cortex/gtmr_var.h	Sun Sep 16 13:21:36 2018
@@ -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 @@ struct gtmr_softc {
 	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

Index: src/sys/arch/arm/sunxi/sunxi_platform.c
diff -u src/sys/arch/arm/sunxi/sunxi_platform.c:1.26 src/sys/arch/arm/sunxi/sunxi_platform.c:1.27
--- src/sys/arch/arm/sunxi/sunxi_platform.c:1.26	Mon Sep 10 11:05:12 2018
+++ src/sys/arch/arm/sunxi/sunxi_platform.c	Sun Sep 16 13:21:36 2018
@@ -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 <jmcne...@invisible.ca>
@@ -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 @@ sunxi_platform_device_register(device_t 
 			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

Reply via email to