2016-06-14 01:19:17 +02:00
|
|
|
/** Test procedures for VILLASfpga
|
|
|
|
*
|
|
|
|
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
|
|
|
* @copyright 2016, Steffen Vogel
|
|
|
|
* This file is part of VILLASnode. All Rights Reserved. Proprietary and confidential.
|
|
|
|
* Unauthorized copying of this file, via any medium is strictly prohibited.
|
|
|
|
*********************************************************************************/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <poll.h>
|
|
|
|
#include <time.h>
|
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
#include <xilinx/xtmrctr.h>
|
|
|
|
#include <xilinx/xintc.h>
|
|
|
|
#include <xilinx/xllfifo.h>
|
|
|
|
#include <xilinx/xaxis_switch.h>
|
|
|
|
#include <xilinx/xaxidma.h>
|
|
|
|
|
2016-06-14 01:19:17 +02:00
|
|
|
#include <villas/utils.h>
|
2016-06-19 19:23:19 +02:00
|
|
|
#include <villas/nodes/fpga.h>
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
#include <villas/fpga/ip.h>
|
2016-06-19 19:23:19 +02:00
|
|
|
#include <villas/fpga/intc.h>
|
2016-06-15 20:05:09 +02:00
|
|
|
|
|
|
|
//#include <villas/fpga/cbmodel.h>
|
|
|
|
|
2016-06-14 01:19:17 +02:00
|
|
|
#include "config.h"
|
|
|
|
#include "config-fpga.h"
|
|
|
|
|
|
|
|
//#include "cbuilder/cbmodel.h"
|
|
|
|
|
|
|
|
#define TEST_LEN 0x1000
|
|
|
|
|
|
|
|
#define CPU_HZ 3392389000
|
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
/* Forward Declarations */
|
|
|
|
int fpga_test_intc(struct fpga *f);
|
|
|
|
int fpga_test_timer(struct fpga *f);
|
|
|
|
int fpga_test_fifo(struct fpga *f);
|
|
|
|
int fpga_test_dma(struct fpga *f);
|
|
|
|
int fpga_test_xsg(struct fpga *f);
|
|
|
|
int fpga_test_rtds_rtt(struct fpga *f);
|
2016-06-15 20:05:09 +02:00
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
int fpga_tests(struct fpga *f)
|
2016-06-15 20:05:09 +02:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
struct {
|
|
|
|
const char *name;
|
2016-06-19 19:23:19 +02:00
|
|
|
int (*func)(struct fpga *f);
|
2016-06-15 20:05:09 +02:00
|
|
|
} tests[] = {
|
|
|
|
{ "Interrupt Controller", fpga_test_intc },
|
|
|
|
{ "Timer Counter", fpga_test_timer },
|
|
|
|
{ "FIFO", fpga_test_fifo },
|
|
|
|
{ "DMA", fpga_test_dma },
|
|
|
|
{ "XSG: multiply_add", fpga_test_xsg },
|
2016-06-19 19:23:19 +02:00
|
|
|
{ "RTDS: RTT Test", fpga_test_rtds_rtt }
|
2016-06-15 20:05:09 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
for (int i = 0; i < ARRAY_LEN(tests); i++) {
|
|
|
|
ret = tests[i].func(f);
|
|
|
|
|
|
|
|
info("%s: %s", tests[i].name, (ret == 0) ? GRN("passed") : RED("failed"));
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
int fpga_test_intc(struct fpga *f)
|
2016-06-14 01:19:17 +02:00
|
|
|
{
|
2016-06-19 19:23:19 +02:00
|
|
|
uint32_t isr;
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
if (!f->intc)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
intc_enable(f->intc, 0xFF00);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
info("ISR %#x", XIntc_In32((uintptr_t) f->map + f->intc->baseaddr + XIN_ISR_OFFSET));
|
|
|
|
info("IER %#x", XIntc_In32((uintptr_t) f->map + f->intc->baseaddr + XIN_IER_OFFSET));
|
|
|
|
info("IMR %#x", XIntc_In32((uintptr_t) f->map + f->intc->baseaddr + XIN_IMR_OFFSET));
|
|
|
|
info("MER %#x", XIntc_In32((uintptr_t) f->map + f->intc->baseaddr + XIN_MER_OFFSET));
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
/* Fake IRQs in software by writing to ISR */
|
|
|
|
XIntc_Out32((uintptr_t) f->map + f->intc->baseaddr + XIN_ISR_OFFSET, 0xFF00);
|
|
|
|
|
|
|
|
/* Wait for 8 SW triggered IRQs */
|
2016-06-14 01:19:17 +02:00
|
|
|
for (int i = 0; i < 8; i++)
|
2016-06-19 19:23:19 +02:00
|
|
|
intc_wait(f, i+8);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
/* Check ISR if all SW IRQs have been deliverd */
|
|
|
|
isr = XIntc_In32((uintptr_t) f->map + f->intc->baseaddr + XIN_ISR_OFFSET);
|
|
|
|
|
|
|
|
intc_disable(f->intc, 0xFF00);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
return (isr & 0xFF00) ? -1 : 0; /* ISR should get cleared by MSI_Grant_signal */
|
|
|
|
}
|
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
int fpga_test_xsg(struct fpga *f)
|
2016-06-14 01:19:17 +02:00
|
|
|
{
|
2016-06-19 19:23:19 +02:00
|
|
|
struct ip *xsg, *dma;
|
|
|
|
int ret;
|
|
|
|
double factor, err = 0;
|
|
|
|
|
|
|
|
xsg = ip_vlnv_lookup(&f->ips, NULL, "sysgen", "xsg_multiply", NULL);
|
2016-06-15 20:05:09 +02:00
|
|
|
dma = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_dma", NULL);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
/* Check if required IP is available on FPGA */
|
|
|
|
if (!dma || !xsg || !dma)
|
|
|
|
return -1;
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
ip_dump(xsg);
|
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
config_setting_t *cfg_params, *cfg_param;
|
|
|
|
struct model_param *p;
|
|
|
|
|
|
|
|
cfg_params = config_setting_get_member(xsg->cfg, "parameters");
|
|
|
|
if (cfg_params) {
|
|
|
|
for (int i = 0; i < config_setting_length(cfg_params); i++) {
|
|
|
|
cfg_param = config_setting_get_elem(cfg_params, i);
|
|
|
|
|
|
|
|
const char *name = config_setting_name(cfg_param);
|
|
|
|
double value = config_setting_get_float(cfg_param);
|
|
|
|
|
|
|
|
p = list_lookup(&xsg->model.parameters, name);
|
|
|
|
if (!p)
|
|
|
|
cerror(cfg_param, "Model %s has no parameter named %s", xsg->name, name);
|
|
|
|
|
|
|
|
model_param_write(p, value);
|
|
|
|
info("Param '%s' updated to: %f", p->name, value);
|
2016-06-14 01:19:17 +02:00
|
|
|
}
|
2016-06-15 20:05:09 +02:00
|
|
|
}
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
p = list_lookup(&xsg->model.parameters, "factor");
|
|
|
|
if (!p)
|
|
|
|
error("Missing parameter 'factor' for model '%s'", xsg->name);
|
|
|
|
|
|
|
|
ret = model_param_read(p, &factor);
|
|
|
|
if (ret)
|
|
|
|
error("Failed to read parameter 'factor' from model '%s'", xsg->name);
|
|
|
|
|
|
|
|
info("Model param: factor = %f", factor);
|
|
|
|
|
|
|
|
switch_connect(f->sw, dma, xsg);
|
|
|
|
switch_connect(f->sw, xsg, dma);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
float *src = (float *) f->dma;
|
|
|
|
float *dst = (float *) f->dma + TEST_LEN;
|
2016-06-19 19:23:19 +02:00
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
for (int i = 0; i < 6; i++)
|
|
|
|
src[i] = 1.1 * (i+1);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
ret = dma_ping_pong(dma, (char *) src, (char *) dst, 6 * sizeof(float));
|
|
|
|
if (ret)
|
|
|
|
error("Failed to to ping pong DMA transfer: %d", ret);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
for (int i = 0; i < 6; i++)
|
2016-06-19 19:23:19 +02:00
|
|
|
err += abs(factor * src[i] - dst[i]);
|
|
|
|
|
|
|
|
info("Error after FPGA operation: err = %f", err);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
return err > 1e-3;
|
2016-06-14 01:19:17 +02:00
|
|
|
}
|
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
int fpga_test_hls_dft(struct fpga *f)
|
2016-06-15 20:05:09 +02:00
|
|
|
{
|
2016-06-19 19:23:19 +02:00
|
|
|
#if 0
|
|
|
|
struct ip *hls, *dma;
|
2016-06-15 20:05:09 +02:00
|
|
|
|
|
|
|
hls = ip_vlnv_lookup(&f->ips, NULL, "hls", NULL, NULL);
|
|
|
|
dma = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_dma", NULL);
|
|
|
|
|
|
|
|
/* Check if required IP is available on FPGA */
|
|
|
|
if (!dma || !hls || !dma)
|
|
|
|
return -1;
|
2016-06-19 19:23:19 +02:00
|
|
|
#endif
|
2016-06-15 20:05:09 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
int fpga_test_fifo(struct fpga *f)
|
2016-06-14 01:19:17 +02:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
ssize_t len;
|
|
|
|
char src[255], dst[255];
|
2016-06-19 19:23:19 +02:00
|
|
|
struct ip *fifo;
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
fifo = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_fifo_mm_s", NULL);
|
2016-06-15 20:05:09 +02:00
|
|
|
if (!fifo)
|
|
|
|
return -1;
|
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
intc_enable(f->intc, (1 << fifo->irq));
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
/* Get some random data to compare */
|
|
|
|
memset(dst, 0, sizeof(dst));
|
|
|
|
ret = read_random((char *) src, sizeof(src));
|
|
|
|
if (ret)
|
|
|
|
error("Failed to get random data");
|
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
ret = switch_connect(f->sw, fifo, fifo);
|
2016-06-14 01:19:17 +02:00
|
|
|
if (ret)
|
|
|
|
error("Failed to configure switch");
|
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
len = fifo_write(fifo, (char *) src, sizeof(src));
|
2016-06-14 01:19:17 +02:00
|
|
|
if (len != sizeof(src))
|
|
|
|
error("Failed to send to FIFO");
|
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
len = fifo_read(fifo, (char *) dst, sizeof(dst));
|
2016-06-14 01:19:17 +02:00
|
|
|
if (len != sizeof(dst))
|
|
|
|
error("Failed to read from FIFO");
|
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
intc_disable(f->intc, (1 << fifo->irq));
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
/* Compare data */
|
|
|
|
return memcmp(src, dst, sizeof(src));
|
|
|
|
}
|
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
int fpga_test_dma(struct fpga *f)
|
2016-06-14 01:19:17 +02:00
|
|
|
{
|
2016-06-19 19:23:19 +02:00
|
|
|
struct ip *bram;
|
|
|
|
ssize_t len = 0x100;
|
2016-06-15 20:05:09 +02:00
|
|
|
int ret;
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
/* Get some random data to compare */
|
|
|
|
char *src = (char *) f->dma;
|
|
|
|
char *dst = (char *) f->dma + len;
|
2016-06-15 20:05:09 +02:00
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
ret = read_random(src, len);
|
|
|
|
if (ret)
|
|
|
|
error("Failed to get random data");
|
2016-06-15 20:05:09 +02:00
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
list_foreach(struct ip *dma, &f->ips) { INDENT
|
|
|
|
if (!ip_vlnv_match(dma, "xilinx.com", "ip", "axi_dma", NULL))
|
|
|
|
continue; /* skip non DMA IP cores */
|
2016-06-15 20:05:09 +02:00
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
int irq_mm2s = dma->irq;
|
|
|
|
int irq_s2mm = dma->irq + 1;
|
|
|
|
|
|
|
|
intc_enable(f->intc, (1 << irq_mm2s) | (1 << irq_s2mm));
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
ret = switch_connect(f->sw, dma, dma);
|
|
|
|
if (ret)
|
|
|
|
error("Failed to configure switch");
|
|
|
|
|
|
|
|
if (dma->dma.HasSg) {
|
|
|
|
/* Init BD rings */
|
|
|
|
bram = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_bram_ctrl", NULL);
|
|
|
|
if (!bram)
|
|
|
|
return -3;
|
|
|
|
|
|
|
|
/* Memory for buffer descriptors */
|
|
|
|
struct dma_mem bd = {
|
|
|
|
.base_virt = (uintptr_t) f->map + bram->baseaddr,
|
|
|
|
.base_phys = bram->baseaddr,
|
|
|
|
.len = bram->bram.size
|
|
|
|
};
|
|
|
|
|
|
|
|
ret = dma_init_rings(dma, &bd);
|
|
|
|
if (ret)
|
|
|
|
return -4;
|
|
|
|
}
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
/* Start transfer */
|
|
|
|
ret = dma_read(dma, dst, len);
|
|
|
|
if (ret)
|
|
|
|
error("Failed to start DMA read: %d", ret);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
ret = dma_write(dma, src, len);
|
|
|
|
if (ret)
|
|
|
|
error("Failed to start DMA write: %d", ret);
|
|
|
|
|
|
|
|
ret = dma_read_complete(dma, NULL, NULL);
|
|
|
|
if (ret)
|
|
|
|
error("Failed to complete DMA read");
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
ret = dma_write_complete(dma, NULL, NULL);
|
|
|
|
if (ret)
|
|
|
|
error("Failed to complete DMA write");
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
ret = memcmp(src, dst, len);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
info("DMA %s (%s): %s", dma->name, dma->dma.HasSg ? "sg" : "simple", ret ? RED("failed") : GRN("passed"));
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
intc_disable(f->intc, (1 << irq_mm2s) | (1 << irq_s2mm));
|
|
|
|
}
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
return ret;
|
2016-06-14 01:19:17 +02:00
|
|
|
}
|
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
int fpga_test_timer(struct fpga *f)
|
2016-06-14 01:19:17 +02:00
|
|
|
{
|
|
|
|
int ret;
|
2016-06-15 20:05:09 +02:00
|
|
|
struct ip *timer;
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
timer = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_timer", NULL);
|
|
|
|
if (!timer)
|
|
|
|
return -1;
|
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
intc_enable(f->intc, (1 << timer->irq));
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
XTmrCtr_SetOptions(&timer->timer, 0, XTC_EXT_COMPARE_OPTION | XTC_DOWN_COUNT_OPTION);
|
|
|
|
XTmrCtr_SetResetValue(&timer->timer, 0, AXI_HZ / 125);
|
|
|
|
XTmrCtr_Start(&timer->timer, 0);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
struct pollfd pfd = {
|
2016-06-15 20:05:09 +02:00
|
|
|
.fd = f->vd.msi_efds[timer->irq],
|
2016-06-14 01:19:17 +02:00
|
|
|
.events = POLLIN
|
|
|
|
};
|
|
|
|
|
|
|
|
ret = poll(&pfd, 1, 1000);
|
|
|
|
if (ret == 1) {
|
2016-06-19 19:23:19 +02:00
|
|
|
uint64_t counter = intc_wait(f, timer->irq);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
info("Got IRQ: counter = %ju", counter);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
if (counter == 1)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
warn("Counter was not 1");
|
|
|
|
}
|
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
intc_disable(f->intc, (1 << timer->irq));
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
int fpga_test_rtds_rtt(struct fpga *f)
|
2016-06-14 01:19:17 +02:00
|
|
|
{
|
2016-06-15 20:05:09 +02:00
|
|
|
#if 0
|
|
|
|
uint32_t tsc = 0;
|
2016-06-14 01:19:17 +02:00
|
|
|
ssize_t len;
|
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
intc_enable(f->intc, (1 << MSI_DMA_MM2S) | (1 << MSI_DMA_S2MM));
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
/* Dump RTDS AXI Stream state */
|
|
|
|
rtds_axis_dump(f->map + BASEADDR_RTDS);
|
|
|
|
|
|
|
|
/* Get some random data to compare */
|
|
|
|
uint32_t *data_rx = (uint32_t *) (f->dma);
|
|
|
|
uint32_t *data_tx = (uint32_t *) (f->dma + 0x1000);
|
|
|
|
|
|
|
|
/* Setup crossbar switch */
|
2016-06-19 19:23:19 +02:00
|
|
|
switch_connect(sw, AXIS_SWITCH_RTDS, switch_port);
|
|
|
|
switch_connect(sw, switch_port, AXIS_SWITCH_RTDS);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
/* Disable blocking Overflow status */
|
|
|
|
int flags = fcntl(f->vd.msi_efds[MSI_RTDS_OVF], F_GETFL, 0);
|
|
|
|
fcntl(f->vd.msi_efds[MSI_RTDS_OVF], F_SETFL, flags | O_NONBLOCK);
|
|
|
|
|
|
|
|
int irq_fifo = f->vd.msi_efds[MSI_FIFO_MM];
|
|
|
|
int rtt2_prev, rtt2;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
#if 0 /* Wait for TS */
|
2016-06-19 19:23:19 +02:00
|
|
|
tsc += intc_wait(f->intc, MSI_RTDS_TS);
|
2016-06-14 01:19:17 +02:00
|
|
|
#else
|
|
|
|
tsc++;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if 0 /* Check for overflow */
|
2016-06-19 19:23:19 +02:00
|
|
|
ovfl += intc_wait(f->intc, MSI_RTDS_OVF);
|
2016-06-14 01:19:17 +02:00
|
|
|
if (tsc % 20000 == 0)
|
|
|
|
warn("Missed %u timesteps", ovfl);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if DATAMOVER == RTDS_DM_FIFO
|
|
|
|
retry: len = fifo_read(&f->fifo, (char *) data_rx, 0x1000, irq_fifo);
|
|
|
|
if (XLlFifo_RxOccupancy(&f->fifo) > 0 )
|
|
|
|
goto retry;
|
|
|
|
#elif DATAMOVER == RTDS_DM_DMA_SIMPLE
|
|
|
|
len = dma_read(&f->dma_simple, virt_to_dma(data_rx, f->dma), 0x1000, -1);//f->vd.msi_efds[MSI_DMA_S2MM]);
|
|
|
|
uint64_t start = rdtscp();
|
|
|
|
XAxiDma_IntrAckIrq(&f->dma_simple, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA);
|
|
|
|
#elif DATAMOVER == RTDS_DM_DMA_SG
|
|
|
|
len = dma_read(&f->dma_sg, virt_to_dma(data_rx, f->dma), 0x1000, f->vd.msi_efds[MSI_DMA_S2MM]);
|
|
|
|
#endif
|
|
|
|
values_rx = len / sizeof(uint32_t);
|
|
|
|
|
|
|
|
for (int i = 0; i < values_tx; i++)
|
|
|
|
data_tx[i] = data_rx[i];
|
|
|
|
|
|
|
|
data_tx[3] = tsc;
|
|
|
|
|
|
|
|
if (data_rx[3] == 0)
|
|
|
|
tsc = 0;
|
|
|
|
|
|
|
|
int rtt = tsc - data_rx[3];
|
|
|
|
|
|
|
|
rtt2_prev = rtt2;
|
|
|
|
rtt2 = tsc - data_rx[0];
|
|
|
|
|
|
|
|
rdtsc_sleep(30000, start);
|
|
|
|
|
|
|
|
#if DATAMOVER == RTDS_DM_FIFO
|
|
|
|
len = fifo_write(&f->fifo, (char *) data_tx, sizeof(uint32_t) * values_tx, irq_fifo);
|
|
|
|
if (len != sizeof(uint32_t) * values_tx)
|
|
|
|
error("Failed to send to FIFO");
|
|
|
|
#elif DATAMOVER == RTDS_DM_DMA_SIMPLE
|
|
|
|
len = dma_write(&f->dma_simple, virt_to_dma(data_tx, f->dma), sizeof(uint32_t) * values_tx, -1);//f->vd.msi_efds[MSI_DMA_MM2S]);
|
|
|
|
XAxiDma_IntrAckIrq(&f->dma_simple, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DMA_TO_DEVICE);
|
|
|
|
#elif DATAMOVER == RTDS_DM_DMA_SG
|
|
|
|
len = dma_write(&f->dma_sg, virt_to_dma(data_tx, f->dma), sizeof(uint32_t) * values_tx, f->vd.msi_efds[MSI_DMA_MM2S]);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
intc_disable(f->intc, (1 << MSI_DMA_MM2S) | (1 << MSI_DMA_S2MM));
|
2016-06-15 20:05:09 +02:00
|
|
|
#endif
|
2016-06-14 01:19:17 +02:00
|
|
|
return 0;
|
|
|
|
}
|