mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-09 00:00:00 +01:00
finished FPGA stuff
This commit is contained in:
parent
80fdc6bda8
commit
3f012c8575
8 changed files with 236 additions and 129 deletions
|
@ -64,6 +64,5 @@ 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_ */
|
|
@ -11,12 +11,28 @@
|
|||
|
||||
#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 ip *c);
|
||||
|
||||
void intc_destroy(struct ip *c);
|
||||
|
||||
int intc_enable(struct ip *c, uint32_t mask, int poll);
|
||||
|
||||
int intc_disable(struct ip *c, uint32_t mask);
|
||||
|
||||
uint64_t intc_wait(struct ip *c, int irq, int poll);
|
||||
uint64_t intc_wait(struct ip *c, int irq);
|
||||
|
||||
#endif /* _INTC_H_ */
|
|
@ -17,6 +17,7 @@
|
|||
#include "fpga/timer.h"
|
||||
#include "fpga/model.h"
|
||||
#include "fpga/dft.h"
|
||||
#include "fpga/intc.h"
|
||||
#include "nodes/fpga.h"
|
||||
|
||||
#define REGISTER_IP_TYPE(ip) \
|
||||
|
@ -44,6 +45,7 @@ struct ip_type {
|
|||
|
||||
int (*parse)(struct ip *c);
|
||||
int (*init)(struct ip *c);
|
||||
int (*reset)(struct ip *c);
|
||||
void (*dump)(struct ip *c);
|
||||
void (*destroy)(struct ip *c);
|
||||
};
|
||||
|
@ -64,14 +66,12 @@ struct ip {
|
|||
|
||||
union {
|
||||
struct model model;
|
||||
struct {
|
||||
int size;
|
||||
} bram;
|
||||
struct timer timer;
|
||||
struct fifo fifo;
|
||||
struct dma dma;
|
||||
struct sw sw;
|
||||
struct dft dft;
|
||||
struct intc intc;
|
||||
};
|
||||
|
||||
struct fpga *card;
|
||||
|
@ -94,6 +94,8 @@ void ip_destroy(struct ip *c);
|
|||
|
||||
void ip_dump(struct ip *c);
|
||||
|
||||
int ip_reset(struct ip *c);
|
||||
|
||||
int ip_parse(struct ip *c, config_setting_t *cfg);
|
||||
|
||||
#endif
|
|
@ -12,14 +12,18 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
#include <pci/pci.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <linux/vfio.h>
|
||||
#include <linux/pci_regs.h>
|
||||
|
||||
#include <villas/list.h>
|
||||
#include "list.h"
|
||||
|
||||
#define VFIO_DEV(x) "/dev/vfio/" x
|
||||
|
||||
/* Forward declaration */
|
||||
struct dma_mem;
|
||||
|
||||
struct vfio_group {
|
||||
int fd; /**< VFIO group file descriptor */
|
||||
int index; /**< Index of the IOMMU group as listed under /sys/kernel/iommu_groups/ */
|
||||
|
@ -38,11 +42,8 @@ struct vfio_dev {
|
|||
struct vfio_device_info info;
|
||||
struct vfio_irq_info *irqs;
|
||||
struct vfio_region_info *regions;
|
||||
|
||||
|
||||
void **mappings;
|
||||
|
||||
int *msi_efds; /**< Array of assigned eventfs for MSI handling */
|
||||
int *msi_irqs; /**< Linux assigned IRQ number for MSI (see /proc/interrupts) */
|
||||
|
||||
struct pci_dev *pdev; /**< libpci handle of the device */
|
||||
struct vfio_group *group; /**< The VFIO group this device belongs to */
|
||||
|
@ -53,6 +54,8 @@ struct vfio_container {
|
|||
int version;
|
||||
int extensions;
|
||||
|
||||
uint64_t iova_next; /**< Next free IOVA address */
|
||||
|
||||
struct list groups;
|
||||
};
|
||||
|
||||
|
@ -71,8 +74,11 @@ int vfio_pci_attach(struct vfio_dev *d, struct vfio_container *c, struct pci_dev
|
|||
/** Hot resets a VFIO-PCI device */
|
||||
int vfio_pci_reset(struct vfio_dev *d);
|
||||
|
||||
/** Create a new eventfd and binds it to the MSI irqs of the device */
|
||||
int vfio_pci_msi_fd(struct vfio_dev *d, uint32_t mask);
|
||||
int vfio_pci_msi_init(struct vfio_dev *d, int efds[32]);
|
||||
|
||||
int vfio_pci_msi_deinit(struct vfio_dev *d, int efds[32]);
|
||||
|
||||
int vfio_pci_msi_find(struct vfio_dev *d, int nos[32]);
|
||||
|
||||
/** Enable memory accesses and bus mastering for PCI device */
|
||||
int vfio_pci_enable(struct vfio_dev *d);
|
||||
|
@ -95,8 +101,11 @@ void vfio_dump(struct vfio_container *c);
|
|||
/** Map a device memory region to the application address space (e.g. PCI BARs) */
|
||||
void * vfio_map_region(struct vfio_dev *d, int idx);
|
||||
|
||||
/** Allocate a virtual memory region and map it for DMA access from the devices */
|
||||
void * vfio_map_dma(struct vfio_container *c, size_t size, size_t pgsize, uint64_t phyaddr);
|
||||
/** Map VM to an IOVA, which is accessible by devices in the container */
|
||||
int vfio_map_dma(struct vfio_container *c, struct dma_mem *mem);
|
||||
|
||||
/** Unmap DMA memory */
|
||||
int vfio_unmap_dma(struct vfio_container *c, struct dma_mem *mem);
|
||||
|
||||
/** munmap() a region which has been mapped by vfio_map_region() */
|
||||
int vfio_unmap_region(struct vfio_dev *d, int idx);
|
||||
|
|
|
@ -21,17 +21,11 @@
|
|||
|
||||
#include <pci/pci.h>
|
||||
|
||||
#include "fpga/dma.h"
|
||||
#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. */
|
||||
|
@ -41,7 +35,6 @@ struct fpga {
|
|||
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;
|
||||
|
@ -60,6 +53,8 @@ struct fpga_dm {
|
|||
|
||||
int use_irqs;
|
||||
|
||||
struct dma_mem dma;
|
||||
|
||||
enum {
|
||||
FPGA_DM_DMA,
|
||||
FPGA_DM_FIFO
|
||||
|
|
277
lib/fpga/dma.c
277
lib/fpga/dma.c
|
@ -85,14 +85,14 @@ int dma_ping_pong(struct ip *c, char *src, char *dst, size_t 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;
|
||||
|
||||
ret = dma_read_complete(c, NULL, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -100,6 +100,8 @@ int dma_write(struct ip *c, char *buf, size_t len)
|
|||
{
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
|
||||
debug(25, "DMA write: dmac=%s buf=%p len=%#x", c->name, buf, len);
|
||||
|
||||
return xdma->HasSg
|
||||
? dma_sg_write(c, buf, len)
|
||||
: dma_simple_write(c, buf, len);
|
||||
|
@ -108,6 +110,8 @@ int dma_write(struct ip *c, char *buf, size_t len)
|
|||
int dma_read(struct ip *c, char *buf, size_t len)
|
||||
{
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
|
||||
debug(25, "DMA read: dmac=%s buf=%p len=%#x", c->name, buf, len);
|
||||
|
||||
return xdma->HasSg
|
||||
? dma_sg_read(c, buf, len)
|
||||
|
@ -117,6 +121,8 @@ int dma_read(struct ip *c, char *buf, size_t len)
|
|||
int dma_read_complete(struct ip *c, char **buf, size_t *len)
|
||||
{
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
|
||||
debug(25, "DMA read complete: dmac=%s", c->name);
|
||||
|
||||
return xdma->HasSg
|
||||
? dma_sg_read_complete(c, buf, len)
|
||||
|
@ -126,6 +132,8 @@ int dma_read_complete(struct ip *c, char **buf, size_t *len)
|
|||
int dma_write_complete(struct ip *c, char **buf, size_t *len)
|
||||
{
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
|
||||
debug(25, "DMA write complete: dmac=%s", c->name);
|
||||
|
||||
return xdma->HasSg
|
||||
? dma_sg_write_complete(c, buf, len)
|
||||
|
@ -134,19 +142,19 @@ int dma_write_complete(struct ip *c, char **buf, size_t *len)
|
|||
|
||||
int dma_sg_write(struct ip *c, char *buf, size_t len)
|
||||
{
|
||||
int ret, bdcnt;
|
||||
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
XAxiDma_BdRing *ring = XAxiDma_GetTxRing(xdma);
|
||||
XAxiDma_Bd *bd;
|
||||
XAxiDma_Bd *bds, *bd;
|
||||
|
||||
int ret;
|
||||
|
||||
buf = virt_to_dma(buf, c->card->dma);
|
||||
uint32_t remaining, bdlen, bdbuf, cr;
|
||||
|
||||
/* Checks */
|
||||
if (!xdma->HasSg)
|
||||
return -1;
|
||||
|
||||
if ((len < 1) || (len > ring->MaxTransferLen))
|
||||
if (len < 1)
|
||||
return -2;
|
||||
|
||||
if (!xdma->HasMm2S)
|
||||
|
@ -158,47 +166,70 @@ int dma_sg_write(struct ip *c, char *buf, size_t len)
|
|||
return -4;
|
||||
}
|
||||
|
||||
ret = XAxiDma_BdRingAlloc(ring, 1, &bd);
|
||||
bdcnt = CEIL(len, FPGA_DMA_BOUNDARY);
|
||||
ret = XAxiDma_BdRingAlloc(ring, bdcnt, &bds);
|
||||
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;
|
||||
remaining = len;
|
||||
bdbuf = (uint32_t) buf;
|
||||
bd = bds;
|
||||
for (int i = 0; i < bdcnt; i++) {
|
||||
bdlen = MIN(remaining, FPGA_DMA_BOUNDARY);
|
||||
|
||||
ret = XAxiDma_BdSetLength(bd, len, ring->MaxTransferLen);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -7;
|
||||
ret = XAxiDma_BdSetBufAddr(bd, bdbuf);
|
||||
if (ret != XST_SUCCESS)
|
||||
goto out;
|
||||
|
||||
/* Set SOF / EOF / ID */
|
||||
XAxiDma_BdSetCtrl(bd, XAXIDMA_BD_CTRL_TXEOF_MASK | XAXIDMA_BD_CTRL_TXSOF_MASK);
|
||||
XAxiDma_BdSetId(bd, (uintptr_t) buf);
|
||||
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, 1, 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_read(struct ip *c, char *buf, size_t len)
|
||||
{
|
||||
int ret, bdcnt;
|
||||
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
XAxiDma_BdRing *ring = XAxiDma_GetRxRing(xdma);
|
||||
XAxiDma_Bd *bd;
|
||||
|
||||
int ret;
|
||||
|
||||
buf = virt_to_dma(buf, c->card->dma);
|
||||
XAxiDma_Bd *bds, *bd;
|
||||
|
||||
uint32_t remaining, bdlen, bdbuf;
|
||||
|
||||
/* Checks */
|
||||
if (!xdma->HasSg)
|
||||
return -1;
|
||||
|
||||
if ((len < 1) || (len > ring->MaxTransferLen))
|
||||
if (len < 1)
|
||||
return -2;
|
||||
|
||||
if (!xdma->HasS2Mm)
|
||||
|
@ -210,56 +241,74 @@ int dma_sg_read(struct ip *c, char *buf, size_t len)
|
|||
return -4;
|
||||
}
|
||||
|
||||
ret = XAxiDma_BdRingAlloc(ring, 1, &bd);
|
||||
bdcnt = CEIL(len, FPGA_DMA_BOUNDARY);
|
||||
ret = XAxiDma_BdRingAlloc(ring, bdcnt, &bds);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -5;
|
||||
|
||||
ret = XAxiDma_BdSetBufAddr(bd, (uintptr_t) buf);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -6;
|
||||
bdbuf = (uint32_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_BdSetLength(bd, len, ring->MaxTransferLen);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -7;
|
||||
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);
|
||||
/* 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);
|
||||
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 ip *c, char **buf, size_t *len)
|
||||
{
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
XAxiDma_BdRing *ring = XAxiDma_GetTxRing(xdma);
|
||||
XAxiDma_Bd *bd;
|
||||
XAxiDma_Bd *bds;
|
||||
|
||||
int processed, ret;
|
||||
|
||||
/* Wait until the one BD TX transaction is done */
|
||||
while ((processed = XAxiDma_BdRingFromHw(ring, XAXIDMA_ALL_BDS, &bd)) == 0)
|
||||
pthread_testcancel();
|
||||
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(bd, XAXIDMA_MAX_TRANSFER_LEN);
|
||||
*len = XAxiDma_BdGetActualLength(bds, XAXIDMA_MAX_TRANSFER_LEN);
|
||||
|
||||
if (buf != NULL)
|
||||
*buf = (char *) (uintptr_t) XAxiDma_BdGetBufAddr(bd);
|
||||
*buf = (char *) (uintptr_t) XAxiDma_BdGetId(bds);
|
||||
|
||||
/* Free all processed TX BDs for future transmission */
|
||||
ret = XAxiDma_BdRingFree(ring, processed, bd);
|
||||
if (ret != XST_SUCCESS) {
|
||||
info("Failed to free %d tx BDs %d", processed, ret);
|
||||
ret = XAxiDma_BdRingFree(ring, processed, bds);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -267,25 +316,48 @@ int dma_sg_read_complete(struct ip *c, char **buf, size_t *len)
|
|||
{
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
XAxiDma_BdRing *ring = XAxiDma_GetRxRing(xdma);
|
||||
XAxiDma_Bd *bd;
|
||||
XAxiDma_Bd *bds, *bd;
|
||||
|
||||
int ret;
|
||||
int ret, bdcnt;
|
||||
uint32_t recvlen, sr;
|
||||
uintptr_t recvbuf;
|
||||
|
||||
if (!xdma->HasSg)
|
||||
return -1;
|
||||
|
||||
while (XAxiDma_BdRingFromHw(ring, 1, &bd) == 0)
|
||||
pthread_testcancel();
|
||||
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 != NULL)
|
||||
*len = XAxiDma_BdGetActualLength(bd, XAXIDMA_MAX_TRANSFER_LEN);
|
||||
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 *) (uintptr_t) XAxiDma_BdGetBufAddr(bd);
|
||||
*buf = (char *) recvbuf;
|
||||
|
||||
/* Free all processed RX BDs for future transmission */
|
||||
ret = XAxiDma_BdRingFree(ring, 1, bd);
|
||||
ret = XAxiDma_BdRingFree(ring, bdcnt, bds);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -3;
|
||||
|
||||
|
@ -297,13 +369,11 @@ int dma_simple_read(struct ip *c, char *buf, size_t len)
|
|||
XAxiDma *xdma = &c->dma.inst;
|
||||
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))
|
||||
if ((len < 1) || (len > FPGA_DMA_BOUNDARY))
|
||||
return -2;
|
||||
|
||||
if (!xdma->HasS2Mm)
|
||||
|
@ -335,13 +405,11 @@ int dma_simple_write(struct ip *c, char *buf, size_t len)
|
|||
XAxiDma *xdma = &c->dma.inst;
|
||||
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))
|
||||
if ((len < 1) || (len > FPGA_DMA_BOUNDARY))
|
||||
return -2;
|
||||
|
||||
if (!xdma->HasMm2S)
|
||||
|
@ -375,7 +443,7 @@ int dma_simple_read_complete(struct ip *c, char **buf, size_t *len)
|
|||
XAxiDma_BdRing *ring = XAxiDma_GetRxRing(xdma);
|
||||
|
||||
while (!(XAxiDma_IntrGetIrq(xdma, XAXIDMA_DEVICE_TO_DMA) & XAXIDMA_IRQ_IOC_MASK))
|
||||
pthread_testcancel();
|
||||
intc_wait(c->card->intc, c->irq + 1);
|
||||
XAxiDma_IntrAckIrq(xdma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA);
|
||||
|
||||
if (len)
|
||||
|
@ -396,7 +464,7 @@ int dma_simple_write_complete(struct ip *c, char **buf, size_t *len)
|
|||
XAxiDma_BdRing *ring = XAxiDma_GetTxRing(xdma);
|
||||
|
||||
while (!(XAxiDma_IntrGetIrq(xdma, XAXIDMA_DMA_TO_DEVICE) & XAXIDMA_IRQ_IOC_MASK))
|
||||
pthread_testcancel();
|
||||
intc_wait(c->card->intc, c->irq);
|
||||
XAxiDma_IntrAckIrq(xdma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DMA_TO_DEVICE);
|
||||
|
||||
if (len)
|
||||
|
@ -428,53 +496,40 @@ static int dma_setup_ring(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);
|
||||
if (ret != XST_SUCCESS) {
|
||||
info("RX create BD ring failed (%d)", ret);
|
||||
return XST_FAILURE;
|
||||
}
|
||||
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) {
|
||||
info("RX clone BD failed %d", ret);
|
||||
return XST_FAILURE;
|
||||
}
|
||||
|
||||
if (ret != XST_SUCCESS)
|
||||
return -2;
|
||||
|
||||
/* Start the channel */
|
||||
ret = XAxiDma_BdRingStart(ring);
|
||||
if (ret != XST_SUCCESS) {
|
||||
info("failed start bdring txsetup %d", ret);
|
||||
return XST_FAILURE;
|
||||
}
|
||||
|
||||
if (ret != XST_SUCCESS)
|
||||
return -3;
|
||||
|
||||
return XST_SUCCESS;
|
||||
}
|
||||
|
||||
int dma_init_rings(struct ip *c, struct dma_mem *bd)
|
||||
static int dma_init_rings(XAxiDma *xdma, struct dma_mem *bd)
|
||||
{
|
||||
int ret;
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
|
||||
/* 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
|
||||
};
|
||||
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 -1;
|
||||
return -2;
|
||||
|
||||
ret = dma_setup_ring(XAxiDma_GetTxRing(xdma), &bd_tx);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -1;
|
||||
return -3;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -482,7 +537,8 @@ int dma_init_rings(struct ip *c, struct dma_mem *bd)
|
|||
int dma_init(struct ip *c)
|
||||
{
|
||||
int ret, sg;
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
struct dma *dma = &c->dma;
|
||||
XAxiDma *xdma = &dma->inst;
|
||||
|
||||
/* Guess DMA type */
|
||||
sg = (XAxiDma_In32((uintptr_t) c->card->map + c->baseaddr + XAXIDMA_TX_OFFSET+ XAXIDMA_SR_OFFSET) &
|
||||
|
@ -507,16 +563,23 @@ int dma_init(struct ip *c)
|
|||
};
|
||||
|
||||
ret = XAxiDma_CfgInitialize(xdma, &xdma_cfg);
|
||||
if (ret != XST_SUCCESS) {
|
||||
info("Initialization failed %d", ret);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Perform selftest */
|
||||
ret = XAxiDma_Selftest(xdma);
|
||||
if (ret != XST_SUCCESS) {
|
||||
info("DMA selftest failed");
|
||||
return -1;
|
||||
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 */
|
||||
|
@ -526,9 +589,17 @@ int dma_init(struct ip *c)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int dma_reset(struct ip *c)
|
||||
{
|
||||
XAxiDma_Reset(&c->dma.inst);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ip_type ip = {
|
||||
.vlnv = { "xilinx.com", "ip", "axi_dma", NULL },
|
||||
.init = dma_init
|
||||
.init = dma_init,
|
||||
.reset = dma_reset
|
||||
};
|
||||
|
||||
REGISTER_IP_TYPE(&ip)
|
|
@ -59,10 +59,10 @@ ssize_t fifo_read(struct ip *c, char *buf, size_t len)
|
|||
XLlFifo *fifo = &c->fifo.inst;
|
||||
|
||||
size_t nextlen = 0;
|
||||
uint32_t rdfo, rxlen;
|
||||
uint32_t rxlen;
|
||||
|
||||
while (!(rdfo = XLlFifo_RxOccupancy(fifo)))
|
||||
pthread_testcancel();
|
||||
while (!XLlFifo_IsRxDone(fifo))
|
||||
intc_wait(c->card->intc, c->irq);
|
||||
XLlFifo_IntClear(fifo, XLLF_INT_RC_MASK);
|
||||
|
||||
/* Get length of next frame */
|
||||
|
@ -89,10 +89,18 @@ int fifo_parse(struct ip *c)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int fifo_reset(struct ip *c)
|
||||
{
|
||||
XLlFifo_Reset(&c->fifo.inst);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ip_type ip = {
|
||||
.vlnv = { "xilinx.com", "ip", "axi_fifo_mm_s", NULL },
|
||||
.init = fifo_init,
|
||||
.parse = fifo_parse
|
||||
.parse = fifo_parse,
|
||||
.reset = fifo_reset
|
||||
};
|
||||
|
||||
REGISTER_IP_TYPE(&ip)
|
|
@ -62,6 +62,13 @@ int ip_init(struct ip *c)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int ip_reset(struct ip *c)
|
||||
{
|
||||
debug(3, "Reset IP core: %s", c->name);
|
||||
|
||||
return c->_vt && c->_vt->reset ? c->_vt->reset(c) : 0;
|
||||
}
|
||||
|
||||
void ip_destroy(struct ip *c)
|
||||
{
|
||||
if (c->_vt && c->_vt->destroy)
|
||||
|
|
Loading…
Add table
Reference in a new issue