Module Name:    src
Committed By:   jmcneill
Date:           Mon Aug 12 23:31:48 UTC 2019

Modified Files:
        src/sys/arch/aarch64/include: armreg.h
        src/sys/arch/arm/cortex: gtmr.c gtmr_var.h
        src/sys/arch/arm/include: armreg.h

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


To generate a diff of this commit:
cvs rdiff -u -r1.25 -r1.26 src/sys/arch/aarch64/include/armreg.h
cvs rdiff -u -r1.40 -r1.41 src/sys/arch/arm/cortex/gtmr.c
cvs rdiff -u -r1.11 -r1.12 src/sys/arch/arm/cortex/gtmr_var.h
cvs rdiff -u -r1.127 -r1.128 src/sys/arch/arm/include/armreg.h

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/aarch64/include/armreg.h
diff -u src/sys/arch/aarch64/include/armreg.h:1.25 src/sys/arch/aarch64/include/armreg.h:1.26
--- src/sys/arch/aarch64/include/armreg.h:1.25	Sun Jun 16 15:16:15 2019
+++ src/sys/arch/aarch64/include/armreg.h	Mon Aug 12 23:31:48 2019
@@ -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 @@ gtmr_cntv_ctl_write(uint32_t val)
 	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 @@ gtmr_cntp_ctl_write(uint32_t val)
 }
 
 /*
+ * 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 @@ gtmr_cntv_tval_write(uint32_t val)
 	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

Index: src/sys/arch/arm/cortex/gtmr.c
diff -u src/sys/arch/arm/cortex/gtmr.c:1.40 src/sys/arch/arm/cortex/gtmr.c:1.41
--- src/sys/arch/arm/cortex/gtmr.c:1.40	Sun Jun 16 10:57:59 2019
+++ src/sys/arch/arm/cortex/gtmr.c	Mon Aug 12 23:31:48 2019
@@ -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 void gtmr_attach(device_t, device
 
 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 @@ gtmr_attach(device_t parent, device_t se
 	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 @@ gtmr_attach(device_t parent, device_t se
 	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 @@ gtmr_attach(device_t parent, device_t se
 	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 @@ gtmr_read_cntvct(struct gtmr_softc *sc)
 		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 @@ gtmr_init_cpu_clock(struct cpu_info *ci)
 	 * 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 @@ gtmr_delay(unsigned int n)
 	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 @@ gtmr_intr(void *arg)
 	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 @@ gtmr_intr(void *arg)
 
 	arm_isb();
 	if (ISSET(sc->sc_flags, GTMR_FLAG_SUN50I_A64_UNSTABLE_TIMER)) {
-		gtmr_cntv_cval_write(now + sc->sc_autoinc - delta);
+		gtmr_write_cval(sc, now + sc->sc_autoinc - delta);
 	} else {
-		gtmr_cntv_tval_write(sc->sc_autoinc - delta);
+		gtmr_write_tval(sc, sc->sc_autoinc - delta);
 	}
 
-	arm_isb();
-	gtmr_cntv_ctl_write(CNTCTL_ENABLE);
+	ctl = gtmr_read_ctl(sc);
+	ctl &= ~CNTCTL_IMASK;
+	ctl |= CNTCTL_ENABLE;
+	gtmr_write_ctl(sc, ctl);
 
 	ci->ci_lastintr = now;
 
@@ -338,6 +402,6 @@ static u_int
 gtmr_get_timecount(struct timecounter *tc)
 {
 	struct gtmr_softc * const sc = tc->tc_priv;
-	arm_isb();	// we want the time NOW, not some instructions later.
-	return (u_int) gtmr_read_cntvct(sc);
+
+	return (u_int) gtmr_read_cntct(sc);
 }

Index: src/sys/arch/arm/cortex/gtmr_var.h
diff -u src/sys/arch/arm/cortex/gtmr_var.h:1.11 src/sys/arch/arm/cortex/gtmr_var.h:1.12
--- src/sys/arch/arm/cortex/gtmr_var.h:1.11	Sun Sep 16 13:21:36 2018
+++ src/sys/arch/arm/cortex/gtmr_var.h	Mon Aug 12 23:31:48 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: gtmr_var.h,v 1.11 2018/09/16 13:21:36 jmcneill Exp $ */
+/* $NetBSD: gtmr_var.h,v 1.12 2019/08/12 23:31:48 jmcneill Exp $ */
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -40,6 +40,7 @@ struct gtmr_softc {
 	uint32_t sc_flags;
 #define	GTMR_FLAG_SUN50I_A64_UNSTABLE_TIMER	__BIT(0)
 	u_long sc_autoinc;
+	bool sc_physical;
 	void *sc_global_ih;
 #ifdef DIAGNOSTIC
 	percpu_t *sc_percpu;

Index: src/sys/arch/arm/include/armreg.h
diff -u src/sys/arch/arm/include/armreg.h:1.127 src/sys/arch/arm/include/armreg.h:1.128
--- src/sys/arch/arm/include/armreg.h:1.127	Thu May  2 15:37:10 2019
+++ src/sys/arch/arm/include/armreg.h	Mon Aug 12 23:31:48 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: armreg.h,v 1.127 2019/05/02 15:37:10 skrll Exp $	*/
+/*	$NetBSD: armreg.h,v 1.128 2019/08/12 23:31:48 jmcneill Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Ben Harris
@@ -990,6 +990,18 @@ gtmr_cntv_ctl_write(uint32_t val)
 	armreg_cntv_ctl_write(val);
 }
 
+
+/*
+ * Counter-timer Physical Timer Control register
+ */
+
+static inline uint32_t
+gtmr_cntp_ctl_read(void)
+{
+
+	return armreg_cntp_ctl_read();
+}
+
 static inline void
 gtmr_cntp_ctl_write(uint32_t val)
 {
@@ -999,6 +1011,24 @@ gtmr_cntp_ctl_write(uint32_t val)
 
 
 /*
+ * Counter-timer Physical Timer TimerValue register
+ */
+static inline uint32_t
+gtmr_cntp_tval_read(void)
+{
+
+	return armreg_cntp_tval_read();
+}
+
+static inline void
+gtmr_cntp_tval_write(uint32_t val)
+{
+
+	armreg_cntp_tval_write(val);
+}
+
+
+/*
  * Counter-timer Virtual Timer TimerValue register
  */
 static inline uint32_t
@@ -1017,6 +1047,24 @@ gtmr_cntv_tval_write(uint32_t val)
 
 
 /*
+ * Counter-timer Physical Timer CompareValue register
+ */
+static inline uint64_t
+gtmr_cntp_cval_read(void)
+{
+
+	return armreg_cntp_cval_read();
+}
+
+static inline void
+gtmr_cntp_cval_write(uint64_t val)
+{
+
+	armreg_cntp_cval_write(val);
+}
+
+
+/*
  * Counter-timer Virtual Timer CompareValue register
  */
 static inline uint64_t

Reply via email to