git: 7ad28b73ec1f - main - arm: Add a userspace physical timer check

From: Andrew Turner <andrew_at_FreeBSD.org>
Date: Fri, 01 Sep 2023 10:07:11 UTC
The branch main has been updated by andrew:

URL: https://cgit.FreeBSD.org/src/commit/?id=7ad28b73ec1fd78a28a708da442d4a4c9e573172

commit 7ad28b73ec1fd78a28a708da442d4a4c9e573172
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2023-08-23 12:34:09 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2023-09-01 09:49:18 +0000

    arm: Add a userspace physical timer check
    
    We currently use the same Arm generic time in both userspace and the
    kernel. As we always enable userspace access to the virtual timer we
    can tell userspace to use it.
    
    Reviewed by:    imp
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D41565
---
 sys/arm/arm/generic_timer.c | 41 ++++++++++++++++++++++++++---------------
 1 file changed, 26 insertions(+), 15 deletions(-)

diff --git a/sys/arm/arm/generic_timer.c b/sys/arm/arm/generic_timer.c
index b9562620848f..998259c5c90f 100644
--- a/sys/arm/arm/generic_timer.c
+++ b/sys/arm/arm/generic_timer.c
@@ -110,7 +110,8 @@ struct arm_tmr_softc {
 	uint32_t		clkfreq;
 	int			irq_count;
 	struct eventtimer	et;
-	bool			physical;
+	bool			physical_sys;
+	bool			physical_user;
 };
 
 static struct arm_tmr_softc *arm_tmr_sc = NULL;
@@ -271,7 +272,7 @@ setup_user_access(void *arg __unused)
 	/* Always enable the virtual timer */
 	cntkctl |= GT_CNTKCTL_PL0VCTEN;
 	/* Enable the physical timer if supported */
-	if (arm_tmr_sc->physical) {
+	if (arm_tmr_sc->physical_user) {
 		cntkctl |= GT_CNTKCTL_PL0PCTEN;
 	}
 	set_el1(cntkctl, cntkctl);
@@ -333,7 +334,7 @@ static unsigned
 arm_tmr_get_timecount(struct timecounter *tc)
 {
 
-	return (arm_tmr_sc->get_cntxct(arm_tmr_sc->physical));
+	return (arm_tmr_sc->get_cntxct(arm_tmr_sc->physical_sys));
 }
 
 static int
@@ -347,11 +348,11 @@ arm_tmr_start(struct eventtimer *et, sbintime_t first,
 
 	if (first != 0) {
 		counts = ((uint32_t)et->et_frequency * first) >> 32;
-		ctrl = get_ctrl(sc->physical);
+		ctrl = get_ctrl(sc->physical_sys);
 		ctrl &= ~GT_CTRL_INT_MASK;
 		ctrl |= GT_CTRL_ENABLE;
-		set_tval(counts, sc->physical);
-		set_ctrl(ctrl, sc->physical);
+		set_tval(counts, sc->physical_sys);
+		set_ctrl(ctrl, sc->physical_sys);
 		return (0);
 	}
 
@@ -375,7 +376,7 @@ arm_tmr_stop(struct eventtimer *et)
 	struct arm_tmr_softc *sc;
 
 	sc = (struct arm_tmr_softc *)et->et_priv;
-	arm_tmr_disable(sc->physical);
+	arm_tmr_disable(sc->physical_sys);
 
 	return (0);
 }
@@ -387,10 +388,10 @@ arm_tmr_intr(void *arg)
 	int ctrl;
 
 	sc = (struct arm_tmr_softc *)arg;
-	ctrl = get_ctrl(sc->physical);
+	ctrl = get_ctrl(sc->physical_sys);
 	if (ctrl & GT_CTRL_INT_STAT) {
 		ctrl |= GT_CTRL_INT_MASK;
-		set_ctrl(ctrl, sc->physical);
+		set_ctrl(ctrl, sc->physical_sys);
 	}
 
 	if (sc->et.et_active)
@@ -616,7 +617,7 @@ arm_tmr_attach(device_t dev)
 	phandle_t node;
 	pcell_t clock;
 #endif
-	int error;
+	int error, user_phys;
 	int i, first_timer, last_timer;
 
 	sc = device_get_softc(dev);
@@ -680,18 +681,28 @@ arm_tmr_attach(device_t dev)
 	 * coordinated with the virtual machine manager.
 	 */
 	if (!HAS_PHYS) {
-		sc->physical = false;
+		sc->physical_sys = false;
 		first_timer = GT_VIRT;
 		last_timer = GT_VIRT;
 	} else
 #endif
 	/* Otherwise set up the secure and non-secure physical timers. */
 	{
-		sc->physical = true;
+		sc->physical_sys = true;
 		first_timer = GT_PHYS_SECURE;
 		last_timer = GT_PHYS_NONSECURE;
 	}
 
+	/*
+	 * The virtual timer is always available on arm and arm64, tell
+	 * userspace to use it.
+	 */
+	sc->physical_user = false;
+	/* Allow use of the physical counter in userspace when available */
+	if (TUNABLE_INT_FETCH("hw.userspace_allow_phys_counter", &user_phys) &&
+	    user_phys != 0)
+		sc->physical_user = sc->physical_sys;
+
 	arm_tmr_sc = sc;
 
 	/* Setup secure, non-secure and virtual IRQs handler */
@@ -790,10 +801,10 @@ arm_tmr_do_delay(int usec, void *arg)
 	else
 		counts = usec * counts_per_usec;
 
-	first = sc->get_cntxct(sc->physical);
+	first = sc->get_cntxct(sc->physical_sys);
 
 	while (counts > 0) {
-		last = sc->get_cntxct(sc->physical);
+		last = sc->get_cntxct(sc->physical_sys);
 		counts -= (int32_t)(last - first);
 		first = last;
 	}
@@ -830,7 +841,7 @@ arm_tmr_fill_vdso_timehands(struct vdso_timehands *vdso_th,
 {
 
 	vdso_th->th_algo = VDSO_TH_ALGO_ARM_GENTIM;
-	vdso_th->th_physical = arm_tmr_sc->physical;
+	vdso_th->th_physical = arm_tmr_sc->physical_user;
 	bzero(vdso_th->th_res, sizeof(vdso_th->th_res));
 	return (1);
 }