From bac0b7309afd7b1d3064c072df9cd26789677b1c Mon Sep 17 00:00:00 2001 From: Niklas Eiling Date: Mon, 7 Nov 2022 09:59:14 -0500 Subject: [PATCH] add card config option "polling" to configure polling mode in IP cores; add json parsing of hwdef to dma IP core to replace hardcoded DMA settings. --- fpga/etc/fpgas.json | 3 +- fpga/include/villas/fpga/card.hpp | 1 + fpga/include/villas/fpga/core.hpp | 7 ++ fpga/include/villas/fpga/ips/dma.hpp | 12 ++- fpga/lib/card.cpp | 7 +- fpga/lib/core.cpp | 3 + fpga/lib/ips/dma.cpp | 141 ++++++++++++++++++++++----- 7 files changed, 146 insertions(+), 28 deletions(-) diff --git a/fpga/etc/fpgas.json b/fpga/etc/fpgas.json index 42865c011..c5c471d49 100644 --- a/fpga/etc/fpgas.json +++ b/fpga/etc/fpgas.json @@ -4,7 +4,8 @@ "id": "10ee:7021", "slot": "0000:88:00.0", "do_reset": true, - "ips": "etc/vc707-xbar-pcie/vc707-xbar-pcie.json" + "ips": "etc/vc707-xbar-pcie/vc707-xbar-pcie.json", + "polling": false } } } diff --git a/fpga/include/villas/fpga/card.hpp b/fpga/include/villas/fpga/card.hpp index 51f94fdaf..7911bb53d 100644 --- a/fpga/include/villas/fpga/card.hpp +++ b/fpga/include/villas/fpga/card.hpp @@ -104,6 +104,7 @@ public: // TODO: make this private bool doReset; // Reset VILLASfpga during startup? int affinity; // Affinity for MSI interrupts + bool polling; // Poll on interrupts? std::string name; // The name of the FPGA card diff --git a/fpga/include/villas/fpga/core.hpp b/fpga/include/villas/fpga/core.hpp index 2cfbc27cc..da86669dd 100644 --- a/fpga/include/villas/fpga/core.hpp +++ b/fpga/include/villas/fpga/core.hpp @@ -302,6 +302,10 @@ public: } protected: + enum PollingMode { + POLL, + IRQ, + }; Logger getLogger() const { @@ -318,6 +322,9 @@ private: return true; } + virtual void configurePollingMode(Core& /* ip */, PollingMode /* mode */) + { } + virtual Vlnv getCompatibleVlnv() const = 0; protected: diff --git a/fpga/include/villas/fpga/ips/dma.hpp b/fpga/include/villas/fpga/ips/dma.hpp index 98e683e7b..bf46b46fc 100644 --- a/fpga/include/villas/fpga/ips/dma.hpp +++ b/fpga/include/villas/fpga/ips/dma.hpp @@ -127,6 +127,8 @@ private: XAxiDma xDma; XAxiDma_Config xConfig; bool hasSG; + bool configSet = false; + bool polling = false; int delay; int coalesce; @@ -161,8 +163,14 @@ public: return Vlnv("xilinx.com:ip:axi_dma:"); } - //virtual bool - //configureJson(Core& ip, json_t* json) override;*/ + virtual bool + configureJson(Core& ip, json_t* json) override; + + virtual void + configurePollingMode(Core& ip, PollingMode mode) + { + dynamic_cast(ip).polling = (mode == POLL); + } }; } /* namespace ip */ diff --git a/fpga/lib/card.cpp b/fpga/lib/card.cpp index 3009a43a5..40ecb4dbb 100644 --- a/fpga/lib/card.cpp +++ b/fpga/lib/card.cpp @@ -57,13 +57,15 @@ PCIeCardFactory::make(json_t *json, std::shared_ptr pci const char* pci_id = nullptr; int do_reset = 0; int affinity = 0; + int polling = 0; - int ret = json_unpack(json_card, "{ s: o, s?: i, s?: b, s?: s, s?: s }", + int ret = json_unpack(json_card, "{ s: o, s?: i, s?: b, s?: s, s?: s, s?: b }", "ips", &json_ips, "affinity", &affinity, "do_reset", &do_reset, "slot", &pci_slot, - "id", &pci_id); + "id", &pci_id, + "polling", &polling); if (ret != 0) { logger->warn("Cannot parse JSON config"); @@ -77,6 +79,7 @@ PCIeCardFactory::make(json_t *json, std::shared_ptr pci card->vfioContainer = std::move(vc); card->affinity = affinity; card->doReset = do_reset != 0; + card->polling = (polling != 0); kernel::pci::Device filter = defaultFilter; diff --git a/fpga/lib/core.cpp b/fpga/lib/core.cpp index de93b0716..cb08a16a8 100644 --- a/fpga/lib/core.cpp +++ b/fpga/lib/core.cpp @@ -249,6 +249,9 @@ CoreFactory::make(PCIeCard* card, json_t *json_ips) continue; } + // Set polling mode + CoreFactory->configurePollingMode(*ip, (card->polling ? PollingMode::POLL : PollingMode::IRQ)); + // IP has been configured now configuredIps.push_back(std::move(ip)); } diff --git a/fpga/lib/ips/dma.cpp b/fpga/lib/ips/dma.cpp index 35a0a29fc..37fc68df9 100644 --- a/fpga/lib/ips/dma.cpp +++ b/fpga/lib/ips/dma.cpp @@ -47,29 +47,30 @@ bool Dma::init() delay = 0; // If there is a scatter-gather interface, then this instance has it - hasSG = busMasterInterfaces.count(sgInterface) == 1; - logger->info("Scatter-Gather support: {}", hasScatterGather()); + // hasSG = busMasterInterfaces.count(sgInterface) == 1; + if (hasScatterGather()) + logger->info("Scatter-Gather support: {}", hasScatterGather()); - XAxiDma_Config xdma_cfg; + xConfig.BaseAddr = getBaseAddr(registerMemory); + if (!configSet) { + xConfig.HasStsCntrlStrm = 0; + xConfig.HasMm2S = 1; + xConfig.HasMm2SDRE = 0; + xConfig.Mm2SDataWidth = 32; + xConfig.HasS2Mm = 1; + xConfig.HasS2MmDRE = 0; + xConfig.HasSg = hasScatterGather(); + xConfig.S2MmDataWidth = 32; + xConfig.Mm2sNumChannels = 1; + xConfig.S2MmNumChannels = 1; + xConfig.Mm2SBurstSize = 16; + xConfig.S2MmBurstSize = 16; + xConfig.MicroDmaMode = 0; + xConfig.AddrWidth = 32; + xConfig.SgLengthWidth = 14; + } - xdma_cfg.BaseAddr = getBaseAddr(registerMemory); - xdma_cfg.HasStsCntrlStrm = 0; - xdma_cfg.HasMm2S = 1; - xdma_cfg.HasMm2SDRE = 0; - xdma_cfg.Mm2SDataWidth = 32; - xdma_cfg.HasS2Mm = 1; - xdma_cfg.HasS2MmDRE = 0; - xdma_cfg.HasSg = hasScatterGather(); - xdma_cfg.S2MmDataWidth = 32; - xdma_cfg.Mm2sNumChannels = 1; - xdma_cfg.S2MmNumChannels = 1; - xdma_cfg.Mm2SBurstSize = 16; - xdma_cfg.S2MmBurstSize = 16; - xdma_cfg.MicroDmaMode = 0; - xdma_cfg.AddrWidth = 32; - xdma_cfg.SgLengthWidth = 14; - - if (XAxiDma_CfgInitialize(&xDma, &xdma_cfg) != XST_SUCCESS) + if (XAxiDma_CfgInitialize(&xDma, &xConfig) != XST_SUCCESS) { logger->error("Cannot initialize Xilinx DMA driver"); return false; @@ -94,9 +95,9 @@ bool Dma::init() XAxiDma_IntrEnable(&xDma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA); // write interrupt - irqs[mm2sInterrupt].irqController->enableInterrupt(irqs[mm2sInterrupt], false); + irqs[mm2sInterrupt].irqController->enableInterrupt(irqs[mm2sInterrupt], polling); // read interrupt - irqs[s2mmInterrupt].irqController->enableInterrupt(irqs[s2mmInterrupt], false); + irqs[s2mmInterrupt].irqController->enableInterrupt(irqs[s2mmInterrupt], polling); return true; } @@ -606,3 +607,97 @@ void Dma::dump() logger->info("MM2S_DMACR: {:x}", XAxiDma_ReadReg(xDma.RegBase, XAXIDMA_TX_OFFSET + XAXIDMA_CR_OFFSET)); logger->info("MM2S_DMASR: {:x}", XAxiDma_ReadReg(xDma.RegBase, XAXIDMA_TX_OFFSET + XAXIDMA_SR_OFFSET)); } + +bool +DmaFactory::configureJson(Core& ip, json_t* json) +{ + auto &dma = dynamic_cast(ip); + enum DmaParameters { + HasStsCntrlStrm, + HasMm2S, + HasMm2SDRE, + Mm2SDataWidth, + HasS2Mm, + HasS2MmDRE, + S2MmDataWidth, + HasSg, + Mm2sNumChannels, + S2MmNumChannels, + MicroDmaMode, + AddrWidth, + SgLengthWidth + }; + static const std::map ParaMap = { + {"c_sg_include_stscntrl_strm", HasStsCntrlStrm}, + {"c_include_mm2s", HasMm2S}, + {"c_include_mm2s_dre", HasMm2SDRE}, + {"c_m_axi_mm2s_data_width", Mm2SDataWidth}, + {"c_include_s2mm", HasS2Mm}, + {"c_include_s2mm_dre", HasS2MmDRE}, + {"c_m_axi_s2mm_data_width", S2MmDataWidth}, + {"c_include_sg", HasSg}, + {"c_num_mm2s_channels", Mm2sNumChannels}, + {"c_num_s2mm_channels", S2MmNumChannels}, + {"c_micro_dma", MicroDmaMode}, + {"c_addr_width", AddrWidth}, + {"c_sg_length_width", SgLengthWidth} + }; + + json_t* json_params = json_object_get(json, "parameters"); + if (!json_is_object(json_params)) + return true; + + const char* paramName; + json_t* json_param; + json_object_foreach(json_params, paramName, json_param) { + auto it = ParaMap.find(paramName); + if (it == ParaMap.end()) + continue; + + switch (it->second) { + case HasStsCntrlStrm: + dma.xConfig.HasStsCntrlStrm = json_integer_value(json_param); + break; + case HasMm2S: + dma.xConfig.HasMm2S = json_integer_value(json_param); + break; + case HasMm2SDRE: + dma.xConfig.HasMm2SDRE = json_integer_value(json_param); + break; + case Mm2SDataWidth: + dma.xConfig.Mm2SDataWidth = json_integer_value(json_param); + break; + case HasS2Mm: + dma.xConfig.HasS2Mm = json_integer_value(json_param); + break; + case HasS2MmDRE: + dma.xConfig.HasS2MmDRE = json_integer_value(json_param); + break; + case S2MmDataWidth: + dma.xConfig.S2MmDataWidth = json_integer_value(json_param); + break; + case HasSg: + dma.xConfig.HasSg = json_integer_value(json_param); + break; + case Mm2sNumChannels: + dma.xConfig.Mm2sNumChannels = json_integer_value(json_param); + break; + case S2MmNumChannels: + dma.xConfig.S2MmNumChannels = json_integer_value(json_param); + break; + case MicroDmaMode: + dma.xConfig.MicroDmaMode = json_integer_value(json_param); + break; + case AddrWidth: + dma.xConfig.AddrWidth = json_integer_value(json_param); + break; + case SgLengthWidth: + dma.xConfig.SgLengthWidth = json_integer_value(json_param); + break; + default: + break; + } + } + dma.configSet = true; + return true; +} \ No newline at end of file