diff --git a/.gitignore b/.gitignore index c6ea066bb..d171861e8 100644 --- a/.gitignore +++ b/.gitignore @@ -3,10 +3,10 @@ *.so *~ -node -pipe -test -signal -fpga +/node +/pipe +/test +/signal +/fpga thirdparty/ diff --git a/Makefile b/Makefile index 911b1e821..890a24575 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,7 @@ endif ######## Node types ######## # file node-type is always supported -LIB_OBJS += file.o +LIB_OBJS += file.o cbuilder.o # Enable Socket node type when libnl3 is available ifeq ($(shell pkg-config libnl-route-3.0; echo $$?),0) @@ -64,8 +64,8 @@ endif # Enable VILLASfpga support when libpci is available ifeq ($(shell pkg-config libpci; echo $$?),0) - LIB_OBJS += vfpga.o pci.o ip.o vfio.o - LIB_OBJS += dma.o model.o fifo.o switch.o rtds_axis.o + LIB_OBJS += fpga.o pci.o ip.o vfio.o + LIB_OBJS += dma.o model.o fifo.o switch.o rtds_axis.o intc.o LDLIBS += -lxil LDFLAGS += -Lthirdparty/xilinx -Wl,-rpath-link,'$$ORIGIN/thirdparty/xilinx' CFLAGS += -Ithirdparty/xilinx/include @@ -113,7 +113,7 @@ all: $(LIBS) $(TARGETS) fpga: LDLIBS += -lpci -lxil node: server.o -fpga: fpga.o fpga-tests.o +fpga: fpga-main.o fpga-tests.o pipe: pipe.o test: test.o signal: signal.o diff --git a/config-fpga.h b/config-fpga.h index afc74b3e4..e92db69da 100644 --- a/config-fpga.h +++ b/config-fpga.h @@ -24,10 +24,6 @@ * except RTDS AXI Stream bridge which runs at RTDS_HZ (100 Mhz) */ #define AXI_HZ 125000000 // 125 MHz -#define virt_to_axi(virt, map) ((char *) ((char *) virt - map)) -#define virt_to_dma(virt, dma) ((char *) ((char *) virt - dma) + BASEADDR_HOST) -#define dma_to_virt(addr, dma) ((char *) ((char *) addr - BASEADDR_HOST) + dma) - #define PCI_VID_XILINX 0x10ee #define PCI_PID_VFPGA 0x7022 diff --git a/etc/vfpga.conf b/etc/fpga-simple.conf similarity index 74% rename from etc/vfpga.conf rename to etc/fpga-simple.conf index d97d1a393..9da5889ef 100644 --- a/etc/vfpga.conf +++ b/etc/fpga-simple.conf @@ -1,5 +1,11 @@ fpga = { - reset = false; + /* Card identification */ + id = "10ee:7022"; + slot = "01:00.0"; + + intc = 0x5000; + reset = 0x2000; + do_reset = true; ips = { switch_0 = { @@ -14,13 +20,12 @@ fpga = { }, dma_0 = { vlnv = "xilinx.com:ip:axi_dma:7.1"; - baseaddr = 0x0000; + baseaddr = 0x1000; 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"; } @@ -34,7 +39,9 @@ fpga = { } nodes = { - fpga_dma = { - + dma = { + datamover = "dma_0"; + use_irqs = false; } + } \ No newline at end of file diff --git a/etc/fpga.conf b/etc/fpga.conf new file mode 100644 index 000000000..e78a84652 --- /dev/null +++ b/etc/fpga.conf @@ -0,0 +1,104 @@ + +fpga = { + /* Card identification */ + id = "10ee:7022"; + slot = "01:00.0"; + + do_reset = true; + + ips = { + axi_pcie_intc_0 = { + vlnv = "acs.eonerc.rwth-aachen.de:user:axi_pcie_intc:1.0"; + baseaddr = 0xb000; + }, + axi_reset_0 = { + vlnv = "xilinx.com:ip:axi_gpio:2.0"; + baseaddr = 0x7000; + }, + bram_0 = { + vlnv = "xilinx.com:ip:axi_bram_ctrl:4.0"; + baseaddr = 0x0000; + size = 0x2000; + }, + xsg_multiply_0 = { + vlnv = "acs.eonerc.rwth-aachen.de:sysgen:xsg_multiply:1.0"; + baseaddr = 0x2000; + port = 4; + parameters = { + factor = 2.0; + } + }, + dma_0 = { + vlnv = "xilinx.com:ip:axi_dma:7.1"; + baseaddr = 0x3000; + port = 1; + irq = 3; /* 3 - 4 */ + }, + timer_0 = { + vlnv = "xilinx.com:ip:axi_timer:2.0"; + baseaddr = 0x4000; + irq = 0; /* 0 - 1 */ + }, + switch_0 = { + vlnv = "xilinx.com:ip:axis_interconnect:2.1" + baseaddr = 0x5000; + numports = 10; + }, + fifo_mm_s_0 = { + vlnv = "xilinx.com:ip:axi_fifo_mm_s:4.1"; + baseaddr = 0x6000; + baseaddr_axi4 = 0xC000; + port = 2; + irq = 2; + }, + rtds_axis_0 = { + vlnv = "acs.eonerc.rwth-aachen.de:user:rtds_axis:1.0"; + baseaddr = 0x8000; + port = 5; + irq = 5; /* 5 -7 */ + }, + hls_multiply_0 = { + vlnv = "acs.eonerc.rwth-aachen.de:hls:hls_multiply:1.1"; + baseaddr = 0x9000; + port = 5; + }, + dma_1 = { + vlnv = "xilinx.com:ip:axi_dma:7.1"; + baseaddr = 0xA000; + port = 7; + irq = 3; /* 3 - 4 */ + }, + hls_decimate_0 = { + vlnv = "acs.eonerc.rwth-aachen.de:hls:hls_decimate:1.0"; + baseaddr = 0xE000; + port = 8; + }, + hls_dft_0 = { + vlnv = "acs.eonerc.rwth-aachen.de:hls:hls_dft:1.0"; + baseaddr = 0xF000; + port = 9; + }, + axis_data_fifo_0 = { + vlnv = "xilinx.com:ip:axis_data_fifo:1.1"; + port = 3; + }, + axis_data_fifo_1 = { + vlnv = "xilinx.com:ip:axis_data_fifo:1.1"; + port = 6; + }, + } + + /* Configure switch */ + paths = ( + { in = "dma", out = "hls_dft" }, + { in = "hls_dft", out = "dma" } + ) +} + +nodes = { + dma = { + datamover = "dma_0"; + use_irqs = false; + } + +} \ No newline at end of file diff --git a/include/villas/fpga/dma.h b/include/villas/fpga/dma.h index f60c27653..b3cd4defd 100644 --- a/include/villas/fpga/dma.h +++ b/include/villas/fpga/dma.h @@ -20,23 +20,34 @@ #define XAXIDMA_SR_SGINCL_MASK 0x00000008 -enum dma_mode { - DMA_MODE_SIMPLE, - DMA_MODE_SG -}; - struct dma_mem { uint32_t base_virt; uint32_t base_phys; size_t len; }; -int dma_init(XAxiDma *xdma, char *baseaddr, enum dma_mode mode, struct dma_mem *bd, struct dma_mem *rx, size_t maxlen); +struct ip; -ssize_t dma_write(XAxiDma *xdma, char *buf, size_t len, int irq); +int dma_write(struct ip *c, char *buf, size_t len); +int dma_read(struct ip *c, char *buf, size_t len); +int dma_read_complete(struct ip *c, char **buf, size_t *len); +int dma_write_complete(struct ip *c, char **buf, size_t *len); -ssize_t dma_read(XAxiDma *xdma, char *buf, size_t len, int irq); +int dma_sg_write(struct ip *c, char *buf, size_t len); +int dma_sg_read(struct ip *c, char *buf, size_t len); -ssize_t dma_ping_pong(XAxiDma *xdma, char *src, char *dst, size_t len, int s2mm_irq); +int dma_sg_write_complete(struct ip *c, char **buf, size_t *len); +int dma_sg_read_complete(struct ip *c, char **buf, size_t *len); + +int dma_simple_read(struct ip *c, char *buf, size_t len); +int dma_simple_write(struct ip *c, char *buf, size_t len); + +int dma_simple_read_complete(struct ip *c, char **buf, size_t *len); +int dma_simple_write_complete(struct ip *c, char **buf, size_t *len); + +int dma_ping_pong(struct ip *c, char *src, char *dst, size_t len); + +int dma_init(struct ip *c); +int dma_init_rings(struct ip *c, struct dma_mem *bd); #endif /* _DMA_H_ */ \ No newline at end of file diff --git a/include/villas/fpga/fifo.h b/include/villas/fpga/fifo.h index 13bbf3567..63f489375 100644 --- a/include/villas/fpga/fifo.h +++ b/include/villas/fpga/fifo.h @@ -17,10 +17,13 @@ #include #include -int fifo_init(XLlFifo *fifo, char *baseaddr, char *axi_baseaddr); +/* Forward declaration */ +struct ip; -ssize_t fifo_write(XLlFifo *fifo, char *buf, size_t len, int irq); +int fifo_init(struct ip *c); -ssize_t fifo_read(XLlFifo *fifo, char *buf, size_t len, int irq); +ssize_t fifo_write(struct ip *c, char *buf, size_t len); + +ssize_t fifo_read(struct ip *c, char *buf, size_t len); #endif /* _FIFO_H_ */ \ No newline at end of file diff --git a/include/villas/fpga/intc.h b/include/villas/fpga/intc.h new file mode 100644 index 000000000..8e0a20d66 --- /dev/null +++ b/include/villas/fpga/intc.h @@ -0,0 +1,20 @@ +/** AXI-PCIe Interrupt controller + * + * @author Steffen Vogel + * @copyright 2015-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 _INTC_H_ +#define _INTC_H_ + +int intc_init(struct ip *c); + +uint32_t intc_enable(struct ip *c, uint32_t mask); + +void intc_disable(struct ip *c, uint32_t mask); + +uint64_t intc_wait(struct fpga *f, int irq); + +#endif /* _INTC_H_ */ \ No newline at end of file diff --git a/include/villas/fpga/ip.h b/include/villas/fpga/ip.h new file mode 100644 index 000000000..c91b845ef --- /dev/null +++ b/include/villas/fpga/ip.h @@ -0,0 +1,75 @@ +#ifndef _IP_H_ +#define _IP_H_ + +#include + +#include +#include +#include +#include +#include + +#include "fpga/dma.h" +#include "fpga/switch.h" +#include "fpga/fifo.h" +#include "fpga/rtds_axis.h" +#include "fpga/model.h" +#include "nodes/fpga.h" + +enum ip_state { + IP_STATE_UNKNOWN, + IP_STATE_INITIALIZED +}; + +struct ip { + char *name; + + struct { + char *vendor; + char *library; + char *name; + char *version; + } vlnv; + + uintptr_t baseaddr; + uintptr_t baseaddr_axi4; + int irq; + int port; + + enum ip_state state; + + union { + struct model model; + struct bram { + int size; + } bram; + + XTmrCtr timer; + XLlFifo fifo_mm; + XAxiDma dma; + XAxis_Switch sw; + }; + + struct fpga *card; + + config_setting_t *cfg; +}; + +/** Return the first IP block in list \p l which matches the VLNV */ +struct ip * ip_vlnv_lookup(struct list *l, const char *vendor, const char *library, const char *name, const char *version); + +/** Check if IP block \p c matched VLNV. */ +int ip_vlnv_match(struct ip *c, const char *vendor, const char *library, const char *name, const char *version); + +/** Tokenizes VLNV \p vlnv and stores it into \p c */ +int ip_vlnv_parse(struct ip *c, const char *vlnv); + +int ip_init(struct ip *c); + +void ip_destroy(struct ip *c); + +void ip_dump(struct ip *c); + +int ip_parse(struct ip *c, config_setting_t *cfg); + +#endif \ No newline at end of file diff --git a/include/villas/fpga/model.h b/include/villas/fpga/model.h index 9c636977d..610a8b0a4 100644 --- a/include/villas/fpga/model.h +++ b/include/villas/fpga/model.h @@ -11,12 +11,16 @@ #define _MODEL_H_ #include -#include +#include #include "list.h" +#define XSG_MAPLEN 0x1000 #define XSG_MAGIC 0xDEADBABE +/* Forward declaration */ +struct ip; + enum model_type { MODEL_TYPE_HLS, MODEL_TYPE_XSG @@ -49,18 +53,15 @@ union model_param_value { }; struct model { - char *xml; /**< Path to a XML file which describes this model */ - enum model_type type; + enum model_type type; /**< Either HLS or XSG model */ + char *xml; /**< An optional path to a XML file which describes this model */ struct list parameters; /**< List of model parameters. */ - struct list infos; - - char *map; - size_t maplen; + struct list infos; /**< A list of key / value pairs with model details */ union { struct xsg_model { - char *map; - size_t maplen; + uint32_t *map; + ssize_t maplen; } xsg; /**< XSG specific model data */ struct hls_model { @@ -84,20 +85,23 @@ struct model_param { union model_param_value default_value; - struct model *model; /**< A pointer to the model structure to which this parameters belongs to. */ + struct ip *ip; /**< A pointer to the model structure to which this parameters belongs to. */ }; -int model_init(struct model *m, uintptr_t baseaddr); +/** Initialize a model */ +int model_init(struct ip *c); -int model_init_from_xsg_map(struct model *m, uintptr_t baseaddr); +/** Destroy a model */ +void model_destroy(struct ip *c); -int model_init_from_xml(struct model *m); +/** Print detailed information about the model to the screen. */ +void model_dump(struct ip *c); -void model_destroy(struct model *m); +/** Add a new parameter to the model */ +void model_param_add(struct ip *c, const char *name, enum model_param_direction dir, enum model_param_type type); -void model_dump(struct model *m); - -void model_param_add(struct model *m, const char *name, enum model_param_direction dir, enum model_param_type type); +/** Remove an existing parameter by its name */ +int model_param_remove(struct ip *c, const char *name); /** Read a model parameter. * @@ -114,10 +118,4 @@ 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_ */ \ No newline at end of file diff --git a/include/villas/fpga/switch.h b/include/villas/fpga/switch.h index 59373dbaf..38c0a069e 100644 --- a/include/villas/fpga/switch.h +++ b/include/villas/fpga/switch.h @@ -14,8 +14,10 @@ #include -int switch_init(XAxis_Switch *sw, char *baseaddr, int micnt, int sicnt); +struct ip; -int switch_connect(XAxis_Switch *sw, int mi, int si); +int switch_init(struct ip *c); + +int switch_connect(struct ip *c, struct ip *mi, struct ip *si); #endif /* _SWITCH_H_ */ \ No newline at end of file diff --git a/include/villas/fpga/timer.h b/include/villas/fpga/timer.h new file mode 100644 index 000000000..e13212102 --- /dev/null +++ b/include/villas/fpga/timer.h @@ -0,0 +1,15 @@ +/** Timer related helper functions + * + * These functions present a simpler interface to Xilinx' Timer Counter driver (XTmrCtr_*) + * + * @file + * @author Steffen Vogel + * @copyright 2015-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 _TIMER_H_ +#define _TIMER_H_ + +#endif \ No newline at end of file diff --git a/include/villas/kernel/pci.h b/include/villas/kernel/pci.h index 1d6820991..9425f4690 100644 --- a/include/villas/kernel/pci.h +++ b/include/villas/kernel/pci.h @@ -12,6 +12,10 @@ #include +struct pci_access * pci_get_handle(); + +void pci_release_handle(); + struct pci_dev * pci_find_device(struct pci_access *pacc, struct pci_filter *f); int pci_attach_driver(struct pci_dev *d, const char *driver); diff --git a/include/villas/log.h b/include/villas/log.h index b3fd5f03c..b94ccb891 100644 --- a/include/villas/log.h +++ b/include/villas/log.h @@ -13,6 +13,8 @@ #include #include +#include "utils.h" + #ifdef __GNUC__ #define INDENT int __attribute__ ((__cleanup__(log_outdent), unused)) _old_indent = log_indent(1); #else @@ -21,7 +23,7 @@ /* The log level which is passed as first argument to print() */ #define LOG_LVL_DEBUG GRY("Debug") -#define LOG_LVL_INFO "" +#define LOG_LVL_INFO WHT("Info ") #define LOG_LVL_WARN YEL("Warn ") #define LOG_LVL_ERROR RED("Error") #define LOG_LVL_STATS MAG("Stats") @@ -40,7 +42,7 @@ enum debug_facilities { /* Node-types */ DBG_SOCKET = (1 << 16), DBG_FILE = (1 << 17), - DBG_GTFPGA = (1 << 18), + DBG_FPGA = (1 << 18), DBG_NGSI = (1 << 19), DBG_WEBSOCKET = (1 << 20), DBG_OPAL = (1 << 21), diff --git a/include/villas/nodes/fpga.h b/include/villas/nodes/fpga.h new file mode 100644 index 000000000..1b049a6d5 --- /dev/null +++ b/include/villas/nodes/fpga.h @@ -0,0 +1,104 @@ +/** Node type: VILLASfpga + * + * This file implements the fpga node-type. + * + * @file + * @author Steffen Vogel + * @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. + */ +/** + * @addtogroup fpga VILLASnode + * @ingroup node + * @{ + *********************************************************************************/ + +#ifndef _FPGA_H_ +#define _FPGA_H_ + +#include "kernel/vfio.h" + +#include + +#include "nodes/fpga.h" +#include "node.h" +#include "list.h" + +#define BASEADDR_HOST 0x80000000 +#define FPGA_BAR 0 /**< The Base Address Register which is mmap()ed to the User Space */ + +#define virt_to_axi(virt, map) ((char *) ((char *) virt - map)) +#define virt_to_dma(virt, dma) ((char *) ((char *) virt - dma) + BASEADDR_HOST) +#define dma_to_virt(addr, dma) ((char *) ((char *) addr - BASEADDR_HOST) + dma) + +struct fpga { + struct pci_filter filter; /**< Filter for libpci with device id & slot */ + struct vfio_dev vd; /**< VFIO device handle. */ + + int do_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; + + /* Some IP cores are special and referenced here */ + struct ip *intc; + struct ip *reset; + struct ip *sw; +}; + +struct fpga_dm { + struct ip *ip; + + bool use_irqs; + + enum { + FPGA_DM_DMA, + FPGA_DM_FIFO + } type; + + struct fpga *card; +}; + +/** @see node_vtable::init */ +int fpga_init(int argc, char * argv[], config_setting_t *cfg); + +/** @see node_vtable::deinit */ +int fpga_deinit(); + +/** @see node_vtable::parse */ +int fpga_parse(struct node *n, config_setting_t *cfg); + +/** Parse the 'fpga' section in the configuration file */ +int fpga_parse_card(struct fpga *v, int argc, char * argv[], config_setting_t *cfg); + +/** @see node_vtable::print */ +char * fpga_print(struct node *n); + +/** @see node_vtable::open */ +int fpga_open(struct node *n); + +/** @see node_vtable::close */ +int fpga_close(struct node *n); + +/** @see node_vtable::read */ +int fpga_read(struct node *n, struct sample *smps[], unsigned cnt); + +/** @see node_vtable::write */ +int fpga_write(struct node *n, struct sample *smps[], unsigned cnt); + +/** Get pointer to internal VILLASfpga datastructure */ +struct fpga * fpga_get(); + +/** Reset VILLASfpga */ +int fpga_reset(struct fpga *f); + +/** Dump some details about the fpga card */ +void fpga_dump(struct fpga *f); + +#endif /** _FPGA_H_ @} */ diff --git a/include/villas/nodes/vfpga.h b/include/villas/nodes/vfpga.h deleted file mode 100644 index 137614b2e..000000000 --- a/include/villas/nodes/vfpga.h +++ /dev/null @@ -1,87 +0,0 @@ -/** Node type: VILLASfpga - * - * This file implements the vfpga node-type. - * - * @file - * @author Steffen Vogel - * @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. - */ -/** - * @addtogroup vfpga VILLASnode - * @ingroup node - * @{ - *********************************************************************************/ - -#ifndef _VFPGA_H_ -#define _VFPGA_H_ - -#include "kernel/vfio.h" - -#include - -#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; /**< Filter for libpci with device id & slot */ - struct vfio_dev vd; /**< VFIO device handle. */ - - 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 */ -int vfpga_init(int argc, char * argv[], config_setting_t *cfg); - -/** @see node_vtable::deinit */ -int vfpga_deinit(); - -/** @see node_vtable::parse */ -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); - -/** @see node_vtable::open */ -int vfpga_open(struct node *n); - -/** @see node_vtable::close */ -int vfpga_close(struct node *n); - -/** @see node_vtable::read */ -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); - -/** 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_ @} */ diff --git a/include/villas/nodes/websocket.h b/include/villas/nodes/websocket.h index 10af64f06..79a5174dc 100644 --- a/include/villas/nodes/websocket.h +++ b/include/villas/nodes/websocket.h @@ -57,4 +57,4 @@ int websocket_read(struct node *n, struct sample *smps[], unsigned cnt); /** @see node_vtable::write */ int websocket_write(struct node *n, struct sample *smps[], unsigned cnt); -#endif /* _WEBSOCKET_H_ */ \ No newline at end of file +#endif /** _WEBSOCKET_H_ @} */ \ No newline at end of file diff --git a/include/villas/utils.h b/include/villas/utils.h index 6ce417ba0..ce3b630a4 100644 --- a/include/villas/utils.h +++ b/include/villas/utils.h @@ -119,6 +119,7 @@ char * vstrcatf(char **dest, const char *fmt, va_list va) /** Format string like strcatf() just starting with empty string */ #define strf(fmt, ...) strcatf(&(char *) { NULL }, fmt, ##__VA_ARGS__) +#define vstrf(fmt, va) vstrcatf(&(char *) { NULL }, fmt, va) /** Format a struct timespec date similar to strftime() */ int strftimespec(char *s, size_t max, const char *format, struct timespec *ts) @@ -169,9 +170,6 @@ int version_parse(const char *s, struct version *v); } while (0) #endif -/** Wait on eventfd */ -uint64_t wait_irq(int irq); - /** Fill buffer with random data */ int read_random(char *buf, size_t len); diff --git a/lib/cfg.c b/lib/cfg.c index ec9535f6f..1ac63d001 100644 --- a/lib/cfg.c +++ b/lib/cfg.c @@ -21,7 +21,7 @@ int config_parse(const char *filename, config_t *cfg, struct settings *set, struct list *nodes, struct list *paths) { int ret; - char *filename_cpy, include_dir; + char *filename_cpy, *include_dir; filename_cpy = strdup(filename); include_dir = dirname(filename_cpy); diff --git a/lib/fpga/dma.c b/lib/fpga/dma.c index a57479c88..9d1f243ba 100644 --- a/lib/fpga/dma.c +++ b/lib/fpga/dma.c @@ -15,18 +15,186 @@ #include "utils.h" #include "fpga/dma.h" +#include "fpga/ip.h" -int dma_write_complete(XAxiDma *xdma, int irq) +int dma_ping_pong(struct ip *c, char *src, char *dst, size_t len) { + int ret; + + ret = dma_read(c, dst, len); + if (ret) + return ret; + + ret = dma_write(c, src, len); + if (ret) + return ret; + + ret = dma_read_complete(c, NULL, NULL); + if (ret) + return ret; + + ret = dma_write_complete(c, NULL, NULL); + if (ret) + return ret; + + return 0; +} + +int dma_write(struct ip *c, char *buf, size_t len) +{ + XAxiDma *xdma = &c->dma; + + return xdma->HasSg + ? dma_sg_write(c, buf, len) + : dma_simple_write(c, buf, len); +} + +int dma_read(struct ip *c, char *buf, size_t len) +{ + XAxiDma *xdma = &c->dma; + + return xdma->HasSg + ? dma_sg_read(c, buf, len) + : dma_simple_read(c, buf, len); +} + +int dma_read_complete(struct ip *c, char **buf, size_t *len) +{ + XAxiDma *xdma = &c->dma; + + return xdma->HasSg + ? dma_sg_read_complete(c, buf, len) + : dma_simple_read_complete(c, buf, len); +} + +int dma_write_complete(struct ip *c, char **buf, size_t *len) +{ + XAxiDma *xdma = &c->dma; + + return xdma->HasSg + ? dma_sg_write_complete(c, buf, len) + : dma_simple_write_complete(c, buf, len); +} + +int dma_sg_write(struct ip *c, char *buf, size_t len) +{ + XAxiDma *xdma = &c->dma; + XAxiDma_BdRing *ring = XAxiDma_GetTxRing(xdma); + XAxiDma_Bd *bd; + + int ret; + + buf = virt_to_dma(buf, c->card->dma); + + /* Checks */ + if (!xdma->HasSg) + return -1; + + if ((len < 1) || (len > ring->MaxTransferLen)) + return -2; + + if (!xdma->HasMm2S) + return -3; + + if (!ring->HasDRE) { + uint32_t mask = xdma->MicroDmaMode ? XAXIDMA_MICROMODE_MIN_BUF_ALIGN : ring->DataWidth - 1; + if ((uintptr_t) buf & mask) + return -4; + } + + ret = XAxiDma_BdRingAlloc(ring, 1, &bd); + if (ret != XST_SUCCESS) + return -5; + + /* Set up the BD using the information of the packet to transmit */ + ret = XAxiDma_BdSetBufAddr(bd, (uintptr_t) buf); + if (ret != XST_SUCCESS) + return -6; + + ret = XAxiDma_BdSetLength(bd, len, ring->MaxTransferLen); + if (ret != XST_SUCCESS) + return -7; + + /* Set SOF / EOF / ID */ + XAxiDma_BdSetCtrl(bd, XAXIDMA_BD_CTRL_TXEOF_MASK | XAXIDMA_BD_CTRL_TXSOF_MASK); + XAxiDma_BdSetId(bd, (uintptr_t) buf); + + /* Give the BD to DMA to kick off the transmission. */ + ret = XAxiDma_BdRingToHw(ring, 1, bd); + if (ret != XST_SUCCESS) + return -8; + + return 0; +} + +int dma_sg_read(struct ip *c, char *buf, size_t len) +{ + XAxiDma *xdma = &c->dma; + XAxiDma_BdRing *ring = XAxiDma_GetRxRing(xdma); + XAxiDma_Bd *bd; + + int ret; + + buf = virt_to_dma(buf, c->card->dma); + + + /* Checks */ + if (!xdma->HasSg) + return -1; + + if ((len < 1) || (len > ring->MaxTransferLen)) + return -2; + + if (!xdma->HasS2Mm) + return -3; + + if (!ring->HasDRE) { + uint32_t mask = xdma->MicroDmaMode ? XAXIDMA_MICROMODE_MIN_BUF_ALIGN : ring->DataWidth - 1; + if ((uintptr_t) buf & mask) + return -4; + } + + ret = XAxiDma_BdRingAlloc(ring, 1, &bd); + if (ret != XST_SUCCESS) + return -5; + + ret = XAxiDma_BdSetBufAddr(bd, (uintptr_t) buf); + if (ret != XST_SUCCESS) + return -6; + + ret = XAxiDma_BdSetLength(bd, len, ring->MaxTransferLen); + if (ret != XST_SUCCESS) + return -7; + + /* Receive BDs do not need to set anything for the control + * The hardware will set the SOF/EOF bits per stream ret */ + XAxiDma_BdSetCtrl(bd, 0); + XAxiDma_BdSetId(bd, (uintptr_t) buf); + + ret = XAxiDma_BdRingToHw(ring, 1, bd); + if (ret != XST_SUCCESS) + return -8; + + return 0; +} + +int dma_sg_write_complete(struct ip *c, char **buf, size_t *len) +{ + XAxiDma *xdma = &c->dma; + XAxiDma_BdRing *ring = XAxiDma_GetTxRing(xdma); + XAxiDma_Bd *bd; + int processed, ret; - XAxiDma_Bd *bd; - XAxiDma_BdRing *ring = XAxiDma_GetTxRing(xdma); - + /* Wait until the one BD TX transaction is done */ while ((processed = XAxiDma_BdRingFromHw(ring, XAXIDMA_ALL_BDS, &bd)) == 0) { - if (irq >= 0) - wait_irq(irq); +// if (c->irq >= 0) { +// intc_wait(c->card, c->irq); +// XAxiDma_IntrAckIrq(xmda, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DMA_TO_DEVICE); +// } +// else + __asm__ ("nop"); } /* Free all processed TX BDs for future transmission */ @@ -36,177 +204,146 @@ int dma_write_complete(XAxiDma *xdma, int irq) return -1; } - return processed; -} - -int dma_read_complete(XAxiDma *xdma, int irq) -{ return 0; } -ssize_t dma_write(XAxiDma *xdma, char *buf, size_t len, int irq) +int dma_sg_read_complete(struct ip *c, char **buf, size_t *len) { - int ret; - - if (xdma->HasSg) { + XAxiDma *xdma = &c->dma; + XAxiDma_BdRing *ring = XAxiDma_GetRxRing(xdma); + XAxiDma_Bd *bd; - XAxiDma_BdRing *ring; - XAxiDma_Bd *bd; - - ring = XAxiDma_GetTxRing(xdma); - - ret = XAxiDma_BdRingAlloc(ring, 1, &bd); - if (ret != XST_SUCCESS) - return -1; - - /* Set up the BD using the information of the packet to transmit */ - ret = XAxiDma_BdSetBufAddr(bd, (uintptr_t) buf); - if (ret != XST_SUCCESS) { - info("Tx set buffer addr %p on BD %p failed %d", buf, bd, ret); - return -1; - } - - ret = XAxiDma_BdSetLength(bd, len, ring->MaxTransferLen); - if (ret != XST_SUCCESS) { - info("Tx set length %zu on BD %p failed %d", len, bd, ret); - return -1; - } - - /* Set SOF / EOF / ID */ - XAxiDma_BdSetCtrl(bd, XAXIDMA_BD_CTRL_TXEOF_MASK | XAXIDMA_BD_CTRL_TXSOF_MASK); - XAxiDma_BdSetId(bd, (uintptr_t) buf); - - /* Give the BD to DMA to kick off the transmission. */ - ret = XAxiDma_BdRingToHw(ring, 1, bd); - if (ret != XST_SUCCESS) { - info("to hw failed %d", ret); - return -1; - } - - dma_write_complete(xdma, irq); - } - else { - ret = XAxiDma_SimpleTransfer(xdma, (uintptr_t) buf, len, XAXIDMA_DMA_TO_DEVICE); - if (ret != XST_SUCCESS) { - warn("Failed DMA transfer"); - return -1; - } - - if (irq >= 0) { - wait_irq(irq); - XAxiDma_IntrAckIrq(xdma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DMA_TO_DEVICE); - } - else { - while (XAxiDma_Busy(xdma, XAXIDMA_DMA_TO_DEVICE)) - __asm__("nop"); - } - } - - return len; -} - -ssize_t dma_read(XAxiDma *xdma, char *buf, size_t len, int irq) -{ - int ret; - - if (xdma->HasSg) { - int freecnt, processed; - - XAxiDma_BdRing *ring; - XAxiDma_Bd *bd; - - ring = XAxiDma_GetRxRing(xdma); - - processed = 0; - do { - /* Wait until the data has been received by the Rx channel */ - while (XAxiDma_BdRingFromHw(ring, 1, &bd) == 0) { - if (irq >= 0) - wait_irq(irq); - } - - //char *bdbuf = XAxiDma_BdGetBufAddr(bd); - //size_t bdlen = XAxiDma_BdGetActualLength(bd, XAXIDMA_MAX_TRANSFER_LEN); - - //memcpy(buf, bdbuf, bdlen); - //buf += bdlen; - - processed++; - } while (XAxiDma_BdGetSts(bd) & XAXIDMA_BD_STS_RXEOF_MASK); - - /* Free all processed RX BDs for future transmission */ - ret = XAxiDma_BdRingFree(ring, processed, bd); - if (ret != XST_SUCCESS) { - info("Failed to free %d rx BDs %d", processed, ret); - return XST_FAILURE; - } - - /* Return processed BDs to RX channel so we are ready to receive new - * packets: - * - Allocate all free RX BDs - * - Pass the BDs to RX channel - */ - freecnt = XAxiDma_BdRingGetFreeCnt(ring); - ret = XAxiDma_BdRingAlloc(ring, freecnt, &bd); - if (ret != XST_SUCCESS) { - info("bd alloc failed"); - return -1; - } - - ret = XAxiDma_BdRingToHw(ring, freecnt, bd); - if (ret != XST_SUCCESS) { - info("Submit %d rx BDs failed %d", freecnt, ret); - return -1; - } - } - else { - ret = XAxiDma_SimpleTransfer(xdma, (uintptr_t) buf, len, XAXIDMA_DEVICE_TO_DMA); - if (ret != XST_SUCCESS) - warn("Failed DMA transfer"); - - if (irq >= 0) { - wait_irq(irq); - XAxiDma_IntrAckIrq(xdma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA); - } - else { - while (XAxiDma_Busy(xdma, XAXIDMA_DEVICE_TO_DMA)) - __asm__("nop"); - } - } - - return len; -} - -ssize_t dma_ping_pong(XAxiDma *xdma, char *src, char *dst, size_t len, int s2mm_irq) -{ int ret; - /* Prepare S2MM transfer */ - ret = XAxiDma_SimpleTransfer(xdma, (uintptr_t) dst, len, XAXIDMA_DEVICE_TO_DMA); - if (ret != XST_SUCCESS) - warn("Failed DMA transfer"); - - /* Start MM2S transfer */ - ret = XAxiDma_SimpleTransfer(xdma, (uintptr_t) src, len, XAXIDMA_DMA_TO_DEVICE); - if (ret != XST_SUCCESS) { - warn("Failed DMA transfer"); + if (!xdma->HasSg) return -1; - } - /* Wait for completion */ - if (s2mm_irq >= 0) { - wait_irq(s2mm_irq); - XAxiDma_IntrAckIrq(xdma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA); - } - else { - while (XAxiDma_Busy(xdma, XAXIDMA_DEVICE_TO_DMA)) + while (XAxiDma_BdRingFromHw(ring, 1, &bd) == 0) { +// if (irq >= 0) { +// intc_wait(c->card, c->irq + 1); +// XAxiDma_IntrAckIrq(xdma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA); +// } +// else __asm__("nop"); } + + if (len != NULL) + *len = XAxiDma_BdGetActualLength(bd, XAXIDMA_MAX_TRANSFER_LEN); - return XAxiDma_ReadReg(xdma->RegBase + XAXIDMA_RX_OFFSET, XAXIDMA_BUFFLEN_OFFSET); + if (buf != NULL) + *buf = (char *) (uintptr_t) XAxiDma_BdGetBufAddr(bd); + + /* Free all processed RX BDs for future transmission */ + ret = XAxiDma_BdRingFree(ring, 1, bd); + if (ret != XST_SUCCESS) + return -3; + + return 0; } -static int dma_setup_bdring(XAxiDma_BdRing *ring, struct dma_mem *bdbuf) +int dma_simple_read(struct ip *c, char *buf, size_t len) +{ + XAxiDma *xdma = &c->dma; + XAxiDma_BdRing *ring = XAxiDma_GetRxRing(xdma); + + buf = virt_to_dma(buf, c->card->dma); + + /* Checks */ + if (xdma->HasSg) + return -1; + + if ((len < 1) || (len > ring->MaxTransferLen)) + return -2; + + if (!xdma->HasS2Mm) + return -3; + + if (!ring->HasDRE) { + uint32_t mask = xdma->MicroDmaMode ? XAXIDMA_MICROMODE_MIN_BUF_ALIGN : ring->DataWidth - 1; + if ((uintptr_t) buf & mask) + return -4; + } + + if(!(XAxiDma_ReadReg(ring->ChanBase, XAXIDMA_SR_OFFSET) & XAXIDMA_HALTED_MASK)) { + if (XAxiDma_Busy(xdma, XAXIDMA_DEVICE_TO_DMA)) + return -5; + } + + XAxiDma_WriteReg(ring->ChanBase, XAXIDMA_DESTADDR_OFFSET, LOWER_32_BITS((uintptr_t) buf)); + if (xdma->AddrWidth > 32) + XAxiDma_WriteReg(ring->ChanBase, XAXIDMA_DESTADDR_MSB_OFFSET, UPPER_32_BITS((uintptr_t) buf)); + + XAxiDma_WriteReg(ring->ChanBase, XAXIDMA_CR_OFFSET, XAxiDma_ReadReg(ring->ChanBase, XAXIDMA_CR_OFFSET) | XAXIDMA_CR_RUNSTOP_MASK); + XAxiDma_WriteReg(ring->ChanBase, XAXIDMA_BUFFLEN_OFFSET, len); + + return XST_SUCCESS; +} + +int dma_simple_write(struct ip *c, char *buf, size_t len) +{ + XAxiDma *xdma = &c->dma; + XAxiDma_BdRing *ring = XAxiDma_GetTxRing(xdma); + + buf = virt_to_dma(buf, c->card->dma); + + /* Checks */ + if (xdma->HasSg) + return -1; + + if ((len < 1) || (len > ring->MaxTransferLen)) + return -2; + + if (!xdma->HasMm2S) + return -3; + + if (!ring->HasDRE) { + uint32_t mask = xdma->MicroDmaMode ? XAXIDMA_MICROMODE_MIN_BUF_ALIGN : ring->DataWidth - 1; + if ((uintptr_t) buf & mask) + return -4; + } + + /* If the engine is doing transfer, cannot submit */ + if(!(XAxiDma_ReadReg(ring->ChanBase, XAXIDMA_SR_OFFSET) & XAXIDMA_HALTED_MASK)) { + if (XAxiDma_Busy(xdma, XAXIDMA_DMA_TO_DEVICE)) + return -5; + } + + XAxiDma_WriteReg(ring->ChanBase, XAXIDMA_SRCADDR_OFFSET, LOWER_32_BITS((uintptr_t) buf)); + if (xdma->AddrWidth > 32) + XAxiDma_WriteReg(ring->ChanBase, XAXIDMA_SRCADDR_MSB_OFFSET, UPPER_32_BITS((uintptr_t) buf)); + + XAxiDma_WriteReg(ring->ChanBase, XAXIDMA_CR_OFFSET, XAxiDma_ReadReg(ring->ChanBase, XAXIDMA_CR_OFFSET) | XAXIDMA_CR_RUNSTOP_MASK); + XAxiDma_WriteReg(ring->ChanBase, XAXIDMA_BUFFLEN_OFFSET, len); + + return XST_SUCCESS; +} + +int dma_simple_read_complete(struct ip *c, char **buf, size_t *len) +{ + XAxiDma *xdma = &c->dma; + XAxiDma_BdRing *ring = XAxiDma_GetRxRing(xdma); + + while (!(XAxiDma_IntrGetIrq(xdma, XAXIDMA_DEVICE_TO_DMA) & XAXIDMA_IRQ_IOC_MASK)); + +// if(!(XAxiDma_ReadReg(ring->ChanBase, XAXIDMA_SR_OFFSET) & XAXIDMA_HALTED_MASK)) { +// if (XAxiDma_Busy(xdma, XAXIDMA_DMA_TO_DEVICE)) +// return -5; +// } + + return 0; +} + +int dma_simple_write_complete(struct ip *c, char **buf, size_t *len) +{ + XAxiDma *xdma = &c->dma; + XAxiDma_BdRing *ring = XAxiDma_GetRxRing(xdma); + + while (!(XAxiDma_IntrGetIrq(xdma, XAXIDMA_DEVICE_TO_DMA) & XAXIDMA_IRQ_IOC_MASK)); + + return 0; +} + +static int dma_setup_ring(XAxiDma_BdRing *ring, struct dma_mem *bdbuf) { int delay = 0; int coalesce = 1; @@ -222,16 +359,13 @@ static int dma_setup_bdring(XAxiDma_BdRing *ring, struct dma_mem *bdbuf) /* Setup Rx BD space */ cnt = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT, bdbuf->len); - ret = XAxiDma_BdRingCreate(ring, bdbuf->base_phys, bdbuf->base_virt, XAXIDMA_BD_MINIMUM_ALIGNMENT, cnt); + ret = XAxiDma_BdRingCreate(ring, bdbuf->base_phys, bdbuf->base_virt, XAXIDMA_BD_MINIMUM_ALIGNMENT, cnt); if (ret != XST_SUCCESS) { info("RX create BD ring failed %d", ret); return XST_FAILURE; } - /* - * Setup an all-zero BD as the template for the Rx channel. - */ XAxiDma_BdClear(&clearbd); ret = XAxiDma_BdRingClone(ring, &clearbd); if (ret != XST_SUCCESS) { @@ -239,113 +373,64 @@ static int dma_setup_bdring(XAxiDma_BdRing *ring, struct dma_mem *bdbuf) return XST_FAILURE; } - return XST_SUCCESS; -} - -static int dma_setup_rx(XAxiDma *AxiDmaInstPtr, struct dma_mem *bdbuf, struct dma_mem *rxbuf, size_t maxlen) -{ - int ret; - - XAxiDma_BdRing *ring; - XAxiDma_Bd *bd, *curbd; - - uint32_t freecnt; - uintptr_t rxptr; - - ring = XAxiDma_GetRxRing(AxiDmaInstPtr); - ret = dma_setup_bdring(ring, bdbuf); - if (ret != XST_SUCCESS) - return -1; - - /* Attach buffers to RxBD ring so we are ready to receive packets */ - freecnt = XAxiDma_BdRingGetFreeCnt(ring); - ret = XAxiDma_BdRingAlloc(ring, freecnt, &bd); - if (ret != XST_SUCCESS) { - info("RX alloc BD failed %d", ret); - return XST_FAILURE; - } - - curbd = bd; - rxptr = rxbuf->base_phys; - for (int i = 0; i < freecnt; i++) { - ret = XAxiDma_BdSetBufAddr(curbd, rxptr); - - if (ret != XST_SUCCESS) { - info("Set buffer addr %#lx on BD %p failed %d", rxptr, curbd, ret); - return XST_FAILURE; - } - - ret = XAxiDma_BdSetLength(curbd, maxlen, ring->MaxTransferLen); - if (ret != XST_SUCCESS) { - info("Rx set length %zu on BD %p failed %d", maxlen, curbd, ret); - return XST_FAILURE; - } - - /* Receive BDs do not need to set anything for the control - * The hardware will set the SOF/EOF bits per stream ret */ - XAxiDma_BdSetCtrl(curbd, 0); - XAxiDma_BdSetId(curbd, rxptr); - - rxptr += maxlen; - curbd = (XAxiDma_Bd *) XAxiDma_BdRingNext(ring, curbd); - } - - /* Clear the receive buffer, so we can verify data */ - memset((void *) (uintptr_t) rxbuf->base_virt, 0, rxbuf->len); - - ret = XAxiDma_BdRingToHw(ring, freecnt, bd); - if (ret != XST_SUCCESS) { - info("RX submit hw failed %d", ret); - return XST_FAILURE; - } - - /* Start RX DMA channel */ - ret = XAxiDma_BdRingStart(ring); - if (ret != XST_SUCCESS) { - info("RX start hw failed %d", ret); - - return XST_FAILURE; - } - - return XST_SUCCESS; -} - -static int dma_setup_tx(XAxiDma *AxiDmaInstPtr, struct dma_mem *bd) -{ - int ret; - - XAxiDma_BdRing *ring; - - ring = XAxiDma_GetTxRing(AxiDmaInstPtr); - ret = dma_setup_bdring(ring, bd); - if (ret != XST_SUCCESS) - return -1; - - /* Start the TX channel */ + /* Start the channel */ ret = XAxiDma_BdRingStart(ring); if (ret != XST_SUCCESS) { info("failed start bdring txsetup %d", ret); return XST_FAILURE; } - return XST_SUCCESS; } -int dma_init(XAxiDma *xdma, char *baseaddr, enum dma_mode mode, struct dma_mem *bd, struct dma_mem *rx, size_t maxlen) +int dma_init_rings(struct ip *c, struct dma_mem *bd) { - int ret, sgincld; + int ret; + XAxiDma *xdma = &c->dma; + + + /* Split BD memory equally between Rx and Tx rings */ + struct dma_mem bd_rx = { + .base_virt = bd->base_virt, + .base_phys = bd->base_phys, + .len = bd->len / 2 + }; + struct dma_mem bd_tx = { + .base_virt = bd->base_virt + bd_rx.len, + .base_phys = bd->base_phys + bd_rx.len, + .len = bd->len - bd_rx.len + }; + + ret = dma_setup_ring(XAxiDma_GetRxRing(xdma), &bd_rx); + if (ret != XST_SUCCESS) + return -1; + + ret = dma_setup_ring(XAxiDma_GetTxRing(xdma), &bd_tx); + if (ret != XST_SUCCESS) + return -1; + + return 0; +} + +int dma_init(struct ip *c) +{ + int ret, sg; + XAxiDma *xdma = &c->dma; + + /* Guess DMA type */ + sg = (XAxiDma_In32((uintptr_t) c->card->map + c->baseaddr + XAXIDMA_TX_OFFSET+ XAXIDMA_SR_OFFSET) & + XAxiDma_In32((uintptr_t) c->card->map + c->baseaddr + XAXIDMA_RX_OFFSET+ XAXIDMA_SR_OFFSET) & XAXIDMA_SR_SGINCL_MASK) ? 1 : 0; XAxiDma_Config xdma_cfg = { - .BaseAddr = (uintptr_t) baseaddr, + .BaseAddr = (uintptr_t) c->card->map + c->baseaddr, .HasStsCntrlStrm = 0, .HasMm2S = 1, - .HasMm2SDRE = 0, - .Mm2SDataWidth = 32, + .HasMm2SDRE = 1, + .Mm2SDataWidth = 128, .HasS2Mm = 1, - .HasS2MmDRE = 0, /* Data Realignment Engine */ - .S2MmDataWidth = 32, - .HasSg = (mode == DMA_MODE_SG) ? 1 : 0, + .HasS2MmDRE = 1, /* Data Realignment Engine */ + .HasSg = sg, + .S2MmDataWidth = 128, .Mm2sNumChannels = 1, .S2MmNumChannels = 1, .Mm2SBurstSize = 64, @@ -360,17 +445,6 @@ int dma_init(XAxiDma *xdma, char *baseaddr, enum dma_mode mode, struct dma_mem * return -1; } - /* Check if correct DMA type */ - sgincld = XAxiDma_In32((uintptr_t) baseaddr + XAXIDMA_TX_OFFSET+ XAXIDMA_SR_OFFSET) & - XAxiDma_In32((uintptr_t) baseaddr + XAXIDMA_RX_OFFSET+ XAXIDMA_SR_OFFSET) & - XAXIDMA_SR_SGINCL_MASK; - - if ((mode == DMA_MODE_SIMPLE && sgincld == XAXIDMA_SR_SGINCL_MASK) || - (mode == DMA_MODE_SG && sgincld != XAXIDMA_SR_SGINCL_MASK)) { - info("This is not a %s DMA controller", (mode == DMA_MODE_SG) ? "SG" : "Simple"); - return -1; - } - /* Perform selftest */ ret = XAxiDma_Selftest(xdma); if (ret != XST_SUCCESS) { @@ -378,29 +452,6 @@ int dma_init(XAxiDma *xdma, char *baseaddr, enum dma_mode mode, struct dma_mem * return -1; } - /* Setup Buffer Descriptor rings for SG DMA */ - if (mode == DMA_MODE_SG) { - /* Split BD memory equally between Rx and Tx rings */ - struct dma_mem bd_rx = { - .base_virt = bd->base_virt, - .base_phys = bd->base_phys, - .len = bd->len / 2 - }; - struct dma_mem bd_tx = { - .base_virt = bd->base_virt + bd_rx.len, - .base_phys = bd->base_phys + bd_rx.len, - .len = bd->len - bd_rx.len - }; - - ret = dma_setup_rx(xdma, &bd_rx, rx, maxlen); - if (ret != XST_SUCCESS) - return -1; - - ret = dma_setup_tx(xdma, &bd_tx); - if (ret != XST_SUCCESS) - return -1; - } - /* Enable completion interrupts for both channels */ XAxiDma_IntrEnable(xdma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DMA_TO_DEVICE); XAxiDma_IntrEnable(xdma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA); diff --git a/lib/fpga/fifo.c b/lib/fpga/fifo.c index 6a389d58e..448b20cf1 100644 --- a/lib/fpga/fifo.c +++ b/lib/fpga/fifo.c @@ -13,42 +13,50 @@ #include #include "utils.h" +#include "fpga/ip.h" #include "fpga/fifo.h" +#include "fpga/intc.h" -int fifo_init(XLlFifo *fifo, char *baseaddr, char *axi_baseaddr) +int fifo_init(struct ip *c) { + XLlFifo *fifo = &c->fifo_mm; + int ret; XLlFifo_Config fifo_cfg = { - .BaseAddress = (uintptr_t) baseaddr, - .Axi4BaseAddress = (uintptr_t) axi_baseaddr, - .Datainterface = (axi_baseaddr == NULL) ? 0 : 1 /* use AXI4 for Data, AXI4-Lite for control */ + .BaseAddress = (uintptr_t) c->card->map + c->baseaddr, + .Axi4BaseAddress = (uintptr_t) c->card->map + c->baseaddr_axi4, + .Datainterface = ((c->baseaddr_axi4) && (c->baseaddr_axi4 != -1)) ? 1 : 0 /* use AXI4 for Data, AXI4-Lite for control */ }; - ret = XLlFifo_CfgInitialize(fifo, &fifo_cfg, (uintptr_t) baseaddr); + ret = XLlFifo_CfgInitialize(fifo, &fifo_cfg, (uintptr_t) c->card->map + c->baseaddr); if (ret != XST_SUCCESS) return -1; - XLlFifo_IntEnable(fifo, XLLF_INT_RC_MASK); + XLlFifo_IntEnable(fifo, XLLF_INT_RC_MASK); /* Receive complete IRQ */ return 0; } -ssize_t fifo_write(XLlFifo *fifo, char *buf, size_t len, int irq) +ssize_t fifo_write(struct ip *c, char *buf, size_t len) { + XLlFifo *fifo = &c->fifo_mm; + XLlFifo_Write(fifo, buf, len); XLlFifo_TxSetLen(fifo, len); return len; } -ssize_t fifo_read(XLlFifo *fifo, char *buf, size_t len, int irq) +ssize_t fifo_read(struct ip *c, char *buf, size_t len) { + XLlFifo *fifo = &c->fifo_mm; + size_t nextlen = 0; while (XLlFifo_RxOccupancy(fifo) == 0) { - if (irq >= 0) - wait_irq(irq); + if (c->irq >= 0) + intc_wait(c->card, c->irq); else __asm__("nop"); } diff --git a/lib/fpga/intc.c b/lib/fpga/intc.c new file mode 100644 index 000000000..6ba2e3780 --- /dev/null +++ b/lib/fpga/intc.c @@ -0,0 +1,77 @@ +/** AXI-PCIe Interrupt controller + * + * @author Steffen Vogel + * @copyright 2015-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. + **********************************************************************************/ + +#include + +#include + +#include "log.h" +#include "nodes/fpga.h" +#include "kernel/vfio.h" +#include "fpga/ip.h" +#include "fpga/intc.h" + +int intc_init(struct ip *c) +{ + struct fpga *f = c->card; + int ret; + + uintptr_t base = (uintptr_t) f->map + c->baseaddr; + + /* Setup IRQs */ + for (int i = 0; i < f->vd.irqs[VFIO_PCI_MSI_IRQ_INDEX].count; i++) { + /* Setup vector */ + XIntc_Out32(base + XIN_IVAR_OFFSET + i * 4, i); + + /* Register eventfd with VFIO */ + ret = vfio_pci_msi_fd(&f->vd, (1 << i)); + if (ret < 0) + serror("Failed to create eventfd for IRQ: ret=%d", f->vd.msi_efds[i]); + } + + XIntc_Out32(base + XIN_IMR_OFFSET, 0); /* Use manual acknowlegement for all IRQs */ + XIntc_Out32(base + XIN_IAR_OFFSET, 0xFFFFFFFF); /* Acknowlege all pending IRQs manually */ + XIntc_Out32(base + XIN_IMR_OFFSET, 0xFFFFFFFF); /* Use fast acknowlegement for all IRQs */ + XIntc_Out32(base + XIN_IER_OFFSET, 0x00000000); /* Disable all IRQs by default */ + XIntc_Out32(base + XIN_MER_OFFSET, XIN_INT_HARDWARE_ENABLE_MASK | XIN_INT_MASTER_ENABLE_MASK); + + return 0; +} + +uint32_t intc_enable(struct ip *c, uint32_t mask) +{ + struct fpga *f = c->card; + + uintptr_t base = (uintptr_t) f->map + c->baseaddr; + uint32_t ier = XIntc_In32(base + XIN_IER_OFFSET); + + XIntc_Out32(base + XIN_IER_OFFSET, ier | mask); + + return ier; +} + +void intc_disable(struct ip *c, uint32_t mask) +{ + struct fpga *f = c->card; + + uintptr_t base = (uintptr_t) f->map + c->baseaddr; + + XIntc_Out32(base + XIN_IER_OFFSET, XIntc_In32(base + XIN_IER_OFFSET) & ~mask); +} + +uint64_t intc_wait(struct fpga *f, int irq) +{ + ssize_t ret; + uint64_t cnt; + + ret = read(f->vd.msi_efds[irq], &cnt, sizeof(cnt)); + if (ret != sizeof(cnt)) + return 0; + + return cnt; +} \ No newline at end of file diff --git a/lib/fpga/ip.c b/lib/fpga/ip.c new file mode 100644 index 000000000..8b5084078 --- /dev/null +++ b/lib/fpga/ip.c @@ -0,0 +1,181 @@ +#include +#include + +#include + +#include "log.h" + +#include "fpga/ip.h" +#include "fpga/intc.h" +#include "fpga/fifo.h" +#include "nodes/fpga.h" + +#include "config-fpga.h" + +struct ip * ip_vlnv_lookup(struct list *l, const char *vendor, const char *library, const char *name, const char *version) +{ + list_foreach(struct ip *c, l) { + if (ip_vlnv_match(c, vendor, library, name, version)) + return c; + } + + return NULL; +} + +int ip_vlnv_match(struct ip *c, const char *vendor, const char *library, const char *name, const char *version) +{ + return ((vendor && strcmp(c->vlnv.vendor, vendor)) || + (library && strcmp(c->vlnv.library, library)) || + (name && strcmp(c->vlnv.name, name)) || + (version && strcmp(c->vlnv.version, version))) ? 0 : 1; +} + +int ip_vlnv_parse(struct ip *c, const char *vlnv) +{ + char *tmp = strdup(vlnv); + + c->vlnv.vendor = strdup(strtok(tmp, ":")); + c->vlnv.library = strdup(strtok(NULL, ":")); + c->vlnv.name = strdup(strtok(NULL, ":")); + c->vlnv.version = strdup(strtok(NULL, ":")); + + free(tmp); + + return 0; +} + +int ip_init(struct ip *c) +{ + struct fpga *f = c->card; + int ret; + + if (ip_vlnv_match(c, "xilinx.com", "ip", "axis_interconnect", NULL)) { + if (c != f->sw) + error("There can be only one AXI4-Stream interconnect per FPGA"); + + ret = switch_init(c); + } + else if (ip_vlnv_match(c, "xilinx.com", "ip", "axi_fifo_mm_s", NULL)) { + ret = fifo_init(c); + } + else if (ip_vlnv_match(c, "xilinx.com", "ip", "axi_dma", NULL)) { + ret = dma_init(c); + } + else if (ip_vlnv_match(c, "xilinx.com", "ip", "axi_timer", NULL)) { + XTmrCtr_Config tmr_cfg = { + .BaseAddress = (uintptr_t) c->card->map + c->baseaddr, + .SysClockFreqHz = AXI_HZ + }; + + XTmrCtr_CfgInitialize(&c->timer, &tmr_cfg, (uintptr_t) c->card->map + c->baseaddr); + XTmrCtr_InitHw(&c->timer); + } + else if (ip_vlnv_match(c, "xilinx.com", "ip", "axi_gpio", NULL)) { + if (strstr(c->name, "reset")) { + if (f->reset) + error("There can be only one reset controller per FPGA"); + + f->reset = c; + } + } + else if (ip_vlnv_match(c, "acs.eonerc.rwth-aachen.de", "user", "axi_pcie_intc", NULL)) { + if (c != f->intc) + error("There can be only one interrupt controller per FPGA"); + + ret = intc_init(c); + } + else if (ip_vlnv_match(c, NULL, "hls", NULL, NULL) || + ip_vlnv_match(c, NULL, "sysgen", NULL, NULL)) { + ret = model_init(c); + } + + if (ret == 0) + c->state = IP_STATE_INITIALIZED; + + return ret; +} + +void ip_destroy(struct ip *c) +{ + if (ip_vlnv_match(c, NULL, "hls", NULL, NULL) || + ip_vlnv_match(c, NULL, "sysgen", NULL, NULL)) + model_destroy(c); + + free(c->vlnv.vendor); + free(c->vlnv.library); + free(c->vlnv.name); + free(c->vlnv.version); +} + +void ip_dump(struct ip *c) +{ + info("IP %s: vlnv=%s:%s:%s:%s baseaddr=%#jx, irq=%d, port=%d", + c->name, c->vlnv.vendor, c->vlnv.library, c->vlnv.name, c->vlnv.version, + c->baseaddr, c->irq, c->port); + + if (ip_vlnv_match(c, NULL, "hls", NULL, NULL) || + ip_vlnv_match(c, NULL, "sysgen", NULL, NULL)) + model_dump(c); +} + +int ip_parse(struct ip *c, config_setting_t *cfg) +{ + const char *vlnv; + long long baseaddr; + + c->name = config_setting_name(cfg); + if (!c->name) + cerror(cfg, "IP is missing a name"); + + if (!config_setting_lookup_string(cfg, "vlnv", &vlnv)) + cerror(cfg, "IP %s is missing the VLNV identifier", c->name); + + ip_vlnv_parse(c, vlnv); + + if (ip_vlnv_match(c, "xilinx.com", "ip", "axis_interconnect", NULL)) { + int numports; + + if (!config_setting_lookup_int(cfg, "numports", &numports)) + cerror(cfg, "Switch IP '%s' requires 'numports' option", c->name); + + c->sw.Config.MaxNumSI = c->sw.Config.MaxNumMI = numports; + } + else if (ip_vlnv_match(c, "xilinx.com", "ip", "axi_bram_ctrl", NULL)) { + if (!config_setting_lookup_int(cfg, "size", &c->bram.size)) + cerror(cfg, "Block RAM requires 'size' option"); + } + else if (ip_vlnv_match(c, "xilinx.com", "ip", "axi_fifo_mm_s", NULL)) { + if (config_setting_lookup_int64(cfg, "baseaddr_axi4", &baseaddr)) + c->baseaddr_axi4 = baseaddr; + else + c->baseaddr_axi4 = -1; + } + else if (ip_vlnv_match(c, NULL, "hls", NULL, NULL) || + ip_vlnv_match(c, NULL, "sysgen", NULL, NULL)) { + + if (strcmp(c->vlnv.library, "hls") == 0) + c->model.type = MODEL_TYPE_HLS; + else if (strcmp(c->vlnv.library, "sysgen") == 0) + c->model.type = MODEL_TYPE_XSG; + else + cerror(cfg, "Invalid model type: %s", c->vlnv.library); + + if (!config_setting_lookup_string(cfg, "xml", (const char **) &c->model.xml)) + c->model.xml = NULL; + } + + /* Common settings */ + if (config_setting_lookup_int64(cfg, "baseaddr", &baseaddr)) + c->baseaddr = baseaddr; + else + c->baseaddr = -1; + + if (!config_setting_lookup_int(cfg, "irq", &c->irq)) + c->irq = -1; + if (!config_setting_lookup_int(cfg, "port", &c->port)) + c->port = -1; + + c->cfg = cfg; + + return 0; +} diff --git a/lib/fpga/model.c b/lib/fpga/model.c index 518018da3..980b1572e 100644 --- a/lib/fpga/model.c +++ b/lib/fpga/model.c @@ -14,24 +14,9 @@ #include #include +#include "fpga/ip.h" #include "fpga/model.h" -int model_init(struct model *m, uintptr_t baseaddr) -{ - 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); @@ -43,146 +28,24 @@ static void model_info_destroy(struct model_info *i) 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) -{ - const char *param_type[] = { "UFix", "Fix", "Float", "Boolean" }; - const char *model_types[] = { "HLS", "XSG" }; - const char *parameter_dirs[] = { "In", "Out", "In/Out" }; - - 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("%#jx: %s (%s) = %.3f %s %u", - p->offset, - p->name, - parameter_dirs[p->direction], - p->default_value.flt, - param_type[p->type], - p->binpt - ); - else if (p->direction == MODEL_PARAM_OUT) - info("%#jx: %s (%s)", - p->offset, - p->name, - parameter_dirs[p->direction] - ); - } - - 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;// TODO: + p->model->baseaddr; - - switch (p->type) { - case MODEL_PARAM_TYPE_UFIX: - *v = (double) ptr->ufix / (1 << p->binpt); - break; - - case MODEL_PARAM_TYPE_FIX: - *v = (double) ptr->fix / (1 << p->binpt); - break; - - case MODEL_PARAM_TYPE_FLOAT: - *v = (double) ptr->flt; - break; - - case MODEL_PARAM_TYPE_BOOLEAN: - *v = (double) ptr->ufix ? 1 : 0; - } - - return 0; -} - -int model_param_write(struct model_param *p, double v) -{ - union model_param_value *ptr = p->offset;// TODO: + p->model->baseaddr; - - switch (p->type) { - case MODEL_PARAM_TYPE_UFIX: - ptr->ufix = (uint32_t) (v * (1 << p->binpt)); - break; - - case MODEL_PARAM_TYPE_FIX: - ptr->fix = (int32_t) (v * (1 << p->binpt)); - break; - - case MODEL_PARAM_TYPE_FLOAT: - ptr->flt = (float) v; - break; - - case MODEL_PARAM_TYPE_BOOLEAN: - ptr->bol = (bool) v; - break; - } - - return 0; -} - -void model_param_add(struct model *m, const char *name, enum model_param_direction dir, enum model_param_type type) -{ - struct model_param *p = alloc(sizeof(struct model_param)); - - p->name = strdup(name); - p->type = type; - p->direction = dir; - - list_push(&m->parameters, p); -} - -int model_init_from_xsg_map(struct model *m, uintptr_t baseaddr) -{ - 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) +static 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); - + int j; struct model_param *p; struct model_info *i; - int j; - + + /* Check magic */ if (map[0] != XSG_MAGIC) error("Invalid magic: %#x", map[0]); @@ -224,40 +87,232 @@ int model_xsg_map_parse(uint32_t *map, size_t len, struct list *parameters, stru 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) +static uint32_t model_xsg_map_read_word(uint32_t offset, void *baseaddr) { -#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; + *addr = offset; /* Update addr reg */ - /* Check start DW */ - magic = get_word(0); + return *data; /* Read data reg */ +} + +static int model_xsg_map_read(uint32_t *map, size_t len, void *baseaddr) +{ + size_t maplen; + uint32_t magic; + + /* Check magic */ + magic = model_xsg_map_read_word(0, baseaddr); if (magic != XSG_MAGIC) return -1; - maplen = get_word(1); + maplen = model_xsg_map_read_word(1, baseaddr); if (maplen < 3) return -2; /* Read Data */ int i; for (i = 0; i < MIN(maplen, len); i++) - map[i] = get_word(i); + map[i] = model_xsg_map_read_word(i, baseaddr); return i; +} -#undef get_word -} \ No newline at end of file +static int model_init_from_xml(struct ip *c) +{ + //struct model *m = &c->model; + + /** @todo Implement */ + + return -1; +} + +static int model_init_from_xsg_map(struct model *m, void *baseaddr) +{ + int ret, chks; + + if (baseaddr == (void *) -1) + return -1; + + m->xsg.map = alloc(XSG_MAPLEN); + m->xsg.maplen = model_xsg_map_read(m->xsg.map, XSG_MAPLEN, baseaddr); + if (m->xsg.maplen < 0) + return -1; + + debug(5, "XSG: memory map length = %#zx", m->xsg.maplen); + + chks = m->xsg.map[m->xsg.maplen - 1]; + if (chks != model_xsg_map_checksum(m->xsg.map, m->xsg.maplen)) + return -2; + + ret = model_xsg_map_parse(m->xsg.map, m->xsg.maplen, &m->parameters, &m->infos); + if (ret) + return -3; + + debug(5, "XSG: Parsed %zu parameters and %zu model infos", list_length(&m->parameters), list_length(&m->infos)); + + return 0; +} + +int model_init(struct ip *c) +{ + int ret; + struct model *m = &c->model; + + list_init(&m->parameters); + list_init(&m->infos); + + if (m->xml) + ret = model_init_from_xml(c); + else if (ip_vlnv_match(c, NULL, "sysgen", NULL, NULL)) + ret = model_init_from_xsg_map(m, c->card->map + c->baseaddr); + else + ret = 0; + + list_foreach(struct model_param *p, &m->parameters) + p->ip = c; + + /* Set default values for parameters */ + list_foreach(struct model_param *p, &m->parameters) { + if (p->direction == MODEL_PARAM_IN) { + model_param_write(p, p->default_value.flt); + info("Set parameter '%s' updated to default value: %f", p->name, p->default_value.flt); + } + } + + if (ret) + error("Failed to init XSG model: %d", ret); + + return 0; +} + +void model_destroy(struct ip *c) +{ + struct model *m = &c->model; + + list_destroy(&m->parameters, (dtor_cb_t) model_param_destroy, true); + list_destroy(&m->infos, (dtor_cb_t) model_info_destroy, true); + + if (m->xsg.map != NULL) + free(m->xsg.map); +} + +void model_dump(struct ip *c) +{ + struct model *m = &c->model; + + const char *param_type[] = { "UFix", "Fix", "Float", "Boolean" }; + const char *parameter_dirs[] = { "In", "Out", "In/Out" }; + + { INDENT + info("Parameters:"); + list_foreach(struct model_param *p, &m->parameters) { INDENT + if (p->direction == MODEL_PARAM_IN) + info("%#jx: %s (%s) = %.3f %s %u", + p->offset, + p->name, + parameter_dirs[p->direction], + p->default_value.flt, + param_type[p->type], + p->binpt + ); + else if (p->direction == MODEL_PARAM_OUT) + info("%#jx: %s (%s)", + p->offset, + p->name, + parameter_dirs[p->direction] + ); + } + + 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) +{ + struct ip *c = p->ip; + + union model_param_value *ptr = (union model_param_value *) (c->card->map + c->baseaddr + p->offset); + + switch (p->type) { + case MODEL_PARAM_TYPE_UFIX: + *v = (double) ptr->ufix / (1 << p->binpt); + break; + + case MODEL_PARAM_TYPE_FIX: + *v = (double) ptr->fix / (1 << p->binpt); + break; + + case MODEL_PARAM_TYPE_FLOAT: + *v = (double) ptr->flt; + break; + + case MODEL_PARAM_TYPE_BOOLEAN: + *v = (double) ptr->ufix ? 1 : 0; + } + + return 0; +} + +int model_param_write(struct model_param *p, double v) +{ + struct ip *c = p->ip; + + union model_param_value *ptr = (union model_param_value *) (c->card->map + c->baseaddr + p->offset); + + switch (p->type) { + case MODEL_PARAM_TYPE_UFIX: + ptr->ufix = (uint32_t) (v * (1 << p->binpt)); + break; + + case MODEL_PARAM_TYPE_FIX: + ptr->fix = (int32_t) (v * (1 << p->binpt)); + break; + + case MODEL_PARAM_TYPE_FLOAT: + ptr->flt = (float) v; + break; + + case MODEL_PARAM_TYPE_BOOLEAN: + ptr->bol = (bool) v; + break; + } + + return 0; +} + +void model_param_add(struct ip *c, const char *name, enum model_param_direction dir, enum model_param_type type) +{ + struct model *m = &c->model; + struct model_param *p = alloc(sizeof(struct model_param)); + + p->name = strdup(name); + p->type = type; + p->direction = dir; + + list_push(&m->parameters, p); +} + +int model_param_remove(struct ip *c, const char *name) +{ + struct model *m = &c->model; + struct model_param *p; + + p = list_lookup(&m->parameters, name); + if (!p) + return -1; + + list_remove(&m->parameters, p); + + return 0; +} diff --git a/lib/fpga/switch.c b/lib/fpga/switch.c index 4acdfec01..e782ffbd3 100644 --- a/lib/fpga/switch.c +++ b/lib/fpga/switch.c @@ -9,19 +9,21 @@ **********************************************************************************/ #include "fpga/switch.h" +#include "fpga/ip.h" -int switch_init(XAxis_Switch *sw, char *baseaddr, int micnt, int sicnt) +int switch_init(struct ip *c) { + XAxis_Switch *sw = &c->sw; int ret; /* Setup AXI-stream switch */ XAxis_Switch_Config sw_cfg = { - .BaseAddress = (uintptr_t) baseaddr, - .MaxNumMI = micnt, - .MaxNumSI = sicnt + .BaseAddress = (uintptr_t) c->card->map + c->baseaddr, + .MaxNumMI = sw->Config.MaxNumMI, + .MaxNumSI = sw->Config.MaxNumSI }; - ret = XAxisScr_CfgInitialize(sw, &sw_cfg, (uintptr_t) baseaddr); + ret = XAxisScr_CfgInitialize(sw, &sw_cfg, (uintptr_t) c->card->map + c->baseaddr); if (ret != XST_SUCCESS) return -1; @@ -39,10 +41,12 @@ int switch_init(XAxis_Switch *sw, char *baseaddr, int micnt, int sicnt) return 0; } -int switch_connect(XAxis_Switch *sw, int mi, int si) +int switch_connect(struct ip *c, struct ip *mi, struct ip *si) { + XAxis_Switch *sw = &c->sw; + XAxisScr_RegUpdateDisable(sw); - XAxisScr_MiPortEnable(sw, mi, si); + XAxisScr_MiPortEnable(sw, mi->port, si->port); XAxisScr_RegUpdateEnable(sw); return 0; diff --git a/lib/kernel/pci.c b/lib/kernel/pci.c index aaabaa1e2..5a80b05be 100644 --- a/lib/kernel/pci.c +++ b/lib/kernel/pci.c @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -16,6 +17,49 @@ #include "kernel/pci.h" #include "config.h" +static struct pci_access *pacc; + +static void pci_log(char *msg, ...) +{ + char *tmp = strdup(msg); + + va_list ap; + va_start(ap, msg); + log_vprint("PCI ", strtok(tmp, "\n"), ap); + va_end(ap); + free(tmp); +} + +struct pci_access * pci_get_handle() +{ + if (pacc) + return pacc; /* Singleton */ + + 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 = pci_log; /* Replace logging and debug functions */ + pacc->warning = pci_log; + pacc->debug = pci_log; + pacc->debugging = 1; + + pci_scan_bus(pacc); /* We want to get the list of devices */ + + return pacc; +} + +void pci_release_handle() +{ + if (pacc) { + //pci_cleanup(pacc); + //pacc = NULL; + } +} + struct pci_dev * pci_find_device(struct pci_access *pacc, struct pci_filter *f) { struct pci_dev *d; diff --git a/lib/nodes/cbuilder.c b/lib/nodes/cbuilder.c new file mode 100644 index 000000000..e1ef24086 --- /dev/null +++ b/lib/nodes/cbuilder.c @@ -0,0 +1,82 @@ +/** Node type: Wrapper around RSCAD CBuilder model + * + * @author Steffen Vogel + * @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. + **********************************************************************************/ + +#include "node.h" + +/* Constants from RSCAD */ +#define PI 3.1415926535897932384626433832795 // definition of PI +#define TWOPI 6.283185307179586476925286766559 // definition of 2.0*PI +#define E 2.71828182845904523536028747135266 // definition of E +#define EINV 0.36787944117144232159552377016147 // definition of E Inverse (1/E) +#define RT2 1.4142135623730950488016887242097 // definition of square root 2.0 +#define RT3 1.7320508075688772935274463415059 // definition of square root 3.0 +#define INV_ROOT2 0.70710678118654752440084436210485 + +double TimeStep; + +/* Add your inputs and outputs here */ +double IntfIn; +double IntfOut; + +/* Add your parameters here */ +double R2; // Resistor [Ohm] in SS2 +double C2; // Capacitance [F] in SS2 + +#include "cbuilder/static.h" +#include "cbuilder/ram_functions.h" + +static double getTimeStep() { + return TimeStep; +} + +int cbuilder_open(struct node *n) +{ + /* Initialize parameters */ + R2 = 1; /**< R2 = 1 Ohm */ + C2 = 0.001; /**< C2 = 1000 uF */ + + TimeStep = 50e-6; + + #include "cbuilder/ram.h" + + return 0; +} + +int cbuilder_read(struct node *n, struct sample *smps[], unsigned cnt) +{ + struct sample *smp = smps[0]; + + smp->values[0].f = IntfOut; + + return 1; +} + +int cbuilder_write(struct node *n, struct sample *smps[], unsigned cnt) +{ + struct sample *smp = smps[0]; + + /* Update inputs */ + IntfIn = smp->values[0].f; + + /* Start calculation of 1 step */ + #include "cbuilder/code.h" + + return 1; +} + +static struct node_type vt = { + .name = "cbuilder", + .description = "RTDS CBuilder model", + .vectorize = 1, + .size = 0, + .open = cbuilder_open, + .read = cbuilder_read, + .write = cbuilder_write, +}; + +REGISTER_NODE_TYPE(&vt) diff --git a/lib/nodes/vfpga.c b/lib/nodes/fpga.c similarity index 57% rename from lib/nodes/vfpga.c rename to lib/nodes/fpga.c index f1266e13d..63da81694 100644 --- a/lib/nodes/vfpga.c +++ b/lib/nodes/fpga.c @@ -7,7 +7,7 @@ *********************************************************************************/ #include -#include +#include #include #include #include @@ -15,7 +15,7 @@ #include "kernel/kernel.h" #include "kernel/pci.h" -#include "nodes/vfpga.h" +#include "nodes/fpga.h" #include "fpga/ip.h" @@ -23,13 +23,10 @@ #include "utils.h" #include "timing.h" -struct vfpga fpga; +struct fpga fpga; struct vfio_container vc; -static struct pci_access *pacc; -typedef void(*log_cb_t)(char *, ...); - -int vfpga_reset(struct vfpga *f) +int fpga_reset(struct fpga *f) { int ret; char state[4096]; @@ -39,7 +36,7 @@ int vfpga_reset(struct vfpga *f) if (ret != sizeof(state)) return -1; - uint32_t *rst_reg = (uint32_t *) (f->map + f->baseaddr.reset); + uint32_t *rst_reg = (uint32_t *) (f->map + f->reset->baseaddr); info("Reset fpga"); rst_reg[0] = 1; @@ -56,11 +53,14 @@ int vfpga_reset(struct vfpga *f) return 0; } -void vfpga_dump(struct vfpga *f) +void fpga_dump(struct fpga *f) { char namebuf[128]; char *name; + struct pci_access *pacc; + + pacc = pci_get_handle(); 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 */ @@ -73,7 +73,7 @@ void vfpga_dump(struct vfpga *f) 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); @@ -83,20 +83,12 @@ void vfpga_dump(struct vfpga *f) vfio_dump(fpga.vd.group->container); } -struct vfpga * vfpga_get() +struct fpga * fpga_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 fpga_parse_card(struct fpga *v, int argc, char * argv[], config_setting_t *cfg) { int ret; const char *slot, *id, *err; @@ -105,13 +97,12 @@ int vfpga_parse(struct vfpga *v, int argc, char * argv[], config_setting_t *cfg) /* 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); + config_setting_lookup_bool(cfg_fpga, "do_reset", &v->do_reset); cfg_slot = config_setting_get_member(cfg_fpga, "slot"); if (cfg_slot) { @@ -142,59 +133,50 @@ int vfpga_parse(struct vfpga *v, int argc, char * argv[], config_setting_t *cfg) cerror(cfg_fpga, "FPGA configuration is missing ips section"); for (int i = 0; i < config_setting_length(cfg_ips); i++) { - struct ip ip; + struct ip *ip; config_setting_t *cfg_ip = config_setting_get_elem(cfg_ips, i); - ret = ip_parse(&ip, cfg_ip); - if (ret) + ip = alloc(sizeof(struct ip)); + ret = ip_parse(ip, cfg_ip); + if (ret) { + free(ip); cerror(cfg_ip, "Failed to parse VILLASfpga ip"); + } - list_push(&v->ips, memdup(&ip, sizeof(struct ip))); + list_push(&v->ips, 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 fpga_init(int argc, char * argv[], config_setting_t *cfg) { int ret; struct pci_access *pacc; struct pci_dev *pdev; - struct vfpga *f; + struct fpga *f; /* For now we only support a single VILALSfpga card */ - f = vfpga_get(); + f = fpga_get(); + + /* Check FPGA configuration */ + f->reset = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_gpio", NULL); + if (!reset) + error("FPGA is missing a reset controller"); - /* Some hardcoded addresses for internal IP blocks */ - f->baseaddr.reset = 0x2000; - f->baseaddr.intc = 0x5000; + f->intc = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_pcie_intc", NULL); + if (!f->intc) + error("FPGA is missing a interrupt controller"); - pacc = vfpga_init_pci(); + f->sw = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axis_interconnect", NULL); + if (!f->sw) + warn("FPGA is missing an AXI4-Stream switch"); + pacc = pci_get_handle(); pci_filter_init(pacc, &f->filter); list_init(&f->ips); - ret = vfpga_parse(f, argc, argv, cfg); + ret = fpga_parse_card(f, argc, argv, cfg); if (ret) cerror(cfg, "Failed to parse VILLASfpga config"); @@ -216,13 +198,6 @@ int vfpga_init(int argc, char * argv[], config_setting_t *cfg) if (ret) error("Failed to attach VFIO device"); - /* Setup IRQs */ - for (int i = 0; i < f->vd.irqs[VFIO_PCI_MSI_IRQ_INDEX].count; i++) { - ret = vfio_pci_msi_fd(&f->vd, (1 << i)); - if (ret < 0) - serror("Failed to create eventfd for IRQ: ret=%d", f->vd.msi_efds[i]); - } - /* Map PCIe BAR */ f->map = vfio_map_region(&f->vd, VFIO_PCI_BAR0_REGION_INDEX); if (f->map == MAP_FAILED) @@ -238,9 +213,9 @@ int vfpga_init(int argc, char * argv[], config_setting_t *cfg) if (ret) serror("Failed to enable PCI device"); - /* Trigger internal reset of fpga card / PCIe endpoint */ - if (f->reset) { - ret = vfpga_reset(f); + /* Reset system ? */ + if (f->do_reset) { + ret = fpga_reset(f); if (ret) serror("Failed to reset fpga card"); @@ -250,6 +225,7 @@ int vfpga_init(int argc, char * argv[], config_setting_t *cfg) serror("Failed to reset PCI device"); } + /* Initialize IP cores */ list_foreach(struct ip *c, &f->ips) { c->card = f; ip_init(c); @@ -258,13 +234,13 @@ int vfpga_init(int argc, char * argv[], config_setting_t *cfg) return 0; } -int vfpga_deinit() +int fpga_deinit() { int ret; list_destroy(&fpga.ips, (dtor_cb_t) ip_destroy, true); - pci_cleanup(pacc); + pci_release_handle(); ret = vfio_destroy(&vc); if (ret) @@ -273,76 +249,118 @@ int vfpga_deinit() return 0; } -int vfpga_parse_node(struct node *n, config_setting_t *cfg) +int fpga_parse(struct node *n, config_setting_t *cfg) { -// struct vfpga *v = n->_vd; + struct fpga_dm *d = n->_vd; + + /* There is currently only support for a single FPGA card */ + d->card = fpga_get(); + + const char *dm; + + if (!config_setting_lookup_string(cfg, "datamover", &dm)) + cerror(cfg, "Node '%s' is missing the 'datamover' setting", node_name(n)); + + d->ip = list_lookup(&d->card->ips, dm); + if (!d->ip) + cerror(cfg, "Datamover '%s' is unknown. Please specify it in the fpga.ips section", dm); + + if (ip_vlnv_match(d->ip, "xilinx.com", "ip", "axi_dma", NULL)) + d->type = FPGA_DM_DMA; + else if (ip_vlnv_match(d->ip, "xilinx.com", "ip", "axi_fifo_mm", NULL)) + d->type = FPGA_DM_FIFO; + else + cerror(cfg, "IP '%s' is not a supported datamover", dm); return 0; } -char * vfpga_print(struct node *n) +char * fpga_print(struct node *n) { - struct vfpga *v = n->_vd; + struct fpga_dm *d = n->_vd; + struct fpga *f = d->card; - return strf("slot=%02"PRIx8":%02"PRIx8".%"PRIx8" id=%04"PRIx16":%04"PRIx16, - v->filter.bus, v->filter.device, v->filter.func, - v->filter.vendor, v->filter.device); + return strf("dm=%s (%s:%s:%s:%s) baseaddr=%#jx port=%u slot=%02"PRIx8":%02"PRIx8".%"PRIx8" id=%04"PRIx16":%04"PRIx16, + d->ip->name, d->ip->vlnv.vendor, d->ip->vlnv.library, d->ip->vlnv.name, d->ip->vlnv.version, d->ip->baseaddr, d->ip->port, + f->filter.bus, f->filter.device, f->filter.func, + f->filter.vendor, f->filter.device); } -int vfpga_open(struct node *n) +int fpga_open(struct node *n) { - struct vfpga *v = n->_vd; - struct pci_dev *dev; +// struct fpga *v = n->_vd; - dev = pci_find_device(pacc, &v->filter); - if (!dev) - error("No vfpga card found"); - - /* @todo */ + /** @todo Implement */ return 0; } -int vfpga_close(struct node *n) +int fpga_close(struct node *n) { -// struct vfpga *v = n->_vd; +// struct fpga *v = n->_vd; - /* @todo */ + /** @todo Implement */ return 0; } -int vfpga_read(struct node *n, struct sample *smps[], unsigned cnt) +int fpga_read(struct node *n, struct sample *smps[], unsigned cnt) { -// struct vfpga *v = n->_vd; + struct fpga_dm *d = n->_vd; + struct sample *smp = smps[0]; - /** @todo */ + char *addr = (char *) smp->values; + size_t len = smp->length * sizeof(smp->values[0]); - return 0; + /* Read data from RTDS */ + switch (d->type) { + case FPGA_DM_DMA: + if (d->ip->dma.HasSg) + return -1; /* Currently not supported */ + else { + len = dma_read(d->ip, addr, len); + XAxiDma_IntrAckIrq(&d->ip->dma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA); + return 1; + } + case FPGA_DM_FIFO: + break; + } + + return -1; } -/** @todo implement */ -int vfpga_write(struct node *n, struct sample *smps[], unsigned cnt) +int fpga_write(struct node *n, struct sample *smps[], unsigned cnt) { -// struct vfpga *v = n->_vd; + struct fpga_dm *d = n->_vd; + struct sample *smp = smps[0]; - /** @todo */ + char *addr = (char *) smp->values; + size_t len = smp->length * sizeof(smp->values[0]); - return 0; + /* Send data to RTDS */ + switch (d->type) { + case FPGA_DM_DMA: + len = dma_write(d->ip, addr, len); + return 1; + case FPGA_DM_FIFO: + break; + } + + return -1; } static struct node_type vt = { - .name = "vfpga", + .name = "fpga", .description = "VILLASfpga PCIe card (libpci)", .vectorize = 1, - .parse = vfpga_parse_node, - .print = vfpga_print, - .open = vfpga_open, - .close = vfpga_close, - .read = vfpga_read, - .write = vfpga_write, - .init = vfpga_init, - .deinit = vfpga_deinit + .parse = fpga_parse, + .print = fpga_print, + .open = fpga_open, + .close = fpga_close, + .read = fpga_read, + .write = fpga_write, + .init = fpga_init, + .deinit = fpga_deinit }; REGISTER_NODE_TYPE(&vt) \ No newline at end of file diff --git a/lib/utils.c b/lib/utils.c index 1fa4bbb91..5e16a235e 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -6,14 +6,17 @@ * Unauthorized copying of this file, via any medium is strictly prohibited. *********************************************************************************/ -#include -#include #include +#include +#include +#include #include #include #include #include #include +#include +#include #include "config.h" #include "cfg.h" @@ -204,26 +207,6 @@ void * memdup(const void *src, size_t bytes) return dst; } -#include -#include -#include -#include -#include - -#include "utils.h" - -uint64_t wait_irq(int irq) -{ - ssize_t ret; - uint64_t cnt; - - ret = read(irq, &cnt, sizeof(cnt)); - if (ret != sizeof(cnt)) - return 0; - - return cnt; -} - int read_random(char *buf, size_t len) { int ret, fd; diff --git a/src/fpga.c b/src/fpga-main.c similarity index 92% rename from src/fpga.c rename to src/fpga-main.c index 3fce8db69..7891cb7fd 100644 --- a/src/fpga.c +++ b/src/fpga-main.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include @@ -25,8 +25,8 @@ #include "config-fpga.h" /* Declarations */ -int fpga_bench(struct vfpga *f); -int fpga_tests(struct vfpga *f); +int fpga_bench(struct fpga *f); +int fpga_tests(struct fpga *f); void usage(char *name) { @@ -45,7 +45,7 @@ void usage(char *name) int main(int argc, char *argv[]) { int ret; - struct vfpga *fpga; + struct fpga *fpga; enum { FPGA_TESTS, FPGA_BENCH @@ -89,13 +89,13 @@ int main(int argc, char *argv[]) /* Initialize VILLASfpga card */ config_setting_t *cfg_root = config_root_setting(&config); - ret = vfpga_init(argc, argv, cfg_root); + ret = fpga_init(argc, argv, cfg_root); if (ret) error("Failed to initialize fpga card"); - fpga = vfpga_get(); + fpga = fpga_get(); - vfpga_dump(fpga); + fpga_dump(fpga); /* Setup scheduler */ cpu_set_t set = integer_to_cpuset(AFFINITY); @@ -121,7 +121,7 @@ int main(int argc, char *argv[]) } /* Shutdown */ - ret = vfpga_deinit(&fpga); + ret = fpga_deinit(&fpga); if (ret) error("Failed to de-initialize fpga card"); diff --git a/src/fpga-tests.c b/src/fpga-tests.c index c2817c8df..6df0a5f1d 100644 --- a/src/fpga-tests.c +++ b/src/fpga-tests.c @@ -20,9 +20,10 @@ #include #include -#include +#include #include +#include //#include @@ -35,30 +36,28 @@ #define CPU_HZ 3392389000 -/* 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); +/* Forward Declarations */ +int fpga_test_intc(struct fpga *f); +int fpga_test_timer(struct fpga *f); +int fpga_test_fifo(struct fpga *f); +int fpga_test_dma(struct fpga *f); +int fpga_test_xsg(struct fpga *f); +int fpga_test_rtds_rtt(struct fpga *f); -int fpga_tests(struct vfpga *f) +int fpga_tests(struct fpga *f) { int ret; struct { const char *name; - int (*func)(struct vfpga *f); + int (*func)(struct fpga *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 } + { "RTDS: RTT Test", fpga_test_rtds_rtt } }; for (int i = 0; i < ARRAY_LEN(tests); i++) { @@ -70,34 +69,42 @@ int fpga_tests(struct vfpga *f) return 0; } -int fpga_test_intc(struct vfpga *f) +int fpga_test_intc(struct fpga *f) { - uint32_t ier, isr; + uint32_t isr; - /* Save old IER */ - ier = XIntc_In32(f->baseaddr.intc + XIN_IER_OFFSET); - XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier | 0xFF00); + if (!f->intc) + return -1; - XIntc_Out32(f->baseaddr.intc + XIN_ISR_OFFSET, 0xFF00); + intc_enable(f->intc, 0xFF00); - debug(3, "Wait for 8 SW triggerd interrupts"); + info("ISR %#x", XIntc_In32((uintptr_t) f->map + f->intc->baseaddr + XIN_ISR_OFFSET)); + info("IER %#x", XIntc_In32((uintptr_t) f->map + f->intc->baseaddr + XIN_IER_OFFSET)); + info("IMR %#x", XIntc_In32((uintptr_t) f->map + f->intc->baseaddr + XIN_IMR_OFFSET)); + info("MER %#x", XIntc_In32((uintptr_t) f->map + f->intc->baseaddr + XIN_MER_OFFSET)); + + /* Fake IRQs in software by writing to ISR */ + XIntc_Out32((uintptr_t) f->map + f->intc->baseaddr + XIN_ISR_OFFSET, 0xFF00); + + /* Wait for 8 SW triggered IRQs */ for (int i = 0; i < 8; i++) - wait_irq(f->vd.msi_efds[i+8]); + intc_wait(f, i+8); - isr = XIntc_In32(f->baseaddr.intc + XIN_ISR_OFFSET); - - /* Restore IER */ - XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier); + /* Check ISR if all SW IRQs have been deliverd */ + isr = XIntc_In32((uintptr_t) f->map + f->intc->baseaddr + XIN_ISR_OFFSET); + + intc_disable(f->intc, 0xFF00); return (isr & 0xFF00) ? -1 : 0; /* ISR should get cleared by MSI_Grant_signal */ } -int fpga_test_xsg(struct vfpga *f) +int fpga_test_xsg(struct fpga *f) { - 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); + struct ip *xsg, *dma; + int ret; + double factor, err = 0; + + xsg = ip_vlnv_lookup(&f->ips, NULL, "sysgen", "xsg_multiply", NULL); dma = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_dma", NULL); /* Check if required IP is available on FPGA */ @@ -106,69 +113,85 @@ int fpga_test_xsg(struct vfpga *f) ip_dump(xsg); - 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); + config_setting_t *cfg_params, *cfg_param; + struct model_param *p; + + cfg_params = config_setting_get_member(xsg->cfg, "parameters"); + if (cfg_params) { + for (int i = 0; i < config_setting_length(cfg_params); i++) { + cfg_param = config_setting_get_elem(cfg_params, i); + + const char *name = config_setting_name(cfg_param); + double value = config_setting_get_float(cfg_param); + + p = list_lookup(&xsg->model.parameters, name); + if (!p) + cerror(cfg_param, "Model %s has no parameter named %s", xsg->name, name); + + model_param_write(p, value); + info("Param '%s' updated to: %f", p->name, value); } } - switch_connect(&sw->sw, dma->port, xsg->port); - switch_connect(&sw->sw, xsg->port, dma->port); + p = list_lookup(&xsg->model.parameters, "factor"); + if (!p) + error("Missing parameter 'factor' for model '%s'", xsg->name); + + ret = model_param_read(p, &factor); + if (ret) + error("Failed to read parameter 'factor' from model '%s'", xsg->name); + + info("Model param: factor = %f", factor); + + switch_connect(f->sw, dma, xsg); + switch_connect(f->sw, xsg, dma); 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); + ret = dma_ping_pong(dma, (char *) src, (char *) dst, 6 * sizeof(float)); + if (ret) + error("Failed to to ping pong DMA transfer: %d", ret); 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]); + err += abs(factor * src[i] - dst[i]); + + info("Error after FPGA operation: err = %f", err); - return 0; + return err > 1e-3; } -int fpga_test_hls_dft(struct vfpga *f) +int fpga_test_hls_dft(struct fpga *f) { - struct ip *hls, *sw, *dma; +#if 0 + struct ip *hls, *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; - +#endif return 0; } -int fpga_test_fifo(struct vfpga *f) +int fpga_test_fifo(struct fpga *f) { int ret; ssize_t len; char src[255], dst[255]; - struct ip *fifo, *sw; - uint32_t ier; + struct ip *fifo; - fifo = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_fifo_mm", NULL); + fifo = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_fifo_mm_s", 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(f->baseaddr.intc + XIN_IER_OFFSET); - XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier | (1 << fifo->irq)); + intc_enable(f->intc, (1 << fifo->irq)); /* Get some random data to compare */ memset(dst, 0, sizeof(dst)); @@ -176,108 +199,106 @@ int fpga_test_fifo(struct vfpga *f) if (ret) error("Failed to get random data"); - ret = switch_connect(&sw->sw, fifo->port, fifo->port); + ret = switch_connect(f->sw, fifo, fifo); if (ret) error("Failed to configure switch"); - len = fifo_write(&fifo->fifo_mm, (char *) src, sizeof(src), f->vd.msi_efds[fifo->irq]); + len = fifo_write(fifo, (char *) src, sizeof(src)); if (len != sizeof(src)) error("Failed to send to FIFO"); - len = fifo_read(&fifo->fifo_mm, (char *) dst, sizeof(dst), f->vd.msi_efds[fifo->irq]); + len = fifo_read(fifo, (char *) dst, sizeof(dst)); if (len != sizeof(dst)) error("Failed to read from FIFO"); - /* Restore IER */ - XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier); + intc_disable(f->intc, (1 << fifo->irq)); /* Compare data */ return memcmp(src, dst, sizeof(src)); } -int fpga_test_dma(struct vfpga *f) +int fpga_test_dma(struct fpga *f) { - struct ip *dma, *sw; - ssize_t len; + struct ip *bram; + ssize_t len = 0x100; int ret; - uint32_t ier; - - dma = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_dma", NULL); - if (!dma) - return -1; - - 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"); - -#ifdef HAS_DMA_SG - /* Memory for buffer descriptors and RX */ - struct dma_mem bd = { - .base_virt = (uintptr_t) f->map + BASEADDR_BRAM, - .base_phys = BASEADDR_BRAM, - .len = 8 * 1024 - }; - - struct dma_mem rx = { - .base_virt = (uintptr_t) f->dma + TEST_LEN, - .base_phys = BASEADDR_HOST + TEST_LEN, - .len = TEST_LEN - }; -#endif /* Get some random data to compare */ char *src = (char *) f->dma; - char *dst = (char *) f->dma + TEST_LEN; + char *dst = (char *) f->dma + len; - ret = read_random(src, TEST_LEN); + ret = read_random(src, 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[irq_mm2s]); - if (len != TEST_LEN) - error("Failed to send to DMAC: %zd", len); + list_foreach(struct ip *dma, &f->ips) { INDENT + if (!ip_vlnv_match(dma, "xilinx.com", "ip", "axi_dma", NULL)) + continue; /* skip non DMA IP cores */ - 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(&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 + int irq_mm2s = dma->irq; + int irq_s2mm = dma->irq + 1; + + intc_enable(f->intc, (1 << irq_mm2s) | (1 << irq_s2mm)); - /* Restore IER */ - XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier); + ret = switch_connect(f->sw, dma, dma); + if (ret) + error("Failed to configure switch"); + + if (dma->dma.HasSg) { + /* Init BD rings */ + bram = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_bram_ctrl", NULL); + if (!bram) + return -3; - /* Check received data */ - return memcmp(src, dst, TEST_LEN); + /* Memory for buffer descriptors */ + struct dma_mem bd = { + .base_virt = (uintptr_t) f->map + bram->baseaddr, + .base_phys = bram->baseaddr, + .len = bram->bram.size + }; + + ret = dma_init_rings(dma, &bd); + if (ret) + return -4; + } + + /* Start transfer */ + ret = dma_read(dma, dst, len); + if (ret) + error("Failed to start DMA read: %d", ret); + + ret = dma_write(dma, src, len); + if (ret) + error("Failed to start DMA write: %d", ret); + + ret = dma_read_complete(dma, NULL, NULL); + if (ret) + error("Failed to complete DMA read"); + + ret = dma_write_complete(dma, NULL, NULL); + if (ret) + error("Failed to complete DMA write"); + + ret = memcmp(src, dst, len); + + info("DMA %s (%s): %s", dma->name, dma->dma.HasSg ? "sg" : "simple", ret ? RED("failed") : GRN("passed")); + + intc_disable(f->intc, (1 << irq_mm2s) | (1 << irq_s2mm)); + } + + return ret; } -int fpga_test_timer(struct vfpga *f) +int fpga_test_timer(struct fpga *f) { int ret; struct ip *timer; - uint32_t ier; timer = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_timer", NULL); if (!timer) return -1; - /* Save old IER */ - ier = XIntc_In32(f->baseaddr.intc + XIN_IER_OFFSET); - XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier | (1 << timer->irq)); + intc_enable(f->intc, (1 << timer->irq)); XTmrCtr_SetOptions(&timer->timer, 0, XTC_EXT_COMPARE_OPTION | XTC_DOWN_COUNT_OPTION); XTmrCtr_SetResetValue(&timer->timer, 0, AXI_HZ / 125); @@ -290,7 +311,7 @@ int fpga_test_timer(struct vfpga *f) ret = poll(&pfd, 1, 1000); if (ret == 1) { - uint64_t counter = wait_irq(f->vd.msi_efds[timer->irq]); + uint64_t counter = intc_wait(f, timer->irq); info("Got IRQ: counter = %ju", counter); @@ -300,106 +321,18 @@ int fpga_test_timer(struct vfpga *f) warn("Counter was not 1"); } - /* Restore IER */ - XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier); + intc_disable(f->intc, (1 << timer->irq)); return -1; } -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(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 + 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(&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[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); - double mdl_params[] = { - 1, /**< R2 = 1 Ohm */ - 0.001 /**< C2 = 1000 uF */ - }; - double mdl_inputs[1]; - double mdl_outputs[1]; - - cbmodel_init(&mdl_params, mdl_dt); - - while (1) { - /* Check for overflow */ - ovfl += wait_irq(f->vd.msi_efds[MSI_RTDS_OVF]); - if (tsc % (int) (1.0 / mdl_dt) == 0) - warn("Missed %u timesteps", ovfl); - - break; - - /* Read data from RTDS */ - 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); - - mdl_inputs[0] = data_rx[0]; /* cast to double */ - - /* 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(&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(f->baseaddr.intc + XIN_IER_OFFSET, ier); -#endif - return 0; -} - -int fpga_test_rtds_rtt(struct vfpga *f) +int fpga_test_rtds_rtt(struct fpga *f) { #if 0 uint32_t tsc = 0; ssize_t len; - uint32_t ier; - /* Save old IER */ - 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)); + intc_enable(f->intc, (1 << MSI_DMA_MM2S) | (1 << MSI_DMA_S2MM)); /* Dump RTDS AXI Stream state */ rtds_axis_dump(f->map + BASEADDR_RTDS); @@ -408,18 +341,9 @@ int fpga_test_rtds_rtt(struct vfpga *f) uint32_t *data_rx = (uint32_t *) (f->dma); uint32_t *data_tx = (uint32_t *) (f->dma + 0x1000); - int switch_port; -#if DATAMOVER == RTDS_DM_FIFO - switch_port = AXIS_SWITCH_FIFO_MM; -#elif DATAMOVER == RTDS_DM_DMA_SIMPLE - switch_port = AXIS_SWITCH_DMA_SIMPLE; -#elif DATAMOVER == RTDS_DM_DMA_SG - switch_port = AXIS_SWITCH_DMA_SG; -#endif - /* Setup crossbar switch */ - switch_connect(&f->sw, AXIS_SWITCH_RTDS, switch_port); - switch_connect(&f->sw, switch_port, AXIS_SWITCH_RTDS); + switch_connect(sw, AXIS_SWITCH_RTDS, switch_port); + switch_connect(sw, switch_port, AXIS_SWITCH_RTDS); /* Disable blocking Overflow status */ int flags = fcntl(f->vd.msi_efds[MSI_RTDS_OVF], F_GETFL, 0); @@ -430,13 +354,13 @@ int fpga_test_rtds_rtt(struct vfpga *f) while (1) { #if 0 /* Wait for TS */ - tsc += wait_irq(f->vd.msi_efds[MSI_RTDS_TS]); + tsc += intc_wait(f->intc, MSI_RTDS_TS); #else tsc++; #endif #if 0 /* Check for overflow */ - ovfl += wait_irq(f->vd.msi_efds[MSI_RTDS_OVF]); + ovfl += intc_wait(f->intc, MSI_RTDS_OVF); if (tsc % 20000 == 0) warn("Missed %u timesteps", ovfl); #endif @@ -481,8 +405,7 @@ retry: len = fifo_read(&f->fifo, (char *) data_rx, 0x1000, irq_fifo); #endif } - /* Restore IER */ - XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier); + intc_disable(f->intc, (1 << MSI_DMA_MM2S) | (1 << MSI_DMA_S2MM)); #endif return 0; }