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

current wip implementing card, many changes in ip too

This commit is contained in:
daniel-k 2017-12-06 17:37:15 +01:00
parent 63a443527c
commit b0e55e6fb2
6 changed files with 292 additions and 50 deletions

View file

@ -30,35 +30,67 @@
#pragma once
#include <jansson.h>
#include "common.h"
#include "kernel/pci.h"
#include "kernel/vfio.h"
#include <list>
#include <string>
#include "plugin.hpp"
#include "config.h"
#define PCI_FILTER_DEFAULT_FPGA { \
.id = { \
.vendor = FPGA_PCI_VID_XILINX, \
.device = FPGA_PCI_PID_VFPGA \
} \
}
namespace villas {
/* Forward declarations */
struct fpga_ip;
struct vfio_container;
class FpgaCardPlugin;
class FpgaIp;
struct fpga_card {
char *name; /**< The name of the FPGA card */
class FpgaCard {
public:
enum state state; /**< The state of this FPGA card. */
friend FpgaCardPlugin;
FpgaCard() : filter(PCI_FILTER_DEFAULT_FPGA) {}
bool start();
bool stop() { return true; }
bool check() { return true; }
bool reset() { return true; }
void dump() { }
using IpList = std::list<FpgaIp*>;
IpList ips; ///< IPs located on this FPGA card
bool do_reset; /**< Reset VILLASfpga during startup? */
int affinity; /**< Affinity for MSI interrupts */
std::string name; /**< The name of the FPGA card */
struct pci *pci;
struct pci_device filter; /**< Filter for PCI device. */
struct vfio_container *vfio_container;
::vfio_container *vfio_container;
struct vfio_device vfio_device; /**< VFIO device handle. */
int do_reset; /**< Reset VILLASfpga during startup? */
int affinity; /**< Affinity for MSI interrupts */
struct list ips; /**< List of IP components on FPGA. */
// struct list ips; /**< List of IP components on FPGA. */
char *map; /**< PCI BAR0 mapping for register access */
@ -66,9 +98,25 @@ struct fpga_card {
size_t dmalen;
/* Some IP cores are special and referenced here */
struct fpga_ip *intc;
struct fpga_ip *reset;
struct fpga_ip *sw;
// struct fpga_ip *intc;
// struct fpga_ip *reset;
// struct fpga_ip *sw;
};
class FpgaCardPlugin : public Plugin {
public:
FpgaCardPlugin() :
Plugin("FPGA Card plugin")
{ pluginType = Plugin::Type::FpgaCard; }
static std::list<FpgaCard*>
make(json_t *json, struct pci* pci, ::vfio_container* vc);
static FpgaCard*
create();
};
/** Initialize FPGA card and its IP components. */

View file

@ -41,7 +41,7 @@
#include "fpga/vlnv.hpp"
#include "plugin.hpp"
#include "card.h"
#include "card.hpp"
#include <jansson.h>
@ -74,11 +74,7 @@ public:
virtual bool start() { return true; }
virtual bool stop() { return true; }
virtual bool reset() { return true; }
virtual void dump()
{
info("IP %s: vlnv=%s baseaddr=%#jx, irq=%d, port=%d",
name.c_str(), vlnv.toString().c_str(), baseaddr, irq, port);
}
virtual void dump();
protected:
uintptr_t
@ -90,12 +86,12 @@ protected:
protected:
// populated by FpgaIpFactory
struct fpga_card *card; /**< FPGA card this IP is instantiated on */
std::string name; /**< Name defined in JSON config */
FpgaVlnv vlnv; /**< VLNV defined in JSON config */
uintptr_t baseaddr; /**< The baseadress of this FPGA IP component */
int irq; /**< The interrupt number of the FPGA IP component. */
int port; /**< The port of the AXI4-Stream switch to which this FPGA IP component is connected. */
FpgaCard* card; /**< FPGA card this IP is instantiated on */
std::string name; /**< Name defined in JSON config */
FpgaVlnv vlnv; /**< VLNV defined in JSON config */
uintptr_t baseaddr; /**< The baseadress of this FPGA IP component */
int irq; /**< The interrupt number of the FPGA IP component. */
int port; /**< The port of the AXI4-Stream switch to which this FPGA IP component is connected. */
};
@ -106,14 +102,16 @@ public:
{ pluginType = Plugin::Type::FpgaIp; }
/// Returns a running and checked FPGA IP
static FpgaIp* make(struct fpga_card* card, json_t *json, std::string name);
static FpgaIp*
make(FpgaCard* card, json_t *json, std::string name);
private:
/// Create a concrete IP instance
virtual FpgaIp* create() = 0;
/// Configure IP instance from JSON config
virtual bool configureJson(FpgaIp* ip, json_t *json) = 0;
virtual bool configureJson(FpgaIp* ip, json_t *json)
{ return true; }
virtual FpgaVlnv getCompatibleVlnv() const = 0;
virtual std::string getName() const = 0;

View file

@ -38,12 +38,13 @@ public:
enum class Type {
Unknown,
FpgaIp,
FpgaCard,
};
Plugin(std::string name);
virtual ~Plugin();
// each plugin is a singleton, so copying is not allowed
// copying a plugin doesn't make sense, so explicitly deny it
Plugin(Plugin const&) = delete;
void operator=(Plugin const&) = delete;
@ -61,20 +62,19 @@ public:
static Plugin *
lookup(Type type, std::string name);
/// Get all plugins of a given type.
static std::list<Plugin*>
lookup(Type type);
// check if this makes sense! (no intermediate plugins)
// TODO: check if this makes sense! (no intermediate plugins)
bool
operator==(const Plugin& other) const;
Type pluginType;
std::string name;
std::string description;
std::string path;
void *handle;
enum state state;
private:

View file

@ -32,11 +32,157 @@
#include "kernel/pci.h"
#include "kernel/vfio.h"
#include "fpga/ip.h"
#include "fpga/card.h"
#include <string>
#include "fpga/ip.hpp"
#include "fpga/card.hpp"
namespace villas {
static FpgaCardPlugin
fpgaCardPlugin;
std::list<FpgaCard*>
FpgaCardPlugin::make(json_t *json, struct pci* pci, ::vfio_container* vc)
{
std::list<FpgaCard*> cards;
const char *card_name;
json_t *json_card;
json_object_foreach(json, card_name, json_card) {
std::cout << "Found config for FPGA card " << card_name << std::endl;
json_t* json_ips = nullptr;
const char* pci_slot = nullptr;
const char* pci_id = nullptr;
int do_reset = 0;
int affinity = 0;
int ret = json_unpack(json_card, "{ s: o, s?: i, s?: b, s?: s, s?: s }",
"ips", &json_ips,
"affinity", &affinity,
"do_reset", &do_reset,
"slot", &pci_slot,
"id", &pci_id);
if(ret != 0) {
std::cout << " Cannot parse JSON config" << std::endl;
continue;
}
FpgaCard* card = create();
// populate generic properties
card->name = std::string(card_name);
card->pci = pci;
card->vfio_container = vc;
card->affinity = affinity;
card->do_reset = do_reset != 0;
const char* error;
if (pci_slot != nullptr and pci_device_parse_slot(&card->filter, pci_slot, &error) != 0)
std::cout << " Failed to parse PCI slot: " << error << std::endl
<< " -> ignoring" << std::endl;
if (pci_id != nullptr and pci_device_parse_id(&card->filter, pci_id, &error) != 0)
std::cout << " Failed to parse PCI ID: " << error << std::endl
<< " -> ignoring" << std::endl;;
// TODO: currently fails, fix and remove comment
// if(not card->start()) {
// std::cout << " cannot start, destroying ..." << std::endl;
// delete card;
// continue;
// }
const char *ip_name;
json_t *json_ip;
json_object_foreach(json_ips, ip_name, json_ip) {
std::cout << " Found IP " << ip_name << std::endl;
FpgaIp* ip = FpgaIpFactory::make(card, json_ip, ip_name);
if(ip == nullptr) {
std::cout << " -> cannot initialize" << std::endl;
continue;
}
card->ips.push_back(ip);
}
if(not card->check()) {
std::cout << " checking failed, destroying ..." << std::endl;
delete card;
continue;
}
cards.push_back(card);
}
return cards;
}
FpgaCard*
FpgaCardPlugin::create()
{
return new FpgaCard;
}
bool FpgaCard::start()
{
int ret;
struct pci_device *pdev;
/* Search for FPGA card */
pdev = pci_lookup_device(pci, &filter);
if (!pdev)
error("Failed to find PCI device");
/* Attach PCIe card to VFIO container */
ret = ::vfio_pci_attach(&vfio_device, vfio_container, pdev);
if (ret)
error("Failed to attach VFIO device");
/* Map PCIe BAR */
map = (char*) vfio_map_region(&vfio_device, VFIO_PCI_BAR0_REGION_INDEX);
if (map == MAP_FAILED)
serror("Failed to mmap() BAR0");
/* Enable memory access and PCI bus mastering for DMA */
ret = vfio_pci_enable(&vfio_device);
if (ret)
serror("Failed to enable PCI device");
/* Reset system? */
if (do_reset) {
/* Reset / detect PCI device */
ret = vfio_pci_reset(&vfio_device);
if (ret)
serror("Failed to reset PCI device");
if(not reset()) {
std::cout << "Failed to reset FGPA card" << std::endl;
return false;
}
}
/* Initialize IP cores */
// for (size_t j = 0; j < list_length(&ips); j++) {
// struct fpga_ip *i = (struct fpga_ip *) list_at(&ips, j);
// ret = fpga_ip_start(i);
// if (ret)
// error("Failed to initalize FPGA IP core: %s (%u)", i->name, ret);
// }
return 0;
}
#if 0
int fpga_card_init(struct fpga_card *c, struct pci *pci, struct vfio_container *vc)
{
assert(c->state == STATE_DESTROYED);
@ -321,4 +467,6 @@ int fpga_card_reset(struct fpga_card *c)
return 0;
}
#endif
} // namespace villas

View file

@ -27,9 +27,15 @@
#include "fpga/ip.hpp"
#include <algorithm>
#include <iostream>
namespace villas {
void FpgaIp::dump() {
info("IP %s: vlnv=%s baseaddr=%#jx, irq=%d, port=%d",
name.c_str(), vlnv.toString().c_str(), baseaddr, irq, port);
}
FpgaIpFactory* FpgaIpFactory::lookup(const FpgaVlnv &vlnv)
{
@ -43,29 +49,45 @@ FpgaIpFactory* FpgaIpFactory::lookup(const FpgaVlnv &vlnv)
return nullptr;
}
FpgaIp *FpgaIpFactory::make(fpga_card *card, json_t *json, std::string name)
FpgaIp *FpgaIpFactory::make(FpgaCard* card, json_t *json, std::string name)
{
// extract VLNV from JSON
int ret;
const char* vlnv_raw;
if(json_unpack(json, "{ s: s }", "vlnv", &vlnv_raw) != 0)
error("IP '%s' has no entry 'vlnv'", name.c_str());
// extract VLNV from JSON
ret = json_unpack(json, "{ s: s }",
"vlnv", &vlnv_raw);
if(ret != 0) {
std::cout << "IP " << name << " has no entry 'vlnv'" << std::endl;
return nullptr;
}
// parse VLNV
FpgaVlnv vlnv(vlnv_raw);
// find the appropriate factory that can create the specified VLNV
// Note:
// This is the magic part! Factories automatically register as a plugin
// as soon as they are instantiated. If there are multiple candidates,
// the first suitable factory will be used.
FpgaVlnv vlnv(vlnv_raw);
FpgaIpFactory* fpgaIpFactory = lookup(vlnv);
if(fpgaIpFactory == nullptr) {
error("No ip factory registered to handle VLNV '%s'", vlnv.toString().c_str());
} else {
info("Using %s for IP %s", fpgaIpFactory->getName().c_str(), vlnv.toString().c_str());
std::cout << "No IP plugin registered to handle VLNV " << vlnv << std::endl;
return nullptr;
}
// create new IP instance
std::cout << "Using " << fpgaIpFactory->getName() << " for IP " << vlnv << std::endl;
// Create new IP instance. Since this function is virtual, it will construct
// the right, specialized type without knowing it here because we have
// already picked the right factory.
FpgaIp* ip = fpgaIpFactory->create();
if(ip == nullptr) {
std::cout << "Cannot create an instance of " << fpgaIpFactory->getName() << std::endl;
goto fail;
}
// setup generic IP type properties
ip->card = card;
@ -73,23 +95,34 @@ FpgaIp *FpgaIpFactory::make(fpga_card *card, json_t *json, std::string name)
ip->vlnv = vlnv;
// extract some optional properties
int ret = json_unpack(json, "{ s?: i, s?: i, s?: i }",
"baseaddr", &ip->baseaddr,
"irq", &ip->irq,
"port", &ip->port);
if(ret != 0)
error("Problem while parsing JSON");
ret = json_unpack(json, "{ s?: i, s?: i, s?: i }",
"baseaddr", &ip->baseaddr,
"irq", &ip->irq,
"port", &ip->port);
if(ret != 0) {
std::cout << "Problem while parsing JSON" << std::endl;
goto fail;
}
// IP-specific setup via JSON config
fpgaIpFactory->configureJson(ip, json);
if(not ip->start())
error("Cannot start IP");
// TODO: currently fails, fix and remove comment
// if(not ip->start()) {
// std::cout << "Cannot start IP" << ip->name << std::endl;
// goto fail;
// }
if(not ip->check())
error("Checking IP failed");
if(not ip->check()) {
std::cout << "Checking IP " << ip->name << " failed" << std::endl;
goto fail;
}
return ip;
fail:
delete ip;
return nullptr;
}
} // namespace villas

View file

@ -29,8 +29,11 @@
#include <villas/fpga/card.h>
#include <villas/fpga/vlnv.h>
#include <villas/plugin.hpp>
#include <villas/fpga/card.hpp>
#define FPGA_CARD "vc707"
#define TEST_CONFIG "/villas/etc/fpga.json"
#define TEST_CONFIG "../etc/fpga.json"
#define TEST_LEN 0x1000
#define CPU_HZ 3392389000
@ -48,6 +51,8 @@ static void init()
FILE *f;
json_error_t err;
villas::Plugin::dumpList();
ret = pci_init(&pci);
cr_assert_eq(ret, 0, "Failed to initialize PCI sub-system");
@ -67,6 +72,16 @@ static void init()
cr_assert_not_null(fpgas, "No section 'fpgas' found in config");
cr_assert(json_object_size(json) > 0, "No FPGAs defined in config");
// get the FPGA card plugin
villas::Plugin* plugin = villas::Plugin::lookup(villas::Plugin::Type::FpgaCard, "");
cr_assert_not_null(plugin, "No plugin for FPGA card found");
villas::FpgaCardPlugin* fpgaCardPlugin = dynamic_cast<villas::FpgaCardPlugin*>(plugin);
// create an FPGA card instance using the corresponding plugin
// villas::FpgaCard* fpgaCard = fpgaCardPlugin->make(json_);
std::list<villas::FpgaCard*> fpgaCards = fpgaCardPlugin->make(fpgas, &pci, &vc);
json_t *json_card = json_object_get(fpgas, FPGA_CARD);
cr_assert_not_null(json_card, "FPGA card " FPGA_CARD " not found");