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

fpga: first compiling version

Signed-off-by: Steffen Vogel <post@steffenvogel.de>
This commit is contained in:
Steffen Vogel 2022-11-03 07:51:23 -04:00
parent de9bda4d74
commit 9a4f8a0b19
2 changed files with 174 additions and 124 deletions

View file

@ -20,15 +20,9 @@
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:"
class FpgaNode : public Node {
protected:
@ -41,49 +35,84 @@ protected:
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();
FpgaNode(const std::string &name = "");
virtual ~FpgaNode();
static int
typeStart(node::SuperNode *sn);
virtual
int parse(json_t *cfg, const uuid_t sn_uuid);
static int
typeStop();
virtual
const std::string & getDetails();
virtual int
parse(json_t *cfg);
virtual
int check();
virtual char *
print();
virtual
int prepare();
virtual int
check();
virtual
int start();
virtual int
prepare();
virtual
int stop();
virtual int
read(struct sample *smps[], unsigned cnt, unsigned *release);
virtual
std::vector<int> getPollFDs();
};
virtual int
write(struct sample *smps[], unsigned cnt, unsigned *release);
virtual int
pollFDs(int fds[]);
class FpgaNodeFactory : public NodeFactory {
public:
using NodeFactory::NodeFactory;
virtual
Node * make()
{
return new FpgaNode;
}
virtual
int getFlags() const
{
return (int) NodeFactory::Flags::SUPPORTS_READ |
(int) NodeFactory::Flags::SUPPORTS_WRITE |
(int) NodeFactory::Flags::SUPPORTS_POLL;
}
virtual
std::string getName() const
{
return "fpga";
}
virtual
std::string getDescription() const
{
return "VILLASfpga";
}
virtual
int start(SuperNode *sn);
virtual
int stop();
};
} /* namespace node */

View file

@ -20,7 +20,7 @@
#include <villas/sample.hpp>
#include <villas/super_node.hpp>
#include <villas/fpga/pcie_card.hpp>
#include <villas/fpga/card.hpp>
#include <villas/fpga/core.hpp>
#include <villas/fpga/vlnv.hpp>
#include <villas/fpga/ips/dma.hpp>
@ -30,12 +30,9 @@ using namespace villas::node;
using namespace villas::fpga;
using namespace villas::utils;
/* Forward declartions */
static struct NodeCompatType p;
/* Global state */
static fpga::Card::List cards;
static std::map<fpga::ip::Dma, struct fpga *> dmaMap;
static std::map<fpga::ip::Dma, FpgaNode *> dmaMap;
static std::shared_ptr<kernel::pci::DeviceList> pciDevices;
static std::shared_ptr<kernel::vfio::Container> vfioContainer;
@ -43,8 +40,8 @@ static std::shared_ptr<kernel::vfio::Container> vfioContainer;
using namespace villas;
using namespace villas::node;
FpgaNode::FpgaNode(struct vnode *n) :
Node(n),
FpgaNode::FpgaNode(const std::string &name) :
Node(name),
irqFd(-1),
coalesce(0),
polling(true)
@ -53,39 +50,11 @@ FpgaNode::FpgaNode(struct vnode *n) :
FpgaNode::~FpgaNode()
{ }
int FpgaNode::typeStart(node::SuperNode *sn)
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_cfg = sn->getConfig();
json_t *json_fpgas = json_object_get(json_cfg, "fpgas");
if (!json_fpgas)
throw ConfigError(json, "node-config-fpgas", "No section 'fpgas' found in config");
// create all FPGA card instances using the corresponding plugin
auto cards = CardFactory::make(json_fpgas, pciDevices, vfioContainer);
cards.splice(cards.end(), cards);
return 0;
}
int FpgaNode::typeStop()
{
vfioContainer.reset(); // TODO: is this the proper way?
return 0;
}
int FpgaNode::parse(json_t *cfg)
{
int ret;
int ret = Node::parse(cfg, sn_uuid);
if (ret)
return ret;
json_error_t err;
@ -94,7 +63,7 @@ int FpgaNode::parse(json_t *cfg)
const char *dma = nullptr;
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,
@ -102,7 +71,7 @@ int FpgaNode::parse(json_t *cfg)
"polling", &polling
);
if (ret)
throw ConfigError(cfg, err, "node-config-fpga", "Failed to parse configuration of node {}", node_name(node));
throw ConfigError(cfg, err, "node-config-fpga", "Failed to parse configuration of node {}", *this);
if (card)
cardName = card;
@ -118,16 +87,20 @@ int FpgaNode::parse(json_t *cfg)
return 0;
}
char * FpgaNode::print()
const std::string & FpgaNode::getDetails()
{
auto &cardName = card ? card->name : cardName;
if (details.empty()) {
auto &name = card ? card->name : cardName;
return strf("fpga=%s, dma=%s, if=%s, polling=%s, coalesce=%d",
cardName.c_str(),
dma->getInstanceName().c_str(),
polling ? "yes" : "no",
coalesce
);
details = fmt::format("fpga={}, dma={}, if={}, polling={}, coalesce={}",
name,
dma->getInstanceName(),
polling ? "yes" : "no",
coalesce
);
}
return details;
}
int FpgaNode::check()
@ -137,8 +110,6 @@ int FpgaNode::check()
int FpgaNode::prepare()
{
int ret;
auto it = cardName.empty()
? cards.begin()
: std::find_if(cards.begin(), cards.end(), [this](const fpga::Card::Ptr &c) {
@ -146,84 +117,107 @@ int FpgaNode::prepare()
});
if (it == cards.end())
throw ConfigError(json_object_get(cfg, "fpga"), "node-config-fpga-card", "Invalid FPGA card name: {}", cardName);
throw ConfigError(json_object_get(config, "fpga"), "node-config-fpga-card", "Invalid FPGA card name: {}", cardName);
card = *it;
auto intf = intfName.empty()
auto intfCore = intfName.empty()
? card->lookupIp(fpga::Vlnv(FPGA_AURORA_VLNV))
: card->lookupIp(intfName);
if (!intf)
throw ConfigError(cfg, "node-config-fpga-interface", "There is no interface IP with the name: {}", 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>(intf);
intf = std::dynamic_pointer_cast<fpga::ip::Node>(intfCore);
if (!intf)
throw RuntimeError("The IP {} is not a interface", *intf);
auto dma = dmaName.empty()
auto dmaCore = dmaName.empty()
? card->lookupIp(fpga::Vlnv(FPGA_DMA_VLNV))
: card->lookupIp(dmaName);
if (!dma)
throw ConfigError(cfg, "node-config-fpga-dma", "There is no DMA IP with the name: {}", dmaName);
if (!dmaCore)
throw ConfigError(config, "node-config-fpga-dma", "There is no DMA IP with the name: {}", dmaName);
dma = std::dynamic_pointer_cast<fpga::ip::Dma>(dma);
dma = std::dynamic_pointer_cast<fpga::ip::Dma>(dmaCore);
if (!dma)
throw RuntimeError("The IP {} is not a DMA controller", *dma);
ret = intf->connect(*(dma), true);
int ret = intf->connect(*(dma), true);
if (ret)
throw RuntimeError("Failed to connect: {} -> {}",
*(intf), *(dma)
);
throw RuntimeError("Failed to connect: {} -> {}", *(intf), *(dma));
auto &alloc = HostDmaRam::getAllocator();
in.mem = alloc.allocate<uint32_t>(0x100 / sizeof(int32_t));
out.mem = alloc.allocate<uint32_t>(0x100 / sizeof(int32_t));
auto memRx = alloc.allocate<uint32_t>(0x100 / sizeof(int32_t));
auto memTx = alloc.allocate<uint32_t>(0x100 / sizeof(int32_t));
in.block = in.mem.getMemoryBlock();
out.block = out.mem.getMemoryBlock();
blockRx = std::unique_ptr<const MemoryBlock>(&memRx.getMemoryBlock());
blockTx = std::unique_ptr<const MemoryBlock>(&memTx.getMemoryBlock());
dma->makeAccesibleFromVA(in.block);
dma->makeAccesibleFromVA(out.block);
dma->makeAccesibleFromVA(*blockRx);
dma->makeAccesibleFromVA(*blockTx);
// Show some debugging infos
auto &mm = MemoryManager::get();
dma->dump();
intf->dump();
MemoryManager::get().getGraph().dump();
mm.getGraph().dump();
return Node::prepare();
}
int FpgaNode::start()
{
int ret = Node::start();
if (!ret)
state = State::STARTED;
return 0;
}
int FpgaNode::read(struct sample *smps[], unsigned cnt, unsigned *release)
int FpgaNode::stop()
{
int ret = Node::stop();
if (ret)
return ret;
return 0;
}
int FpgaNode::_read(Sample *smps[], unsigned cnt)
{
unsigned read;
struct sample *smp = smps[0];
Sample *smp = smps[0];
assert(cnt == 1);
dma->read(in.block, in.block.getSize()); // TODO: calc size
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++)
smp->data[i].i = in.mem[i];
auto mem = MemoryAccessor<uint32_t>(*blockRx);
smp->signals = &node->in.signals;
for (unsigned i = 0; i < MIN(read, smp->capacity); i++)
smp->data[i].i = mem[i];
smp->signals = in.signals;
return read;
}
int FpgaNode::write(struct sample *smps[], unsigned cnt, unsigned *release)
int FpgaNode::_write(Sample *smps[], unsigned cnt)
{
int written;
struct sample *smp = smps[0];
Sample *smp = smps[0];
assert(cnt == 1);
for (unsigned i = 0; i < smps[0]->length; i++)
out.mem[i] = smps[0]->data[i].i;
auto mem = MemoryAccessor<uint32_t>(*blockTx);
bool state = dma->write(out.block, smp->length * sizeof(int32_t));
for (unsigned i = 0; i < smps[0]->length; i++)
mem[i] = smps[0]->data[i].i;
bool state = dma->write(*blockTx, smp->length * sizeof(int32_t));
if (!state)
return -1;
@ -232,17 +226,44 @@ int FpgaNode::write(struct sample *smps[], unsigned cnt, unsigned *release)
return written;
}
int FpgaNode::pollFDs(int fds[])
std::vector<int> FpgaNode::getPollFDs()
{
if (polling)
return 0;
else {
fds[0] = irqFd;
std::vector<int> fds;
return 1; /* The number of file descriptors which have been set in fds */
}
if (!polling)
fds.push_back(irqFd);
return fds;
}
static char n[] = "fpga";
static char d[] = "VILLASfpga";
static NodePlugin<FpgaNode, n , d, (int) NodeFactory::Flags::SUPPORTS_READ | (int) NodeFactory::Flags::SUPPORTS_WRITE | (int) NodeFactory::Flags::SUPPORTS_POLL> p;
int FpgaNodeFactory::start(SuperNode *sn)
{
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_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 cards = fpga::PCIeCardFactory::make(json_fpgas, pciDevices, vfioContainer);
cards.splice(cards.end(), cards);
return 0;
}
int FpgaNodeFactory::stop()
{
vfioContainer.reset(); // TODO: is this the proper way?
return 0;
}
static FpgaNodeFactory p;