git: 4ab2a84e0924 - main - riscv: dcache flush hooks

From: Mitchell Horne <mhorne_at_FreeBSD.org>
Date: Mon, 25 Nov 2024 21:08:45 UTC
The branch main has been updated by mhorne:

URL: https://cgit.FreeBSD.org/src/commit/?id=4ab2a84e092467be04d3c85ab2ceebc1e722004c

commit 4ab2a84e092467be04d3c85ab2ceebc1e722004c
Author:     Mitchell Horne <mhorne@FreeBSD.org>
AuthorDate: 2024-11-21 18:11:30 +0000
Commit:     Mitchell Horne <mhorne@FreeBSD.org>
CommitDate: 2024-11-25 21:08:03 +0000

    riscv: dcache flush hooks
    
    Cache management operations were, for a long time, unspecified by the
    RISC-V ISA, and thus these functions have been no-ops. To cope, hardware
    with non-coherent I/O has implemented custom cache flush mechanisms,
    either in the form of custom instructions or special device registers.
    Additionally, the RISC-V CMO extension is ratified and these official
    instructions will start to show up in hardware eventually. Therefore, a
    method is needed to select the dcache management routines at runtime.
    
    Add a simple set of function hooks, as well as a routine to install them
    and specify the minimum dcache line size. The first consumer will be the
    non-standard cache management instructions for T-HEAD CPUs.
    
    The unused I-cache variables and macros are removed.
    
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D47454
---
 sys/conf/files.riscv        |  1 +
 sys/riscv/include/cpufunc.h | 42 +++++++++++++++++++++++++++++------
 sys/riscv/riscv/cache.c     | 53 +++++++++++++++++++++++++++++++++++++++++++++
 sys/riscv/riscv/machdep.c   | 17 ---------------
 sys/riscv/riscv/pmap.c      |  2 +-
 5 files changed, 90 insertions(+), 25 deletions(-)

diff --git a/sys/conf/files.riscv b/sys/conf/files.riscv
index d325502e03ee..915bce34603d 100644
--- a/sys/conf/files.riscv
+++ b/sys/conf/files.riscv
@@ -36,6 +36,7 @@ riscv/riscv/bus_machdep.c	standard
 riscv/riscv/bus_space_asm.S	standard
 riscv/riscv/busdma_bounce.c	standard
 riscv/riscv/busdma_machdep.c	standard
+riscv/riscv/cache.c		standard
 riscv/riscv/clock.c		standard
 riscv/riscv/copyinout.S		standard
 riscv/riscv/cpufunc_asm.S	standard
diff --git a/sys/riscv/include/cpufunc.h b/sys/riscv/include/cpufunc.h
index 4521e1605d8f..8f5b87d24ce3 100644
--- a/sys/riscv/include/cpufunc.h
+++ b/sys/riscv/include/cpufunc.h
@@ -44,6 +44,8 @@ breakpoint(void)
 
 #ifdef _KERNEL
 
+#include <sys/_null.h>
+
 #include <machine/riscvreg.h>
 
 static __inline register_t
@@ -107,16 +109,42 @@ sfence_vma_page(uintptr_t addr)
 #define	rdinstret()			csr_read64(instret)
 #define	rdhpmcounter(n)			csr_read64(hpmcounter##n)
 
+/* Cache hooks. */
+
 extern int64_t dcache_line_size;
-extern int64_t icache_line_size;
 
-#define	cpu_dcache_wbinv_range(a, s)
-#define	cpu_dcache_inv_range(a, s)
-#define	cpu_dcache_wb_range(a, s)
+typedef void (*cache_op_t)(vm_offset_t start, vm_size_t size);
+
+struct riscv_cache_ops {
+	cache_op_t dcache_wbinv_range;
+	cache_op_t dcache_inv_range;
+	cache_op_t dcache_wb_range;
+};
+
+extern struct riscv_cache_ops cache_ops;
+
+static __inline void
+cpu_dcache_wbinv_range(vm_offset_t addr, vm_size_t size)
+{
+	if (cache_ops.dcache_wbinv_range != NULL)
+		cache_ops.dcache_wbinv_range(addr, size);
+}
+
+static __inline void
+cpu_dcache_inv_range(vm_offset_t addr, vm_size_t size)
+{
+	if (cache_ops.dcache_inv_range != NULL)
+		cache_ops.dcache_inv_range(addr, size);
+}
+
+static __inline void
+cpu_dcache_wb_range(vm_offset_t addr, vm_size_t size)
+{
+	if (cache_ops.dcache_wb_range != NULL)
+		cache_ops.dcache_wb_range(addr, size);
+}
 
-#define	cpu_idcache_wbinv_range(a, s)
-#define	cpu_icache_sync_range(a, s)
-#define	cpu_icache_sync_range_checked(a, s)
+void riscv_cache_install_hooks(struct riscv_cache_ops *, u_int);
 
 #define	cpufunc_nullop()		riscv_nullop()
 
diff --git a/sys/riscv/riscv/cache.c b/sys/riscv/riscv/cache.c
new file mode 100644
index 000000000000..edbaebc9abd6
--- /dev/null
+++ b/sys/riscv/riscv/cache.c
@@ -0,0 +1,53 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 The FreeBSD Foundation
+ *
+ * This software was developed by Mitchell Horne <mhorne@FreeBSD.org> under
+ * sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+
+#include <machine/cpufunc.h>
+
+struct riscv_cache_ops __read_frequently cache_ops;
+
+int64_t __read_frequently dcache_line_size;	/* The minimum D cache line size */
+
+static bool cache_initialized;
+
+void
+riscv_cache_install_hooks(struct riscv_cache_ops *newops, u_int line_size)
+{
+	if (cache_initialized)
+		panic("cache hooks already installed!");
+
+	bcopy(newops, &cache_ops, sizeof(cache_ops));
+	dcache_line_size = line_size;
+
+	cache_initialized = true;
+}
diff --git a/sys/riscv/riscv/machdep.c b/sys/riscv/riscv/machdep.c
index eda7ebc32bbf..c5da4832dd36 100644
--- a/sys/riscv/riscv/machdep.c
+++ b/sys/riscv/riscv/machdep.c
@@ -113,10 +113,6 @@ int cold = 1;
 
 struct kva_md_info kmi;
 
-int64_t dcache_line_size;	/* The minimum D cache line size */
-int64_t icache_line_size;	/* The minimum I cache line size */
-int64_t idcache_line_size;	/* The minimum cache line size */
-
 #define BOOT_HART_INVALID	0xffffffff
 uint32_t boot_hart = BOOT_HART_INVALID;	/* The hart we booted on. */
 
@@ -329,17 +325,6 @@ try_load_dtb(caddr_t kmdp)
 }
 #endif
 
-static void
-cache_setup(void)
-{
-
-	/* TODO */
-
-	dcache_line_size = 0;
-	icache_line_size = 0;
-	idcache_line_size = 0;
-}
-
 /*
  * Fake up a boot descriptor table.
  */
@@ -550,8 +535,6 @@ initriscv(struct riscv_bootparams *rvbp)
 	/* Do basic tuning, hz etc */
 	init_param1();
 
-	cache_setup();
-
 #ifdef FDT
 	/*
 	 * XXX: Unconditionally exclude the lowest 2MB of physical memory, as
diff --git a/sys/riscv/riscv/pmap.c b/sys/riscv/riscv/pmap.c
index 69eb36c2cd4c..e11adba0d832 100644
--- a/sys/riscv/riscv/pmap.c
+++ b/sys/riscv/riscv/pmap.c
@@ -5013,7 +5013,7 @@ pmap_change_attr_locked(vm_offset_t va, vm_size_t size, int mode)
 	if (anychanged) {
 		pmap_invalidate_range(kernel_pmap, base, tmpva);
 		if (mode == VM_MEMATTR_UNCACHEABLE)
-			cpu_dcache_wbinv_range((void *)base, size);
+			cpu_dcache_wbinv_range(base, size);
 	}
 
 	return (error);