soc: add initial DMA bus support (optionally provided by CPU(s) for cache coherency).

When provided, the modules doing DMA shall connect the DMA to the dma_bus to allow the CPU(s) to manage cache coherency
and avoid the manual cache flushes.

This has been tested with VexRiscv SMP and LiteSDCard doing DMA while loading Linux binaries.
This commit is contained in:
Florent Kermarrec 2020-07-22 18:43:28 +02:00
parent 2361abb12d
commit d38048baac
2 changed files with 44 additions and 8 deletions

View File

@ -106,8 +106,8 @@ class SoCBusHandler(Module):
supported_address_width = [32] supported_address_width = [32]
# Creation ------------------------------------------------------------------------------------- # Creation -------------------------------------------------------------------------------------
def __init__(self, standard, data_width=32, address_width=32, timeout=1e6, reserved_regions={}): def __init__(self, name="SoCBusHandler", standard="wishbone", data_width=32, address_width=32, timeout=1e6, reserved_regions={}):
self.logger = logging.getLogger("SoCBusHandler") self.logger = logging.getLogger(name)
self.logger.info("Creating Bus Handler...") self.logger.info("Creating Bus Handler...")
# Check Standard # Check Standard
@ -130,7 +130,7 @@ class SoCBusHandler(Module):
if address_width not in self.supported_address_width: if address_width not in self.supported_address_width:
self.logger.error("Unsupported {} {}, supporteds: {:s}".format( self.logger.error("Unsupported {} {}, supporteds: {:s}".format(
colorer("Address Width", color="red"), colorer("Address Width", color="red"),
colorer(data_width), colorer(address_width),
colorer(", ".join(str(x) for x in self.supported_address_width)))) colorer(", ".join(str(x) for x in self.supported_address_width))))
raise raise
@ -815,7 +815,18 @@ class SoC(Module):
self.irq.add(name, loc) self.irq.add(name, loc)
self.add_config("CPU_HAS_INTERRUPT") self.add_config("CPU_HAS_INTERRUPT")
# Create optional DMA Bus (for Cache Coherence)
if hasattr(self.cpu, "dma_bus"):
self.submodules.dma_bus = SoCBusHandler(
name = "SoCDMABusHandler",
standard = "wishbone",
data_width = self.bus.data_width,
)
dma_bus = wishbone.Interface(data_width=self.bus.data_width)
self.dma_bus.add_slave("dma", slave=dma_bus, region=SoCRegion(origin=0x00000000, size=0x80000000)) # FIXME: size
self.submodules += wishbone.Converter(dma_bus, self.cpu.dma_bus)
# Connect SoCController's reset to CPU reset
if hasattr(self, "ctrl"): if hasattr(self, "ctrl"):
if hasattr(self.ctrl, "reset"): if hasattr(self.ctrl, "reset"):
self.comb += self.cpu.reset.eq(self.ctrl.reset) self.comb += self.cpu.reset.eq(self.ctrl.reset)
@ -840,6 +851,8 @@ class SoC(Module):
self.logger.info(colorer("Finalized SoC:")) self.logger.info(colorer("Finalized SoC:"))
self.logger.info(colorer("-"*80, color="bright")) self.logger.info(colorer("-"*80, color="bright"))
self.logger.info(self.bus) self.logger.info(self.bus)
if hasattr(self, "dma_bus"):
self.logger.info(self.dma_bus)
self.logger.info(self.csr) self.logger.info(self.csr)
self.logger.info(self.irq) self.logger.info(self.irq)
self.logger.info(colorer("-"*80, color="bright")) self.logger.info(colorer("-"*80, color="bright"))
@ -871,6 +884,28 @@ class SoC(Module):
self.add_constant("CONFIG_BUS_DATA_WIDTH", self.bus.data_width) self.add_constant("CONFIG_BUS_DATA_WIDTH", self.bus.data_width)
self.add_constant("CONFIG_BUS_ADDRESS_WIDTH", self.bus.address_width) self.add_constant("CONFIG_BUS_ADDRESS_WIDTH", self.bus.address_width)
# SoC DMA Bus Interconnect (Cache Coherence) -----------------------------------------------
if hasattr(self, "dma_bus"):
if len(self.dma_bus.masters) and len(self.dma_bus.slaves):
# If 1 bus_master, 1 bus_slave and no address translation, use InterconnectPointToPoint.
if ((len(self.dma_bus.masters) == 1) and
(len(self.dma_bus.slaves) == 1) and
(next(iter(self.dma_bus.regions.values())).origin == 0)):
self.submodules.bus_interconnect = wishbone.InterconnectPointToPoint(
master = next(iter(self.dma_bus.masters.values())),
slave = next(iter(self.dma_bus.slaves.values())))
# Otherwise, use InterconnectShared.
else:
self.submodules.dma_bus_interconnect = wishbone.InterconnectShared(
masters = self.dma_bus.masters.values(),
slaves = [(self.dma_bus.regions[n].decoder(self.dma_bus), s) for n, s in self.dma_bus.slaves.items()],
register = True)
self.bus.logger.info("DMA Interconnect: {} ({} <-> {}).".format(
colorer(self.dma_bus_interconnect.__class__.__name__),
colorer(len(self.dma_bus.masters)),
colorer(len(self.dma_bus.slaves))))
self.add_constant("CONFIG_CPU_HAS_DMA_BUS")
# SoC CSR Interconnect --------------------------------------------------------------------- # SoC CSR Interconnect ---------------------------------------------------------------------
self.submodules.csr_bankarray = csr_bus.CSRBankArray(self, self.submodules.csr_bankarray = csr_bus.CSRBankArray(self,
address_map = self.csr.address_map, address_map = self.csr.address_map,
@ -1299,10 +1334,8 @@ class LiteXSoC(SoC):
bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.address_width) bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.address_width)
self.submodules.sdblock2mem = SDBlock2MemDMA(bus=bus, endianness=self.cpu.endianness) self.submodules.sdblock2mem = SDBlock2MemDMA(bus=bus, endianness=self.cpu.endianness)
self.comb += self.sdcore.source.connect(self.sdblock2mem.sink) self.comb += self.sdcore.source.connect(self.sdblock2mem.sink)
if hasattr(self.cpu, "dmabus"): # FIXME: VexRiscv SMP / DMA test. dma_bus = self.bus if not hasattr(self, "dma_bus") else self.dma_bus
self.submodules += wishbone.Converter(bus, self.cpu.dmabus) dma_bus.add_master("sdblock2mem", master=bus)
else:
self.bus.add_master("sdblock2mem", master=bus)
self.add_csr("sdblock2mem") self.add_csr("sdblock2mem")
# Mem2Block DMA # Mem2Block DMA
@ -1310,5 +1343,6 @@ class LiteXSoC(SoC):
bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.address_width) bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.address_width)
self.submodules.sdmem2block = SDMem2BlockDMA(bus=bus, endianness=self.cpu.endianness) self.submodules.sdmem2block = SDMem2BlockDMA(bus=bus, endianness=self.cpu.endianness)
self.comb += self.sdmem2block.source.connect(self.sdcore.sink) self.comb += self.sdmem2block.source.connect(self.sdcore.sink)
self.bus.add_master("sdmem2block", master=bus) dma_bus = self.bus if not hasattr(self, "dma_bus") else self.dma_bus
dma_bus.add_master("sdmem2block", master=bus)
self.add_csr("sdmem2block") self.add_csr("sdmem2block")

View File

@ -576,11 +576,13 @@ sdcard_set_block_count(count);
sdcard_stop_transmission(); sdcard_stop_transmission();
#ifndef CONFIG_CPU_HAS_DMA_BUS
/* Flush CPU caches */ /* Flush CPU caches */
flush_cpu_dcache(); flush_cpu_dcache();
#ifdef CONFIG_L2_SIZE #ifdef CONFIG_L2_SIZE
flush_l2_cache(); flush_l2_cache();
#endif #endif
#endif
} }
#endif #endif