1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-09 00:00:00 +01:00

Merge pull request #621 from VILLASframework/node-fpga

New VILLASfpga node-type
This commit is contained in:
Steffen Vogel 2023-01-09 11:43:47 +01:00 committed by GitHub
commit 8a2818aa14
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 281 additions and 656 deletions

View file

@ -97,7 +97,7 @@ endif()
set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/lib/pkgconfig:/usr/local/lib64/pkgconfig:/usr/local/share/pkgconfig:/usr/lib64/pkgconfig")
pkg_check_modules(JANSSON IMPORTED_TARGET REQUIRED jansson>=2.9)
pkg_check_modules(JANSSON IMPORTED_TARGET REQUIRED jansson>=2.13)
pkg_check_modules(LIBWEBSOCKETS IMPORTED_TARGET REQUIRED libwebsockets>=3.1.0)
pkg_check_modules(PROTOBUF IMPORTED_TARGET protobuf>=2.6.0)
pkg_check_modules(PROTOBUFC IMPORTED_TARGET libprotobuf-c>=1.1.0)
@ -118,12 +118,11 @@ pkg_check_modules(UUID IMPORTED_TARGET REQUIRED uuid>=2.23)
pkg_check_modules(CGRAPH IMPORTED_TARGET libcgraph>=2.30)
pkg_check_modules(GVC IMPORTED_TARGET libgvc>=2.30)
pkg_check_modules(LIBUSB IMPORTED_TARGET libusb-1.0>=1.0.23)
pkg_check_modules(XIL IMPORTED_TARGET libxil)
pkg_check_modules(NANOMSG IMPORTED_TARGET nanomsg)
if(NOT NANOMSG_FOUND)
pkg_check_modules(NANOMSG IMPORTED_TARGET libnanomsg>=1.0.0)
endif()
pkg_check_modules(RE IMPORTED_TARGET re>=0.5.6)
pkg_check_modules(RE IMPORTED_TARGET re>=2.9.0)
if(NOT RE_FOUND)
pkg_check_modules(RE IMPORTED_TARGET libre>=0.5.6)
endif()
@ -156,7 +155,7 @@ cmake_dependent_option(WITH_API "Build with remote control API"
cmake_dependent_option(WITH_CLIENTS "Build client applications" ON "TOPLEVEL_PROJECT" OFF)
cmake_dependent_option(WITH_CONFIG "Build with support for libconfig configuration syntax" ON "LIBCONFIG_FOUND" OFF)
cmake_dependent_option(WITH_DOC "Build documentation" ON "TOPLEVEL_PROJECT" OFF)
cmake_dependent_option(WITH_FPGA "Build with support for VILLASfpga" ON "XIL_FOUND; FOUND_SUBMODULE_FPGA" OFF)
cmake_dependent_option(WITH_FPGA "Build with support for VILLASfpga" ON "FOUND_SUBMODULE_FPGA" OFF)
cmake_dependent_option(WITH_GO "Build with Go" ON "GO" OFF)
cmake_dependent_option(WITH_GRAPHVIZ "Build with Graphviz" ON "CGRAPH_FOUND; GVC_FOUND" OFF)
cmake_dependent_option(WITH_HOOKS "Build with support for processing hook plugins" ON "" OFF)

2
common

@ -1 +1 @@
Subproject commit 950857f1d792e2dad81d6e1f2e5b2d8cab60fd71
Subproject commit 729b877a405b3bd80205fa1c54bfedbf2f030dc2

View file

@ -4,18 +4,31 @@ logging = {
fpgas = {
vc707 = {
id = "10ee:7022"
# Card identification
id = "10ee:7021"
# slot = "88:00.0"
do_reset = true
ips = "@include ../etc/examples/nodes/vc707_ips.conf"
ips = "/global/projects/villas/fpga/software/etc/vc707-xbar-pcie/vc707-xbar-pcie.json"
paths = (
{
from = "aurora_8b10b_ch2"
to = "aurora_8b10b_ch3"
reverse = true
}
)
}
}
nodes = {
dma_0 = {
type = "fpga",
fpga = "vc707"
target = ""
card = "vc707"
datamover = "dma_0"
use_irqs = false
}
@ -24,10 +37,11 @@ nodes = {
paths = (
{
in = "dma_0"
out = [ ]
hooks = (
{ type = "print" }
{
type = "print"
}
)
}
)

View file

@ -1,253 +0,0 @@
{
"timer_0_axi_timer_0": {
"vlnv": "xilinx.com:ip:axi_timer:2.0",
"irqs": {
"generateout0": "pcie_0_axi_pcie_intc_0:0"
}
},
"hier_0_axis_data_fifo_1": {
"ports": [
{
"role": "master",
"name": "AXIS",
"target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:S04_AXIS"
},
{
"role": "slave",
"name": "AXIS",
"target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:M04_AXIS"
}
],
"vlnv": "xilinx.com:ip:axis_data_fifo:2.0"
},
"hier_0_axis_interconnect_0_axis_interconnect_0_xbar": {
"ports": [
{
"role": "slave",
"name": "S00_AXIS",
"target": "hier_0_aurora_axis_0:m_axis"
},
{
"role": "master",
"name": "M00_AXIS",
"target": "hier_0_aurora_axis_0:s_axis"
},
{
"role": "slave",
"name": "S01_AXIS",
"target": "hier_0_axi_dma_axi_dma_0:MM2S"
},
{
"role": "master",
"name": "M01_AXIS",
"target": "hier_0_axi_dma_axi_dma_0:S2MM"
},
{
"role": "slave",
"name": "S02_AXIS",
"target": "hier_0_axi_fifo_mm_s_0:STR_TXD"
},
{
"role": "master",
"name": "M02_AXIS",
"target": "hier_0_axi_fifo_mm_s_0:STR_RXD"
},
{
"role": "slave",
"name": "S03_AXIS",
"target": "hier_0_axis_data_fifo_0:AXIS"
},
{
"role": "master",
"name": "M03_AXIS",
"target": "hier_0_axis_data_fifo_0:AXIS"
},
{
"role": "slave",
"name": "S04_AXIS",
"target": "hier_0_axis_data_fifo_1:AXIS"
},
{
"role": "master",
"name": "M04_AXIS",
"target": "hier_0_axis_data_fifo_1:AXIS"
}
],
"num_ports": 5,
"vlnv": "xilinx.com:ip:axis_switch:1.1"
},
"hier_0_axis_data_fifo_0": {
"ports": [
{
"role": "master",
"name": "AXIS",
"target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:S03_AXIS"
},
{
"role": "slave",
"name": "AXIS",
"target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:M03_AXIS"
}
],
"vlnv": "xilinx.com:ip:axis_data_fifo:2.0"
},
"hier_0_aurora_axis_0": {
"ports": [
{
"role": "master",
"name": "m_axis",
"target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:S00_AXIS"
},
{
"role": "slave",
"name": "s_axis",
"target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:M00_AXIS"
}
],
"vlnv": "acs.eonerc.rwth-aachen.de:user:aurora_axis:1.16"
},
"pcie_0_axi_reset_0": {
"vlnv": "xilinx.com:ip:axi_gpio:2.0"
},
"hier_0_axi_fifo_mm_s_0": {
"ports": [
{
"role": "master",
"name": "STR_TXD",
"target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:S02_AXIS"
},
{
"role": "slave",
"name": "STR_RXD",
"target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:M02_AXIS"
}
],
"vlnv": "xilinx.com:ip:axi_fifo_mm_s:4.2",
"irqs": {
"interrupt": "pcie_0_axi_pcie_intc_0:1"
}
},
"hier_0_axi_dma_axi_dma_0": {
"ports": [
{
"role": "master",
"name": "MM2S",
"target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:S01_AXIS"
},
{
"role": "slave",
"name": "S2MM",
"target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:M01_AXIS"
}
],
"vlnv": "xilinx.com:ip:axi_dma:7.1",
"memory-view": {
"M_AXI_MM2S": {
"pcie_0_axi_pcie_0": {
"BAR0": {
"highaddr": 4294967295,
"size": 4294967296,
"baseaddr": 0
}
}
},
"M_AXI_S2MM": {
"pcie_0_axi_pcie_0": {
"BAR0": {
"highaddr": 4294967295,
"size": 4294967296,
"baseaddr": 0
}
}
}
},
"irqs": {
"s2mm_introut": "pcie_0_axi_pcie_intc_0:3",
"mm2s_introut": "pcie_0_axi_pcie_intc_0:2"
}
},
"pcie_0_axi_pcie_intc_0": {
"vlnv": "acs.eonerc.rwth-aachen.de:user:axi_pcie_intc:1.4"
},
"pcie_0_axi_pcie_0": {
"vlnv": "xilinx.com:ip:axi_pcie:2.9",
"memory-view": {
"M_AXI": {
"timer_0_axi_timer_0": {
"Reg": {
"highaddr": 20479,
"size": 4096,
"baseaddr": 16384
}
},
"hier_0_axi_fifo_mm_s_0": {
"Mem0": {
"highaddr": 40959,
"size": 8192,
"baseaddr": 32768
},
"Mem1": {
"highaddr": 57343,
"size": 8192,
"baseaddr": 49152
}
},
"pcie_0_axi_pcie_0": {
"CTL0": {
"highaddr": 536870911,
"size": 268435456,
"baseaddr": 268435456
}
},
"hier_0_aurora_axis_0": {
"reg0": {
"highaddr": 12287,
"size": 4096,
"baseaddr": 8192
}
},
"pcie_0_axi_reset_0": {
"Reg": {
"highaddr": 32767,
"size": 4096,
"baseaddr": 28672
}
},
"hier_0_axis_interconnect_0_axis_interconnect_0_xbar": {
"Reg": {
"highaddr": 24575,
"size": 4096,
"baseaddr": 20480
}
},
"hier_0_axi_dma_axi_dma_0": {
"Reg": {
"highaddr": 16383,
"size": 4096,
"baseaddr": 12288
}
},
"pcie_0_axi_pcie_intc_0": {
"reg0": {
"highaddr": 8191,
"size": 4096,
"baseaddr": 4096
}
}
}
},
"pcie_bars": {
"BAR0": {
"translation": 0
}
},
"axi_bars": {
"BAR0": {
"highaddr": 4294967295,
"size": 4294967296,
"translation": 0,
"baseaddr": 0
}
}
}
}

2
fpga

@ -1 +1 @@
Subproject commit 0a225cd3e15296372e71aae7983debdb4508d75d
Subproject commit 05581018b85fad8202a5604ce62c0d80d77a0eb5

View file

@ -411,14 +411,12 @@ public:
return 0;
}
bool
isInternal() const
bool isInternal() const
{
return getFlags() & (int) Flags::INTERNAL;
}
bool
isHidden() const
bool isHidden() const
{
return isInternal() || getFlags() & (int) Flags::HIDDEN;
}
@ -461,14 +459,14 @@ public:
return vectorize;
}
virtual std::string
getName() const
virtual
std::string getName() const
{
return name;
}
virtual std::string
getDescription() const
virtual
std::string getDescription() const
{
return desc;
}

View file

@ -9,6 +9,7 @@
#pragma once
#include <villas/node/config.hpp>
#include <villas/node.hpp>
#include <villas/format.hpp>
#include <villas/timing.hpp>
@ -19,15 +20,12 @@
namespace villas {
namespace node {
/* Forward declarations */
class NodeCompat;
using namespace villas;
#define FPGA_DMA_VLNV
#define FPGA_AURORA_VLNV "acs.eonerc.rwth-aachen.de:user:aurora_axis:"
struct fpga_node {
class FpgaNode : public Node {
protected:
int irqFd;
int coalesce;
bool polling;
@ -37,41 +35,82 @@ struct fpga_node {
std::shared_ptr<fpga::ip::Dma> dma;
std::shared_ptr<fpga::ip::Node> intf;
struct {
struct {
MemoryAccessor<int32_t> i;
MemoryAccessor<float> f;
} accessor;
MemoryBlock::Ptr block;
} in, out;
std::unique_ptr<const MemoryBlock> blockRx;
std::unique_ptr<const MemoryBlock> blockTx;
// Config only
std::string cardName;
std::string intfName;
std::string dmaName;
protected:
virtual
int _read(Sample *smps[], unsigned cnt);
virtual
int _write(Sample *smps[], unsigned cnt);
public:
FpgaNode(const std::string &name = "");
virtual
~FpgaNode();
virtual
int parse(json_t *cfg, const uuid_t sn_uuid);
virtual
const std::string & getDetails();
virtual
int check();
virtual
int prepare();
virtual
std::vector<int> getPollFDs();
};
int fpga_type_start(SuperNode *sn);
int fpga_type_stop();
class FpgaNodeFactory : public NodeFactory {
int fpga_init(NodeCompat *n);
public:
using NodeFactory::NodeFactory;
int fpga_destroy(NodeCompat *n);
virtual
Node * make()
{
auto *n = new FpgaNode;
int fpga_parse(NodeCompat *n, json_t *json);
init(n);
char * fpga_print(NodeCompat *n);
return n;
}
int fpga_check(NodeCompat *n);
virtual
int getFlags() const
{
return (int) NodeFactory::Flags::SUPPORTS_READ |
(int) NodeFactory::Flags::SUPPORTS_WRITE |
(int) NodeFactory::Flags::SUPPORTS_POLL;
}
int fpga_prepare(NodeCompat *n);
virtual
std::string getName() const
{
return "fpga";
}
int fpga_write(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
virtual
std::string getDescription() const
{
return "VILLASfpga";
}
int fpga_read(NodeCompat *n, struct Sample * const smps[], unsigned cnt);
int fpga_poll_fds(NodeCompat *n, int fds[]);
virtual
int start(SuperNode *sn);
};
} /* namespace node */
} /* namespace villas */

View file

@ -33,7 +33,6 @@ struct Pool {
struct CQueue queue; /**< The queue which is used to keep track of free blocks */
};
#define INLINE static inline __attribute__((unused))
#define pool_buffer(p) ((char *) (p) + (p)->buffer_off)
/** Initiazlize a pool
@ -56,29 +55,16 @@ int pool_destroy(struct Pool *p) __attribute__ ((warn_unused_result));
* This number can be smaller than the requested \p cnt blocks
* in case the pool currently holds less than \p cnt blocks.
*/
INLINE ssize_t pool_get_many(struct Pool *p, void *blocks[], size_t cnt)
{
return queue_pull_many(&p->queue, blocks, cnt);
}
ssize_t pool_get_many(struct Pool *p, void *blocks[], size_t cnt);
/** Push \p cnt values which are giving by the array values to the stack. */
INLINE ssize_t pool_put_many(struct Pool *p, void *blocks[], size_t cnt)
{
return queue_push_many(&p->queue, blocks, cnt);
}
ssize_t pool_put_many(struct Pool *p, void *blocks[], size_t cnt);
/** Get a free memory block from pool. */
INLINE void * pool_get(struct Pool *p)
{
void *ptr;
return queue_pull(&p->queue, &ptr) == 1 ? ptr : nullptr;
}
void * pool_get(struct Pool *p);
/** Release a memory block back to the pool. */
INLINE int pool_put(struct Pool *p, void *buf)
{
return queue_push(&p->queue, buf);
}
int pool_put(struct Pool *p, void *buf);
} /* namespace node */
} /* namespace villas */

View file

@ -353,7 +353,7 @@ json_t * Config::expandIncludes(json_t *in)
if (!incl)
incl = other;
else if (json_is_object(incl) && json_is_object(other)) {
ret = json_object_update(incl, other);
ret = json_object_update_recursive(incl, other);
if (ret)
throw ConfigError(str, "Can not mix object and array-typed include files");
}

View file

@ -181,13 +181,13 @@ int ExecNode::_write(struct Sample * smps[], unsigned cnt)
const std::string & ExecNode::getDetails()
{
std::string wd = working_dir;
if (wd.empty()) {
char buf[128];
wd = getcwd(buf, sizeof(buf));
}
if (details.empty()) {
std::string wd = working_dir;
if (wd.empty()) {
char buf[128];
wd = getcwd(buf, sizeof(buf));
}
details = fmt::format("exec={}, shell={}, flush={}, #environment={}, #arguments={}, working_dir={}",
command,
shell ? "yes" : "no",

View file

@ -20,20 +20,19 @@
#include <villas/sample.hpp>
#include <villas/super_node.hpp>
#include <villas/fpga/card.hpp>
#include <villas/fpga/core.hpp>
#include <villas/fpga/vlnv.hpp>
#include <villas/fpga/ips/dma.hpp>
using namespace villas;
using namespace villas::node;
using namespace villas::fpga;
using namespace villas::utils;
/* Forward declartions */
static struct NodeCompatType p;
/* Global state */
static fpga::PCIeCard::List cards;
static std::map<fpga::ip::Dma, struct fpga_node *> dmaMap;
static fpga::Card::List cards;
static std::map<fpga::ip::Dma, FpgaNode *> dmaMap;
static std::shared_ptr<kernel::pci::DeviceList> pciDevices;
static std::shared_ptr<kernel::vfio::Container> vfioContainer;
@ -41,260 +40,166 @@ static std::shared_ptr<kernel::vfio::Container> vfioContainer;
using namespace villas;
using namespace villas::node;
int villas::node::fpga_type_start(SuperNode *sn)
FpgaNode::FpgaNode(const std::string &name) :
Node(name),
irqFd(-1),
coalesce(0),
polling(true)
{ }
FpgaNode::~FpgaNode()
{ }
int FpgaNode::parse(json_t *cfg, const uuid_t sn_uuid)
{
vfioContainer = kernel::vfio::Container::create();
pciDevices = std::make_shared<kernel::pci::DeviceList>();
// get the FPGA card plugin
auto pcieCardPlugin = plugin::registry->lookup<fpga::PCIeCardFactory>("pcie");
if (!pcieCardPlugin)
throw RuntimeError("No FPGA PCIe plugin found");
json_t *json = sn->getConfig();
json_t *fpgas = json_object_get(json, "fpgas");
if (!fpgas)
throw ConfigError(json, "node-config-fpgas", "No section 'fpgas' found in config");
// create all FPGA card instances using the corresponding plugin
auto pcieCards = pcieCardPlugin->make(fpgas, pciDevices, vfioContainer);
cards.splice(cards.end(), pcieCards);
return 0;
}
int villas::node::fpga_type_stop()
{
vfioContainer.reset(); // TODO: is this the proper way?
return 0;
}
int villas::node::fpga_init(NodeCompat *n)
{
auto *f = n->getData<struct fpga_node>();
f->coalesce = 0;
f->irqFd = -1;
f->polling = true;
new (&f->cardName) std::string();
new (&f->dmaName) std::string();
new (&f->intfName) std::string();
new (&f->card) std::shared_ptr<fpga::PCIeCard>();
new (&f->dma) std::shared_ptr<fpga::ip::Node>();
new (&f->intf) std::shared_ptr<fpga::ip::Node>();
new (&f->in.block) std::unique_ptr<MemoryBlock>();
new (&f->out.block) std::unique_ptr<MemoryBlock>();
return 0;
}
int villas::node::fpga_destroy(NodeCompat *n)
{
auto *f = n->getData<struct fpga_node>();
// using maiptr = MemoryAccessor<uint32_t>;
// using mafptr = MemoryAccessor<float>;
using mbptr = MemoryBlock::Ptr;
using cptr = std::shared_ptr<fpga::PCIeCard>;
using nptr = std::shared_ptr<fpga::ip::Node>;
using dptr = std::shared_ptr<fpga::ip::Dma>;
using sptr = std::string;
f->cardName.~sptr();
f->dmaName.~sptr();
f->intfName.~sptr();
f->card.~cptr();
f->dma.~dptr();
f->intf.~nptr();
f->in.block.~mbptr();
f->out.block.~mbptr();
return 0;
}
int villas::node::fpga_parse(NodeCompat *n, json_t *json)
{
int ret;
auto *f = n->getData<struct fpga_node>();
int ret = Node::parse(cfg, sn_uuid);
if (ret)
return ret;
json_error_t err;
const char *card = nullptr;
const char *intf = nullptr;
const char *dma = nullptr;
int polling = f->polling;
int poll = polling;
ret = json_unpack_ex(json, &err, 0, "{ s?: s, s?: s, s?: s, s?: i, s?: b }",
ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s?: s, s?: s, s?: i, s?: b }",
"card", &card,
"interface", &intf,
"dma", &dma,
"coalesce", &f->coalesce,
"coalesce", &coalesce,
"polling", &polling
);
if (ret)
throw ConfigError(json, err, "node-config-node-fpga");
throw ConfigError(cfg, err, "node-config-fpga", "Failed to parse configuration of node {}", *this);
if (card)
f->cardName = card;
cardName = card;
if (intf)
f->intfName = intf;
intfName = intf;
if (dma)
f->dmaName = dma;
dmaName = dma;
f->polling = polling; // cast int to bool
polling = poll; // cast int to bool
return 0;
}
char * villas::node::fpga_print(NodeCompat *n)
const std::string & FpgaNode::getDetails()
{
auto *f = n->getData<struct fpga_node>();
if (details.empty()) {
auto &name = card ? card->name : cardName;
return strf("fpga=%s, dma=%s, if=%s, polling=%s, coalesce=%d",
f->card->name.c_str(),
f->dma->getInstanceName().c_str(),
f->polling ? "yes" : "no",
f->coalesce
);
details = fmt::format("fpga={}, dma={}, if={}, polling={}, coalesce={}",
name,
dma->getInstanceName(),
polling ? "yes" : "no",
coalesce
);
}
return details;
}
int villas::node::fpga_prepare(NodeCompat *n)
int FpgaNode::check()
{
int ret;
auto *f = n->getData<struct fpga_node>();
return 0;
}
// Select first FPGA card
auto it = f->cardName.empty()
int FpgaNode::prepare()
{
auto it = cardName.empty()
? cards.begin()
: std::find_if(cards.begin(), cards.end(), [f](const fpga::PCIeCard::Ptr &c) {
return c->name == f->cardName;
: std::find_if(cards.begin(), cards.end(), [this](const fpga::Card::Ptr &c) {
return c->name == cardName;
});
if (it == cards.end())
throw ConfigError(json_object_get(n->getConfig(), "fpga"), "node-config-node-fpga-card", "Invalid FPGA card name: {}", f->cardName);
throw ConfigError(json_object_get(config, "fpga"), "node-config-fpga-card", "Invalid FPGA card name: {}", cardName);
f->card = *it;
card = *it;
// Select interface IP core
auto intf = f->intfName.empty()
? f->card->lookupIp(fpga::Vlnv(FPGA_AURORA_VLNV))
: f->card->lookupIp(f->intfName);
auto intfCore = intfName.empty()
? card->lookupIp(fpga::Vlnv(FPGA_AURORA_VLNV))
: card->lookupIp(intfName);
if (!intfCore)
throw ConfigError(config, "node-config-fpga-interface", "There is no interface IP with the name: {}", intfName);
intf = std::dynamic_pointer_cast<fpga::ip::Node>(intfCore);
if (!intf)
throw ConfigError(n->getConfig(), "node-config-node-fpga-interface", "There is no interface IP with the name: {}", f->intfName);
f->intf = std::dynamic_pointer_cast<fpga::ip::Node>(intf);
if (!f->intf)
throw RuntimeError("The IP {} is not a interface", *intf);
// Select DMA IP core
auto dma = f->dmaName.empty()
? f->card->lookupIp(fpga::Vlnv(FPGA_DMA_VLNV))
: f->card->lookupIp(f->dmaName);
if (!dma)
throw ConfigError(n->getConfig(), "node-config-node-fpga-dma", "There is no DMA IP with the name: {}", f->dmaName);
auto dmaCore = dmaName.empty()
? card->lookupIp(fpga::Vlnv(FPGA_DMA_VLNV))
: card->lookupIp(dmaName);
if (!dmaCore)
throw ConfigError(config, "node-config-fpga-dma", "There is no DMA IP with the name: {}", dmaName);
f->dma = std::dynamic_pointer_cast<fpga::ip::Dma>(dma);
if (!f->dma)
dma = std::dynamic_pointer_cast<fpga::ip::Dma>(dmaCore);
if (!dma)
throw RuntimeError("The IP {} is not a DMA controller", *dma);
ret = f->intf->connect(*(f->dma), true);
int ret = intf->connect(*(dma), true);
if (ret)
throw RuntimeError("Failed to connect: {} -> {}",
*(f->intf), *(f->dma)
);
throw RuntimeError("Failed to connect: {} -> {}", *(intf), *(dma));
auto &alloc = HostDmaRam::getAllocator();
f->in.block = std::move(alloc.allocateBlock(0x100 / sizeof(int32_t)));
f->out.block = std::move(alloc.allocateBlock(0x100 / sizeof(int32_t)));
auto memRx = alloc.allocate<uint32_t>(0x100 / sizeof(int32_t));
auto memTx = alloc.allocate<uint32_t>(0x100 / sizeof(int32_t));
f->in.accessor.i = MemoryAccessor<int32_t>(*f->in.block);
f->in.accessor.f = MemoryAccessor<float>(*f->in.block);
blockRx = std::unique_ptr<const MemoryBlock>(&memRx.getMemoryBlock());
blockTx = std::unique_ptr<const MemoryBlock>(&memTx.getMemoryBlock());
f->out.accessor.i = MemoryAccessor<int32_t>(*f->out.block);
f->out.accessor.f = MemoryAccessor<float>(*f->out.block);
dma->makeAccesibleFromVA(*blockRx);
dma->makeAccesibleFromVA(*blockTx);
f->dma->makeAccesibleFromVA(*f->in.block);
f->dma->makeAccesibleFromVA(*f->out.block);
// Show some debugging infos
auto &mm = MemoryManager::get();
f->dma->dump();
f->intf->dump();
MemoryManager::get().getGraph().dump();
dma->dump();
intf->dump();
mm.getGraph().dump();
return 0;
return Node::prepare();
}
int villas::node::fpga_read(NodeCompat *n, struct Sample * const smps[], unsigned cnt)
int FpgaNode::_read(Sample *smps[], unsigned cnt)
{
unsigned read;
auto *f = n->getData<struct fpga_node>();
struct Sample *smp = smps[0];
Sample *smp = smps[0];
assert(cnt == 1);
f->dma->read(*f->in.block.get(), f->in.block->getSize()); // TODO: calc size
const size_t bytesRead = f->dma->readComplete();
dma->read(*blockRx, blockRx->getSize()); // TODO: calc size
const size_t bytesRead = dma->readComplete();
read = bytesRead / sizeof(int32_t);
for (unsigned i = 0; i < MIN(read, smp->capacity); i++) {
auto sig = n->getInputSignals(false)->getByIndex(i);
auto mem = MemoryAccessor<uint32_t>(*blockRx);
switch (sig->type) {
case SignalType::INTEGER:
smp->data[i].i = f->in.accessor.i[i];
break;
for (unsigned i = 0; i < MIN(read, smp->capacity); i++)
smp->data[i].i = mem[i];
case SignalType::FLOAT:
smp->data[i].f = f->in.accessor.f[i];
break;
default: {}
}
}
smp->signals = n->getInputSignals(false);
smp->length = bytesRead / sizeof(uint32_t);
smp->flags = (int) SampleFlags::HAS_DATA;
smp->signals = in.signals;
return read;
}
int villas::node::fpga_write(NodeCompat *n, struct Sample * const smps[], unsigned cnt)
int FpgaNode::_write(Sample *smps[], unsigned cnt)
{
int written;
auto *f = n->getData<struct fpga_node>();
struct Sample *smp = smps[0];
Sample *smp = smps[0];
assert(cnt == 1);
for (unsigned i = 0; i < smps[0]->length; i++) {
auto sig = smp->signals->getByIndex(i);
auto mem = MemoryAccessor<uint32_t>(*blockTx);
switch (sig->type) {
case SignalType::INTEGER:
f->out.accessor.i[i] = smps[0]->data[i].i;
break;
for (unsigned i = 0; i < smps[0]->length; i++)
mem[i] = smps[0]->data[i].i;
case SignalType::FLOAT:
f->out.accessor.f[i] = smps[0]->data[i].f;
break;
default: {}
}
}
bool state = f->dma->write(*f->out.block.get(), smp->length * sizeof(int32_t));
bool state = dma->write(*blockTx, smp->length * sizeof(int32_t));
if (!state)
return -1;
@ -303,36 +208,37 @@ int villas::node::fpga_write(NodeCompat *n, struct Sample * const smps[], unsign
return written;
}
int villas::node::fpga_poll_fds(NodeCompat *n, int fds[])
std::vector<int> FpgaNode::getPollFDs()
{
auto *f = n->getData<struct fpga_node>();
std::vector<int> fds;
if (f->polling)
return 0;
else {
fds[0] = f->irqFd;
if (!polling)
fds.push_back(irqFd);
return 1; /* The number of file descriptors which have been set in fds */
}
return fds;
}
__attribute__((constructor(110)))
static void register_plugin() {
p.name = "fpga";
p.description = "Communicate with VILLASfpga Xilinx FPGA boards";
p.vectorize = 1;
p.size = sizeof(struct fpga_node);
p.type.start = fpga_type_start;
p.type.stop = fpga_type_stop;
p.init = fpga_init;
p.destroy = fpga_destroy;
p.prepare = fpga_prepare;
p.parse = fpga_parse;
p.print = fpga_print;
p.read = fpga_read;
p.write = fpga_write;
p.poll_fds = fpga_poll_fds;
int FpgaNodeFactory::start(SuperNode *sn)
{
vfioContainer = std::make_shared<kernel::vfio::Container>();
pciDevices = std::make_shared<kernel::pci::DeviceList>();
static NodeCompatFactory ncp(&p);
// Get the FPGA card plugin
auto pcieCardPlugin = plugin::registry->lookup<fpga::PCIeCardFactory>("pcie");
if (!pcieCardPlugin)
throw RuntimeError("No FPGA PCIe plugin found");
json_t *json_cfg = sn->getConfig();
json_t *json_fpgas = json_object_get(json_cfg, "fpgas");
if (!json_fpgas)
throw ConfigError(json_cfg, "node-config-fpgas", "No section 'fpgas' found in config");
// Create all FPGA card instances using the corresponding plugin
auto piceCards = fpga::PCIeCardFactory::make(json_fpgas, pciDevices, vfioContainer);
cards.splice(cards.end(), piceCards);
return 0;
}
static FpgaNodeFactory p;

View file

@ -15,6 +15,7 @@
#include <villas/nodes/rtp.hpp>
extern "C" {
#include <re/re_net.h>
#include <re/re_main.h>
#include <re/re_types.h>
#include <re/re_mbuf.h>
@ -548,7 +549,7 @@ retry: mbuf_set_pos(r->send_mb, RTP_HEADER_SIZE);
mbuf_set_pos(r->send_mb, RTP_HEADER_SIZE);
/* Send dataset */
ret = rtp_send(r->rs, &r->out.saddr_rtp, false, false, RTP_PACKET_TYPE, ts, r->send_mb);
ret = rtp_send(r->rs, &r->out.saddr_rtp, false, false, RTP_PACKET_TYPE, ts, 0, r->send_mb);
if (ret)
throw RuntimeError("Error from rtp_send, reason: {}", ret);
@ -564,22 +565,6 @@ int villas::node::rtp_poll_fds(NodeCompat *n, int fds[])
return 1;
}
int villas::node::rtp_netem_fds(NodeCompat *n, int fds[])
{
auto *r = n->getData<struct rtp>();
int m = 0;
struct udp_sock *rtp = (struct udp_sock *) rtp_sock(r->rs);
struct udp_sock *rtcp = (struct udp_sock *) rtcp_sock(r->rs);
fds[m++] = udp_sock_fd(rtp, AF_INET);
if (r->rtcp.enabled)
fds[m++] = udp_sock_fd(rtcp, AF_INET);
return m;
}
__attribute__((constructor(110)))
static void register_plugin() {
p.name = "rtp";
@ -602,5 +587,4 @@ static void register_plugin() {
p.write = rtp_write;
p.reverse = rtp_reverse;
p.poll_fds = rtp_poll_fds;
p.netem_fds = rtp_netem_fds;
}

View file

@ -62,3 +62,24 @@ int villas::node::pool_destroy(struct Pool *p)
return ret;
}
ssize_t villas::node::pool_get_many(struct Pool *p, void *blocks[], size_t cnt)
{
return queue_pull_many(&p->queue, blocks, cnt);
}
ssize_t villas::node::pool_put_many(struct Pool *p, void *blocks[], size_t cnt)
{
return queue_push_many(&p->queue, blocks, cnt);
}
void * villas::node::pool_get(struct Pool *p)
{
void *ptr;
return queue_pull(&p->queue, &ptr) == 1 ? ptr : nullptr;
}
int villas::node::pool_put(struct Pool *p, void *buf)
{
return queue_push(&p->queue, buf);
}

View file

@ -16,21 +16,6 @@ MAKE_OPTS+="--jobs=${MAKE_THREADS}"
git config --global http.postBuffer 524288000
git config --global core.compression 0
if [ -n "${PACKAGE}" ]; then
TARGET="package"
CMAKE_OPTS+=" -DCPACK_GENERATOR=RPM"
# Prepare rpmbuild dir
mkdir -p ~/rpmbuild/SOURCES
mkdir -p rpms
dnf -y install \
xmlto \
systemd-devel
else
TARGET="install"
fi
DIR=$(mktemp -d)
pushd ${DIR}
@ -42,22 +27,18 @@ if ! pkg-config "criterion >= 2.3.1" && \
mkdir -p Criterion/build
pushd Criterion/build
cmake ${CMAKE_OPTS} ..
if [ -z "${PACKAGE}" ]; then
make ${MAKE_OPTS} install
fi
make ${MAKE_OPTS} install
popd
fi
# Build & Install libjansson
if ! pkg-config "jansson >= 2.7" && \
if ! pkg-config "jansson >= 2.13" && \
[ -z "${SKIP_JANSSON}" ]; then
git clone ${GIT_OPTS} --branch v2.14 https://github.com/akheron/jansson
pushd jansson
autoreconf -i
./configure ${CONFIGURE_OPTS}
if [ -z "${PACKAGE}" ]; then
make ${MAKE_OPTS} install
fi
make ${MAKE_OPTS} install
popd
fi
@ -71,10 +52,8 @@ if ! ( pkg-config "lua >= 5.1" || \
) && [ -z "${SKIP_LUA}" ]; then
wget http://www.lua.org/ftp/lua-5.3.6.tar.gz -O - | tar -xz
pushd lua-5.3.6
if [ -z "${PACKAGE}" ]; then
make ${MAKE_OPTS} MYCFLAGS=-fPIC linux
make ${MAKE_OPTS} MYCFLAGS=-fPIC install
fi
make ${MAKE_OPTS} MYCFLAGS=-fPIC linux
make ${MAKE_OPTS} MYCFLAGS=-fPIC install
popd
fi
@ -89,7 +68,7 @@ if ! pkg-config "libmosquitto >= 1.4.15" && \
-DWITH_APPS=OFF \
-DDOCUMENTATION=OFF \
${CMAKE_OPTS} ..
make ${MAKE_OPTS} ${TARGET}
make ${MAKE_OPTS} install
popd
fi
@ -100,7 +79,7 @@ if ! pkg-config "librabbitmq >= 0.8.0" && \
mkdir -p rabbitmq-c/build
pushd rabbitmq-c/build
cmake ${CMAKE_OPTS} ..
make ${MAKE_OPTS} ${TARGET}
make ${MAKE_OPTS} install
popd
fi
@ -114,7 +93,7 @@ if ! pkg-config "libzmq >= 2.2.0" && \
-DZMQ_BUILD_TESTS=OFF \
-DENABLE_CPACK=OFF \
${CMAKE_OPTS} ..
make ${MAKE_OPTS} ${TARGET}
make ${MAKE_OPTS} install
popd
fi
@ -124,13 +103,7 @@ if [ -z "${SKIP_ETHERLAB}" ]; then
pushd ethercat
./bootstrap
./configure --enable-userlib=yes --enable-kernel=no ${CONFIGURE_OPTS}
if [ -z "${PACKAGE}" ]; then
make ${MAKE_OPTS} ${TARGET}
else
wget https://etherlab.org/download/ethercat/ethercat-1.5.2.tar.bz2
cp ethercat-1.5.2.tar.bz2 ~/rpmbuild/SOURCES
rpmbuild -ba ethercat.spec
fi
make ${MAKE_OPTS} install
popd
fi
@ -141,10 +114,7 @@ if ! pkg-config "libiec61850 >= 1.3.1" && \
mkdir -p libiec61850/build
pushd libiec61850/build
cmake ${CMAKE_OPTS} ..
make ${MAKE_OPTS} ${TARGET}
if [ -n "${PACKAGE}" ]; then
cp libiec61850/build/*.rpm rpms
fi
make ${MAKE_OPTS} install
popd
fi
@ -155,10 +125,7 @@ if ! pkg-config "lib60870 >= 2.3.1" && \
mkdir -p lib60870/build
pushd lib60870/build
cmake ${CMAKE_OPTS} ../lib60870-C
make ${MAKE_OPTS} ${TARGET}
if [ -n "${PACKAGE}" ]; then
cp lib60870/build/*.rpm rpms
fi
make ${MAKE_OPTS} install
popd
fi
@ -171,7 +138,7 @@ if ! pkg-config "rdkafka >= 1.5.0" && \
cmake -DRDKAFKA_BUILD_TESTS=OFF \
-DRDKAFKA_BUILD_EXAMPLES=OFF \
${CMAKE_OPTS} ..
make ${MAKE_OPTS} ${TARGET}
make ${MAKE_OPTS} install
popd
fi
@ -183,7 +150,7 @@ if ! ( pkg-config "libcgraph >= 2.30" && \
mkdir -p graphviz/build
pushd graphviz/build
cmake ${CMAKE_OPTS} ..
make ${MAKE_OPTS} ${TARGET}
make ${MAKE_OPTS} install
popd
fi
@ -196,13 +163,7 @@ if ! pkg-config "libuldaq >= 1.2.0" && \
./configure \
--disable-examples \
${CONFIGURE_OPTS}
if [ -z "${PACKAGE}" ]; then
make ${MAKE_OPTS} install
else
make dist
cp fedora/uldaq_ldconfig.patch libuldaq-1.2.0.tar.gz ~/rpmbuild/SOURCES
rpmbuild -ba fedora/uldaq.spec
fi
make ${MAKE_OPTS} install
popd
fi
@ -216,9 +177,7 @@ if ! ( pkg-config "libnl-3.0 >= 3.2.25" && \
./configure \
--enable-cli=no \
${CONFIGURE_OPTS}
if [ -z "${PACKAGE}" ]; then
make ${MAKE_OPTS} install
fi
make ${MAKE_OPTS} install
popd
fi
@ -232,9 +191,7 @@ if ! pkg-config "libconfig >= 1.4.9" && \
--disable-tests \
--disable-examples \
--disable-doc
if [ -z "${PACKAGE}" ]; then
make ${MAKE_OPTS} install
fi
make ${MAKE_OPTS} install
popd
fi
@ -247,28 +204,16 @@ if ! pkg-config "comedilib >= 0.11.0" && \
./configure \
--disable-docbook \
${CONFIGURE_OPTS}
if [ -z "${PACKAGE}" ]; then
make ${MAKE_OPTS} install
else
touch doc/pdf/comedilib.pdf # skip build of PDF which is broken..
make dist
cp comedilib-0.12.0.tar.gz ~/rpmbuild/SOURCES
rpmbuild -ba comedilib.spec
fi
make ${MAKE_OPTS} install
popd
fi
# Build & Install libre
if ! pkg-config "libre >= 0.5.6" && \
if ! pkg-config "libre >= 2.9.0" && \
[ -z "${SKIP_LIBRE}" ]; then
git clone ${GIT_OPTS} --branch v0.6.1 https://github.com/creytiv/re.git
git clone ${GIT_OPTS} --branch v2.9.0 https://github.com/baresip/re.git
pushd re
if [ -z "${PACKAGE}" ]; then
make ${MAKE_OPTS} install
else
tar --transform 's|^\.|re-0.6.1|' -czvf ~/rpmbuild/SOURCES/re-0.6.1.tar.gz .
rpmbuild -ba rpm/re.spec
fi
make ${MAKE_OPTS} install
popd
fi
@ -284,9 +229,7 @@ if ! pkg-config "nanomsg >= 1.0.0" && \
-DNN_ENABLE_DOC=OFF \
-DNN_ENABLE_COVERAGE=OFF \
${CMAKE_OPTS} ..
if [ -z "${PACKAGE}" ]; then
make ${MAKE_OPTS} install
fi
make ${MAKE_OPTS} install
popd
fi
@ -297,9 +240,7 @@ if ! pkg-config "libxil >= 1.0.0" && \
mkdir -p libxil/build
pushd libxil/build
cmake ${CMAKE_OPTS} ..
if [ -z "${PACKAGE}" ]; then
make ${MAKE_OPTS} install
fi
make ${MAKE_OPTS} install
popd
fi
@ -312,7 +253,7 @@ if ! pkg-config "hiredis>1.0.0" && \
cmake -DDISABLE_TESTS=ON \
-DENABLE_SSL=ON \
${CMAKE_OPTS} ..
make ${MAKE_OPTS} ${TARGET}
make ${MAKE_OPTS} install
popd
fi
@ -329,7 +270,7 @@ if [ -z "${SKIP_REDISPP}" -a -z "${SKIP_REDIS}" ]; then
-DREDIS_PLUS_PLUS_BUILD_STATIC=OFF \
-DREDIS_PLUS_PLUS_CXX_STANDARD=17 \
${REDISPP_CMAKE_OPTS} ${CMAKE_OPTS} ..
make ${MAKE_OPTS} ${TARGET} VERBOSE=1
make ${MAKE_OPTS} install VERBOSE=1
popd
fi
@ -342,10 +283,7 @@ if ! pkg-config "fmt >= 6.1.2" && \
cmake -DBUILD_SHARED_LIBS=1 \
-DFMT_TEST=OFF \
${CMAKE_OPTS} ..
make ${MAKE_OPTS} ${TARGET}
if [ -n "${PACKAGE}" ]; then
cp fmt/build/*.rpm rpms
fi
make ${MAKE_OPTS} install
popd
fi
@ -360,10 +298,7 @@ if ! pkg-config "spdlog >= 1.8.2" && \
-DSPDLOG_BUILD_SHARED=ON \
-DSPDLOG_BUILD_TESTS=OFF \
${CMAKE_OPTS} ..
make ${MAKE_OPTS} ${TARGET}
if [ -n "${PACKAGE}" ]; then
cp spdlog/build/*.rpm rpms
fi
make ${MAKE_OPTS} install
popd
fi
@ -378,18 +313,14 @@ if ! pkg-config "libwebsockets >= 3.1.0" && \
-DLWS_WITHOUT_EXTENSIONS=OFF \
-DLWS_WITH_SERVER_STATUS=ON \
${CMAKE_OPTS} ..
make ${MAKE_OPTS} ${TARGET}
make ${MAKE_OPTS} install
popd
fi
if [ -n "${PACKAGE}" ]; then
cp ~/rpmbuild/RPMS/x86_64/*.rpm rpms
fi
popd
rm -rf ${DIR}
# Update linker cache
if [ -z "${PACKAGE}" -a -z "${SKIP_LDCONFIG}" ]; then
if [ -z "${SKIP_LDCONFIG}" ]; then
ldconfig
fi

View file

@ -79,7 +79,7 @@ static void * producer(void *ctx)
/* Wait for global start signal */
while (p->start == 0)
pthread_yield();
sched_yield();
/* Wait for a random time */
for (size_t i = 0; i != nops; i += 1)
@ -89,7 +89,7 @@ static void * producer(void *ctx)
for (intptr_t count = 0; count < p->iter_count; count++) {
do {
ret = queue_push(&p->queue, (void *) count);
pthread_yield();
sched_yield();
} while (ret != 1);
}
@ -106,7 +106,7 @@ static void * consumer(void *ctx)
/* Wait for global start signal */
while (p->start == 0)
pthread_yield();
sched_yield();
/* Wait for a random time */
for (size_t i = 0; i != nops; i += 1)
@ -138,7 +138,7 @@ void * producer_consumer(void *ctx)
/* Wait for global start signal */
while (p->start == 0)
pthread_yield();
sched_yield();
/* Wait for a random time */
for (size_t i = 0; i != nops; i += 1)
@ -150,13 +150,13 @@ void * producer_consumer(void *ctx)
for (intptr_t i = 0; i < p->batch_size; i++) {
void *ptr = (void *) (iter * p->batch_size + i);
while (!queue_push(&p->queue, ptr))
pthread_yield(); /* queue full, let other threads proceed */
sched_yield(); /* queue full, let other threads proceed */
}
for (intptr_t i = 0; i < p->batch_size; i++) {
void *ptr;
while (!queue_pull(&p->queue, &ptr))
pthread_yield(); /* queue empty, let other threads proceed */
sched_yield(); /* queue empty, let other threads proceed */
}
}
@ -172,7 +172,7 @@ void * producer_consumer_many(void *ctx)
/* Wait for global start signal */
while (p->start == 0)
pthread_yield();
sched_yield();
/* Wait for a random time */
for (size_t i = 0; i != nops; i += 1)
@ -190,14 +190,14 @@ void * producer_consumer_many(void *ctx)
do {
pushed += queue_push_many(&p->queue, &ptrs[pushed], p->batch_size - pushed);
if (pushed != p->batch_size)
pthread_yield(); /* queue full, let other threads proceed */
sched_yield(); /* queue full, let other threads proceed */
} while (pushed < p->batch_size);
int pulled = 0;
do {
pulled += queue_pull_many(&p->queue, &ptrs[pulled], p->batch_size - pulled);
if (pulled != p->batch_size)
pthread_yield(); /* queue empty, let other threads proceed */
sched_yield(); /* queue empty, let other threads proceed */
} while (pulled < p->batch_size);
}