mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-09 00:00:00 +01:00
lib: remove old and unused C files
This commit is contained in:
parent
f025f5dcc7
commit
4f6694420f
18 changed files with 0 additions and 2607 deletions
|
@ -1,103 +0,0 @@
|
|||
/** FPGA card
|
||||
*
|
||||
* This class represents a FPGA device.
|
||||
*
|
||||
* @file
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASfpga
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
/** @addtogroup fpga VILLASfpga
|
||||
* @{
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <jansson.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "kernel/pci.h"
|
||||
#include "kernel/vfio.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Forward declarations */
|
||||
struct fpga_ip;
|
||||
struct vfio_container;
|
||||
|
||||
struct fpga_card {
|
||||
char *name; /**< The name of the FPGA card */
|
||||
|
||||
enum state state; /**< The state of this FPGA card. */
|
||||
|
||||
struct pci *pci;
|
||||
struct pci_device filter; /**< Filter for PCI device. */
|
||||
|
||||
struct vfio_container *vfio_container;
|
||||
struct vfio_device vfio_device; /**< VFIO device handle. */
|
||||
|
||||
int do_reset; /**< Reset VILLASfpga during startup? */
|
||||
int affinity; /**< Affinity for MSI interrupts */
|
||||
|
||||
struct list ips; /**< List of IP components on FPGA. */
|
||||
|
||||
char *map; /**< PCI BAR0 mapping for register access */
|
||||
|
||||
size_t maplen;
|
||||
size_t dmalen;
|
||||
|
||||
/* Some IP cores are special and referenced here */
|
||||
struct fpga_ip *intc;
|
||||
struct fpga_ip *reset;
|
||||
struct fpga_ip *sw;
|
||||
};
|
||||
|
||||
/** Initialize FPGA card and its IP components. */
|
||||
int fpga_card_init(struct fpga_card *c, struct pci *pci, struct vfio_container *vc);
|
||||
|
||||
/** Parse configuration of FPGA card including IP cores from config. */
|
||||
int fpga_card_parse(struct fpga_card *c, json_t *cfg, const char *name);
|
||||
|
||||
int fpga_card_parse_list(struct list *l, json_t *cfg);
|
||||
|
||||
/** Check if the FPGA card configuration is plausible. */
|
||||
int fpga_card_check(struct fpga_card *c);
|
||||
|
||||
/** Start FPGA card. */
|
||||
int fpga_card_start(struct fpga_card *c);
|
||||
|
||||
/** Stop FPGA card. */
|
||||
int fpga_card_stop(struct fpga_card *c);
|
||||
|
||||
/** Destroy FPGA card. */
|
||||
int fpga_card_destroy(struct fpga_card *c);
|
||||
|
||||
/** Dump details of FPGA card to stdout. */
|
||||
void fpga_card_dump(struct fpga_card *c);
|
||||
|
||||
/** Reset the FPGA to a known state */
|
||||
int fpga_card_reset(struct fpga_card *c);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} */
|
|
@ -1,126 +0,0 @@
|
|||
/** Interlectual Property component.
|
||||
*
|
||||
* This class represents a module within the FPGA.
|
||||
*
|
||||
* @file
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASfpga
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
/** @addtogroup fpga VILLASfpga
|
||||
* @{
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "fpga/vlnv.h"
|
||||
|
||||
#include "fpga/ips/dma.h"
|
||||
#include "fpga/ips/switch.h"
|
||||
#include "fpga/ips/fifo.h"
|
||||
#include "fpga/ips/rtds_axis.h"
|
||||
#include "fpga/ips/timer.h"
|
||||
#include "fpga/ips/model.h"
|
||||
#include "fpga/ips/dft.h"
|
||||
#include "fpga/ips/intc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum fpga_ip_types {
|
||||
FPGA_IP_TYPE_DM_DMA, /**< A datamover IP exchanges streaming data between the FPGA and the CPU. */
|
||||
FPGA_IP_TYPE_DM_FIFO, /**< A datamover IP exchanges streaming data between the FPGA and the CPU. */
|
||||
FPGA_IP_TYPE_MODEL, /**< A model IP simulates a system on the FPGA. */
|
||||
FPGA_IP_TYPE_MATH, /**< A math IP performs some kind of mathematical operation on the streaming data */
|
||||
FPGA_IP_TYPE_MISC, /**< Other IP components like timer, counters, interrupt conctrollers or routing. */
|
||||
FPGA_IP_TYPE_INTERFACE /**< A interface IP connects the FPGA to another system or controller. */
|
||||
};
|
||||
|
||||
struct fpga_ip_type {
|
||||
struct fpga_vlnv vlnv;
|
||||
|
||||
enum fpga_ip_types type;
|
||||
|
||||
int (*init)(struct fpga_ip *c);
|
||||
int (*parse)(struct fpga_ip *c, json_t *cfg);
|
||||
int (*check)(struct fpga_ip *c);
|
||||
int (*start)(struct fpga_ip *c);
|
||||
int (*stop)(struct fpga_ip *c);
|
||||
int (*destroy)(struct fpga_ip *c);
|
||||
int (*reset)(struct fpga_ip *c);
|
||||
void (*dump)(struct fpga_ip *c);
|
||||
|
||||
size_t size; /**< Amount of memory which should be reserved for struct fpga_ip::_vd */
|
||||
};
|
||||
|
||||
struct fpga_ip {
|
||||
char *name; /**< Name of the FPGA IP component. */
|
||||
struct fpga_vlnv vlnv; /**< The Vendor, Library, Name, Version tag of the FPGA IP component. */
|
||||
|
||||
enum state state; /**< The current state of the FPGA IP component. */
|
||||
|
||||
struct fpga_ip_type *_vt; /**< Vtable containing FPGA IP type function pointers. */
|
||||
void *_vd; /**< Virtual data (used by struct fpga_ip::_vt functions) */
|
||||
|
||||
uintptr_t baseaddr; /**< The baseadress of this FPGA IP component */
|
||||
uintptr_t baseaddr_axi4; /**< Used by AXI4 FIFO DM */
|
||||
|
||||
int port; /**< The port of the AXI4-Stream switch to which this FPGA IP component is connected. */
|
||||
int irq; /**< The interrupt number of the FPGA IP component. */
|
||||
|
||||
struct fpga_card *card; /**< The FPGA to which this IP instance belongs to. */
|
||||
};
|
||||
|
||||
/** Initialize IP core. */
|
||||
int fpga_ip_init(struct fpga_ip *c, struct fpga_ip_type *vt);
|
||||
|
||||
/** Parse IP core configuration from configuration file */
|
||||
int fpga_ip_parse(struct fpga_ip *c, json_t *cfg, const char *name);
|
||||
|
||||
/** Check configuration of IP core. */
|
||||
int fpga_ip_check(struct fpga_ip *c);
|
||||
|
||||
/** Start IP core. */
|
||||
int fpga_ip_start(struct fpga_ip *c);
|
||||
|
||||
/** Stop IP core. */
|
||||
int fpga_ip_stop(struct fpga_ip *c);
|
||||
|
||||
/** Release dynamic memory allocated by this IP core. */
|
||||
int fpga_ip_destroy(struct fpga_ip *c);
|
||||
|
||||
/** Dump details about this IP core to stdout. */
|
||||
void fpga_ip_dump(struct fpga_ip *c);
|
||||
|
||||
/** Reset IP component to its initial state. */
|
||||
int fpga_ip_reset(struct fpga_ip *c);
|
||||
|
||||
/** Find a registered FPGA IP core type with the given VLNV identifier. */
|
||||
struct fpga_ip_type * fpga_ip_type_lookup(const char *vstr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} */
|
|
@ -1,88 +0,0 @@
|
|||
/** DMA related helper functions.
|
||||
*
|
||||
* These functions present a simpler interface to Xilinx' DMA driver (XAxiDma_*).
|
||||
*
|
||||
* @file
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Steffen Vogel
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASfpga
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
/** @addtogroup fpga VILLASfpga
|
||||
* @{
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <xilinx/xaxidma.h>
|
||||
|
||||
/* Forward declarations */
|
||||
struct fpga_ip;
|
||||
|
||||
#define FPGA_DMA_BASEADDR 0x00000000
|
||||
#define FPGA_DMA_BOUNDARY 0x1000
|
||||
#define FPGA_DMA_BD_OFFSET 0xC0000000
|
||||
#define FPGA_DMA_BD_SIZE (32 << 20) // 32 MB
|
||||
|
||||
#define XAXIDMA_SR_SGINCL_MASK 0x00000008
|
||||
|
||||
struct dma_mem {
|
||||
char *base_virt;
|
||||
char *base_phys;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
struct dma {
|
||||
XAxiDma inst;
|
||||
|
||||
struct dma_mem bd;
|
||||
};
|
||||
|
||||
struct ip;
|
||||
|
||||
int dma_mem_split(struct dma_mem *o, struct dma_mem *a, struct dma_mem *b);
|
||||
|
||||
int dma_alloc(struct fpga_ip *c, struct dma_mem *mem, size_t len, int flags);
|
||||
int dma_free(struct fpga_ip *c, struct dma_mem *mem);
|
||||
|
||||
int dma_write(struct fpga_ip *c, char *buf, size_t len);
|
||||
int dma_read(struct fpga_ip *c, char *buf, size_t len);
|
||||
int dma_read_complete(struct fpga_ip *c, char **buf, size_t *len);
|
||||
int dma_write_complete(struct fpga_ip *c, char **buf, size_t *len);
|
||||
|
||||
int dma_sg_write(struct fpga_ip *c, char *buf, size_t len);
|
||||
int dma_sg_read(struct fpga_ip *c, char *buf, size_t len);
|
||||
|
||||
int dma_sg_write_complete(struct fpga_ip *c, char **buf, size_t *len);
|
||||
int dma_sg_read_complete(struct fpga_ip *c, char **buf, size_t *len);
|
||||
|
||||
int dma_simple_read(struct fpga_ip *c, char *buf, size_t len);
|
||||
int dma_simple_write(struct fpga_ip *c, char *buf, size_t len);
|
||||
|
||||
int dma_simple_read_complete(struct fpga_ip *c, char **buf, size_t *len);
|
||||
int dma_simple_write_complete(struct fpga_ip *c, char **buf, size_t *len);
|
||||
|
||||
int dma_ping_pong(struct fpga_ip *c, char *src, char *dst, size_t len);
|
||||
|
||||
int dma_start(struct fpga_ip *c);
|
||||
|
||||
/** @} */
|
|
@ -1,52 +0,0 @@
|
|||
/** FIFO related helper functions
|
||||
*
|
||||
* These functions present a simpler interface to Xilinx' FIFO driver (XLlFifo_*)
|
||||
*
|
||||
* @file
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Steffen Vogel
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASfpga
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
/** @addtogroup fpga VILLASfpga
|
||||
* @{
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <xilinx/xstatus.h>
|
||||
#include <xilinx/xllfifo.h>
|
||||
|
||||
struct fifo {
|
||||
XLlFifo inst;
|
||||
|
||||
uint32_t baseaddr_axi4;
|
||||
};
|
||||
|
||||
/* Forward declarations */
|
||||
struct ip;
|
||||
|
||||
int fifo_start(struct fpga_ip *c);
|
||||
|
||||
ssize_t fifo_write(struct fpga_ip *c, char *buf, size_t len);
|
||||
|
||||
ssize_t fifo_read(struct fpga_ip *c, char *buf, size_t len);
|
||||
|
||||
/** @} */
|
|
@ -1,56 +0,0 @@
|
|||
/** AXI-PCIe Interrupt controller
|
||||
*
|
||||
* @file
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Steffen Vogel
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASfpga
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
/** @addtogroup fpga VILLASfpga
|
||||
* @{
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <xilinx/xintc.h>
|
||||
|
||||
enum intc_flags {
|
||||
INTC_ENABLED = (1 << 0),
|
||||
INTC_POLLING = (1 << 1)
|
||||
};
|
||||
|
||||
struct intc {
|
||||
int num_irqs; /**< Number of available MSI vectors */
|
||||
|
||||
int efds[32]; /**< Event FDs */
|
||||
int nos[32]; /**< Interrupt numbers from /proc/interrupts */
|
||||
|
||||
int flags[32]; /**< Mask of intc_flags */
|
||||
};
|
||||
|
||||
int intc_init(struct fpga_ip *c);
|
||||
|
||||
int intc_destroy(struct fpga_ip *c);
|
||||
|
||||
int intc_enable(struct fpga_ip *c, uint32_t mask, int poll);
|
||||
|
||||
int intc_disable(struct fpga_ip *c, uint32_t mask);
|
||||
|
||||
uint64_t intc_wait(struct fpga_ip *c, int irq);
|
||||
|
||||
/** @} */
|
|
@ -1,67 +0,0 @@
|
|||
/** AXI Stream interconnect related helper functions
|
||||
*
|
||||
* These functions present a simpler interface to Xilinx' AXI Stream switch driver (XAxis_Switch_*)
|
||||
*
|
||||
* @file
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Steffen Vogel
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASfpga
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
/** @addtogroup fpga VILLASfpga
|
||||
* @{
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <jansson.h>
|
||||
#include <xilinx/xaxis_switch.h>
|
||||
|
||||
#include "list.h"
|
||||
|
||||
/* Forward declarations */
|
||||
struct ip;
|
||||
|
||||
struct sw_path {
|
||||
const char *in;
|
||||
const char *out;
|
||||
};
|
||||
|
||||
struct sw {
|
||||
XAxis_Switch inst;
|
||||
|
||||
int num_ports;
|
||||
struct list paths;
|
||||
};
|
||||
|
||||
struct ip;
|
||||
|
||||
int switch_start(struct fpga_ip *c);
|
||||
|
||||
/** Initialize paths which have been parsed by switch_parse() */
|
||||
int switch_init_paths(struct fpga_ip *c);
|
||||
|
||||
int switch_destroy(struct fpga_ip *c);
|
||||
|
||||
int switch_parse(struct fpga_ip *c, json_t *cfg);
|
||||
|
||||
int switch_connect(struct fpga_ip *c, struct fpga_ip *mi, struct fpga_ip *si);
|
||||
|
||||
int switch_disconnect(struct fpga_ip *c, struct fpga_ip *mi, struct fpga_ip *si);
|
||||
|
||||
/** @} */
|
|
@ -1,43 +0,0 @@
|
|||
/** Timer related helper functions
|
||||
*
|
||||
* These functions present a simpler interface to Xilinx' Timer Counter driver (XTmrCtr_*)
|
||||
*
|
||||
* @file
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Steffen Vogel
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASfpga
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
/** @addtogroup fpga VILLASfpga
|
||||
* @{
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <xilinx/xtmrctr.h>
|
||||
|
||||
/* Forward declarations */
|
||||
struct fpga_ip;
|
||||
|
||||
struct timer {
|
||||
XTmrCtr inst;
|
||||
};
|
||||
|
||||
int timer_start(struct fpga_ip *c);
|
||||
|
||||
/** @} */
|
|
@ -1,61 +0,0 @@
|
|||
/** Vendor, Library, Name, Version (VLNV) tag.
|
||||
*
|
||||
* @file
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASfpga
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
/** @addtogroup fpga VILLASfpga
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _FPGA_VLNV_H_
|
||||
#define _FPGA_VLNV_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Forward declarations */
|
||||
struct list;
|
||||
|
||||
struct fpga_vlnv {
|
||||
char *vendor;
|
||||
char *library;
|
||||
char *name;
|
||||
char *version;
|
||||
};
|
||||
|
||||
/** Return the first IP block in list \p l which matches the VLNV */
|
||||
struct fpga_ip * fpga_vlnv_lookup(struct list *l, struct fpga_vlnv *v);
|
||||
|
||||
/** Check if IP block \p c matched VLNV. */
|
||||
int fpga_vlnv_cmp(struct fpga_vlnv *a, struct fpga_vlnv *b);
|
||||
|
||||
/** Tokenizes VLNV \p vlnv and stores it into \p c */
|
||||
int fpga_vlnv_parse(struct fpga_vlnv *c, const char *vlnv);
|
||||
|
||||
/** Release memory allocated by fpga_vlnv_parse(). */
|
||||
int fpga_vlnv_destroy(struct fpga_vlnv *v);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /** _FPGA_VLNV_H_ @} */
|
|
@ -1,82 +0,0 @@
|
|||
/** Loadable / plugin support.
|
||||
*
|
||||
* @file
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASfpga
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "utils.h"
|
||||
#include "fpga/ip.h"
|
||||
|
||||
/** @todo This is ugly as hell and broken on OS X / Clang anyway. */
|
||||
#define REGISTER_PLUGIN(p) \
|
||||
__attribute__((constructor(110))) static void UNIQUE(__ctor)() {\
|
||||
if (plugins.state == STATE_DESTROYED) \
|
||||
list_init(&plugins); \
|
||||
list_push(&plugins, p); \
|
||||
} \
|
||||
__attribute__((destructor(110))) static void UNIQUE(__dtor)() { \
|
||||
if (plugins.state != STATE_DESTROYED) \
|
||||
list_remove(&plugins, p); \
|
||||
}
|
||||
|
||||
extern struct list plugins;
|
||||
|
||||
enum plugin_type {
|
||||
PLUGIN_TYPE_FPGA_IP,
|
||||
};
|
||||
|
||||
struct plugin {
|
||||
const char *name;
|
||||
const char *description;
|
||||
void *handle;
|
||||
char *path;
|
||||
|
||||
enum plugin_type type;
|
||||
|
||||
enum state state;
|
||||
|
||||
int (*load)(struct plugin *p);
|
||||
int (*unload)(struct plugin *p);
|
||||
|
||||
struct fpga_ip_type ip;
|
||||
};
|
||||
|
||||
/** Return a pointer to the plugin structure */
|
||||
#define plugin(vt) ((struct plugin *) ((char *) (vt) - offsetof(struct plugin, api)))
|
||||
|
||||
#define plugin_name(vt) plugin(vt)->name
|
||||
#define plugin_description(vt) plugin(vt)->description
|
||||
|
||||
int plugin_init(struct plugin *p);
|
||||
|
||||
int plugin_destroy(struct plugin *p);
|
||||
|
||||
int plugin_parse(struct plugin *p, json_t *cfg);
|
||||
|
||||
int plugin_load(struct plugin *p);
|
||||
|
||||
int plugin_unload(struct plugin *p);
|
||||
|
||||
void plugin_dump(enum plugin_type type);
|
||||
|
||||
/** Find registered and loaded plugin with given name and type. */
|
||||
struct plugin * plugin_lookup(enum plugin_type type, const char *name);
|
315
fpga/lib/card.c
315
fpga/lib/card.c
|
@ -1,315 +0,0 @@
|
|||
/** FPGA card.
|
||||
*
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASfpga
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "log_config.h"
|
||||
#include "list.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "kernel/pci.h"
|
||||
#include "kernel/vfio.h"
|
||||
|
||||
#include "fpga/ip.h"
|
||||
#include "fpga/card.h"
|
||||
|
||||
int fpga_card_init(struct fpga_card *c, struct pci *pci, struct vfio_container *vc)
|
||||
{
|
||||
assert(c->state == STATE_DESTROYED);
|
||||
|
||||
c->vfio_container = vc;
|
||||
c->pci = pci;
|
||||
|
||||
list_init(&c->ips);
|
||||
|
||||
/* Default values */
|
||||
c->filter.id.vendor = FPGA_PCI_VID_XILINX;
|
||||
c->filter.id.device = FPGA_PCI_PID_VFPGA;
|
||||
|
||||
c->affinity = 0;
|
||||
c->do_reset = 0;
|
||||
|
||||
c->state = STATE_INITIALIZED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fpga_card_parse(struct fpga_card *c, json_t *cfg, const char *name)
|
||||
{
|
||||
int ret;
|
||||
|
||||
json_t *json_ips;
|
||||
json_t *json_slot = NULL;
|
||||
json_t *json_id = NULL;
|
||||
json_error_t err;
|
||||
|
||||
c->name = strdup(name);
|
||||
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: i, s?: b, s?: o, s?: o, s: o }",
|
||||
"affinity", &c->affinity,
|
||||
"do_reset", &c->do_reset,
|
||||
"slot", &json_slot,
|
||||
"id", &json_id,
|
||||
"ips", &json_ips
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse FPGA vard configuration");
|
||||
|
||||
if (json_slot) {
|
||||
const char *err, *slot;
|
||||
|
||||
slot = json_string_value(json_slot);
|
||||
if (slot) {
|
||||
ret = pci_device_parse_slot(&c->filter, slot, &err);
|
||||
if (ret)
|
||||
error("Failed to parse PCI slot: %s", err);
|
||||
}
|
||||
else
|
||||
error("PCI slot must be a string");
|
||||
}
|
||||
|
||||
if (json_id) {
|
||||
const char *err, *id;
|
||||
|
||||
id = json_string_value(json_id);
|
||||
if (id) {
|
||||
ret = pci_device_parse_id(&c->filter, (char*) id, &err);
|
||||
if (ret)
|
||||
error("Failed to parse PCI id: %s", err);
|
||||
}
|
||||
else
|
||||
error("PCI ID must be a string");
|
||||
}
|
||||
|
||||
if (!json_is_object(json_ips))
|
||||
error("FPGA card IPs section must be an object");
|
||||
|
||||
const char *name_ip;
|
||||
json_t *json_ip;
|
||||
json_object_foreach(json_ips, name_ip, json_ip) {
|
||||
const char *vlnv;
|
||||
|
||||
struct fpga_ip_type *vt;
|
||||
struct fpga_ip *ip = (struct fpga_ip *) alloc(sizeof(struct fpga_ip));
|
||||
|
||||
ip->card = c;
|
||||
|
||||
ret = json_unpack_ex(json_ip, &err, 0, "{ s: s }", "vlnv", &vlnv);
|
||||
if (ret)
|
||||
error("Failed to parse FPGA IP '%s' of card '%s'", name_ip, name);
|
||||
|
||||
vt = fpga_ip_type_lookup(vlnv);
|
||||
if (!vt)
|
||||
error("FPGA IP core VLNV identifier '%s' is invalid", vlnv);
|
||||
|
||||
ret = fpga_ip_init(ip, vt);
|
||||
if (ret)
|
||||
error("Failed to initalize FPGA IP core");
|
||||
|
||||
ret = fpga_ip_parse(ip, json_ip, name_ip);
|
||||
if (ret)
|
||||
error("Failed to parse FPGA IP core");
|
||||
|
||||
list_push(&c->ips, ip);
|
||||
}
|
||||
|
||||
c->state = STATE_PARSED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fpga_card_parse_list(struct list *cards, json_t *cfg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!json_is_object(cfg))
|
||||
error("FPGA card configuration section must be a JSON object");
|
||||
|
||||
const char *name;
|
||||
json_t *json_fpga;
|
||||
json_object_foreach(cfg, name, json_fpga) {
|
||||
struct fpga_card *c = (struct fpga_card *) alloc(sizeof(struct fpga_card));
|
||||
|
||||
ret = fpga_card_parse(c, json_fpga, name);
|
||||
if (ret)
|
||||
error("Failed to parse FPGA card configuration");
|
||||
|
||||
list_push(cards, c);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fpga_card_start(struct fpga_card *c)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct pci_device *pdev;
|
||||
|
||||
assert(c->state == STATE_INITIALIZED);
|
||||
|
||||
/* Search for FPGA card */
|
||||
pdev = pci_lookup_device(c->pci, &c->filter);
|
||||
if (!pdev)
|
||||
error("Failed to find PCI device");
|
||||
|
||||
/* Attach PCIe card to VFIO container */
|
||||
ret = vfio_pci_attach(&c->vfio_device, c->vfio_container, pdev);
|
||||
if (ret)
|
||||
error("Failed to attach VFIO device");
|
||||
|
||||
/* Map PCIe BAR */
|
||||
c->map = vfio_map_region(&c->vfio_device, VFIO_PCI_BAR0_REGION_INDEX);
|
||||
if (c->map == MAP_FAILED)
|
||||
serror("Failed to mmap() BAR0");
|
||||
|
||||
/* Enable memory access and PCI bus mastering for DMA */
|
||||
ret = vfio_pci_enable(&c->vfio_device);
|
||||
if (ret)
|
||||
serror("Failed to enable PCI device");
|
||||
|
||||
/* Reset system? */
|
||||
if (c->do_reset) {
|
||||
/* Reset / detect PCI device */
|
||||
ret = vfio_pci_reset(&c->vfio_device);
|
||||
if (ret)
|
||||
serror("Failed to reset PCI device");
|
||||
|
||||
ret = fpga_card_reset(c);
|
||||
if (ret)
|
||||
error("Failed to reset FGPA card");
|
||||
}
|
||||
|
||||
/* Initialize IP cores */
|
||||
for (size_t j = 0; j < list_length(&c->ips); j++) {
|
||||
struct fpga_ip *i = (struct fpga_ip *) list_at(&c->ips, j);
|
||||
|
||||
ret = fpga_ip_start(i);
|
||||
if (ret)
|
||||
error("Failed to initalize FPGA IP core: %s (%u)", i->name, ret);
|
||||
}
|
||||
|
||||
c->state = STATE_STARTED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fpga_card_stop(struct fpga_card *c)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(c->state == STATE_STOPPED);
|
||||
|
||||
for (size_t j = 0; j < list_length(&c->ips); j++) {
|
||||
struct fpga_ip *i = (struct fpga_ip *) list_at(&c->ips, j);
|
||||
|
||||
ret = fpga_ip_stop(i);
|
||||
if (ret)
|
||||
error("Failed to stop FPGA IP core: %s (%u)", i->name, ret);
|
||||
}
|
||||
|
||||
c->state = STATE_STOPPED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fpga_card_dump(struct fpga_card *c)
|
||||
{
|
||||
info("VILLASfpga card:");
|
||||
{ INDENT
|
||||
info("Slot: %04x:%02x:%02x.%d", c->vfio_device.pci_device->slot.domain, c->vfio_device.pci_device->slot.bus, c->vfio_device.pci_device->slot.device, c->vfio_device.pci_device->slot.function);
|
||||
info("Vendor ID: %04x", c->vfio_device.pci_device->id.vendor);
|
||||
info("Device ID: %04x", c->vfio_device.pci_device->id.device);
|
||||
info("Class ID: %04x", c->vfio_device.pci_device->id.class_code);
|
||||
|
||||
info("BAR0 mapped at %p", c->map);
|
||||
|
||||
info("IP blocks:");
|
||||
for (size_t j = 0; j < list_length(&c->ips); j++) { INDENT
|
||||
struct fpga_ip *i = (struct fpga_ip *) list_at(&c->ips, j);
|
||||
|
||||
fpga_ip_dump(i);
|
||||
}
|
||||
}
|
||||
|
||||
vfio_dump(c->vfio_device.group->container);
|
||||
}
|
||||
|
||||
int fpga_card_check(struct fpga_card *c)
|
||||
{
|
||||
assert(c->state == STATE_PARSED);
|
||||
|
||||
/* Check FPGA configuration */
|
||||
c->reset = fpga_vlnv_lookup(&c->ips, &(struct fpga_vlnv) { "xilinx.com", "ip", "axi_gpio", NULL });
|
||||
if (!c->reset)
|
||||
error("FPGA is missing a reset controller");
|
||||
|
||||
c->intc = fpga_vlnv_lookup(&c->ips, &(struct fpga_vlnv) { "acs.eonerc.rwth-aachen.de", "user", "axi_pcie_intc", NULL });
|
||||
if (!c->intc)
|
||||
error("FPGA is missing a interrupt controller");
|
||||
|
||||
c->sw = fpga_vlnv_lookup(&c->ips, &(struct fpga_vlnv) { "xilinx.com", "ip", "axis_interconnect", NULL });
|
||||
if (!c->sw)
|
||||
warn("FPGA is missing an AXI4-Stream switch");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fpga_card_destroy(struct fpga_card *c)
|
||||
{
|
||||
list_destroy(&c->ips, (dtor_cb_t) fpga_ip_destroy, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fpga_card_reset(struct fpga_card *c)
|
||||
{
|
||||
int ret;
|
||||
char state[4096];
|
||||
|
||||
/* Save current state of PCI configuration space */
|
||||
ret = pread(c->vfio_device.fd, state, sizeof(state), (off_t) VFIO_PCI_CONFIG_REGION_INDEX << 40);
|
||||
if (ret != sizeof(state))
|
||||
return -1;
|
||||
|
||||
uint32_t *rst_reg = (uint32_t *) (c->map + c->reset->baseaddr);
|
||||
|
||||
debug(3, "FPGA: reset");
|
||||
rst_reg[0] = 1;
|
||||
|
||||
usleep(100000);
|
||||
|
||||
/* Restore previous state of PCI configuration space */
|
||||
ret = pwrite(c->vfio_device.fd, state, sizeof(state), (off_t) VFIO_PCI_CONFIG_REGION_INDEX << 40);
|
||||
if (ret != sizeof(state))
|
||||
return -1;
|
||||
|
||||
/* After reset the value should be zero again */
|
||||
if (rst_reg[0])
|
||||
return -2;
|
||||
|
||||
c->state = STATE_INITIALIZED;
|
||||
|
||||
return 0;
|
||||
}
|
167
fpga/lib/ip.c
167
fpga/lib/ip.c
|
@ -1,167 +0,0 @@
|
|||
/** FPGA IP component.
|
||||
*
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASfpga
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
#include "log_config.h"
|
||||
#include "log.h"
|
||||
#include "plugin.h"
|
||||
|
||||
int fpga_ip_init(struct fpga_ip *c, struct fpga_ip_type *vt)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(c->state == STATE_DESTROYED);
|
||||
|
||||
c->_vt = vt;
|
||||
c->_vd = alloc(vt->size);
|
||||
|
||||
ret = c->_vt->init ? c->_vt->init(c) : 0;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
c->state = STATE_INITIALIZED;
|
||||
|
||||
debug(8, "IP Core %s initalized (%u)", c->name, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fpga_ip_parse(struct fpga_ip *c, json_t *cfg, const char *name)
|
||||
{
|
||||
int ret, baseaddr = -1;
|
||||
|
||||
assert(c->state != STATE_STARTED && c->state != STATE_DESTROYED);
|
||||
|
||||
c->name = strdup(name);
|
||||
c->baseaddr = -1;
|
||||
c->irq = -1;
|
||||
c->port = -1;
|
||||
|
||||
json_error_t err;
|
||||
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: i, s?: i, s?: i }",
|
||||
"baseaddr", &baseaddr,
|
||||
"irq", &c->irq,
|
||||
"port", &c->port
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration for FPGA IP '%s'", name);
|
||||
|
||||
c->baseaddr = baseaddr;
|
||||
|
||||
/* Type sepecific settings */
|
||||
ret = c->_vt && c->_vt->parse ? c->_vt->parse(c, cfg) : 0;
|
||||
if (ret)
|
||||
error("Failed to parse settings for IP core '%s'", name);
|
||||
|
||||
c->state = STATE_PARSED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fpga_ip_start(struct fpga_ip *c)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(c->state == STATE_CHECKED);
|
||||
|
||||
ret = c->_vt->start ? c->_vt->start(c) : 0;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
c->state = STATE_STARTED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fpga_ip_stop(struct fpga_ip *c)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(c->state == STATE_STARTED);
|
||||
|
||||
ret = c->_vt->stop ? c->_vt->stop(c) : 0;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
c->state = STATE_STOPPED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fpga_ip_destroy(struct fpga_ip *c)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(c->state != STATE_DESTROYED);
|
||||
|
||||
fpga_vlnv_destroy(&c->vlnv);
|
||||
|
||||
ret = c->_vt->destroy ? c->_vt->destroy(c) : 0;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
c->state = STATE_DESTROYED;
|
||||
|
||||
free(c->_vd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fpga_ip_reset(struct fpga_ip *c)
|
||||
{
|
||||
debug(3, "Reset IP core: %s", c->name);
|
||||
|
||||
return c->_vt->reset ? c->_vt->reset(c) : 0;
|
||||
}
|
||||
|
||||
void fpga_ip_dump(struct fpga_ip *c)
|
||||
{
|
||||
assert(c->state != STATE_DESTROYED);
|
||||
|
||||
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 (c->_vt->dump)
|
||||
c->_vt->dump(c);
|
||||
}
|
||||
|
||||
struct fpga_ip_type * fpga_ip_type_lookup(const char *vstr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct fpga_vlnv vlnv;
|
||||
|
||||
ret = fpga_vlnv_parse(&vlnv, vstr);
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
/* Try to find matching IP type */
|
||||
for (size_t i = 0; i < list_length(&plugins); i++) {
|
||||
struct plugin *p = (struct plugin *) list_at(&plugins, i);
|
||||
|
||||
if (p->type == PLUGIN_TYPE_FPGA_IP && !fpga_vlnv_cmp(&vlnv, &p->ip.vlnv))
|
||||
return &p->ip;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
|
@ -1,657 +0,0 @@
|
|||
/** DMA related helper functions
|
||||
*
|
||||
* These functions present a simpler interface to Xilinx' DMA driver (XAxiDma_*)
|
||||
*
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Steffen Vogel
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASfpga
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "plugin.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "fpga/ip.h"
|
||||
#include "fpga/card.h"
|
||||
#include "fpga/ips/dma.h"
|
||||
|
||||
int dma_mem_split(struct dma_mem *o, struct dma_mem *a, struct dma_mem *b)
|
||||
{
|
||||
int split = o->len / 2;
|
||||
|
||||
a->base_virt = o->base_virt;
|
||||
a->base_phys = o->base_phys;
|
||||
|
||||
b->base_virt = a->base_virt + split;
|
||||
b->base_phys = a->base_phys + split;
|
||||
|
||||
a->len = split;
|
||||
b->len = o->len - split;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dma_alloc(struct fpga_ip *c, struct dma_mem *mem, size_t len, int flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct fpga_card *f = c->card;
|
||||
|
||||
/* Align to next bigger page size chunk */
|
||||
if (len & 0xFFF) {
|
||||
len += 0x1000;
|
||||
len &= ~0xFFF;
|
||||
}
|
||||
|
||||
mem->len = len;
|
||||
mem->base_phys = (void *) -1; /* find free */
|
||||
mem->base_virt = mmap(0, mem->len, PROT_READ | PROT_WRITE, flags | MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, 0, 0);
|
||||
if (mem->base_virt == MAP_FAILED)
|
||||
return -1;
|
||||
|
||||
ret = vfio_map_dma(f->vfio_device.group->container, (uint64_t) mem->base_virt, (uint64_t) mem->base_phys, mem->len);
|
||||
if (ret)
|
||||
return -2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dma_free(struct fpga_ip *c, struct dma_mem *mem)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = vfio_unmap_dma(c->card->vfio_device.group->container, (uint64_t) mem->base_virt, (uint64_t) mem->base_phys, mem->len);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = munmap(mem->base_virt, mem->len);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dma_ping_pong(struct fpga_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_write_complete(c, NULL, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = dma_read_complete(c, NULL, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dma_write(struct fpga_ip *c, char *buf, size_t len)
|
||||
{
|
||||
struct dma *dma = (struct dma *) c->_vd;
|
||||
|
||||
XAxiDma *xdma = &dma->inst;
|
||||
|
||||
debug(25, "DMA write: dmac=%s buf=%p len=%#zx", c->name, buf, len);
|
||||
|
||||
return xdma->HasSg
|
||||
? dma_sg_write(c, buf, len)
|
||||
: dma_simple_write(c, buf, len);
|
||||
}
|
||||
|
||||
int dma_read(struct fpga_ip *c, char *buf, size_t len)
|
||||
{
|
||||
struct dma *dma = (struct dma *) c->_vd;
|
||||
|
||||
XAxiDma *xdma = &dma->inst;
|
||||
|
||||
debug(25, "DMA read: dmac=%s buf=%p len=%#zx", c->name, buf, len);
|
||||
|
||||
return xdma->HasSg
|
||||
? dma_sg_read(c, buf, len)
|
||||
: dma_simple_read(c, buf, len);
|
||||
}
|
||||
|
||||
int dma_read_complete(struct fpga_ip *c, char **buf, size_t *len)
|
||||
{
|
||||
struct dma *dma = (struct dma *) c->_vd;
|
||||
|
||||
XAxiDma *xdma = &dma->inst;
|
||||
|
||||
debug(25, "DMA read complete: dmac=%s", c->name);
|
||||
|
||||
return xdma->HasSg
|
||||
? dma_sg_read_complete(c, buf, len)
|
||||
: dma_simple_read_complete(c, buf, len);
|
||||
}
|
||||
|
||||
int dma_write_complete(struct fpga_ip *c, char **buf, size_t *len)
|
||||
{
|
||||
struct dma *dma = (struct dma *) c->_vd;
|
||||
|
||||
XAxiDma *xdma = &dma->inst;
|
||||
|
||||
debug(25, "DMA write complete: dmac=%s", c->name);
|
||||
|
||||
return xdma->HasSg
|
||||
? dma_sg_write_complete(c, buf, len)
|
||||
: dma_simple_write_complete(c, buf, len);
|
||||
}
|
||||
|
||||
int dma_sg_write(struct fpga_ip *c, char *buf, size_t len)
|
||||
{
|
||||
int ret, bdcnt;
|
||||
|
||||
struct dma *dma = (struct dma *) c->_vd;
|
||||
|
||||
XAxiDma *xdma = &dma->inst;
|
||||
XAxiDma_BdRing *ring = XAxiDma_GetTxRing(xdma);
|
||||
XAxiDma_Bd *bds, *bd;
|
||||
|
||||
uint32_t remaining, bdlen, bdbuf, cr;
|
||||
|
||||
/* Checks */
|
||||
if (!xdma->HasSg)
|
||||
return -1;
|
||||
|
||||
if (len < 1)
|
||||
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;
|
||||
}
|
||||
|
||||
bdcnt = CEIL(len, FPGA_DMA_BOUNDARY);
|
||||
ret = XAxiDma_BdRingAlloc(ring, bdcnt, &bds);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -5;
|
||||
|
||||
remaining = len;
|
||||
bdbuf = (uintptr_t) buf;
|
||||
bd = bds;
|
||||
for (int i = 0; i < bdcnt; i++) {
|
||||
bdlen = MIN(remaining, FPGA_DMA_BOUNDARY);
|
||||
|
||||
ret = XAxiDma_BdSetBufAddr(bd, bdbuf);
|
||||
if (ret != XST_SUCCESS)
|
||||
goto out;
|
||||
|
||||
ret = XAxiDma_BdSetLength(bd, bdlen, ring->MaxTransferLen);
|
||||
if (ret != XST_SUCCESS)
|
||||
goto out;
|
||||
|
||||
/* Set SOF / EOF / ID */
|
||||
cr = 0;
|
||||
if (i == 0)
|
||||
cr |= XAXIDMA_BD_CTRL_TXSOF_MASK;
|
||||
if (i == bdcnt - 1)
|
||||
cr |= XAXIDMA_BD_CTRL_TXEOF_MASK;
|
||||
|
||||
XAxiDma_BdSetCtrl(bd, cr);
|
||||
XAxiDma_BdSetId(bd, (uintptr_t) buf);
|
||||
|
||||
remaining -= bdlen;
|
||||
bdbuf += bdlen;
|
||||
bd = (XAxiDma_Bd *) XAxiDma_BdRingNext(ring, bd);
|
||||
}
|
||||
|
||||
/* Give the BD to DMA to kick off the transmission. */
|
||||
ret = XAxiDma_BdRingToHw(ring, bdcnt, bds);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -8;
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
ret = XAxiDma_BdRingUnAlloc(ring, bdcnt, bds);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -6;
|
||||
|
||||
return -5;
|
||||
}
|
||||
|
||||
int dma_sg_read(struct fpga_ip *c, char *buf, size_t len)
|
||||
{
|
||||
int ret, bdcnt;
|
||||
|
||||
struct dma *dma = (struct dma *) c->_vd;
|
||||
|
||||
XAxiDma *xdma = &dma->inst;
|
||||
XAxiDma_BdRing *ring = XAxiDma_GetRxRing(xdma);
|
||||
XAxiDma_Bd *bds, *bd;
|
||||
|
||||
uint32_t remaining, bdlen, bdbuf;
|
||||
|
||||
/* Checks */
|
||||
if (!xdma->HasSg)
|
||||
return -1;
|
||||
|
||||
if (len < 1)
|
||||
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;
|
||||
}
|
||||
|
||||
bdcnt = CEIL(len, FPGA_DMA_BOUNDARY);
|
||||
ret = XAxiDma_BdRingAlloc(ring, bdcnt, &bds);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -5;
|
||||
|
||||
bdbuf = (uintptr_t) buf;
|
||||
remaining = len;
|
||||
bd = bds;
|
||||
for (int i = 0; i < bdcnt; i++) {
|
||||
bdlen = MIN(remaining, FPGA_DMA_BOUNDARY);
|
||||
ret = XAxiDma_BdSetLength(bd, bdlen, ring->MaxTransferLen);
|
||||
if (ret != XST_SUCCESS)
|
||||
goto out;
|
||||
|
||||
ret = XAxiDma_BdSetBufAddr(bd, bdbuf);
|
||||
if (ret != XST_SUCCESS)
|
||||
goto out;
|
||||
|
||||
/* 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);
|
||||
|
||||
remaining -= bdlen;
|
||||
bdbuf += bdlen;
|
||||
bd = (XAxiDma_Bd *) XAxiDma_BdRingNext(ring, bd);
|
||||
}
|
||||
|
||||
ret = XAxiDma_BdRingToHw(ring, bdcnt, bds);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -8;
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
ret = XAxiDma_BdRingUnAlloc(ring, bdcnt, bds);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -6;
|
||||
|
||||
return -5;
|
||||
}
|
||||
|
||||
int dma_sg_write_complete(struct fpga_ip *c, char **buf, size_t *len)
|
||||
{
|
||||
struct dma *dma = (struct dma *) c->_vd;
|
||||
|
||||
XAxiDma *xdma = &dma->inst;
|
||||
XAxiDma_BdRing *ring = XAxiDma_GetTxRing(xdma);
|
||||
XAxiDma_Bd *bds;
|
||||
|
||||
int processed, ret;
|
||||
|
||||
/* Wait until the one BD TX transaction is done */
|
||||
while (!(XAxiDma_IntrGetIrq(xdma, XAXIDMA_DMA_TO_DEVICE) & XAXIDMA_IRQ_IOC_MASK))
|
||||
intc_wait(c->card->intc, c->irq);
|
||||
XAxiDma_IntrAckIrq(xdma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DMA_TO_DEVICE);
|
||||
|
||||
processed = XAxiDma_BdRingFromHw(ring, XAXIDMA_ALL_BDS, &bds);
|
||||
|
||||
if (len != NULL)
|
||||
*len = XAxiDma_BdGetActualLength(bds, XAXIDMA_MAX_TRANSFER_LEN);
|
||||
|
||||
if (buf != NULL)
|
||||
*buf = (char *) (uintptr_t) XAxiDma_BdGetId(bds);
|
||||
|
||||
/* Free all processed TX BDs for future transmission */
|
||||
ret = XAxiDma_BdRingFree(ring, processed, bds);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dma_sg_read_complete(struct fpga_ip *c, char **buf, size_t *len)
|
||||
{
|
||||
struct dma *dma = (struct dma *) c->_vd;
|
||||
|
||||
XAxiDma *xdma = &dma->inst;
|
||||
XAxiDma_BdRing *ring = XAxiDma_GetRxRing(xdma);
|
||||
XAxiDma_Bd *bds, *bd;
|
||||
|
||||
int ret, bdcnt;
|
||||
uint32_t recvlen, sr;
|
||||
uintptr_t recvbuf = 0;
|
||||
|
||||
if (!xdma->HasSg)
|
||||
return -1;
|
||||
|
||||
while (!(XAxiDma_IntrGetIrq(xdma, XAXIDMA_DEVICE_TO_DMA) & XAXIDMA_IRQ_IOC_MASK))
|
||||
intc_wait(c->card->intc, c->irq + 1);
|
||||
XAxiDma_IntrAckIrq(xdma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA);
|
||||
|
||||
bdcnt = XAxiDma_BdRingFromHw(ring, XAXIDMA_ALL_BDS, &bds);
|
||||
|
||||
recvlen = 0;
|
||||
|
||||
bd = bds;
|
||||
for (int i = 0; i < bdcnt; i++) {
|
||||
recvlen += XAxiDma_BdGetActualLength(bd, ring->MaxTransferLen);
|
||||
|
||||
sr = XAxiDma_BdGetSts(bd);
|
||||
if (sr & XAXIDMA_BD_STS_RXSOF_MASK)
|
||||
if (i != 0)
|
||||
warn("sof not first");
|
||||
|
||||
if (sr & XAXIDMA_BD_STS_RXEOF_MASK)
|
||||
if (i != bdcnt - 1)
|
||||
warn("eof not last");
|
||||
|
||||
recvbuf = XAxiDma_BdGetId(bd);
|
||||
|
||||
bd = (XAxiDma_Bd *) XAxiDma_BdRingNext(ring, bd);
|
||||
}
|
||||
|
||||
if (len != NULL)
|
||||
*len = recvlen;
|
||||
if (buf != NULL)
|
||||
*buf = (char *) recvbuf;
|
||||
|
||||
/* Free all processed RX BDs for future transmission */
|
||||
ret = XAxiDma_BdRingFree(ring, bdcnt, bds);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -3;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dma_simple_read(struct fpga_ip *c, char *buf, size_t len)
|
||||
{
|
||||
struct dma *dma = (struct dma *) c->_vd;
|
||||
|
||||
XAxiDma *xdma = &dma->inst;
|
||||
XAxiDma_BdRing *ring = XAxiDma_GetRxRing(xdma);
|
||||
|
||||
/* Checks */
|
||||
if (xdma->HasSg)
|
||||
return -1;
|
||||
|
||||
if ((len < 1) || (len > FPGA_DMA_BOUNDARY))
|
||||
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 fpga_ip *c, char *buf, size_t len)
|
||||
{
|
||||
struct dma *dma = (struct dma *) c->_vd;
|
||||
|
||||
XAxiDma *xdma = &dma->inst;
|
||||
XAxiDma_BdRing *ring = XAxiDma_GetTxRing(xdma);
|
||||
|
||||
/* Checks */
|
||||
if (xdma->HasSg)
|
||||
return -1;
|
||||
|
||||
if ((len < 1) || (len > FPGA_DMA_BOUNDARY))
|
||||
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 fpga_ip *c, char **buf, size_t *len)
|
||||
{
|
||||
struct dma *dma = (struct dma *) c->_vd;
|
||||
|
||||
XAxiDma *xdma = &dma->inst;
|
||||
XAxiDma_BdRing *ring = XAxiDma_GetRxRing(xdma);
|
||||
|
||||
while (!(XAxiDma_IntrGetIrq(xdma, XAXIDMA_DEVICE_TO_DMA) & XAXIDMA_IRQ_IOC_MASK))
|
||||
intc_wait(c->card->intc, c->irq + 1);
|
||||
XAxiDma_IntrAckIrq(xdma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA);
|
||||
|
||||
if (len)
|
||||
*len = XAxiDma_ReadReg(ring->ChanBase, XAXIDMA_BUFFLEN_OFFSET);
|
||||
|
||||
if (buf) {
|
||||
*buf = (char *) (uintptr_t) XAxiDma_ReadReg(ring->ChanBase, XAXIDMA_DESTADDR_OFFSET);
|
||||
if (xdma->AddrWidth > 32)
|
||||
*buf += XAxiDma_ReadReg(ring->ChanBase, XAXIDMA_DESTADDR_MSB_OFFSET);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dma_simple_write_complete(struct fpga_ip *c, char **buf, size_t *len)
|
||||
{
|
||||
struct dma *dma = (struct dma *) c->_vd;
|
||||
|
||||
XAxiDma *xdma = &dma->inst;
|
||||
XAxiDma_BdRing *ring = XAxiDma_GetTxRing(xdma);
|
||||
|
||||
while (!(XAxiDma_IntrGetIrq(xdma, XAXIDMA_DMA_TO_DEVICE) & XAXIDMA_IRQ_IOC_MASK))
|
||||
intc_wait(c->card->intc, c->irq);
|
||||
XAxiDma_IntrAckIrq(xdma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DMA_TO_DEVICE);
|
||||
|
||||
if (len)
|
||||
*len = XAxiDma_ReadReg(ring->ChanBase, XAXIDMA_BUFFLEN_OFFSET);
|
||||
|
||||
if (buf) {
|
||||
*buf = (char *) (uintptr_t) XAxiDma_ReadReg(ring->ChanBase, XAXIDMA_SRCADDR_OFFSET);
|
||||
if (xdma->AddrWidth > 32)
|
||||
*buf += XAxiDma_ReadReg(ring->ChanBase, XAXIDMA_SRCADDR_MSB_OFFSET);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dma_setup_ring(XAxiDma_BdRing *ring, struct dma_mem *bdbuf)
|
||||
{
|
||||
int delay = 0;
|
||||
int coalesce = 1;
|
||||
int ret, cnt;
|
||||
|
||||
XAxiDma_Bd clearbd;
|
||||
|
||||
/* Disable all RX interrupts before RxBD space setup */
|
||||
XAxiDma_BdRingIntDisable(ring, XAXIDMA_IRQ_ALL_MASK);
|
||||
|
||||
/* Set delay and coalescing */
|
||||
XAxiDma_BdRingSetCoalesce(ring, coalesce, delay);
|
||||
|
||||
/* Setup Rx BD space */
|
||||
cnt = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT, bdbuf->len);
|
||||
|
||||
ret = XAxiDma_BdRingCreate(ring, (uintptr_t) bdbuf->base_phys, (uintptr_t) bdbuf->base_virt, XAXIDMA_BD_MINIMUM_ALIGNMENT, cnt);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -1;
|
||||
|
||||
XAxiDma_BdClear(&clearbd);
|
||||
ret = XAxiDma_BdRingClone(ring, &clearbd);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -2;
|
||||
|
||||
/* Start the channel */
|
||||
ret = XAxiDma_BdRingStart(ring);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -3;
|
||||
|
||||
return XST_SUCCESS;
|
||||
}
|
||||
|
||||
static int dma_init_rings(XAxiDma *xdma, struct dma_mem *bd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct dma_mem bd_rx, bd_tx;
|
||||
|
||||
ret = dma_mem_split(bd, &bd_rx, &bd_tx);
|
||||
if (ret)
|
||||
return -1;
|
||||
|
||||
ret = dma_setup_ring(XAxiDma_GetRxRing(xdma), &bd_rx);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -2;
|
||||
|
||||
ret = dma_setup_ring(XAxiDma_GetTxRing(xdma), &bd_tx);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -3;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dma_start(struct fpga_ip *c)
|
||||
{
|
||||
int ret, sg;
|
||||
struct dma *dma = (struct dma *) c->_vd;
|
||||
|
||||
XAxiDma *xdma = &dma->inst;
|
||||
|
||||
/* 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) c->card->map + c->baseaddr,
|
||||
.HasStsCntrlStrm = 0,
|
||||
.HasMm2S = 1,
|
||||
.HasMm2SDRE = 1,
|
||||
.Mm2SDataWidth = 128,
|
||||
.HasS2Mm = 1,
|
||||
.HasS2MmDRE = 1, /* Data Realignment Engine */
|
||||
.HasSg = sg,
|
||||
.S2MmDataWidth = 128,
|
||||
.Mm2sNumChannels = 1,
|
||||
.S2MmNumChannels = 1,
|
||||
.Mm2SBurstSize = 64,
|
||||
.S2MmBurstSize = 64,
|
||||
.MicroDmaMode = 0,
|
||||
.AddrWidth = 32
|
||||
};
|
||||
|
||||
ret = XAxiDma_CfgInitialize(xdma, &xdma_cfg);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -1;
|
||||
|
||||
/* Perform selftest */
|
||||
ret = XAxiDma_Selftest(xdma);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -2;
|
||||
|
||||
/* Map buffer descriptors */
|
||||
if (xdma->HasSg) {
|
||||
ret = dma_alloc(c, &dma->bd, FPGA_DMA_BD_SIZE, 0);
|
||||
if (ret)
|
||||
return -3;
|
||||
|
||||
ret = dma_init_rings(xdma, &dma->bd);
|
||||
if (ret)
|
||||
return -4;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dma_reset(struct fpga_ip *c)
|
||||
{
|
||||
struct dma *dma = (struct dma *) c->_vd;
|
||||
|
||||
XAxiDma_Reset(&dma->inst);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct plugin p = {
|
||||
.name = "Xilinx's AXI4 Direct Memory Access Controller",
|
||||
.description = "Transfer data streams between VILLASnode and VILLASfpga",
|
||||
.type = PLUGIN_TYPE_FPGA_IP,
|
||||
.ip = {
|
||||
.vlnv = { "xilinx.com", "ip", "axi_dma", NULL },
|
||||
.type = FPGA_IP_TYPE_DM_DMA,
|
||||
.init = dma_start,
|
||||
.reset = dma_reset,
|
||||
.size = sizeof(struct dma)
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_PLUGIN(&p)
|
|
@ -1,153 +0,0 @@
|
|||
/** FIFO related helper functions
|
||||
*
|
||||
* These functions present a simpler interface to Xilinx' FIFO driver (XLlFifo_*)
|
||||
*
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Steffen Vogel
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASfpga
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "plugin.h"
|
||||
|
||||
#include "fpga/ip.h"
|
||||
#include "fpga/card.h"
|
||||
#include "fpga/ips/fifo.h"
|
||||
#include "fpga/ips/intc.h"
|
||||
|
||||
int fifo_start(struct fpga_ip *c)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct fpga_card *f = c->card;
|
||||
struct fifo *fifo = (struct fifo *) c->_vd;
|
||||
|
||||
XLlFifo *xfifo = &fifo->inst;
|
||||
XLlFifo_Config fifo_cfg = {
|
||||
.BaseAddress = (uintptr_t) f->map + c->baseaddr,
|
||||
.Axi4BaseAddress = (uintptr_t) c->card->map + fifo->baseaddr_axi4,
|
||||
.Datainterface = (fifo->baseaddr_axi4 != -1) ? 1 : 0 /* use AXI4 for Data, AXI4-Lite for control */
|
||||
};
|
||||
|
||||
ret = XLlFifo_CfgInitialize(xfifo, &fifo_cfg, (uintptr_t) c->card->map + c->baseaddr);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -1;
|
||||
|
||||
XLlFifo_IntEnable(xfifo, XLLF_INT_RC_MASK); /* Receive complete IRQ */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fifo_stop(struct fpga_ip *c)
|
||||
{
|
||||
struct fifo *fifo = (struct fifo *) c->_vd;
|
||||
|
||||
XLlFifo *xfifo = &fifo->inst;
|
||||
|
||||
XLlFifo_IntDisable(xfifo, XLLF_INT_RC_MASK); /* Receive complete IRQ */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t fifo_write(struct fpga_ip *c, char *buf, size_t len)
|
||||
{
|
||||
struct fifo *fifo = (struct fifo *) c->_vd;
|
||||
|
||||
XLlFifo *xllfifo = &fifo->inst;
|
||||
|
||||
uint32_t tdfv;
|
||||
|
||||
tdfv = XLlFifo_TxVacancy(xllfifo);
|
||||
if (tdfv < len)
|
||||
return -1;
|
||||
|
||||
XLlFifo_Write(xllfifo, buf, len);
|
||||
XLlFifo_TxSetLen(xllfifo, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
ssize_t fifo_read(struct fpga_ip *c, char *buf, size_t len)
|
||||
{
|
||||
struct fifo *fifo = (struct fifo *) c->_vd;
|
||||
|
||||
XLlFifo *xllfifo = &fifo->inst;
|
||||
|
||||
size_t nextlen = 0;
|
||||
uint32_t rxlen;
|
||||
|
||||
while (!XLlFifo_IsRxDone(xllfifo))
|
||||
intc_wait(c->card->intc, c->irq);
|
||||
XLlFifo_IntClear(xllfifo, XLLF_INT_RC_MASK);
|
||||
|
||||
/* Get length of next frame */
|
||||
rxlen = XLlFifo_RxGetLen(xllfifo);
|
||||
nextlen = MIN(rxlen, len);
|
||||
|
||||
/* Read from FIFO */
|
||||
XLlFifo_Read(xllfifo, buf, nextlen);
|
||||
|
||||
return nextlen;
|
||||
}
|
||||
|
||||
int fifo_parse(struct fpga_ip *c, json_t *cfg)
|
||||
{
|
||||
struct fifo *fifo = (struct fifo *) c->_vd;
|
||||
|
||||
int baseaddr_axi4 = -1, ret;
|
||||
|
||||
json_error_t err;
|
||||
|
||||
fifo->baseaddr_axi4 = -1;
|
||||
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: i }", "baseaddr_axi4", &baseaddr_axi4);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of FPGA IP '%s'", c->name);
|
||||
|
||||
fifo->baseaddr_axi4 = baseaddr_axi4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fifo_reset(struct fpga_ip *c)
|
||||
{
|
||||
struct fifo *fifo = (struct fifo *) c->_vd;
|
||||
|
||||
XLlFifo_Reset(&fifo->inst);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct plugin p = {
|
||||
.name = "Xilinx's AXI4 FIFO data mover",
|
||||
.description = "",
|
||||
.type = PLUGIN_TYPE_FPGA_IP,
|
||||
.ip = {
|
||||
.vlnv = { "xilinx.com", "ip", "axi_fifo_mm_s", NULL },
|
||||
.type = FPGA_IP_TYPE_DM_FIFO,
|
||||
.start = fifo_start,
|
||||
.stop = fifo_stop,
|
||||
.parse = fifo_parse,
|
||||
.reset = fifo_reset,
|
||||
.size = sizeof(struct fifo)
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_PLUGIN(&p)
|
|
@ -1,180 +0,0 @@
|
|||
/** AXI-PCIe Interrupt controller
|
||||
*
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Steffen Vogel
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASfpga
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "plugin.h"
|
||||
|
||||
#include "kernel/vfio.h"
|
||||
#include "kernel/kernel.h"
|
||||
|
||||
#include "fpga/ip.h"
|
||||
#include "fpga/card.h"
|
||||
#include "fpga/ips/intc.h"
|
||||
|
||||
int intc_start(struct fpga_ip *c)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct fpga_card *f = c->card;
|
||||
struct intc *intc = (struct intc *) c->_vd;
|
||||
|
||||
uintptr_t base = (uintptr_t) f->map + c->baseaddr;
|
||||
|
||||
if (c != f->intc)
|
||||
error("There can be only one interrupt controller per FPGA");
|
||||
|
||||
intc->num_irqs = vfio_pci_msi_init(&f->vfio_device, intc->efds);
|
||||
if (intc->num_irqs < 0)
|
||||
return -1;
|
||||
|
||||
ret = vfio_pci_msi_find(&f->vfio_device, intc->nos);
|
||||
if (ret)
|
||||
return -2;
|
||||
|
||||
/* For each IRQ */
|
||||
for (int i = 0; i < intc->num_irqs; i++) {
|
||||
/* Pin to core */
|
||||
ret = kernel_irq_setaffinity(intc->nos[i], f->affinity, NULL);
|
||||
if (ret)
|
||||
serror("Failed to change affinity of VFIO-MSI interrupt");
|
||||
|
||||
/* Setup vector */
|
||||
XIntc_Out32(base + XIN_IVAR_OFFSET + i * 4, 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);
|
||||
|
||||
debug(4, "FPGA: enabled interrupts");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int intc_destroy(struct fpga_ip *c)
|
||||
{
|
||||
struct fpga_card *f = c->card;
|
||||
struct intc *intc = (struct intc *) c->_vd;
|
||||
|
||||
vfio_pci_msi_deinit(&f->vfio_device, intc->efds);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int intc_enable(struct fpga_ip *c, uint32_t mask, int flags)
|
||||
{
|
||||
struct fpga_card *f = c->card;
|
||||
struct intc *intc = (struct intc *) c->_vd;
|
||||
|
||||
uint32_t ier, imr;
|
||||
uintptr_t base = (uintptr_t) f->map + c->baseaddr;
|
||||
|
||||
/* Current state of INTC */
|
||||
ier = XIntc_In32(base + XIN_IER_OFFSET);
|
||||
imr = XIntc_In32(base + XIN_IMR_OFFSET);
|
||||
|
||||
/* Clear pending IRQs */
|
||||
XIntc_Out32(base + XIN_IAR_OFFSET, mask);
|
||||
|
||||
for (int i = 0; i < intc->num_irqs; i++) {
|
||||
if (mask & (1 << i))
|
||||
intc->flags[i] = flags;
|
||||
}
|
||||
|
||||
if (flags & INTC_POLLING) {
|
||||
XIntc_Out32(base + XIN_IMR_OFFSET, imr & ~mask);
|
||||
XIntc_Out32(base + XIN_IER_OFFSET, ier & ~mask);
|
||||
}
|
||||
else {
|
||||
XIntc_Out32(base + XIN_IER_OFFSET, ier | mask);
|
||||
XIntc_Out32(base + XIN_IMR_OFFSET, imr | mask);
|
||||
}
|
||||
|
||||
debug(3, "New ier = %#x", XIntc_In32(base + XIN_IER_OFFSET));
|
||||
debug(3, "New imr = %#x", XIntc_In32(base + XIN_IMR_OFFSET));
|
||||
debug(3, "New isr = %#x", XIntc_In32(base + XIN_ISR_OFFSET));
|
||||
|
||||
debug(8, "FPGA: Interupt enabled: mask=%#x flags=%#x", mask, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int intc_disable(struct fpga_ip *c, uint32_t mask)
|
||||
{
|
||||
struct fpga_card *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 0;
|
||||
}
|
||||
|
||||
uint64_t intc_wait(struct fpga_ip *c, int irq)
|
||||
{
|
||||
struct fpga_card *f = c->card;
|
||||
struct intc *intc = (struct intc *) c->_vd;
|
||||
|
||||
uintptr_t base = (uintptr_t) f->map + c->baseaddr;
|
||||
|
||||
if (intc->flags[irq] & INTC_POLLING) {
|
||||
uint32_t isr, mask = 1 << irq;
|
||||
|
||||
do {
|
||||
isr = XIntc_In32(base + XIN_ISR_OFFSET);
|
||||
pthread_testcancel();
|
||||
} while ((isr & mask) != mask);
|
||||
|
||||
XIntc_Out32(base + XIN_IAR_OFFSET, mask);
|
||||
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
uint64_t cnt;
|
||||
ssize_t ret = read(intc->efds[irq], &cnt, sizeof(cnt));
|
||||
if (ret != sizeof(cnt))
|
||||
return 0;
|
||||
|
||||
return cnt;
|
||||
}
|
||||
}
|
||||
|
||||
static struct plugin p = {
|
||||
.name = "Xilinx's programmable interrupt controller",
|
||||
.description = "",
|
||||
.type = PLUGIN_TYPE_FPGA_IP,
|
||||
.ip = {
|
||||
.vlnv = { "acs.eonerc.rwth-aachen.de", "user", "axi_pcie_intc", NULL },
|
||||
.type = FPGA_IP_TYPE_MISC,
|
||||
.start = intc_start,
|
||||
.destroy = intc_destroy,
|
||||
.size = sizeof(struct intc)
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_PLUGIN(&p)
|
|
@ -1,221 +0,0 @@
|
|||
/** AXI Stream interconnect related helper functions
|
||||
*
|
||||
* These functions present a simpler interface to Xilinx' AXI Stream switch driver (XAxis_Switch_*)
|
||||
*
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Steffen Vogel
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASfpga
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
#include "log_config.h"
|
||||
#include "plugin.h"
|
||||
|
||||
#include "fpga/ip.h"
|
||||
#include "fpga/card.h"
|
||||
#include "fpga/ips/switch.h"
|
||||
|
||||
int switch_start(struct fpga_ip *c)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct fpga_card *f = c->card;
|
||||
struct sw *sw = (struct sw *) c->_vd;
|
||||
|
||||
XAxis_Switch *xsw = &sw->inst;
|
||||
|
||||
if (c != f->sw)
|
||||
error("There can be only one AXI4-Stream interconnect per FPGA");
|
||||
|
||||
|
||||
/* Setup AXI-stream switch */
|
||||
XAxis_Switch_Config sw_cfg = {
|
||||
.BaseAddress = (uintptr_t) f->map + c->baseaddr,
|
||||
.MaxNumMI = sw->num_ports,
|
||||
.MaxNumSI = sw->num_ports
|
||||
};
|
||||
|
||||
ret = XAxisScr_CfgInitialize(xsw, &sw_cfg, (uintptr_t) c->card->map + c->baseaddr);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -1;
|
||||
|
||||
/* Disable all masters */
|
||||
XAxisScr_RegUpdateDisable(xsw);
|
||||
XAxisScr_MiPortDisableAll(xsw);
|
||||
XAxisScr_RegUpdateEnable(xsw);
|
||||
|
||||
switch_init_paths(c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int switch_init_paths(struct fpga_ip *c)
|
||||
{
|
||||
int ret;
|
||||
struct sw *sw = (struct sw *) c->_vd;
|
||||
|
||||
XAxis_Switch *xsw = &sw->inst;
|
||||
|
||||
XAxisScr_RegUpdateDisable(xsw);
|
||||
XAxisScr_MiPortDisableAll(xsw);
|
||||
|
||||
for (size_t i = 0; i < list_length(&sw->paths); i++) {
|
||||
struct sw_path *p = (struct sw_path *) list_at(&sw->paths, i);
|
||||
struct fpga_ip *mi, *si;
|
||||
|
||||
mi = list_lookup(&c->card->ips, p->out);
|
||||
si = list_lookup(&c->card->ips, p->in);
|
||||
|
||||
if (!mi || !si || mi->port == -1 || si->port == -1)
|
||||
error("Invalid path configuration for FPGA");
|
||||
|
||||
ret = switch_connect(c, mi, si);
|
||||
if (ret)
|
||||
error("Failed to configure switch");
|
||||
}
|
||||
|
||||
XAxisScr_RegUpdateEnable(xsw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int switch_destroy(struct fpga_ip *c)
|
||||
{
|
||||
struct sw *sw = (struct sw *) c->_vd;
|
||||
|
||||
list_destroy(&sw->paths, NULL, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int switch_parse(struct fpga_ip *c, json_t *cfg)
|
||||
{
|
||||
struct sw *sw = (struct sw *) c->_vd;
|
||||
|
||||
int ret;
|
||||
size_t index;
|
||||
json_error_t err;
|
||||
json_t *json_path, *json_paths = NULL;
|
||||
|
||||
list_init(&sw->paths);
|
||||
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s: i, s?: o }",
|
||||
"num_ports", &sw->num_ports,
|
||||
"paths", &json_paths
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of FPGA IP '%s'", c->name);
|
||||
|
||||
if (!json_paths)
|
||||
return 0; /* no switch config available */
|
||||
|
||||
if (!json_is_array(json_paths))
|
||||
error("Setting 'paths' of FPGA IP '%s' should be an array of JSON objects", c->name);
|
||||
|
||||
json_array_foreach(json_paths, index, json_path) {
|
||||
struct sw_path *p = (struct sw_path *) alloc(sizeof(struct sw_path));
|
||||
int reverse = 0;
|
||||
|
||||
ret = json_unpack_ex(json_path, &err, 0, "{ s?: b, s: s, s: s }",
|
||||
"reverse", &reverse,
|
||||
"in", &p->in,
|
||||
"out", &p->out
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse path %zu of FPGA IP '%s'", index, c->name);
|
||||
|
||||
list_push(&sw->paths, p);
|
||||
|
||||
if (reverse) {
|
||||
struct sw_path *r = memdup(p, sizeof(struct sw_path));
|
||||
|
||||
r->in = p->out;
|
||||
r->out = p->in;
|
||||
|
||||
list_push(&sw->paths, r);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int switch_connect(struct fpga_ip *c, struct fpga_ip *mi, struct fpga_ip *si)
|
||||
{
|
||||
struct sw *sw = (struct sw *) c->_vd;
|
||||
XAxis_Switch *xsw = &sw->inst;
|
||||
|
||||
uint32_t mux, port;
|
||||
|
||||
/* Check if theres already something connected */
|
||||
for (int i = 0; i < sw->num_ports; i++) {
|
||||
mux = XAxisScr_ReadReg(xsw->Config.BaseAddress, XAXIS_SCR_MI_MUX_START_OFFSET + i * 4);
|
||||
if (!(mux & XAXIS_SCR_MI_X_DISABLE_MASK)) {
|
||||
port = mux & ~XAXIS_SCR_MI_X_DISABLE_MASK;
|
||||
|
||||
if (port == si->port) {
|
||||
warn("Switch: Slave port %s (%u) has been connected already to port %u. Disconnecting...", si->name, si->port, i);
|
||||
XAxisScr_RegUpdateDisable(xsw);
|
||||
XAxisScr_MiPortDisable(xsw, i);
|
||||
XAxisScr_RegUpdateEnable(xsw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Reconfigure switch */
|
||||
XAxisScr_RegUpdateDisable(xsw);
|
||||
XAxisScr_MiPortEnable(xsw, mi->port, si->port);
|
||||
XAxisScr_RegUpdateEnable(xsw);
|
||||
|
||||
/* Reset IPs */
|
||||
/*ip_reset(mi);
|
||||
ip_reset(si);*/
|
||||
|
||||
debug(8, "FPGA: Switch connected %s (%u) to %s (%u)", mi->name, mi->port, si->name, si->port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int switch_disconnect(struct fpga_ip *c, struct fpga_ip *mi, struct fpga_ip *si)
|
||||
{
|
||||
struct sw *sw = (struct sw *) c->_vd;
|
||||
XAxis_Switch *xsw = &sw->inst;
|
||||
|
||||
if (!XAxisScr_IsMiPortEnabled(xsw, mi->port, si->port))
|
||||
return -1;
|
||||
|
||||
XAxisScr_MiPortDisable(xsw, mi->port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct plugin p = {
|
||||
.name = "Xilinx's AXI4-Stream switch",
|
||||
.description = "",
|
||||
.type = PLUGIN_TYPE_FPGA_IP,
|
||||
.ip = {
|
||||
.vlnv = { "xilinx.com", "ip", "axis_interconnect", NULL },
|
||||
.type = FPGA_IP_TYPE_MISC,
|
||||
.start = switch_start,
|
||||
.destroy = switch_destroy,
|
||||
.parse = switch_parse,
|
||||
.size = sizeof(struct sw)
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_PLUGIN(&p)
|
|
@ -1,61 +0,0 @@
|
|||
/** Timer related helper functions
|
||||
*
|
||||
* These functions present a simpler interface to Xilinx' Timer Counter driver (XTmrCtr_*)
|
||||
*
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Steffen Vogel
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASfpga
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
#include "plugin.h"
|
||||
|
||||
#include "fpga/ip.h"
|
||||
#include "fpga/card.h"
|
||||
#include "fpga/ips/timer.h"
|
||||
|
||||
int timer_start(struct fpga_ip *c)
|
||||
{
|
||||
struct fpga_card *f = c->card;
|
||||
struct timer *tmr = (struct timer *) c->_vd;
|
||||
|
||||
XTmrCtr *xtmr = &tmr->inst;
|
||||
XTmrCtr_Config xtmr_cfg = {
|
||||
.BaseAddress = (uintptr_t) f->map + c->baseaddr,
|
||||
.SysClockFreqHz = FPGA_AXI_HZ
|
||||
};
|
||||
|
||||
XTmrCtr_CfgInitialize(xtmr, &xtmr_cfg, (uintptr_t) f->map + c->baseaddr);
|
||||
XTmrCtr_InitHw(xtmr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct plugin p = {
|
||||
.name = "Xilinx's programmable timer / counter",
|
||||
.description = "",
|
||||
.type = PLUGIN_TYPE_FPGA_IP,
|
||||
.ip = {
|
||||
.vlnv = { "xilinx.com", "ip", "axi_timer", NULL },
|
||||
.type = FPGA_IP_TYPE_MISC,
|
||||
.start = timer_start,
|
||||
.size = sizeof(struct timer)
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_PLUGIN(&p)
|
|
@ -1,111 +0,0 @@
|
|||
/** Loadable / plugin support.
|
||||
*
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASfpga
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "plugin.h"
|
||||
|
||||
/** Global list of all known plugins */
|
||||
struct list plugins = { .state = STATE_DESTROYED };
|
||||
|
||||
LIST_INIT_STATIC(&plugins)
|
||||
|
||||
int plugin_init(struct plugin *p)
|
||||
{
|
||||
assert(p->state == STATE_DESTROYED);
|
||||
|
||||
p->state = STATE_INITIALIZED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plugin_parse(struct plugin *p, json_t *cfg)
|
||||
{
|
||||
const char *path;
|
||||
|
||||
path = json_string_value(cfg);
|
||||
if (!path)
|
||||
return -1;
|
||||
|
||||
p->path = strdup(path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plugin_load(struct plugin *p)
|
||||
{
|
||||
p->handle = dlopen(p->path, RTLD_NOW);
|
||||
if (!p->path)
|
||||
return -1;
|
||||
|
||||
p->state = STATE_LOADED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plugin_unload(struct plugin *p)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(p->state == STATE_LOADED);
|
||||
|
||||
ret = dlclose(p->handle);
|
||||
if (ret)
|
||||
return -1;
|
||||
|
||||
p->state = STATE_UNLOADED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plugin_destroy(struct plugin *p)
|
||||
{
|
||||
assert(p->state != STATE_DESTROYED && p->state != STATE_LOADED);
|
||||
|
||||
if (p->path)
|
||||
free(p->path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct plugin * plugin_lookup(enum plugin_type type, const char *name)
|
||||
{
|
||||
for (size_t i = 0; i < list_length(&plugins); i++) {
|
||||
struct plugin *p = (struct plugin *) list_at(&plugins, i);
|
||||
|
||||
if (p->type == type && strcmp(p->name, name) == 0)
|
||||
return p;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void plugin_dump(enum plugin_type type)
|
||||
{
|
||||
for (size_t i = 0; i < list_length(&plugins); i++) {
|
||||
struct plugin *p = (struct plugin *) list_at(&plugins, i);
|
||||
|
||||
if (p->type == type)
|
||||
printf(" - %-13s: %s\n", p->name, p->description);
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/** Vendor, Library, Name, Version (VLNV) tag
|
||||
*
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASfpga
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fpga/vlnv.h"
|
||||
#include "fpga/ip.h"
|
||||
|
||||
struct fpga_ip * fpga_vlnv_lookup(struct list *l, struct fpga_vlnv *v)
|
||||
{
|
||||
return (struct fpga_ip *) list_search(l, (cmp_cb_t) fpga_vlnv_cmp, v);
|
||||
}
|
||||
|
||||
int fpga_vlnv_cmp(struct fpga_vlnv *a, struct fpga_vlnv *b)
|
||||
{
|
||||
return ((!a->vendor || !b->vendor || !strcmp(a->vendor, b->vendor )) &&
|
||||
(!a->library || !b->library || !strcmp(a->library, b->library)) &&
|
||||
(!a->name || !b->name || !strcmp(a->name, b->name )) &&
|
||||
(!a->version || !b->version || !strcmp(a->version, b->version))) ? 0 : 1;
|
||||
}
|
||||
|
||||
int fpga_vlnv_parse(struct fpga_vlnv *c, const char *vlnv)
|
||||
{
|
||||
char *tmp = strdup(vlnv);
|
||||
|
||||
c->vendor = strdup(strtok(tmp, ":"));
|
||||
c->library = strdup(strtok(NULL, ":"));
|
||||
c->name = strdup(strtok(NULL, ":"));
|
||||
c->version = strdup(strtok(NULL, ":"));
|
||||
|
||||
free(tmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fpga_vlnv_destroy(struct fpga_vlnv *v)
|
||||
{
|
||||
free(v->vendor);
|
||||
free(v->library);
|
||||
free(v->name);
|
||||
free(v->version);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Reference in a new issue