git: dfe57951f061 - main - riscv: add custom T-HEAD dcache ops

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

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

commit dfe57951f0610c6de42190b32c7ed844a97ee593
Author:     Mitchell Horne <mhorne@FreeBSD.org>
AuthorDate: 2024-11-21 18:11:51 +0000
Commit:     Mitchell Horne <mhorne@FreeBSD.org>
CommitDate: 2024-11-25 21:08:04 +0000

    riscv: add custom T-HEAD dcache ops
    
    This is the first major quirk we need to support in order to run on
    current T-HEAD/XuanTie CPUs, e.g. the C906 or C910, found in several
    existing RISC-V SBCs. With these custom dcache routines installed,
    busdma can reliably communicate with devices which are not coherent
    w.r.t. the CPU's data caches.
    
    This patch introduces the first quirk/errata handling functions to
    identcpu.c, and thus is forced to make some decisions about how this
    code is structured. It will be amended with the changes that follow in
    the series, yet I feel the final result is (unavoidably) somewhat
    clumsy. I expect the CPU identification code will continue to evolve as
    more CPUs and their quirks are eventually supported.
    
    Discussed with: jrtc27
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D47455
---
 sys/conf/files.riscv       |  2 +
 sys/riscv/include/thead.h  | 35 ++++++++++++++++
 sys/riscv/riscv/identcpu.c | 21 ++++++++++
 sys/riscv/thead/thead.c    | 99 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 157 insertions(+)

diff --git a/sys/conf/files.riscv b/sys/conf/files.riscv
index 915bce34603d..6186ae9b3371 100644
--- a/sys/conf/files.riscv
+++ b/sys/conf/files.riscv
@@ -84,5 +84,7 @@ riscv/vmm/vmm_riscv.c				optional	vmm
 riscv/vmm/vmm_sbi.c				optional	vmm
 riscv/vmm/vmm_switch.S				optional	vmm
 
+riscv/thead/thead.c		standard
+
 # Zstd
 contrib/zstd/lib/freebsd/zstd_kfreebsd.c		optional zstdio compile-with ${ZSTD_C}
diff --git a/sys/riscv/include/thead.h b/sys/riscv/include/thead.h
new file mode 100644
index 000000000000..e11d5c37374c
--- /dev/null
+++ b/sys/riscv/include/thead.h
@@ -0,0 +1,35 @@
+/*-
+ * 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.
+ */
+#ifndef _RISCV_THEAD_H_
+#define	_RISCV_THEAD_H_
+
+void thead_setup_cache(void);
+
+#endif /* _RISCV_THEAD_H_ */
diff --git a/sys/riscv/riscv/identcpu.c b/sys/riscv/riscv/identcpu.c
index 7823830c3136..f85aed88d3b9 100644
--- a/sys/riscv/riscv/identcpu.c
+++ b/sys/riscv/riscv/identcpu.c
@@ -52,6 +52,7 @@
 #include <machine/cpufunc.h>
 #include <machine/elf.h>
 #include <machine/md_var.h>
+#include <machine/thead.h>
 
 #ifdef FDT
 #include <dev/fdt/fdt_common.h>
@@ -463,6 +464,25 @@ identify_cpu_ids(struct cpu_desc *desc)
 	}
 }
 
+static void
+handle_thead_quirks(u_int cpu, struct cpu_desc *desc)
+{
+	if (cpu != 0)
+		return;
+
+	thead_setup_cache();
+}
+
+static void
+handle_cpu_quirks(u_int cpu, struct cpu_desc *desc)
+{
+	switch (mvendorid) {
+	case MVENDORID_THEAD:
+		handle_thead_quirks(cpu, desc);
+		break;
+	}
+}
+
 void
 identify_cpu(u_int cpu)
 {
@@ -472,6 +492,7 @@ identify_cpu(u_int cpu)
 	identify_cpu_features(cpu, desc);
 
 	update_global_capabilities(cpu, desc);
+	handle_cpu_quirks(cpu, desc);
 }
 
 void
diff --git a/sys/riscv/thead/thead.c b/sys/riscv/thead/thead.c
new file mode 100644
index 000000000000..f959d32cfed8
--- /dev/null
+++ b/sys/riscv/thead/thead.c
@@ -0,0 +1,99 @@
+/*-
+ * 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 <machine/thead.h>
+
+/* ----------------- dcache ops --------------------- */
+
+
+/* th.dcache.civa: clean & invalidate at VA stored in t0. */
+#define	THEAD_DCACHE_CIVA	".long 0x0272800b\n"
+
+/* th.dcache.iva: invalidate at VA stored in t0. */
+#define	THEAD_DCACHE_IVA	".long 0x0262800b\n"
+
+/* th.dcache.cva: clean at VA stored in t0. */
+#define	THEAD_DCACHE_CVA	".long 0x0252800b\n"
+
+/* th.sync.s: two-way instruction barrier */
+#define	THEAD_SYNC_S		".long 0x0190000b\n"
+
+/* MHTODO: we could parse this information from the device tree. */
+#define	THEAD_DCACHE_SIZE	64
+
+static void
+thead_cpu_dcache_wbinv_range(vm_offset_t va, vm_size_t len)
+{
+	register vm_offset_t t0 __asm("t0") = rounddown(va, dcache_line_size);
+
+	for (; t0 < va + len; t0 += dcache_line_size) {
+		__asm __volatile(THEAD_DCACHE_CIVA
+		                 :: "r" (t0) : "memory");
+	}
+	__asm __volatile(THEAD_SYNC_S ::: "memory");
+}
+
+static void
+thead_cpu_dcache_inv_range(vm_offset_t va, vm_size_t len)
+{
+	register vm_offset_t t0 __asm("t0") = rounddown(va, dcache_line_size);
+
+	for (; t0 < va + len; t0 += dcache_line_size) {
+		__asm __volatile(THEAD_DCACHE_IVA
+				 :: "r" (t0) : "memory");
+	}
+	__asm __volatile(THEAD_SYNC_S ::: "memory");
+}
+
+static void
+thead_cpu_dcache_wb_range(vm_offset_t va, vm_size_t len)
+{
+	register vm_offset_t t0 __asm("t0") = rounddown(va, dcache_line_size);
+
+	for (; t0 < va + len; t0 += dcache_line_size) {
+		__asm __volatile(THEAD_DCACHE_CVA
+				 :: "r" (t0) : "memory");
+	}
+	__asm __volatile(THEAD_SYNC_S ::: "memory");
+}
+
+void
+thead_setup_cache(void)
+{
+	struct riscv_cache_ops thead_ops;
+
+	thead_ops.dcache_wbinv_range = thead_cpu_dcache_wbinv_range;
+	thead_ops.dcache_inv_range = thead_cpu_dcache_inv_range;
+	thead_ops.dcache_wb_range = thead_cpu_dcache_wb_range;
+
+	riscv_cache_install_hooks(&thead_ops, THEAD_DCACHE_SIZE);
+}