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

first steps towards flexible and configurable VILLASfpga / VILLASnode integration

This commit is contained in:
Steffen Vogel 2016-06-15 20:05:09 +02:00
parent bffb47dca8
commit 98fb370e85
15 changed files with 709 additions and 846 deletions

View file

@ -64,7 +64,8 @@ endif
# Enable VILLASfpga support when libpci is available
ifeq ($(shell pkg-config libpci; echo $$?),0)
LIB_OBJS += vfpga.o pci.o dma.o model.o fifo.o xsg.o vfio.o switch.o rtds_axis.o
LIB_OBJS += vfpga.o pci.o ip.o vfio.o
LIB_OBJS += dma.o model.o fifo.o switch.o rtds_axis.o
LDLIBS += -lxil
LDFLAGS += -Lthirdparty/xilinx -Wl,-rpath-link,'$$ORIGIN/thirdparty/xilinx'
CFLAGS += -Ithirdparty/xilinx/include

View file

@ -28,83 +28,6 @@
#define virt_to_dma(virt, dma) ((char *) ((char *) virt - dma) + BASEADDR_HOST)
#define dma_to_virt(addr, dma) ((char *) ((char *) addr - BASEADDR_HOST) + dma)
#if 0
/** Base addresses in AXI bus of FPGA */
enum {
BASEADDR_BRAM = 0x0000, /* 8 KB Block RAM for DMA SG descriptors */
BASEADDR_XSG = 0x2000, /* Xilinx System Generator Model */
BASEADDR_DMA_SG = 0x3000, /* Scatter Gather DMA controller registers */
BASEADDR_TIMER = 0x4000, /* Timer Counter registers */
BASEADDR_SWITCH = 0x5000, /* AXI Stream switch registers */
BASEADDR_FIFO_MM = 0x6000, /* Memory-mapped to AXI Stream FIFO */
BASEADDR_RESET = 0x7000, /* Internal Reset register */
BASEADDR_RTDS = 0x8000, /* RTDS to AXI Stream bridge */
BASEADDR_HLS = 0x9000, /* High-level Synthesis model registers */
BASEADDR_DMA_SIMPLE = 0xA000, /* Simple DMA controller registers */
BASEADDR_INTC = 0xB000, /* PCIe MSI Interrupt controller registers */
BASEADDR_FIFO_MM_AXI4 = 0xC000, /* AXI4 (full) interface of AXI Stream FIFO */
BASEADDR_HOST = 0x80000000 /* Start of host memory (0x0 of IOMMU) */
};
/** MSI vector table for VILLASfpga components */
enum {
MSI_TMRCTR0 = 0, /* Sensivity: rising edge, synchronous: axi_clk */
MSI_TMRCTR1 = 1, /* Sensivity: rising edge, synchronous: axi_clk */
MSI_FIFO_MM = 2, /* Sensivity: level high, synchronous: axi_clk */
MSI_DMA_MM2S = 3, /* Sensivity: level high, synchronous: axi_clk */
MSI_DMA_S2MM = 4, /* Sensivity: level high, synchronous: axi_clk */
MSI_RTDS_TS = 5, /* Sensivity: rising edge, synchronous: rtds_clk100m (New timestep started) */
MSI_RTDS_OVF = 6, /* Sensivity: rising edge, synchronous: rtds_clk100m (UserTxInProgress overlapped with UserTStepPulse)*/
MSI_RTDS_CASE = 7 /* Sensivity: rising edge, synchronous: rtds_clk100m (New RSCAD case started) */
};
/** Mapping of VILLASfpga components to AXI Stream interconnect ports */
enum {
AXIS_SWITCH_RTDS = 0,
AXIS_SWITCH_DMA_SG = 1,
AXIS_SWITCH_FIFO_MM = 2,
AXIS_SWITCH_FIFO0 = 3,
AXIS_SWITCH_XSG = 4,
AXIS_SWITCH_HLS = 5,
AXIS_SWITCH_FIFO1 = 6,
AXIS_SWITCH_DMA_SIMPLE = 7,
AXI_SWITCH_NUM = 8 /* Number of master and slave interfaces */
};
#else
#define HAS_DMA_SIMPLE 1
#define HAS_SWITCH 1
#define HAS_XSG 1
/** Base addresses in AXI bus of FPGA */
enum {
BASEADDR_SWITCH = 0x0000, /* AXI Stream switch registers */
BASEADDR_DMA_SIMPLE = 0x1000, /* Simple DMA controller registers */
BASEADDR_RESET = 0x2000, /* Internal Reset register */
BASEADDR_RTDS = 0x3000, /* RTDS to AXI Stream bridge */
BASEADDR_XSG = 0x4000, /* Xilinx System Generator Model */
BASEADDR_INTC = 0x5000, /* PCIe MSI Interrupt controller registers */
BASEADDR_PCIE = 0x10000000, /* PCIe config space */
BASEADDR_HOST = 0x80000000 /* Start of host memory (0x0 of IOMMU) */
};
/** MSI vector table for VILLASfpga components */
enum {
MSI_DMA_MM2S = 0, /* Sensivity: level high, synchronous: axi_clk */
MSI_DMA_S2MM = 1, /* Sensivity: level high, synchronous: axi_clk */
MSI_RTDS_TS = 2, /* Sensivity: rising edge, synchronous: rtds_clk100m (New timestep started) */
MSI_RTDS_OVF = 3, /* Sensivity: rising edge, synchronous: rtds_clk100m (UserTxInProgress overlapped with UserTStepPulse)*/
MSI_RTDS_CASE = 4 /* Sensivity: rising edge, synchronous: rtds_clk100m (New RSCAD case started) */
};
/** Mapping of VILLASfpga components to AXI Stream interconnect ports */
enum {
AXIS_SWITCH_RTDS = 0,
AXIS_SWITCH_XSG = 1,
AXIS_SWITCH_DMA_SIMPLE = 2,
AXI_SWITCH_NUM = 3 /* Number of master and slave interfaces */
};
#endif
#define PCI_VID_XILINX 0x10ee
#define PCI_PID_VFPGA 0x7022

40
etc/vfpga.conf Normal file
View file

@ -0,0 +1,40 @@
fpga = {
reset = false;
ips = {
switch_0 = {
vlnv = "xilinx.com:ip:axis_interconnect:2.1"
baseaddr = 0x0000;
numports = 3;
},
rtds_0 = {
vlnv = "acs.eonerc.rwth-aachen.de:user:rtds_axis:1.0"
baseaddr = 0x3000;
port = 0;
},
dma_0 = {
vlnv = "xilinx.com:ip:axi_dma:7.1";
baseaddr = 0x0000;
port = 2;
irq = 0
},
hls_dft_0 = {
vlnv = "acs.eonerc.rwth-aachen.de:hls:hls_dft:1.0";
baseaddr = 0x0000;
port = 1;
switch = "switch_0";
}
}
/* Configure switch */
paths = (
{ in = "dma", out = "hls_dft" },
{ in = "hls_dft", out = "dma" }
)
}
nodes = {
fpga_dma = {
}
}

View file

@ -1,21 +0,0 @@
/** Benchmarks for VILLASfpga
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2015-2016, Steffen Vogel
* This file is part of VILLASnode. All Rights Reserved. Proprietary and confidential.
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
#ifndef _BENCH_H_
#define _BENCH_H_
#include "nodes/vfpga.h"
int bench_memcpy(struct vfpga *f);
int bench_memcpy(struct vfpga *f);
int bench_dm(struct vfpga *f);
#endif /* _BENCH_H_ */

View file

@ -1,29 +0,0 @@
/** Test procedures for VILLASfpga
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2016, Steffen Vogel
* This file is part of VILLASnode. All Rights Reserved. Proprietary and confidential.
* Unauthorized copying of this file, via any medium is strictly prohibited.
*********************************************************************************/
#ifndef _TESTS_H_
#define _TESTS_H_
#include "nodes/vfpga.h"
int test_intc(struct vfpga *f);
int test_xsg(struct vfpga *f, const char *name);
int test_fifo(struct vfpga *f);
int test_dma(struct vfpga *f);
int test_timer(struct vfpga *f);
int test_rtds_rtt(struct vfpga *f);
int test_rtds_cbuilder(struct vfpga *f);
#endif /* _TESTS_H_ */

View file

@ -13,27 +13,19 @@
#include <stdlib.h>
#include <inttypes.h>
#include <villas/list.h>
#include "list.h"
#include "xsg.h"
#define XSG_MAGIC 0xDEADBABE
enum model_type {
MODEL_TYPE_HLS,
MODEL_TYPE_XSG
};
struct model {
char *name; /**< Name / Identifier of model */
void *baseaddr; /**< Base of register map. */
enum model_type type; /**< Model type. */
struct list parameters; /**< List of model parameters. */
union {
struct xsg_model xsg; /**< XSG specific model data */
//struct hls_model hls; /**< HLS specific model data */
};
enum model_xsg_block_type {
XSG_BLOCK_GATEWAY_IN = 0x1000,
XSG_BLOCK_GATEWAY_OUT = 0x1001,
XSG_BLOCK_INFO = 0x2000
};
enum model_param_type {
@ -56,6 +48,31 @@ union model_param_value {
bool bol;
};
struct model {
char *xml; /**< Path to a XML file which describes this model */
enum model_type type;
struct list parameters; /**< List of model parameters. */
struct list infos;
char *map;
size_t maplen;
union {
struct xsg_model {
char *map;
size_t maplen;
} xsg; /**< XSG specific model data */
struct hls_model {
} hls; /**< HLS specific model data */
};
};
struct model_info {
char *field;
char *value;
};
struct model_param {
char *name; /**< Name of the parameter */
@ -63,25 +80,25 @@ struct model_param {
enum model_param_type type; /**< Data type. Integers are represented by MODEL_GW_TYPE_(U)FIX with model_gw::binpt == 0 */
int binpt; /**< Binary point for type == MODEL_GW_TYPE_(U)FIX */
int offset; /**< Register offset to model::baseaddress */
uintptr_t offset; /**< Register offset to model::baseaddress */
union model_param_value default_value;
struct model *model; /**< A pointer to the model structure to which this parameters belongs to. */
};
int model_init(struct model *m, const char *xml);
int model_init(struct model *m, uintptr_t baseaddr);
int model_init_from_xsg_map(struct model *m, uintptr_t baseaddr);
int model_init_from_xml(struct model *m);
void model_destroy(struct model *m);
void model_dump(struct model *m);
void model_param_destroy(struct model_param *r);
void model_param_add(struct model *m, const char *name, enum model_param_direction dir, enum model_param_type type);
char * xsg_get_info(struct xsg_model *x, const char *key);
/** Read a model parameter.
*
* Note: the data type of the register is taken into account.
@ -97,4 +114,10 @@ int model_param_read(struct model_param *p, double *v);
*/
int model_param_write(struct model_param *p, double v);
/** Read the XSG model information from ROM */
int model_xsg_map_read(void *offset, void *dst, size_t len);
/** Parse binary model information from ROM */
int model_xsg_map_parse(uint32_t *map, size_t len, struct list *parameters, struct list *infos);
#endif /* _MODEL_H_ */

View file

@ -1,54 +0,0 @@
/** Interface to Xilinx System Generator Models via VILLASfpga
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2016, Steffen Vogel
* This file is part of S2SS. All Rights Reserved. Proprietary and confidential.
* Unauthorized copying of this file, via any medium is strictly prohibited.
*********************************************************************************/
#ifndef _XSG_H_
#define _XSG_H_
#define XSG_MAGIC 0xDEADBABE
/* Forward declaration */
struct model;
enum xsg_block_type {
XSG_BLOCK_GATEWAY_IN = 0x1000,
XSG_BLOCK_GATEWAY_OUT = 0x1001,
XSG_BLOCK_INFO = 0x2000
};
struct xsg_model {
int version;
char *map;
size_t maplen;
struct list infos;
};
struct xsg_info {
char *field;
char *value;
};
int xsg_init_from_map(struct model *m);
int xsg_init_from_xml(struct model *m, const char *xml);
void xsg_destroy(struct xsg_model *x);
void xsg_dump(struct xsg_model *x);
void xsg_info_destroy(struct xsg_info *i);
/** Read the XSG model information from ROM */
int xsg_map_read(void *offset, void *dst, size_t len);
/** Parse binary model information from ROM */
int xsg_map_parse(uint32_t *map, size_t len, struct list *parameters, struct list *infos);
#endif /* _XSG_H_ */

View file

@ -17,53 +17,36 @@
#ifndef _VFPGA_H_
#define _VFPGA_H_
#include <xilinx/xtmrctr.h>
#include <xilinx/xintc.h>
#include <xilinx/xllfifo.h>
#include <xilinx/xaxis_switch.h>
#include <xilinx/xaxidma.h>
#include "kernel/vfio.h"
#include "fpga/switch.h"
#include "fpga/model.h"
#include "fpga/dma.h"
#include "fpga/fifo.h"
#include "fpga/rtds_axis.h"
#include <pci/pci.h>
#include "nodes/vfpga.h"
#include "node.h"
#include "list.h"
#define BASEADDR_HOST 0x8000000
#define VFPGA_BAR 0 /**< The Base Address Register which is mmap()ed to the User Space */
struct vfpga {
struct pci_filter filter;
enum {
vfpga_MODE_FIFO,
vfpga_MODE_DMA
} mode;
int features;
struct list models; /**< List of XSG and HLS model blocks on FPGA. */
struct pci_filter filter; /**< Filter for libpci with device id & slot */
struct vfio_dev vd; /**< VFIO device handle. */
/* Xilinx IP blocks */
XTmrCtr tmr;
XLlFifo fifo;
XAxiDma dma_simple;
XAxiDma dma_sg;
XAxis_Switch sw;
int reset; /**< Reset VILLASfpga during startup? */
struct list ips; /**< List of IP components on FPGA. */
char *map; /**< PCI BAR0 mapping for register access */
char *dma; /**< DMA mapped memory */
size_t maplen;
size_t dmalen;
/** Base addresses for internal IP blocks */
struct {
uintptr_t reset;
uintptr_t intc;
} baseaddr;
};
/** @see node_vtable::init */
@ -73,7 +56,9 @@ int vfpga_init(int argc, char * argv[], config_setting_t *cfg);
int vfpga_deinit();
/** @see node_vtable::parse */
int vfpga_parse(struct node *n, config_setting_t *cfg);
int vfpga_parse_node(struct node *n, config_setting_t *cfg);
int vfpga_parse(struct vfpga *v, int argc, char * argv[], config_setting_t *cfg);
/** @see node_vtable::print */
char * vfpga_print(struct node *n);
@ -90,14 +75,13 @@ int vfpga_read(struct node *n, struct sample *smps[], unsigned cnt);
/** @see node_vtable::write */
int vfpga_write(struct node *n, struct sample *smps[], unsigned cnt);
//////////
int vfpga_init2(struct vfpga *f, struct vfio_container *vc, struct pci_dev *pdev);
int vfpga_deinit2(struct vfpga *f);
/** Get pointer to internal VILLASfpga datastructure */
struct vfpga * vfpga_get();
/** Reset VILLASfpga */
int vfpga_reset(struct vfpga *f);
/** Dump some details about the fpga card */
void vfpga_dump(struct vfpga *f);
#endif /** _VFPGA_H_ @} */

View file

@ -20,16 +20,18 @@
int config_parse(const char *filename, config_t *cfg, struct settings *set,
struct list *nodes, struct list *paths)
{
char *filename_cpy = strdup(filename);
char *include_dir = dirname(filename_cpy);
int ret;
char *filename_cpy, include_dir;
filename_cpy = strdup(filename);
include_dir = dirname(filename_cpy);
free(filename_cpy);
/* Setup libconfig */
config_set_auto_convert(cfg, 1);
config_set_include_dir(cfg, include_dir);
free(filename_cpy);
int ret = strcmp("-", filename) ? config_read_file(cfg, filename) : config_read(cfg, stdin);
ret = strcmp("-", filename) ? config_read_file(cfg, filename) : config_read(cfg, stdin);
if (ret != CONFIG_TRUE) {
error("Failed to parse configuration: %s in %s:%d",
config_error_text(cfg),

View file

@ -15,20 +15,40 @@
#include <villas/log.h>
#include "fpga/model.h"
#include "fpga/xsg.h"
int model_init(struct model *m, const char *xml)
int model_init(struct model *m, uintptr_t baseaddr)
{
/** @todo: parse XML model descriptions */
int ret;
/** @todo: Currently only XSG models are supported */
list_init(&m->parameters);
list_init(&m->infos);
ret = model_init_from_xsg_map(m, baseaddr);
if (ret)
error("Failed to init XSG model: %d", ret);
return 0;
}
static void model_param_destroy(struct model_param *p)
{
free(p->name);
}
static void model_info_destroy(struct model_info *i)
{
free(i->field);
free(i->value);
}
void model_destroy(struct model *m)
{
list_destroy(&m->parameters, (dtor_cb_t) model_param_destroy, true);
list_destroy(&m->infos, (dtor_cb_t) model_info_destroy, true);
free(m->map);
}
void model_dump(struct model *m)
@ -37,13 +57,13 @@ void model_dump(struct model *m)
const char *model_types[] = { "HLS", "XSG" };
const char *parameter_dirs[] = { "In", "Out", "In/Out" };
info("Model: %s (baseaddr=%p, type=%s)", m->name, m->baseaddr, model_types[m->type]);
info("Model: (type=%s)", model_types[m->type]);
{ INDENT
info("Parameters:");
list_foreach(struct model_param *p, &m->parameters) { INDENT
if (p->direction == MODEL_PARAM_IN)
info("%#x: %s (%s) = %.3f %s %u",
info("%#jx: %s (%s) = %.3f %s %u",
p->offset,
p->name,
parameter_dirs[p->direction],
@ -52,27 +72,23 @@ void model_dump(struct model *m)
p->binpt
);
else if (p->direction == MODEL_PARAM_OUT)
info("%#x: %s (%s)",
info("%#jx: %s (%s)",
p->offset,
p->name,
parameter_dirs[p->direction]
);
}
switch (m->type) {
case MODEL_TYPE_HLS:
//hls_dump(&m->hls);
break;
case MODEL_TYPE_XSG:
xsg_dump(&m->xsg);
break;
info("Infos:");
list_foreach(struct model_info *i, &m->infos) { INDENT
info("%s: %s", i->field, i->value);
}
}
}
int model_param_read(struct model_param *p, double *v)
{
union model_param_value *ptr = p->offset + p->model->baseaddr;
union model_param_value *ptr = p->offset;// TODO: + p->model->baseaddr;
switch (p->type) {
case MODEL_PARAM_TYPE_UFIX:
@ -96,7 +112,7 @@ int model_param_read(struct model_param *p, double *v)
int model_param_write(struct model_param *p, double v)
{
union model_param_value *ptr = p->offset + p->model->baseaddr;
union model_param_value *ptr = p->offset;// TODO: + p->model->baseaddr;
switch (p->type) {
case MODEL_PARAM_TYPE_UFIX:
@ -130,7 +146,118 @@ void model_param_add(struct model *m, const char *name, enum model_param_directi
list_push(&m->parameters, p);
}
void model_param_destroy(struct model_param *p)
int model_init_from_xsg_map(struct model *m, uintptr_t baseaddr)
{
free(p->name);
int ret;
list_init(&m->infos);
m->map = alloc(1024);
m->maplen = model_xsg_map_read(baseaddr, m->map, 1024 / 4);
if (m->maplen < 0)
return -1;
debug(5, "XSG: memory map length = %#zx", m->maplen);
ret = model_xsg_map_parse((uint32_t *) m->map, m->maplen, &m->parameters, &m->infos);
if (ret)
return -2;
return 0;
}
static uint32_t model_xsg_map_checksum(uint32_t *map, size_t len)
{
uint32_t chks = 0;
for (int i = 2; i < len-1; i++)
chks += map[i];
return chks; /* moduluo 2^32 because of overflow */
}
int model_xsg_map_parse(uint32_t *map, size_t len, struct list *parameters, struct list *infos)
{
#define copy_string(off) strndup((char *) (data + (off)), (length - (off)) * 4);
struct model_param *p;
struct model_info *i;
int j;
if (map[0] != XSG_MAGIC)
error("Invalid magic: %#x", map[0]);
for (j = 2; j < len-1;) {
uint16_t type = map[j] & 0xFFFF;
uint16_t length = map[j] >> 16;
uint32_t *data = &map[j+1];
switch (type) {
case XSG_BLOCK_GATEWAY_IN:
case XSG_BLOCK_GATEWAY_OUT:
if (length < 4)
break; /* block is to small to describe a gateway */
p = alloc(sizeof(*p));
p->name = copy_string(3);
p->default_value.flt = *((float *) &data[1]);
p->offset = data[2];
p->direction = type & 0x1;
p->type = (data[0] >> 0) & 0xFF;
p->binpt = (data[0] >> 8) & 0xFF;
list_push(parameters, p);
break;
case XSG_BLOCK_INFO:
i = alloc(sizeof(struct model_info));
i->field = copy_string(0);
i->value = copy_string((int) ceil((double) (strlen(i->field) + 1) / 4))
list_push(infos, i);
break;
default:
warn("Unknown block type: %#06x", type);
}
j += length + 1;
}
if (model_xsg_map_checksum(map, len) != map[j])
error("XSG: Invalid checksum");
return 0;
#undef copy_string
}
int model_xsg_map_read(void *baseaddr, void *dst, size_t len)
{
#define get_word(a) ({ *addr = a; *data; })
volatile uint32_t *addr = baseaddr + 0x00;
volatile uint32_t *data = baseaddr + 0x04;
uint32_t *map = dst;
uint32_t maplen, magic;
/* Check start DW */
magic = get_word(0);
if (magic != XSG_MAGIC)
return -1;
maplen = get_word(1);
if (maplen < 3)
return -2;
/* Read Data */
int i;
for (i = 0; i < MIN(maplen, len); i++)
map[i] = get_word(i);
return i;
#undef get_word
}

View file

@ -1,176 +0,0 @@
/** Interface to Xilinx System Generator Models via VILLASfpga
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2016, Steffen Vogel
* This file is part of VILLASnode. All Rights Reserved. Proprietary and confidential.
* Unauthorized copying of this file, via any medium is strictly prohibited.
*********************************************************************************/
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <sys/types.h>
#include <villas/list.h>
#include <villas/utils.h>
#include <villas/log.h>
#include "fpga/model.h"
#include "fpga/xsg.h"
#include "utils.h"
int xsg_init_from_map(struct model *m)
{
int ret;
struct xsg_model *x = &m->xsg;
list_init(&x->infos);
x->map = alloc(1024);
x->maplen = xsg_map_read(m->baseaddr, x->map, 1024 / 4);
if (x->maplen < 0)
return -1;
debug(5, "XSG: memory map length = %#zx", x->maplen);
ret = xsg_map_parse((uint32_t *) x->map, x->maplen, &m->parameters, &x->infos);
if (ret)
return -2;
m->name = xsg_get_info(x, "Name");
return 0;
}
int xsg_init_from_xml(struct model *m, const char *xml)
{
/** @todo: parse Simulink .mdl file here (XML based) */
return -1;
}
void xsg_destroy(struct xsg_model *x)
{
list_destroy(&x->infos, (dtor_cb_t) xsg_info_destroy, true);
free(x->map);
}
char * xsg_get_info(struct xsg_model *x, const char *key)
{
struct xsg_info *info = list_lookup(&x->infos, key);
return info ? info->value : NULL;
}
void xsg_info_destroy(struct xsg_info *i)
{
free(i->field);
free(i->value);
}
void xsg_dump(struct xsg_model *x)
{
info("XSG Infos:");
list_foreach(struct xsg_info *i, &x->infos) { INDENT
info("%s: %s", i->field, i->value);
}
}
static uint32_t xsg_map_checksum(uint32_t *map, size_t len)
{
uint32_t chks = 0;
for (int i = 2; i < len-1; i++)
chks += map[i];
return chks; /* moduluo 2^32 because of overflow */
}
int xsg_map_parse(uint32_t *map, size_t len, struct list *parameters, struct list *infos)
{
#define copy_string(off) strndup((char *) (data + (off)), (length - (off)) * 4);
struct model_param *p;
struct xsg_info *info;
int i;
if (map[0] != XSG_MAGIC)
error("Invalid magic: %#x", map[0]);
for (i = 2; i < len-1;) {
uint16_t type = map[i] & 0xFFFF;
uint16_t length = map[i] >> 16;
uint32_t *data = &map[i+1];
switch (type) {
case XSG_BLOCK_GATEWAY_IN:
case XSG_BLOCK_GATEWAY_OUT:
if (length < 4)
break; /* block is to small to describe a gateway */
p = alloc(sizeof(*p));
p->name = copy_string(3);
p->default_value.flt = *((float *) &data[1]);
p->offset = data[2];
p->direction = type & 0x1;
p->type = (data[0] >> 0) & 0xFF;
p->binpt = (data[0] >> 8) & 0xFF;
list_push(parameters, p);
break;
case XSG_BLOCK_INFO:
info = alloc(sizeof(*info));
info->field = copy_string(0);
info->value = copy_string((int) ceil((double) (strlen(info->field) + 1) / 4))
list_push(infos, info);
break;
default:
warn("Unknown block type: %#06x", type);
}
i += length + 1;
}
if (xsg_map_checksum(map, len) != map[i])
error("XSG: Invalid checksum");
return 0;
#undef copy_string
}
int xsg_map_read(void *baseaddr, void *dst, size_t len)
{
#define get_word(a) ({ *addr = a; *data; })
volatile uint32_t *addr = baseaddr + 0x00;
volatile uint32_t *data = baseaddr + 0x04;
uint32_t *map = dst;
uint32_t maplen, magic;
/* Check start DW */
magic = get_word(0);
if (magic != XSG_MAGIC)
return -1;
maplen = get_word(1);
if (maplen < 3)
return -2;
/* Read Data */
int i;
for (i = 0; i < MIN(maplen, len); i++)
map[i] = get_word(i);
return i;
#undef get_word
}

View file

@ -7,7 +7,7 @@
*********************************************************************************/
#include <stdio.h>
#include <inttypes.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
@ -17,28 +17,202 @@
#include "nodes/vfpga.h"
#include "config.h"
#include "fpga/ip.h"
#include "config-fpga.h"
#include "utils.h"
#include "timing.h"
struct vfpga fpga;
struct vfio_container vc;
static struct pci_access *pacc;
typedef void(*log_cb_t)(char *, ...);
int vfpga_init2(struct vfpga *f, struct vfio_container *vc, struct pci_dev *pdev)
int vfpga_reset(struct vfpga *f)
{
int ret;
char state[4096];
list_init(&f->models);
/* Save current state of PCI configuration space */
ret = pread(f->vd.fd, state, sizeof(state), (off_t) VFIO_PCI_CONFIG_REGION_INDEX << 40);
if (ret != sizeof(state))
return -1;
uint32_t *rst_reg = (uint32_t *) (f->map + f->baseaddr.reset);
info("Reset fpga");
rst_reg[0] = 1;
usleep(100000);
/* Restore previous state of PCI configuration space */
ret = pwrite(f->vd.fd, state, sizeof(state), (off_t) VFIO_PCI_CONFIG_REGION_INDEX << 40);
if (ret != sizeof(state))
return -1;
info("Reset status = %#x", *rst_reg);
return 0;
}
void vfpga_dump(struct vfpga *f)
{
char namebuf[128];
char *name;
name = pci_lookup_name(pacc, namebuf, sizeof(namebuf), PCI_LOOKUP_DEVICE, fpga.vd.pdev->vendor_id, fpga.vd.pdev->device_id);
pci_fill_info(fpga.vd.pdev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS); /* Fill in header info we need */
info("VILLASfpga card: %s", name);
{ INDENT
info("Slot: %04x:%02x:%02x.%d", fpga.vd.pdev->domain, fpga.vd.pdev->bus, fpga.vd.pdev->dev, fpga.vd.pdev->func);
info("Vendor ID: %04x", fpga.vd.pdev->vendor_id);
info("Device ID: %04x", fpga.vd.pdev->device_id);
info("Class ID: %04x", fpga.vd.pdev->device_class);
info("BAR0 mapped at %p", fpga.map);
info("DMA mapped at %p", fpga.dma);
info("IP blocks:");
list_foreach(struct ip *i, &f->ips) { INDENT
ip_dump(i);
}
}
vfio_dump(fpga.vd.group->container);
}
struct vfpga * vfpga_get()
{
return &fpga;
}
static void vfpga_debug(char *msg, ...) {
va_list ap;
va_start(ap, msg);
log_vprint(LOG_LVL_DEBUG, msg, ap);
va_end(ap);
}
int vfpga_parse(struct vfpga *v, int argc, char * argv[], config_setting_t *cfg)
{
int ret;
const char *slot, *id, *err;
config_setting_t *cfg_fpga, *cfg_ips, *cfg_slot, *cfg_id;
/* Default values */
v->filter.vendor = PCI_VID_XILINX;
v->filter.device = PCI_PID_VFPGA;
v->reset = false;
cfg_fpga = config_setting_get_member(cfg, "fpga");
if (!cfg_fpga)
cerror(cfg, "Config file is missing VILLASfpga configuration");
config_setting_lookup_bool(cfg_fpga, "reset", &v->reset);
cfg_slot = config_setting_get_member(cfg_fpga, "slot");
if (cfg_slot) {
slot = config_setting_get_string(cfg_slot);
if (slot) {
err = pci_filter_parse_slot(&v->filter, (char*) slot);
if (err)
cerror(cfg_slot, "%s", err);
}
else
cerror(cfg_slot, "Invalid slot format");
}
cfg_id = config_setting_get_member(cfg_fpga, "id");
if (cfg_id) {
id = config_setting_get_string(cfg_id);
if (id) {
err = pci_filter_parse_id(&v->filter, (char*) id);
if (err)
cerror(cfg_id, "%s", err);
}
else
cerror(cfg_slot, "Invalid id format");
}
f->features = 0;
cfg_ips = config_setting_get_member(cfg_fpga, "ips");
if (!cfg_ips)
cerror(cfg_fpga, "FPGA configuration is missing ips section");
for (int i = 0; i < config_setting_length(cfg_ips); i++) {
struct ip ip;
config_setting_t *cfg_ip = config_setting_get_elem(cfg_ips, i);
ret = ip_parse(&ip, cfg_ip);
if (ret)
cerror(cfg_ip, "Failed to parse VILLASfpga ip");
list_push(&v->ips, memdup(&ip, sizeof(struct ip)));
}
return 0;
}
struct pci_access * vfpga_init_pci()
{
struct pci_access *pacc;
pacc = pci_alloc(); /* Get the pci_access structure */
if (!pacc)
error("Failed to allocate PCI access structure");
pci_init(pacc); /* Initialize the PCI library */
pci_scan_bus(pacc); /* We want to get the list of devices */
pacc->error = (log_cb_t) error; /* Replace logging and debug functions */
pacc->warning = (log_cb_t) warn;
pacc->debug = vfpga_debug;
pci_scan_bus(pacc); /* We want to get the list of devices */
return pacc;
}
int vfpga_init(int argc, char * argv[], config_setting_t *cfg)
{
int ret;
struct pci_access *pacc;
struct pci_dev *pdev;
struct vfpga *f;
/* For now we only support a single VILALSfpga card */
f = vfpga_get();
/* Some hardcoded addresses for internal IP blocks */
f->baseaddr.reset = 0x2000;
f->baseaddr.intc = 0x5000;
pacc = vfpga_init_pci();
pci_filter_init(pacc, &f->filter);
list_init(&f->ips);
ret = vfpga_parse(f, argc, argv, cfg);
if (ret)
cerror(cfg, "Failed to parse VILLASfpga config");
/* Search for fpga card */
pdev = pci_find_device(pacc, &f->filter);
if (!pdev)
error("Failed to find PCI device");
if (pdev->vendor_id != PCI_VID_XILINX)
error("This is not a Xilinx FPGA board!");
/* Get VFIO handles and details */
ret = vfio_init(&vc);
if (ret)
serror("Failed to initialize VFIO");
/* Attach PCIe card to VFIO container */
ret = vfio_pci_attach(&f->vd, vc, pdev);
ret = vfio_pci_attach(&f->vd, &vc, pdev);
if (ret)
error("Failed to attach VFIO device");
@ -64,223 +238,44 @@ int vfpga_init2(struct vfpga *f, struct vfio_container *vc, struct pci_dev *pdev
if (ret)
serror("Failed to enable PCI device");
#if 1
/* Trigger internal reset of fpga card / PCIe endpoint */
ret = vfpga_reset(f);
if (ret)
serror("Failed to reset fpga card");
#endif
/* Reset / detect PCI device */
ret = vfio_pci_reset(&f->vd);
if (ret)
serror("Failed to reset PCI device");
/* Initialize Interrupt controller */
XIntc_Out32((uintptr_t) f->map + BASEADDR_INTC + XIN_IMR_OFFSET, 0);
XIntc_Out32((uintptr_t) f->map + BASEADDR_INTC + XIN_IAR_OFFSET, 0xFFFFFFFF); /* Acknowlege all pending IRQs */
usleep(1000);
/* Setup Vectors */
for (int i = 0; i < 16; i++)
XIntc_Out32((uintptr_t) f->map + BASEADDR_INTC + XIN_IVAR_OFFSET + i * sizeof(uint32_t), i);
XIntc_Out32((uintptr_t) f->map + BASEADDR_INTC + XIN_IMR_OFFSET, 0xFFFFFFFF); /* Use fast acknowlegement for all IRQs */
XIntc_Out32((uintptr_t) f->map + BASEADDR_INTC + XIN_IER_OFFSET, 0x00000000);
XIntc_Out32((uintptr_t) f->map + BASEADDR_INTC + XIN_MER_OFFSET, XIN_INT_HARDWARE_ENABLE_MASK | XIN_INT_MASTER_ENABLE_MASK);
#ifdef HAS_SWITCH
/* Initialize AXI4-Sream crossbar switch */
ret = switch_init(&f->sw, f->map + BASEADDR_SWITCH, AXI_SWITCH_NUM, AXI_SWITCH_NUM);
if (ret)
error("Failed to initialize switch");
#endif
#ifdef HAS_XSG
/* Initialize System Generator model */
struct model *m = alloc(sizeof(struct model));
m->baseaddr = f->map + BASEADDR_XSG;
m->type = MODEL_TYPE_XSG;
ret = model_init(m, NULL);
if (ret)
error("Failed to init model: %d", ret);
ret = xsg_init_from_map(m);
if (ret)
error("Failed to init XSG model: %d", ret);
list_push(&f->models, m);
#endif
#ifdef HAS_FIFO_MM
/* Initialize AXI4-Stream Memory Mapped FIFO */
ret = fifo_init(&f->fifo, f->map + BASEADDR_FIFO_MM, f->map + BASEADDR_FIFO_MM_AXI4);
if (ret)
error("Failed to initialize FIFO");
#endif
#ifdef HAS_DMA_SG
/* Initialize Scatter Gather DMA controller */
struct dma_mem bd = {
.base_virt = (uintptr_t) f->map + BASEADDR_BRAM,
.base_phys = BASEADDR_BRAM,
.len = 0x2000
};
struct dma_mem rx = {
.base_virt = (uintptr_t) f->dma,
.base_phys = BASEADDR_HOST,
.len = 0x10000
};
ret = dma_init(&f->dma_sg, f->map + BASEADDR_DMA_SG, DMA_MODE_SG, &bd, &rx, sizeof(uint32_t) * 64);
if (ret)
return -1;
#endif
#ifdef HAS_DMA_SIMPLE
/* Initialize Simple DMA controller */
ret = dma_init(&f->dma_simple, f->map + BASEADDR_DMA_SIMPLE, DMA_MODE_SIMPLE, 0, 0, 0);
if (ret)
return -1;
#endif
#ifdef HAS_TIMER
/* Initialize timer */
XTmrCtr_Config tmr_cfg = {
.BaseAddress = (uintptr_t) f->map + BASEADDR_TIMER,
.SysClockFreqHz = AXI_HZ
};
XTmrCtr_CfgInitialize(&f->tmr, &tmr_cfg, (uintptr_t) f->map + BASEADDR_TIMER);
XTmrCtr_InitHw(&f->tmr);
#endif
return 0;
}
int vfpga_deinit2(struct vfpga *f)
{
list_destroy(&f->models, (dtor_cb_t) model_destroy, true);
return 0;
}
int vfpga_reset(struct vfpga *f)
{
int ret;
char state[4096];
/* Save current state of PCI configuration space */
ret = pread(f->vd.fd, state, sizeof(state), (off_t) VFIO_PCI_CONFIG_REGION_INDEX << 40);
if (ret != sizeof(state))
return -1;
uint32_t *rst_reg = (uint32_t *) (f->map + BASEADDR_RESET);
info("Reset fpga");
rst_reg[0] = 1;
usleep(100000);
/* Restore previous state of PCI configuration space */
ret = pwrite(f->vd.fd, state, sizeof(state), (off_t) VFIO_PCI_CONFIG_REGION_INDEX << 40);
if (ret != sizeof(state))
return -1;
info("Reset status = %#x", *rst_reg);
return 0;
}
/* Dump some details about the fpga card */
void vfpga_dump(struct vfpga *f)
{
char namebuf[128];
char *name;
name = pci_lookup_name(pacc, namebuf, sizeof(namebuf), PCI_LOOKUP_DEVICE, f->vd.pdev->vendor_id, f->vd.pdev->device_id);
pci_fill_info(f->vd.pdev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS); /* Fill in header info we need */
info("Found fpga card: %s", name);
{ INDENT
info("slot=%04x:%02x:%02x.%d", f->vd.pdev->domain, f->vd.pdev->bus, f->vd.pdev->dev, f->vd.pdev->func);
info("vendor=%04x", f->vd.pdev->vendor_id);
info("device=%04x", f->vd.pdev->device_id);
info("class=%04x", f->vd.pdev->device_class);
if (f->reset) {
ret = vfpga_reset(f);
if (ret)
serror("Failed to reset fpga card");
/* Reset / detect PCI device */
ret = vfio_pci_reset(&f->vd);
if (ret)
serror("Failed to reset PCI device");
}
info("BAR0 mapped at %p", f->map);
vfio_dump(f->vd.group->container);
}
static void vfpga_debug(char *msg, ...) {
va_list ap;
va_start(ap, msg);
log_vprint(LOG_LVL_DEBUG, msg, ap);
va_end(ap);
}
int vfpga_init(int argc, char * argv[], config_setting_t *cfg)
{
if (getuid() != 0)
error("The vfpga node-type requires superuser privileges!");
pacc = pci_alloc(); /* Get the pci_access structure */
if (!pacc)
error("Failed to allocate PCI access structure");
pci_init(pacc); /* Initialize the PCI library */
pacc->error = (log_cb_t) error; /* Replace logging and debug functions */
pacc->warning = (log_cb_t) warn;
pacc->debug = vfpga_debug;
pci_scan_bus(pacc); /* We want to get the list of devices */
list_foreach(struct ip *c, &f->ips) {
c->card = f;
ip_init(c);
}
return 0;
}
int vfpga_deinit()
{
int ret;
list_destroy(&fpga.ips, (dtor_cb_t) ip_destroy, true);
pci_cleanup(pacc);
ret = vfio_destroy(&vc);
if (ret)
error("Failed to deinitialize VFIO module");
return 0;
}
int vfpga_parse(struct node *n, config_setting_t *cfg)
int vfpga_parse_node(struct node *n, config_setting_t *cfg)
{
struct vfpga *v = n->_vd;
const char *slot, *id, *err;
config_setting_t *cfg_slot, *cfg_id;
pci_filter_init(NULL, &v->filter);
cfg_slot = config_setting_get_member(cfg, "slot");
if (cfg_slot) {
slot = config_setting_get_string(cfg_slot);
if (slot) {
err = pci_filter_parse_slot(&v->filter, (char*) slot);
if (err)
cerror(cfg_slot, "%s", err);
}
else
cerror(cfg_slot, "Invalid slot format");
}
cfg_id = config_setting_get_member(cfg, "id");
if (cfg_id) {
id = config_setting_get_string(cfg_id);
if (id) {
err = pci_filter_parse_id(&v->filter, (char*) id);
if (err)
cerror(cfg_id, "%s", err);
}
else
cerror(cfg_slot, "Invalid id format");
}
// struct vfpga *v = n->_vd;
return 0;
}
@ -339,8 +334,8 @@ int vfpga_write(struct node *n, struct sample *smps[], unsigned cnt)
static struct node_type vt = {
.name = "vfpga",
.description = "VILLASfpga PCIe card (libpci)",
.vectorize = 0,
.parse = vfpga_parse,
.vectorize = 1,
.parse = vfpga_parse_node,
.print = vfpga_print,
.open = vfpga_open,
.close = vfpga_close,

View file

@ -31,7 +31,7 @@ enum benchmarks {
MAX_BENCHS
};
static int bench_run(struct vfpga *f, int polling, int bench)
int fpga_bench(struct vfpga *f, int polling, int bench)
{
struct hist hist;
uint64_t start, stop;
@ -87,7 +87,7 @@ static int bench_run(struct vfpga *f, int polling, int bench)
hist_destroy(&hist);
}
int bench_dm(struct vfpga *f)
int fpga_bench_dm(struct vfpga *f)
{
int irq_fifo, irq_dma_mm2s, irq_dma_s2mm;
int polling = true;
@ -106,7 +106,7 @@ int bench_dm(struct vfpga *f)
return 0;
}
int bench_memcpy(struct vfpga *f)
int fpga_bench_memcpy(struct vfpga *f)
{
uint64_t start, end, total = 0;

View file

@ -13,10 +13,19 @@
#include <poll.h>
#include <time.h>
#include <xilinx/xtmrctr.h>
#include <xilinx/xintc.h>
#include <xilinx/xllfifo.h>
#include <xilinx/xaxis_switch.h>
#include <xilinx/xaxidma.h>
#include <villas/utils.h>
#include <villas/nodes/vfpga.h>
#include "fpga-tests.h"
#include <villas/fpga/ip.h>
//#include <villas/fpga/cbmodel.h>
#include "config.h"
#include "config-fpga.h"
@ -26,83 +35,140 @@
#define CPU_HZ 3392389000
int test_intc(struct vfpga *f)
/* Declarations */
int fpga_test_intc(struct vfpga *f);
int fpga_test_timer(struct vfpga *f);
int fpga_test_fifo(struct vfpga *f);
int fpga_test_dma(struct vfpga *f);
int fpga_test_xsg(struct vfpga *f);
int fpga_test_rtds_rtt(struct vfpga *f);
int fpga_test_rtds_cbuilder(struct vfpga *f);
int fpga_tests(struct vfpga *f)
{
int ret;
struct {
const char *name;
int (*func)(struct vfpga *f);
} tests[] = {
{ "Interrupt Controller", fpga_test_intc },
{ "Timer Counter", fpga_test_timer },
{ "FIFO", fpga_test_fifo },
{ "DMA", fpga_test_dma },
{ "XSG: multiply_add", fpga_test_xsg },
{ "RTDS: RTT Test", fpga_test_rtds_rtt },
{ "RTDS: CBuilder", fpga_test_rtds_cbuilder }
};
for (int i = 0; i < ARRAY_LEN(tests); i++) {
ret = tests[i].func(f);
info("%s: %s", tests[i].name, (ret == 0) ? GRN("passed") : RED("failed"));
}
return 0;
}
int fpga_test_intc(struct vfpga *f)
{
uint32_t ier, isr;
/* Save old IER */
ier = XIntc_In32((uintptr_t) f->map + BASEADDR_INTC + XIN_IER_OFFSET);
XIntc_Out32((uintptr_t) f->map + BASEADDR_INTC + XIN_IER_OFFSET, ier | 0xFF00);
ier = XIntc_In32(f->baseaddr.intc + XIN_IER_OFFSET);
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier | 0xFF00);
XIntc_Out32((uintptr_t) f->map + BASEADDR_INTC + XIN_ISR_OFFSET, 0xFF00);
XIntc_Out32(f->baseaddr.intc + XIN_ISR_OFFSET, 0xFF00);
debug(3, "Wait for 8 SW triggerd interrupts");
for (int i = 0; i < 8; i++)
wait_irq(f->vd.msi_efds[i+8]);
isr = XIntc_In32((uintptr_t) f->map + BASEADDR_INTC + XIN_ISR_OFFSET);
isr = XIntc_In32(f->baseaddr.intc + XIN_ISR_OFFSET);
/* Restore IER */
XIntc_Out32((uintptr_t) f->map + BASEADDR_INTC + XIN_IER_OFFSET, ier);
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier);
return (isr & 0xFF00) ? -1 : 0; /* ISR should get cleared by MSI_Grant_signal */
}
#ifdef HAS_XSG
int test_xsg(struct vfpga *f, const char *name)
int fpga_test_xsg(struct vfpga *f)
{
struct model *m;
struct ip *xsg, *dma, *sw;
xsg = ip_vlnv_lookup(&f->ips, NULL, "xsg", "xsg_multiply_add", NULL);
sw = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axis_interconnect", NULL);
dma = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_dma", NULL);
m = list_lookup(&f->models, name);
if (m) {
model_dump(m);
/* Check if required IP is available on FPGA */
if (!dma || !xsg || !dma)
return -1;
list_foreach(struct model_param *p, &m->parameters) {
if (p->direction == MODEL_PARAM_IN) {
model_param_write(p, p->default_value.flt);
info("Param '%s' updated to: %f", p->name, p->default_value.flt);
}
}
ip_dump(xsg);
if (strcmp(m->name, "xsg_multiply_add") == 0) {
switch_connect(&f->sw, AXIS_SWITCH_DMA_SIMPLE, AXIS_SWITCH_XSG);
switch_connect(&f->sw, AXIS_SWITCH_XSG, AXIS_SWITCH_DMA_SIMPLE);
float *src = (float *) f->dma;
float *dst = (float *) f->dma + TEST_LEN;
for (int i = 0; i < 6; i++)
src[i] = 1.1 * (i+1);
ssize_t len = dma_ping_pong(&f->dma_simple, virt_to_dma(src, f->dma), virt_to_dma(dst, f->dma), 6 * sizeof(float), -1);
if (len != 6 * sizeof(float))
error("Failed to to ping pong DMA transfer: %zd", len);
for (int i = 0; i < 6; i++)
info("src[%d] = %f", i, src[i]);
for (int i = 0; i < 6; i++)
info("dst[%d] = %f", i, dst[i]);
list_foreach(struct model_param *p, &xsg->model.parameters) {
if (p->direction == MODEL_PARAM_IN) {
model_param_write(p, p->default_value.flt);
info("Param '%s' updated to: %f", p->name, p->default_value.flt);
}
}
else
warn("There is no model named '%s'", name);
switch_connect(&sw->sw, dma->port, xsg->port);
switch_connect(&sw->sw, xsg->port, dma->port);
float *src = (float *) f->dma;
float *dst = (float *) f->dma + TEST_LEN;
for (int i = 0; i < 6; i++)
src[i] = 1.1 * (i+1);
ssize_t len = dma_ping_pong(&dma->dma, virt_to_dma(src, f->dma), virt_to_dma(dst, f->dma), 6 * sizeof(float), -1);
if (len != 6 * sizeof(float))
error("Failed to to ping pong DMA transfer: %zd", len);
for (int i = 0; i < 6; i++)
info("src[%d] = %f", i, src[i]);
for (int i = 0; i < 6; i++)
info("dst[%d] = %f", i, dst[i]);
return 0;
}
#endif
#ifdef HAS_FIFO_MM
int test_fifo(struct vfpga *f)
int fpga_test_hls_dft(struct vfpga *f)
{
struct ip *hls, *sw, *dma;
hls = ip_vlnv_lookup(&f->ips, NULL, "hls", NULL, NULL);
sw = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axis_interconnect", NULL);
dma = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_dma", NULL);
/* Check if required IP is available on FPGA */
if (!dma || !hls || !dma)
return -1;
return 0;
}
int fpga_test_fifo(struct vfpga *f)
{
int ret;
ssize_t len;
uintptr_t baseaddr = (uintptr_t) (f->map + BASEADDR_FIFO_MM);
char src[255], dst[255];
struct ip *fifo, *sw;
uint32_t ier;
fifo = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_fifo_mm", NULL);
if (!fifo)
return -1;
sw = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axis_interconnect", NULL);
if (!sw)
return -1;
/* Save old IER */
ier = XIntc_In32((uintptr_t) f->map + BASEADDR_INTC + XIN_IER_OFFSET);
XIntc_Out32((uintptr_t) f->map + BASEADDR_INTC + XIN_IER_OFFSET, ier | (1 << MSI_FIFO_MM));
ier = XIntc_In32(f->baseaddr.intc + XIN_IER_OFFSET);
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier | (1 << fifo->irq));
/* Get some random data to compare */
memset(dst, 0, sizeof(dst));
@ -110,38 +176,48 @@ int test_fifo(struct vfpga *f)
if (ret)
error("Failed to get random data");
ret = switch_connect(&f->sw, AXIS_SWITCH_FIFO_MM, AXIS_SWITCH_FIFO_MM);
ret = switch_connect(&sw->sw, fifo->port, fifo->port);
if (ret)
error("Failed to configure switch");
len = fifo_write(&f->fifo, (char *) src, sizeof(src), f->vd.msi_efds[MSI_FIFO_MM]);
len = fifo_write(&fifo->fifo_mm, (char *) src, sizeof(src), f->vd.msi_efds[fifo->irq]);
if (len != sizeof(src))
error("Failed to send to FIFO");
len = fifo_read(&f->fifo, (char *) dst, sizeof(dst), f->vd.msi_efds[MSI_FIFO_MM]);
len = fifo_read(&fifo->fifo_mm, (char *) dst, sizeof(dst), f->vd.msi_efds[fifo->irq]);
if (len != sizeof(dst))
error("Failed to read from FIFO");
/* Restore IER */
XIntc_Out32((uintptr_t) f->map + BASEADDR_INTC + XIN_IER_OFFSET, ier);
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier);
/* Compare data */
return memcmp(src, dst, sizeof(src));
}
#endif
#if defined(HAS_DMA_SG) || defined(HAS_DMA_SIMPLE)
int test_dma(struct vfpga *f)
int fpga_test_dma(struct vfpga *f)
{
int ret;
struct ip *dma, *sw;
ssize_t len;
int ret;
uint32_t ier;
/* Save old IER */
ier = XIntc_In32((uintptr_t) f->map + BASEADDR_INTC + XIN_IER_OFFSET);
XIntc_Out32((uintptr_t) f->map + BASEADDR_INTC + XIN_IER_OFFSET, ier | (1 << MSI_DMA_MM2S) | (1 << MSI_DMA_S2MM));
dma = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_dma", NULL);
if (!dma)
return -1;
ret = switch_connect(&f->sw, AXIS_SWITCH_DMA_SIMPLE, AXIS_SWITCH_DMA_SIMPLE);
sw = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axis_interconnect", NULL);
if (!sw)
return -1;
int irq_mm2s = dma->irq;
int irq_s2mm = dma->irq + 1;
/* Save old IER */
ier = XIntc_In32(f->baseaddr.intc + XIN_IER_OFFSET);
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier | (1 << irq_mm2s) | (1 << irq_s2mm));
ret = switch_connect(&sw->sw, dma->port, dma->port);
if (ret)
error("Failed to configure switch");
@ -161,60 +237,62 @@ int test_dma(struct vfpga *f)
#endif
/* Get some random data to compare */
char *src = f->dma;
char *dst = f->dma + TEST_LEN;
char *src = (char *) f->dma;
char *dst = (char *) f->dma + TEST_LEN;
ret = read_random(src, TEST_LEN);
if (ret)
error("Failed to get random data");
#if 0
len = dma_write(&f->dma_simple, virt_to_dma(src, f->dma), TEST_LEN, -1);//f->vd.msi_efds[MSI_DMA_MM2S]);
len = dma_write(&f->dma_simple, virt_to_dma(src, f->dma), TEST_LEN, -1);//f->vd.msi_efds[irq_mm2s]);
if (len != TEST_LEN)
error("Failed to send to DMAC: %zd", len);
len = dma_read(&f->dma_simple, virt_to_dma(dst, f->dma), TEST_LEN, -1);//f->vd.msi_efds[MSI_DMA_S2MM]);
len = dma_read(&f->dma_simple, virt_to_dma(dst, f->dma), TEST_LEN, -1);//f->vd.msi_efds[irq_s2mm]);
if (len != TEST_LEN)
error("Failed to send to DMAC: %zd", len);
#else
len = dma_ping_pong(&f->dma_simple, virt_to_dma(src, f->dma), virt_to_dma(dst, f->dma), TEST_LEN, f->vd.msi_efds[MSI_DMA_S2MM]);
len = dma_ping_pong(&dma->dma, virt_to_dma(src, f->dma), virt_to_dma(dst, f->dma), TEST_LEN, f->vd.msi_efds[irq_s2mm]);
if (len != TEST_LEN)
error("Failed to to ping pong DMA transfer: %zd", len);
#endif
/* Restore IER */
XIntc_Out32((uintptr_t) f->map + BASEADDR_INTC + XIN_IER_OFFSET, ier);
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier);
/* Check received data */
return memcmp(src, dst, TEST_LEN);
}
#endif
#ifdef HAS_TIMER
int test_timer(struct vfpga *f)
int fpga_test_timer(struct vfpga *f)
{
int ret;
bool success;
struct ip *timer;
uint32_t ier;
/* Save old IER */
ier = XIntc_In32((uintptr_t) f->map + BASEADDR_INTC + XIN_IER_OFFSET);
XIntc_Out32((uintptr_t) f->map + BASEADDR_INTC + XIN_IER_OFFSET, ier | (1 << MSI_TMRCTR0));
timer = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_timer", NULL);
if (!timer)
return -1;
XTmrCtr_SetOptions(&f->tmr, 0, XTC_EXT_COMPARE_OPTION | XTC_DOWN_COUNT_OPTION);
XTmrCtr_SetResetValue(&f->tmr, 0, AXI_HZ / 125);
XTmrCtr_Start(&f->tmr, 0);
/* Save old IER */
ier = XIntc_In32(f->baseaddr.intc + XIN_IER_OFFSET);
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier | (1 << timer->irq));
XTmrCtr_SetOptions(&timer->timer, 0, XTC_EXT_COMPARE_OPTION | XTC_DOWN_COUNT_OPTION);
XTmrCtr_SetResetValue(&timer->timer, 0, AXI_HZ / 125);
XTmrCtr_Start(&timer->timer, 0);
struct pollfd pfd = {
.fd = f->vd.msi_efds[MSI_TMRCTR0],
.fd = f->vd.msi_efds[timer->irq],
.events = POLLIN
};
ret = poll(&pfd, 1, 1000);
if (ret == 1) {
uint64_t counter = wait_irq(f->vd.msi_efds[MSI_TMRCTR0]);
uint64_t counter = wait_irq(f->vd.msi_efds[timer->irq]);
info("Got IRQ: counter = %llu", counter);
info("Got IRQ: counter = %ju", counter);
if (counter == 1)
return 0;
@ -223,41 +301,51 @@ int test_timer(struct vfpga *f)
}
/* Restore IER */
XIntc_Out32((uintptr_t) f->map + BASEADDR_INTC + XIN_IER_OFFSET, ier);
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier);
return -1;
}
#endif
#ifdef HAS_RTDS_AXIS
int test_rtds_cbuilder(struct vfpga *f)
int fpga_test_rtds_cbuilder(struct vfpga *f)
{
#if 0
int ret;
int values_tx = 1;
int values_rx;
uint32_t tsc = 0, ovfl = 0;
ssize_t len;
uint32_t ier;
struct ip *rtds, *dma;
int irq_rtds_ovf = rtds->irq + 1;
rtds = ip_vlnv_lookup(&f->ips, "acs.eonerc.rwth-aachen.de", "user", "rtds_axis", NULL);
if (!rtds)
return -1;
dma = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_dma", NULL);
if (!dma)
return -1;
/* Save old IER */
ier = XIntc_In32((uintptr_t) f->map + BASEADDR_INTC + XIN_IER_OFFSET);
// XIntc_Out32((uintptr_t) f->map + BASEADDR_INTC + XIN_IER_OFFSET, ier | (1 << MSI_DMA_MM2S) | (1 << MSI_DMA_S2MM));
XIntc_Out32((uintptr_t) f->map + BASEADDR_INTC + XIN_IER_OFFSET, ier | (1 << MSI_RTDS_OVF));
ier = XIntc_In32(f->baseaddr.intc + XIN_IER_OFFSET);
// XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier | (1 << MSI_DMA_MM2S) | (1 << MSI_DMA_S2MM));
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier | (1 << irq_rtds_ovf);
/* Dump RTDS AXI Stream state */
rtds_axis_dump(f->map + BASEADDR_RTDS);
rtds_axis_dump(f->map + rtds->baseaddr);
/* Get some random data to compare */
float *data_rx = (uint32_t *) (f->dma);
float *data_tx = (uint32_t *) (f->dma + 0x1000);
/* Setup crossbar switch */
switch_connect(&f->sw, AXIS_SWITCH_RTDS, AXIS_SWITCH_DMA_SIMPLE);
switch_connect(&f->sw, AXIS_SWITCH_DMA_SIMPLE, AXIS_SWITCH_RTDS);
switch_connect(&sw->sw, rtds->port, dma->port);
switch_connect(&sw->sw, dma->port, rtds->port);
/* Disable blocking Overflow status */
int flags = fcntl(f->vd.msi_efds[MSI_RTDS_OVF], F_GETFL, 0);
fcntl(f->vd.msi_efds[MSI_RTDS_OVF], F_SETFL, flags | O_NONBLOCK);
int flags = fcntl(f->vd.msi_efds[irq_rtds_ovf], F_GETFL, 0);
fcntl(f->vd.msi_efds[irq_rtds_ovf], F_SETFL, flags | O_NONBLOCK);
/* Initialize CBuilder model */
double mdl_dt = rtds_axis_dt(f->map + BASEADDR_RTDS);
@ -279,9 +367,8 @@ int test_rtds_cbuilder(struct vfpga *f)
break;
/* Read data from RTDS */
len = dma_read(&f->dma_simple, virt_to_dma(data_rx, f->dma), 0x1000, -1);
uint64_t start = rdtscp();
XAxiDma_IntrAckIrq(&f->dma_simple, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA);
len = dma_read(&dma->dma, virt_to_dma(data_rx, f->dma), 0x1000, -1);
XAxiDma_IntrAckIrq(&dma->dma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA);
values_rx = len / sizeof(uint32_t);
@ -289,32 +376,30 @@ int test_rtds_cbuilder(struct vfpga *f)
/* Run CBuilder model */
cbmodel_step(mdl_inputs, mdl_outputs);
data_tx[0] = mdl_outputs[0]; /* cast to float */
/* Send data to RTDS */
len = dma_write(&f->dma_simple, virt_to_dma(data_tx, f->dma), sizeof(uint32_t) * values_tx, -1);
XAxiDma_IntrAckIrq(&f->dma_simple, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DMA_TO_DEVICE);
len = dma_write(&dma->dma, virt_to_dma(data_tx, f->dma), sizeof(uint32_t) * values_tx, -1);
XAxiDma_IntrAckIrq(&dma->dma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DMA_TO_DEVICE);
}
/* Restore IER */
XIntc_Out32((uintptr_t) f->map + BASEADDR_INTC + XIN_IER_OFFSET, ier);
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier);
#endif
return 0;
}
int test_rtds_rtt(struct vfpga *f)
int fpga_test_rtds_rtt(struct vfpga *f)
{
int ret;
int values_tx = 64;
int values_rx;
uint32_t tsc = 0, ovfl = 0;
#if 0
uint32_t tsc = 0;
ssize_t len;
uint32_t ier;
/* Save old IER */
ier = XIntc_In32((uintptr_t) f->map + BASEADDR_INTC + XIN_IER_OFFSET);
// XIntc_Out32((uintptr_t) f->map + BASEADDR_INTC + XIN_IER_OFFSET, ier | (1 << MSI_DMA_MM2S) | (1 << MSI_DMA_S2MM));
ier = XIntc_In32(f->baseaddr.intc + XIN_IER_OFFSET);
// XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier | (1 << MSI_DMA_MM2S) | (1 << MSI_DMA_S2MM));
/* Dump RTDS AXI Stream state */
rtds_axis_dump(f->map + BASEADDR_RTDS);
@ -397,8 +482,7 @@ retry: len = fifo_read(&f->fifo, (char *) data_rx, 0x1000, irq_fifo);
}
/* Restore IER */
XIntc_Out32((uintptr_t) f->map + BASEADDR_INTC + XIN_IER_OFFSET, ier);
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier);
#endif
return 0;
}
#endif

View file

@ -9,10 +9,8 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <getopt.h>
#include <sched.h>
@ -26,59 +24,59 @@
#include "config.h"
#include "config-fpga.h"
#include "fpga-tests.h"
#include "fpga-bench.h"
static struct pci_access *pacc;
/* Declarations */
int fpga_bench(struct vfpga *f);
int fpga_tests(struct vfpga *f);
void usage(char *name)
{
printf("Usage: %s [ARGS]\n", name);
printf(" -d Set log level\n");
printf(" -i ID pair of PCI device: [vendor]:[device][:class]\n");
printf(" -s Slot of PCI device: [[[domain]:][bus]:][slot][.[func]]\n\n");
printf("fpga PCIutil %s (built on %s %s)\n",
VERSION, __DATE__, __TIME__);
printf(" copyright 2014-2015, Institute for Automation of Complex Power Systems, EONERC\n");
printf(" Steffen Vogel <StVogel@eonerc.rwth-aachen.de>\n");
printf("Usage: %s CONFIGFILE CMD [OPTIONS]\n", name);
printf(" Commands:\n");
printf(" tests Test functionality of VILLASfpga card\n");
printf(" bench Do benchmarks\n\n");
printf(" Options:\n");
printf(" -d Set log level\n\n");
print_copyright();
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[])
{
int ret;
char *err;
struct vfpga fpga;
struct vfio_container vc;
struct pci_dev *pdev;
struct pci_filter filter;
/* Init libpci */
pacc = pci_alloc(); /* Get the pci_access structure */
pci_init(pacc); /* Initialize the PCI library */
pci_scan_bus(pacc); /* We want to get the list of devices */
pci_filter_init(pacc, &filter);
/* Default filter */
filter.vendor = PCI_VID_XILINX;
filter.device = PCI_PID_VFPGA;
struct vfpga *fpga;
enum {
FPGA_TESTS,
FPGA_BENCH
} subcommand;
config_t config;
if (argc < 3)
usage(argv[0]);
if (strcmp(argv[2], "tests") == 0)
subcommand = FPGA_TESTS;
else if (strcmp(argv[2], "bench") == 0)
subcommand = FPGA_BENCH;
else
usage(argv[0]);
/* Setup libconfig */
config_init(&config);
ret = config_read_file(&config, argv[1]);
if (ret != CONFIG_TRUE) {
error("Failed to parse configuration: %s in %s:%d",
config_error_text(&config),
config_error_file(&config) ? config_error_file(&config) : argv[1],
config_error_line(&config)
);
}
/* Parse arguments */
char c, *endptr;
while ((c = getopt (argc, argv, "i:s:d:")) != -1) {
while ((c = getopt (argc-1, argv+1, "d:")) != -1) {
switch (c) {
case 's':
err = pci_filter_parse_slot(&filter, optarg);
if (err)
error("Failed to parse slot: %s", err);
break;
case 'i':
err = pci_filter_parse_id(&filter, optarg);
if (err)
error("Failed to parse ID: %s", err);
break;
case 'd':
log_setlevel(strtoul(optarg, &endptr, 10), ~0);
break;
@ -89,22 +87,15 @@ int main(int argc, char *argv[])
}
}
/* Search for fpga card */
pdev = pci_find_device(pacc, &filter);
if (!pdev)
error("Failed to find PCI device");
/* Get VFIO handles and details */
ret = vfio_init(&vc);
if (ret)
serror("Failed to initialize VFIO");
/* Initialize fpga card */
ret = vfpga_init2(&fpga, &vc, pdev);
/* Initialize VILLASfpga card */
config_setting_t *cfg_root = config_root_setting(&config);
ret = vfpga_init(argc, argv, cfg_root);
if (ret)
error("Failed to initialize fpga card");
fpga = vfpga_get();
vfpga_dump(&fpga);
vfpga_dump(fpga);
/* Setup scheduler */
cpu_set_t set = integer_to_cpuset(AFFINITY);
@ -117,49 +108,22 @@ int main(int argc, char *argv[])
if (ret)
serror("Failed to change scheduler");
for (int i = 0; i < fpga.vd.irqs[VFIO_PCI_MSI_IRQ_INDEX].count; i++) {
ret = kernel_irq_setaffinity(fpga.vd.msi_irqs[i], AFFINITY, NULL);
for (int i = 0; i < fpga->vd.irqs[VFIO_PCI_MSI_IRQ_INDEX].count; i++) {
ret = kernel_irq_setaffinity(fpga->vd.msi_irqs[i], AFFINITY, NULL);
if (ret)
serror("Failed to change affinity of VFIO-MSI interrupt");
}
/* Start tests */
ret = test_intc(&fpga);
info("INTC Test: %s", (ret == 0) ? GRN("passed") : RED("failed"));
ret = test_xsg(&fpga, "xsg_multiply_add");
info("XSG Test: %s", (ret == 0) ? GRN("passed") : RED("failed"));
// ret = test_timer(&fpga);
// info("Timer Test: %s", (ret == 0) ? GRN("passed") : RED("failed"));
// ret = test_fifo(&fpga);
// info("FIFO Test: %s", (ret == 0) ? GRN("passed") : RED("failed"));
ret = test_dma(&fpga);
info("DMA Test: %s", (ret == 0) ? GRN("passed") : RED("failed"));
// ret = test_rtds_rtt(&fpga);
// info("RTDS RTT Test: %s", (ret == 0) ? GRN("passed") : RED("failed"));
// ret = test_rtds_cbuilder(&fpga);
// info("RTDS RTT Test: %s", (ret == 0) ? GRN("passed") : RED("failed"));
/* Start benchmarks */
#if 0
ret = bench_memcpy(&fpga);
#endif
/* Start subcommand */
switch (subcommand) {
case FPGA_TESTS: fpga_tests(fpga); break;
case FPGA_BENCH: /*fpga_bench(fpga);*/ break;
}
/* Shutdown */
ret = vfpga_deinit2(&fpga);
ret = vfpga_deinit(&fpga);
if (ret)
error("Failed to de-initialize fpga card");
ret = vfio_destroy(&vc);
if (ret)
error("Failed to deinitialize VFIO module");
pci_cleanup(pacc);
return 0;
}