Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 17 Feb 2025 16:37:00 GMT
From:      Andrew Turner <andrew@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 43b3e755d075 - main - arm64: use FEAT_WFxT for DELAY() when available
Message-ID:  <202502171637.51HGb0kT082898@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by andrew:

URL: https://cgit.FreeBSD.org/src/commit/?id=43b3e755d07576da8a169a2d000d0f4b4ce33f19

commit 43b3e755d07576da8a169a2d000d0f4b4ce33f19
Author:     Harry Moulton <harry.moulton@arm.com>
AuthorDate: 2025-02-17 16:01:48 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2025-02-17 16:07:36 +0000

    arm64: use FEAT_WFxT for DELAY() when available
    
    Use a wfet, rather than a busy wait, in DELAY() when the FEAT_WFxT
    extension is available.
    
    Reviewed by:    andrew
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D48580
    Signed-off-by: Harry Moulton <harry.moulton@arm.com>
---
 sys/arm/arm/generic_timer.c | 86 +++++++++++++++++++++++++++++++++++----------
 1 file changed, 67 insertions(+), 19 deletions(-)

diff --git a/sys/arm/arm/generic_timer.c b/sys/arm/arm/generic_timer.c
index 775290960ebd..685398117396 100644
--- a/sys/arm/arm/generic_timer.c
+++ b/sys/arm/arm/generic_timer.c
@@ -60,6 +60,8 @@
 
 #if defined(__aarch64__)
 #include <machine/undefined.h>
+#include <machine/cpufunc.h>
+#include <machine/cpu_feat.h>
 #endif
 
 #ifdef FDT
@@ -94,6 +96,10 @@
 #define	GT_CNTKCTL_PL0VCTEN	(1 << 1) /* PL0 CNTVCT and CNTFRQ access */
 #define	GT_CNTKCTL_PL0PCTEN	(1 << 0) /* PL0 CNTPCT and CNTFRQ access */
 
+#if defined(__aarch64__)
+static bool __read_mostly enable_wfxt = false;
+#endif
+
 struct arm_tmr_softc;
 
 struct arm_tmr_irq {
@@ -805,12 +811,10 @@ EARLY_DRIVER_MODULE(timer, acpi, arm_tmr_acpi_driver, 0, 0,
     BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
 #endif
 
-static void
-arm_tmr_do_delay(int usec, void *arg)
+static int64_t
+arm_tmr_get_counts(int usec)
 {
-	struct arm_tmr_softc *sc = arg;
-	int32_t counts, counts_per_usec;
-	uint32_t first, last;
+	int64_t counts, counts_per_usec;
 
 	/* Get the number of times to count */
 	counts_per_usec = ((arm_tmr_timecount.tc_frequency / 1000000) + 1);
@@ -826,12 +830,30 @@ arm_tmr_do_delay(int usec, void *arg)
 	else
 		counts = usec * counts_per_usec;
 
+	return counts;
+}
+
+static void
+arm_tmr_do_delay(int usec, void *arg)
+{
+	struct arm_tmr_softc *sc = arg;
+	int64_t counts;
+	uint64_t first;
+#if defined(__aarch64__)
+	int64_t end;
+#endif
+
+	counts = arm_tmr_get_counts(usec);
 	first = sc->get_cntxct(sc->physical_sys);
+#if defined(__aarch64__)
+	end = first + counts;
+#endif
 
-	while (counts > 0) {
-		last = sc->get_cntxct(sc->physical_sys);
-		counts -= (int32_t)(last - first);
-		first = last;
+	while ((sc->get_cntxct(sc->physical_sys) - first) < counts) {
+#if defined(__aarch64__)
+		if (enable_wfxt)
+			wfet(end);
+#endif
 	}
 }
 
@@ -843,21 +865,47 @@ DELAY(int usec)
 
 	TSENTER();
 	/*
-	 * Check the timers are setup, if not just
-	 * use a for loop for the meantime
-	 */
-	if (arm_tmr_sc == NULL) {
+	 * We have two options for a delay: using the timer, or using the wfet
+	 * instruction. However, both of these are dependent on timers being
+	 * setup, and if they're not just use a loop for the meantime.
+	*/
+	if (arm_tmr_sc != NULL) {
+		arm_tmr_do_delay(usec, arm_tmr_sc);
+	} else {
 		for (; usec > 0; usec--)
 			for (counts = 200; counts > 0; counts--)
-				/*
-				 * Prevent the compiler from optimizing
-				 * out the loop
-				 */
+				/* Prevent the compiler from optimizing out the loop */
 				cpufunc_nullop();
-	} else
-		arm_tmr_do_delay(usec, arm_tmr_sc);
+	}
 	TSEXIT();
 }
+
+static bool
+wfxt_check(const struct cpu_feat *feat __unused, u_int midr __unused)
+{
+	uint64_t id_aa64isar2;
+
+	if (!get_kernel_reg(ID_AA64ISAR2_EL1, &id_aa64isar2))
+		return (false);
+	return (ID_AA64ISAR2_WFxT_VAL(id_aa64isar2) != ID_AA64ISAR2_WFxT_NONE);
+}
+
+static void
+wfxt_enable(const struct cpu_feat *feat __unused,
+    cpu_feat_errata errata_status __unused, u_int *errata_list __unused,
+    u_int errata_count __unused)
+{
+	/* will be called if wfxt_check returns true */
+	enable_wfxt = true;
+}
+
+static struct cpu_feat feat_wfxt = {
+	.feat_name		= "FEAT_WFXT",
+	.feat_check		= wfxt_check,
+	.feat_enable		= wfxt_enable,
+	.feat_flags		= CPU_FEAT_AFTER_DEV | CPU_FEAT_SYSTEM,
+};
+DATA_SET(cpu_feat_set, feat_wfxt);
 #endif
 
 static uint32_t



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202502171637.51HGb0kT082898>