From 316cf7515abc4a78b41103f8b88945b4dbb3773c Mon Sep 17 00:00:00 2001 From: kettenis Date: Wed, 5 May 2021 19:26:51 +0000 Subject: [PATCH] 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@ --- sys/arch/riscv64/conf/GENERIC | 2 + sys/arch/riscv64/conf/RAMDISK | 4 +- sys/arch/riscv64/conf/files.riscv64 | 4 + sys/arch/riscv64/dev/sfcc.c | 110 ++++++++++++++++++++++++++++ sys/arch/riscv64/include/cpufunc.h | 6 +- sys/arch/riscv64/riscv64/bus_dma.c | 20 ++--- sys/arch/riscv64/riscv64/cpu.c | 9 +++ 7 files changed, 141 insertions(+), 14 deletions(-) create mode 100644 sys/arch/riscv64/dev/sfcc.c 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 + * + * 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 +#include +#include + +#include +#include +#include + +#include +#include + +/* 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; -- 2.20.1