summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2021-05-05 19:26:52 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2021-05-05 19:26:52 +0000
commitd900f64c090dc3a88917f39f50f28726d6c01c99 (patch)
tree4f84c0ef72791990bf1aa06875a2858ada3ca343
parent768fd8d57afb4404cbdc02c38c79b7e84e13ac89 (diff)
The StarFive JH7100 SoC found on the BeagleV beta boards has most of
its peripherals hooked up through a bus that doesn't maintain cache coherency. So in order to use DMA we will need to flush the L2 caches before/after a DMA tranfer. Add a driver for the L2 cache controller for these SoCs and infrastructure to do the necessary cache maintenance. Since this particular L2 cache controller needs physical addresses, this makes the bus_dma(4) code deviate from its arm64 counterpart. ok drahn@
-rw-r--r--sys/arch/riscv64/conf/GENERIC2
-rw-r--r--sys/arch/riscv64/conf/RAMDISK4
-rw-r--r--sys/arch/riscv64/conf/files.riscv644
-rw-r--r--sys/arch/riscv64/dev/sfcc.c110
-rw-r--r--sys/arch/riscv64/include/cpufunc.h6
-rw-r--r--sys/arch/riscv64/riscv64/bus_dma.c20
-rw-r--r--sys/arch/riscv64/riscv64/cpu.c9
7 files changed, 141 insertions, 14 deletions
diff --git a/sys/arch/riscv64/conf/GENERIC b/sys/arch/riscv64/conf/GENERIC
index 4014ac7349b..1aac99a6de9 100644
--- a/sys/arch/riscv64/conf/GENERIC
+++ b/sys/arch/riscv64/conf/GENERIC
@@ -45,6 +45,8 @@ viornd* at virtio? # Random Source
simplebus* at fdt?
# Platform Level Interrupt Controller
plic* at fdt? early 1
+# L2 Cache Controller
+sfcc* at fdt? early 1
syscon* at fdt? early 1
gfrtc* at fdt?
diff --git a/sys/arch/riscv64/conf/RAMDISK b/sys/arch/riscv64/conf/RAMDISK
index 4c6eb617020..6c9f1a2e7fb 100644
--- a/sys/arch/riscv64/conf/RAMDISK
+++ b/sys/arch/riscv64/conf/RAMDISK
@@ -1,4 +1,4 @@
-# $OpenBSD: RAMDISK,v 1.6 2021/05/04 16:38:06 kettenis Exp $
+# $OpenBSD: RAMDISK,v 1.7 2021/05/05 19:26:51 kettenis Exp $
#
# GENERIC machine description file
#
@@ -64,6 +64,8 @@ viornd* at virtio? # Random Source
simplebus* at fdt?
# Platform Level Interrupt Controller
plic* at fdt? early 1
+# L2 Cache Controller
+sfcc* at fdt? early 1
syscon* at fdt? early 1
gfrtc* at fdt?
diff --git a/sys/arch/riscv64/conf/files.riscv64 b/sys/arch/riscv64/conf/files.riscv64
index f0d0db59a91..f137da9c369 100644
--- a/sys/arch/riscv64/conf/files.riscv64
+++ b/sys/arch/riscv64/conf/files.riscv64
@@ -80,6 +80,10 @@ device plic
attach plic at fdt
file arch/riscv64/dev/plic.c plic
+# L2 cache controller
+device sfcc
+attach sfcc at fdt
+file arch/riscv64/dev/sfcc.c sfcc
# Paravirtual device bus and virtio
include "dev/pv/files.pv"
diff --git a/sys/arch/riscv64/dev/sfcc.c b/sys/arch/riscv64/dev/sfcc.c
new file mode 100644
index 00000000000..b05401d7e50
--- /dev/null
+++ b/sys/arch/riscv64/dev/sfcc.c
@@ -0,0 +1,110 @@
+/* $OpenBSD: sfcc.c,v 1.1 2021/05/05 19:26:51 kettenis Exp $ */
+/*
+ * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+#include <machine/cpufunc.h>
+#include <machine/fdt.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/fdt.h>
+
+/* Registers. */
+#define SFCC_FLUSH64 0x200
+
+struct sfcc_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+
+ uint32_t sc_line_size;
+};
+
+struct sfcc_softc *sfcc_sc;
+
+int sfcc_match(struct device *, void *, void *);
+void sfcc_attach(struct device *, struct device *, void *);
+
+const struct cfattach sfcc_ca = {
+ sizeof (struct sfcc_softc), sfcc_match, sfcc_attach
+};
+
+struct cfdriver sfcc_cd = {
+ NULL, "sfcc", DV_DULL
+};
+
+void sfcc_cache_wbinv_range(vaddr_t, vsize_t);
+
+int
+sfcc_match(struct device *parent, void *match, void *aux)
+{
+ struct fdt_attach_args *faa = aux;
+
+ return OF_is_compatible(faa->fa_node, "sifive,fu540-c000-ccache");
+}
+
+void
+sfcc_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct sfcc_softc *sc = (struct sfcc_softc *)self;
+ struct fdt_attach_args *faa = aux;
+
+ if (faa->fa_nreg < 1) {
+ printf(": no registers\n");
+ return;
+ }
+
+ sc->sc_iot = faa->fa_iot;
+ if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
+ faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
+ printf(": can't map registers\n");
+ return;
+ }
+
+ printf("\n");
+
+ sc->sc_line_size = OF_getpropint(faa->fa_node, "cache-block-size", 64);
+ sfcc_sc = sc;
+
+ /*
+ * Cache lines can only be flushed, so we use the same
+ * operation everywhere.
+ */
+ cpu_dcache_wbinv_range = sfcc_cache_wbinv_range;
+ cpu_dcache_inv_range = sfcc_cache_wbinv_range;
+ cpu_dcache_wb_range = sfcc_cache_wbinv_range;
+}
+
+void
+sfcc_cache_wbinv_range(paddr_t pa, paddr_t len)
+{
+ struct sfcc_softc *sc = sfcc_sc;
+
+ len += pa & (sc->sc_line_size - 1);
+ pa &= ~(sc->sc_line_size - 1);
+
+ __asm volatile ("fence iorw,iorw" ::: "memory");
+ while (len > 0) {
+ bus_space_write_8(sc->sc_iot, sc->sc_ioh, SFCC_FLUSH64, pa);
+ __asm volatile ("fence iorw,iorw" ::: "memory");
+ pa += sc->sc_line_size;
+ len -= sc->sc_line_size;
+ }
+}
diff --git a/sys/arch/riscv64/include/cpufunc.h b/sys/arch/riscv64/include/cpufunc.h
index e1cce97ec17..c171da0bed2 100644
--- a/sys/arch/riscv64/include/cpufunc.h
+++ b/sys/arch/riscv64/include/cpufunc.h
@@ -87,9 +87,9 @@ sfence_vma_page_asid(uintptr_t addr, uint64_t asid)
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)
+extern void (*cpu_dcache_wbinv_range)(paddr_t, psize_t);
+extern void (*cpu_dcache_inv_range)(paddr_t, psize_t);
+extern void (*cpu_dcache_wb_range)(paddr_t, psize_t);
#define cpu_idcache_wbinv_range(a, s)
#define cpu_icache_sync_range(a, s)
diff --git a/sys/arch/riscv64/riscv64/bus_dma.c b/sys/arch/riscv64/riscv64/bus_dma.c
index ebd5a5dbe08..0d424a247af 100644
--- a/sys/arch/riscv64/riscv64/bus_dma.c
+++ b/sys/arch/riscv64/riscv64/bus_dma.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: bus_dma.c,v 1.2 2021/05/05 13:12:26 kettenis Exp $ */
+/* $OpenBSD: bus_dma.c,v 1.3 2021/05/05 19:26:51 kettenis Exp $ */
/*
* Copyright (c) 2003-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -359,20 +359,20 @@ _dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map)
}
static void
-_dmamap_sync_segment(vaddr_t va, vsize_t len, int ops)
+_dmamap_sync_segment(paddr_t pa, psize_t len, int ops)
{
switch (ops) {
case BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE:
case BUS_DMASYNC_PREREAD:
- cpu_dcache_wbinv_range(va, len);
+ cpu_dcache_wbinv_range(pa, len);
break;
case BUS_DMASYNC_PREWRITE:
- cpu_dcache_wb_range(va, len);
+ cpu_dcache_wb_range(pa, len);
break;
/*
- * Cortex CPUs can do speculative loads so we need to clean the cache
+ * RISC-V CPUs can do speculative loads so we need to clean the cache
* after a DMA read to deal with any speculatively loaded cache lines.
* Since these can't be dirty, we can just invalidate them and don't
* have to worry about having to write back their contents.
@@ -380,7 +380,7 @@ _dmamap_sync_segment(vaddr_t va, vsize_t len, int ops)
case BUS_DMASYNC_POSTREAD:
case BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE:
membar_sync();
- cpu_dcache_inv_range(va, len);
+ cpu_dcache_inv_range(pa, len);
break;
}
}
@@ -410,18 +410,18 @@ _dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t addr,
curseg = 0;
while (size && nsegs) {
- vaddr_t vaddr;
+ paddr_t paddr;
bus_size_t ssize;
ssize = map->dm_segs[curseg].ds_len;
- vaddr = map->dm_segs[curseg]._ds_vaddr;
+ paddr = map->dm_segs[curseg]._ds_paddr;
if (addr != 0) {
if (addr >= ssize) {
addr -= ssize;
ssize = 0;
} else {
- vaddr += addr;
+ paddr += addr;
ssize -= addr;
addr = 0;
}
@@ -430,7 +430,7 @@ _dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t addr,
ssize = size;
if (ssize != 0) {
- _dmamap_sync_segment(vaddr, ssize, op);
+ _dmamap_sync_segment(paddr, ssize, op);
size -= ssize;
}
curseg++;
diff --git a/sys/arch/riscv64/riscv64/cpu.c b/sys/arch/riscv64/riscv64/cpu.c
index 89b49fe9eca..11203d2e5f8 100644
--- a/sys/arch/riscv64/riscv64/cpu.c
+++ b/sys/arch/riscv64/riscv64/cpu.c
@@ -180,3 +180,12 @@ cpu_clockspeed(int *freq)
*freq = clock_get_frequency(cpu_node, NULL) / 1000000;
return 0;
}
+
+void
+cpu_cache_nop_range(paddr_t pa, psize_t len)
+{
+}
+
+void (*cpu_dcache_wbinv_range)(paddr_t, psize_t) = cpu_cache_nop_range;
+void (*cpu_dcache_inv_range)(paddr_t, psize_t) = cpu_cache_nop_range;
+void (*cpu_dcache_wb_range)(paddr_t, psize_t) = cpu_cache_nop_range;