git: 43b3e755d075 - main - arm64: use FEAT_WFxT for DELAY() when available
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 17 Feb 2025 16:37:00 UTC
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