1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-16 00:00:02 +01:00
VILLASnode/lib/nodes/fpga.c

293 lines
6.1 KiB
C
Raw Normal View History

2016-06-14 01:19:17 +02:00
/** Node type: VILLASfpga
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017, Steffen Vogel
2016-06-14 01:19:17 +02:00
*********************************************************************************/
#include <stdio.h>
2016-06-19 19:23:19 +02:00
#include <inttypes.h>
2016-06-14 01:19:17 +02:00
#include "kernel/kernel.h"
#include "kernel/pci.h"
2016-06-19 19:23:19 +02:00
#include "nodes/fpga.h"
2016-06-14 01:19:17 +02:00
2016-07-18 15:09:49 +02:00
#include "config.h"
2016-06-14 01:19:17 +02:00
#include "utils.h"
#include "timing.h"
#include "plugin.h"
2016-06-14 01:19:17 +02:00
2017-02-18 10:43:58 -05:00
#include "fpga/card.h"
2016-06-14 01:19:17 +02:00
2017-02-18 10:43:58 -05:00
static struct list cards;
static struct pci pci;
static struct vfio_container vc;
2016-06-14 01:19:17 +02:00
2016-06-19 19:23:19 +02:00
void fpga_dump(struct fpga *f)
2016-06-14 01:19:17 +02:00
{
2017-02-18 10:43:58 -05:00
struct fpga_card *c = f->ip->card;
2017-03-03 20:21:33 -04:00
fpga_card_dump(c);
}
int fpga_init(struct super_node *sn)
{
int ret;
config_setting_t *cfg, *cfg_fpgas;
2017-02-18 10:43:58 -05:00
ret = pci_init(&pci);
if (ret)
error("Failed to initialize PCI sub-system");
2017-02-18 10:43:58 -05:00
ret = vfio_init(&vc);
if (ret)
error("Failed to initiliaze VFIO sub-system");
2017-02-18 10:43:58 -05:00
/* Parse FPGA configuration */
cfg = config_root_setting(&sn->cfg);
cfg_fpgas = config_setting_lookup(cfg, "fpgas");
if (!cfg_fpgas)
cerror(cfg, "Config file is missing 'fpgas' section");
ret = fpga_card_parse_list(&cards, cfg_fpgas);
if (ret)
2017-02-18 10:43:58 -05:00
cerror(cfg, "Failed to parse VILLASfpga config");
return 0;
}
2016-06-19 19:23:19 +02:00
int fpga_deinit()
{
int ret;
2017-02-18 10:43:58 -05:00
list_destroy(&cards, (dtor_cb_t) fpga_card_destroy, true);
pci_destroy(&pci);
ret = vfio_destroy(&vc);
if (ret)
2017-02-18 10:43:58 -05:00
error("Failed to deinitialize VFIO sub-system");
ret = pci_destroy(&pci);
if (ret)
error("Failed to deinitialize PCI sub-system");
return 0;
}
2016-06-19 19:23:19 +02:00
int fpga_parse(struct node *n, config_setting_t *cfg)
{
2017-02-18 10:43:58 -05:00
struct fpga *f = n->_vd;
struct fpga_card *card;
struct fpga_ip *ip;
2016-06-19 19:23:19 +02:00
2017-02-18 10:43:58 -05:00
char *cpy, *card_name, *ip_name;
const char *dm;
2016-06-19 19:23:19 +02:00
2017-02-18 10:43:58 -05:00
if (!config_setting_lookup_string(cfg, "datamover", &dm))
2016-06-19 19:23:19 +02:00
cerror(cfg, "Node '%s' is missing the 'datamover' setting", node_name(n));
2017-02-18 10:43:58 -05:00
if (!config_setting_lookup_bool(cfg, "use_irqs", &f->use_irqs))
f->use_irqs = false;
cpy = strdup(dm); /* strtok can not operate on type const char * */
card_name = strtok(cpy, ":");
ip_name = strtok(NULL, ":");
card = list_lookup(&cards, card_name);
if (!card)
cerror(cfg, "There is no FPGA card named '%s", card_name);
ip = list_lookup(&card->ips, ip_name);
if (!ip)
cerror(cfg, "There is no datamover named '%s' on the FPGA card '%s'", ip_name, card_name);
if (ip->_vt->type != FPGA_IP_TYPE_DM_DMA && ip->_vt->type != FPGA_IP_TYPE_DM_FIFO)
2017-02-18 10:43:58 -05:00
cerror(cfg, "The IP '%s' on FPGA card '%s' is not a datamover", ip_name, card_name);
free(cpy);
f->ip = ip;
2016-06-14 01:19:17 +02:00
return 0;
}
2016-06-19 19:23:19 +02:00
char * fpga_print(struct node *n)
2016-06-14 01:19:17 +02:00
{
2017-02-18 10:43:58 -05:00
struct fpga *f = n->_vd;
struct fpga_card *c = f->ip->card;
2017-02-18 10:43:58 -05:00
if (f->ip)
return strf("dm=%s (%s:%s:%s:%s) baseaddr=%#jx port=%u slot=%02"PRIx8":%02"PRIx8".%"PRIx8" id=%04"PRIx16":%04"PRIx16,
2017-02-18 10:43:58 -05:00
f->ip->name, f->ip->vlnv.vendor, f->ip->vlnv.library, f->ip->vlnv.name, f->ip->vlnv.version,
f->ip->baseaddr, f->ip->port,
c->filter.slot.bus, c->filter.slot.device, c->filter.slot.function,
c->filter.id.vendor, c->filter.id.device);
else
2017-02-18 10:43:58 -05:00
return strf("dm=%s", f->ip->name);
}
2016-06-14 01:19:17 +02:00
int fpga_start(struct node *n)
2016-06-14 01:19:17 +02:00
{
int ret;
2016-07-08 13:31:23 +02:00
2017-02-18 10:43:58 -05:00
struct fpga *f = n->_vd;
struct fpga_card *c = f->ip->card;
fpga_card_init(c, f->pci, f->vfio_container);
2016-07-08 13:31:23 +02:00
int flags = 0;
2017-02-18 10:43:58 -05:00
if (!f->use_irqs)
2016-07-08 13:31:23 +02:00
flags |= INTC_POLLING;
switch (f->ip->_vt->type) {
case FPGA_IP_TYPE_DM_DMA:
2016-07-08 13:31:23 +02:00
/* Map DMA accessible memory */
2017-02-18 10:43:58 -05:00
ret = dma_alloc(f->ip, &f->dma, 0x1000, 0);
2016-07-08 13:31:23 +02:00
if (ret)
return ret;
2017-02-18 10:43:58 -05:00
intc_enable(c->intc, (1 << (f->ip->irq )), flags); /* MM2S */
intc_enable(c->intc, (1 << (f->ip->irq + 1)), flags); /* S2MM */
break;
case FPGA_IP_TYPE_DM_FIFO:
2017-02-18 10:43:58 -05:00
intc_enable(c->intc, (1 << f->ip->irq), flags); /* MM2S & S2MM */
break;
default: { }
}
2016-06-14 01:19:17 +02:00
return 0;
}
int fpga_stop(struct node *n)
2016-06-14 01:19:17 +02:00
{
2016-07-08 13:31:23 +02:00
int ret;
2017-02-18 10:43:58 -05:00
struct fpga *f = n->_vd;
struct fpga_card *c = f->ip->card;
2016-07-08 13:31:23 +02:00
switch (f->ip->_vt->type) {
case FPGA_IP_TYPE_DM_DMA:
2017-02-18 10:43:58 -05:00
intc_disable(c->intc, f->ip->irq); /* MM2S */
intc_disable(c->intc, f->ip->irq + 1); /* S2MM */
2016-07-08 13:31:23 +02:00
2017-02-18 10:43:58 -05:00
ret = dma_free(f->ip, &f->dma);
2016-07-08 13:31:23 +02:00
if (ret)
return ret;
case FPGA_IP_TYPE_DM_FIFO:
2017-02-18 10:43:58 -05:00
if (f->use_irqs)
intc_disable(c->intc, f->ip->irq); /* MM2S & S2MM */
default: { }
}
2016-06-14 01:19:17 +02:00
return 0;
}
2016-06-19 19:23:19 +02:00
int fpga_read(struct node *n, struct sample *smps[], unsigned cnt)
2016-06-14 01:19:17 +02:00
{
2016-07-08 13:31:23 +02:00
int ret;
2017-02-18 10:43:58 -05:00
struct fpga *f = n->_vd;
2016-06-19 19:23:19 +02:00
struct sample *smp = smps[0];
size_t recvlen;
2016-07-08 13:31:23 +02:00
size_t len = SAMPLE_DATA_LEN(64);
/* We dont get a sequence no from the FPGA. Lets fake it */
smp->sequence = -1;
smp->ts.origin = time_now();
2016-06-19 19:23:19 +02:00
/* Read data from RTDS */
switch (f->ip->_vt->type) {
case FPGA_IP_TYPE_DM_DMA:
2017-02-18 10:43:58 -05:00
ret = dma_read(f->ip, f->dma.base_phys + 0x800, len);
if (ret)
return ret;
2017-02-18 10:43:58 -05:00
ret = dma_read_complete(f->ip, NULL, &recvlen);
if (ret)
return ret;
2017-02-18 10:43:58 -05:00
memcpy(smp->data, f->dma.base_virt + 0x800, recvlen);
smp->length = recvlen / 4;
return 1;
case FPGA_IP_TYPE_DM_FIFO:
2017-02-18 10:43:58 -05:00
recvlen = fifo_read(f->ip, (char *) smp->data, len);
smp->length = recvlen / 4;
return 1;
default: { }
2016-06-19 19:23:19 +02:00
}
2016-06-14 01:19:17 +02:00
2016-06-19 19:23:19 +02:00
return -1;
2016-06-14 01:19:17 +02:00
}
2016-06-19 19:23:19 +02:00
int fpga_write(struct node *n, struct sample *smps[], unsigned cnt)
2016-06-14 01:19:17 +02:00
{
int ret;
2017-02-18 10:43:58 -05:00
struct fpga *f = n->_vd;
2016-06-19 19:23:19 +02:00
struct sample *smp = smps[0];
size_t sentlen;
size_t len = smp->length * sizeof(smp->data[0]);
2016-06-19 19:23:19 +02:00
/* Send data to RTDS */
switch (f->ip->_vt->type) {
case FPGA_IP_TYPE_DM_DMA:
2017-02-18 10:43:58 -05:00
memcpy(f->dma.base_virt, smp->data, len);
2017-02-18 10:43:58 -05:00
ret = dma_write(f->ip, f->dma.base_phys, len);
if (ret)
return ret;
2017-02-18 10:43:58 -05:00
ret = dma_write_complete(f->ip, NULL, &sentlen);
if (ret)
return ret;
//info("Sent %u bytes to FPGA", sentlen);
2016-06-19 19:23:19 +02:00
return 1;
case FPGA_IP_TYPE_DM_FIFO:
2017-02-18 10:43:58 -05:00
sentlen = fifo_write(f->ip, (char *) smp->data, len);
return sentlen / sizeof(smp->data[0]);
2016-06-19 19:23:19 +02:00
break;
default: { }
2016-06-19 19:23:19 +02:00
}
return -1;
2016-06-14 01:19:17 +02:00
}
2017-03-03 20:21:33 -04:00
struct fpga_card * fpga_lookup_card(const char *name)
{
return (struct fpga_card *) list_lookup(&cards, name);
}
static struct plugin p = {
2016-06-19 19:23:19 +02:00
.name = "fpga",
.description = "VILLASfpga PCIe card (libxil)",
.type = PLUGIN_TYPE_NODE,
.node = {
2017-02-18 10:43:58 -05:00
.size = sizeof(struct fpga),
.vectorize = 1,
.parse = fpga_parse,
.print = fpga_print,
.start = fpga_start,
.stop = fpga_stop,
.read = fpga_read,
.write = fpga_write,
.init = fpga_init,
.deinit = fpga_deinit,
.instances = LIST_INIT()
}
2016-06-14 01:19:17 +02:00
};
REGISTER_PLUGIN(&p)