The StarFive JH7100 SoC found on the BeagleV beta boards has most of
authorkettenis <kettenis@openbsd.org>
Wed, 5 May 2021 19:26:51 +0000 (19:26 +0000)
committerkettenis <kettenis@openbsd.org>
Wed, 5 May 2021 19:26:51 +0000 (19:26 +0000)
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@

sys/arch/riscv64/conf/GENERIC
sys/arch/riscv64/conf/RAMDISK
sys/arch/riscv64/conf/files.riscv64
sys/arch/riscv64/dev/sfcc.c [new file with mode: 0644]
sys/arch/riscv64/include/cpufunc.h
sys/arch/riscv64/riscv64/bus_dma.c
sys/arch/riscv64/riscv64/cpu.c

index 4014ac7..1aac99a 100644 (file)
@@ -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?
index 4c6eb61..6c9f1a2 100644 (file)
@@ -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?
index f0d0db5..f137da9 100644 (file)
@@ -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 (file)
index 0000000..b05401d
--- /dev/null
@@ -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;
+       }
+}
index e1cce97..c171da0 100644 (file)
@@ -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)
index ebd5a5d..0d424a2 100644 (file)
@@ -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++;
index 89b49fe..11203d2 100644 (file)
@@ -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;