xref: /dpdk/drivers/raw/ifpga/afu_pmd_n3000.c (revision f665790a5dbad7b645ff46f31d65e977324e7bfc)
17d63899aSWei Huang /* SPDX-License-Identifier: BSD-3-Clause
27d63899aSWei Huang  * Copyright(c) 2022 Intel Corporation
37d63899aSWei Huang  */
47d63899aSWei Huang 
57d63899aSWei Huang #include <errno.h>
67d63899aSWei Huang #include <stdio.h>
77d63899aSWei Huang #include <stdint.h>
87d63899aSWei Huang #include <stdlib.h>
97d63899aSWei Huang #include <inttypes.h>
107d63899aSWei Huang #include <unistd.h>
117d63899aSWei Huang #include <fcntl.h>
127d63899aSWei Huang #include <poll.h>
137d63899aSWei Huang #include <sys/eventfd.h>
147d63899aSWei Huang #include <sys/ioctl.h>
157d63899aSWei Huang 
167d63899aSWei Huang #include <rte_eal.h>
177d63899aSWei Huang #include <rte_malloc.h>
187d63899aSWei Huang #include <rte_memcpy.h>
197d63899aSWei Huang #include <rte_io.h>
207d63899aSWei Huang #include <rte_vfio.h>
211f37cb2bSDavid Marchand #include <bus_pci_driver.h>
22925c074eSDavid Marchand #include <bus_ifpga_driver.h>
237d63899aSWei Huang #include <rte_rawdev.h>
247d63899aSWei Huang 
257d63899aSWei Huang #include "afu_pmd_core.h"
267d63899aSWei Huang #include "afu_pmd_n3000.h"
277d63899aSWei Huang 
287d63899aSWei Huang static int nlb_afu_config(struct afu_rawdev *dev)
297d63899aSWei Huang {
307d63899aSWei Huang 	struct n3000_afu_priv *priv = NULL;
317d63899aSWei Huang 	struct rte_pmd_afu_nlb_cfg *cfg = NULL;
327d63899aSWei Huang 	struct nlb_csr_cfg v;
337d63899aSWei Huang 
347d63899aSWei Huang 	if (!dev)
357d63899aSWei Huang 		return -EINVAL;
367d63899aSWei Huang 
377d63899aSWei Huang 	if (!dev->priv)
387d63899aSWei Huang 		return -ENOENT;
397d63899aSWei Huang 
407d63899aSWei Huang 	priv = (struct n3000_afu_priv *)dev->priv;
417d63899aSWei Huang 	cfg = &priv->nlb_cfg;
427d63899aSWei Huang 
437d63899aSWei Huang 	v.csr = 0;
447d63899aSWei Huang 
457d63899aSWei Huang 	if (cfg->cont)
467d63899aSWei Huang 		v.cont = 1;
477d63899aSWei Huang 
487d63899aSWei Huang 	if (cfg->cache_policy == NLB_WRPUSH_I)
497d63899aSWei Huang 		v.wrpush_i = 1;
507d63899aSWei Huang 	else
517d63899aSWei Huang 		v.wrthru_en = cfg->cache_policy;
527d63899aSWei Huang 
537d63899aSWei Huang 	if (cfg->cache_hint == NLB_RDLINE_MIXED)
547d63899aSWei Huang 		v.rdsel = 3;
557d63899aSWei Huang 	else
567d63899aSWei Huang 		v.rdsel = cfg->cache_hint;
577d63899aSWei Huang 
587d63899aSWei Huang 	v.mode = cfg->mode;
597d63899aSWei Huang 	v.chsel = cfg->read_vc;
607d63899aSWei Huang 	v.wr_chsel = cfg->write_vc;
617d63899aSWei Huang 	v.wrfence_chsel = cfg->wrfence_vc;
627d63899aSWei Huang 	v.wrthru_en = cfg->cache_policy;
637d63899aSWei Huang 	v.multicl_len = cfg->multi_cl - 1;
647d63899aSWei Huang 
657d63899aSWei Huang 	IFPGA_RAWDEV_PMD_DEBUG("cfg: 0x%08x", v.csr);
667d63899aSWei Huang 	rte_write32(v.csr, priv->nlb_ctx.addr + CSR_CFG);
677d63899aSWei Huang 
687d63899aSWei Huang 	return 0;
697d63899aSWei Huang }
707d63899aSWei Huang 
717d63899aSWei Huang static void nlb_afu_report(struct afu_rawdev *dev, uint32_t cl)
727d63899aSWei Huang {
737d63899aSWei Huang 	struct n3000_afu_priv *priv = NULL;
747d63899aSWei Huang 	struct rte_pmd_afu_nlb_cfg *cfg = NULL;
757d63899aSWei Huang 	struct nlb_dsm_status *stat = NULL;
767d63899aSWei Huang 	uint64_t ticks = 0;
777d63899aSWei Huang 	double num, rd_bw, wr_bw;
787d63899aSWei Huang 
797d63899aSWei Huang 	if (!dev || !dev->priv)
807d63899aSWei Huang 		return;
817d63899aSWei Huang 
827d63899aSWei Huang 	priv = (struct n3000_afu_priv *)dev->priv;
837d63899aSWei Huang 
847d63899aSWei Huang 	cfg = &priv->nlb_cfg;
857d63899aSWei Huang 	stat = priv->nlb_ctx.status_ptr;
867d63899aSWei Huang 
877d63899aSWei Huang 	if (cfg->cont)
887d63899aSWei Huang 		ticks = stat->num_clocks - stat->start_overhead;
897d63899aSWei Huang 	else
907d63899aSWei Huang 		ticks = stat->num_clocks -
917d63899aSWei Huang 			(stat->start_overhead + stat->end_overhead);
927d63899aSWei Huang 
937d63899aSWei Huang 	if (cfg->freq_mhz == 0)
947d63899aSWei Huang 		cfg->freq_mhz = 200;
957d63899aSWei Huang 
967d63899aSWei Huang 	num = (double)stat->num_reads;
977d63899aSWei Huang 	rd_bw = (num * CLS_TO_SIZE(1) * MHZ(cfg->freq_mhz)) / ticks;
987d63899aSWei Huang 	num = (double)stat->num_writes;
997d63899aSWei Huang 	wr_bw = (num * CLS_TO_SIZE(1) * MHZ(cfg->freq_mhz)) / ticks;
1007d63899aSWei Huang 
1017d63899aSWei Huang 	printf("Cachelines  Read_Count Write_Count Clocks@%uMHz   "
1027d63899aSWei Huang 		"Rd_Bandwidth   Wr_Bandwidth\n", cfg->freq_mhz);
1037d63899aSWei Huang 	printf("%10u  %10u %11u  %12"PRIu64"   %7.3f GB/s   %7.3f GB/s\n",
1047d63899aSWei Huang 		cl, stat->num_reads, stat->num_writes, ticks,
1057d63899aSWei Huang 		rd_bw / 1e9, wr_bw / 1e9);
1067d63899aSWei Huang }
1077d63899aSWei Huang 
1087d63899aSWei Huang static int nlb_afu_test(struct afu_rawdev *dev)
1097d63899aSWei Huang {
1107d63899aSWei Huang 	struct n3000_afu_priv *priv = NULL;
1117d63899aSWei Huang 	struct nlb_afu_ctx *ctx = NULL;
1127d63899aSWei Huang 	struct rte_pmd_afu_nlb_cfg *cfg = NULL;
1137d63899aSWei Huang 	struct nlb_csr_ctl ctl;
1147d63899aSWei Huang 	uint32_t *ptr = NULL;
1157d63899aSWei Huang 	uint32_t i, j, cl, val = 0;
1167d63899aSWei Huang 	uint64_t sval = 0;
1177d63899aSWei Huang 	int ret = 0;
1187d63899aSWei Huang 
1197d63899aSWei Huang 	if (!dev)
1207d63899aSWei Huang 		return -EINVAL;
1217d63899aSWei Huang 
1227d63899aSWei Huang 	if (!dev->priv)
1237d63899aSWei Huang 		return -ENOENT;
1247d63899aSWei Huang 
1257d63899aSWei Huang 	priv = (struct n3000_afu_priv *)dev->priv;
1267d63899aSWei Huang 	ctx = &priv->nlb_ctx;
1277d63899aSWei Huang 	cfg = &priv->nlb_cfg;
1287d63899aSWei Huang 
1297d63899aSWei Huang 	/* initialize registers */
1307d63899aSWei Huang 	IFPGA_RAWDEV_PMD_DEBUG("dsm_addr: 0x%"PRIx64, ctx->dsm_iova);
1317d63899aSWei Huang 	rte_write64(ctx->dsm_iova, ctx->addr + CSR_AFU_DSM_BASEL);
1327d63899aSWei Huang 
1337d63899aSWei Huang 	ctl.csr = 0;
1347d63899aSWei Huang 	rte_write32(ctl.csr, ctx->addr + CSR_CTL);
1357d63899aSWei Huang 	ctl.reset = 1;
1367d63899aSWei Huang 	rte_write32(ctl.csr, ctx->addr + CSR_CTL);
1377d63899aSWei Huang 
1387d63899aSWei Huang 	IFPGA_RAWDEV_PMD_DEBUG("src_addr: 0x%"PRIx64, ctx->src_iova);
1397d63899aSWei Huang 	rte_write64(SIZE_TO_CLS(ctx->src_iova), ctx->addr + CSR_SRC_ADDR);
1407d63899aSWei Huang 	IFPGA_RAWDEV_PMD_DEBUG("dst_addr: 0x%"PRIx64, ctx->dest_iova);
1417d63899aSWei Huang 	rte_write64(SIZE_TO_CLS(ctx->dest_iova), ctx->addr + CSR_DST_ADDR);
1427d63899aSWei Huang 
1437d63899aSWei Huang 	ret = nlb_afu_config(dev);
1447d63899aSWei Huang 	if (ret)
1457d63899aSWei Huang 		return ret;
1467d63899aSWei Huang 
1477d63899aSWei Huang 	/* initialize src data */
1487d63899aSWei Huang 	ptr = (uint32_t *)ctx->src_ptr;
1497d63899aSWei Huang 	j = CLS_TO_SIZE(cfg->end) >> 2;
1507d63899aSWei Huang 	for (i = 0; i < j; i++)
1517d63899aSWei Huang 		*ptr++ = i;
1527d63899aSWei Huang 
1537d63899aSWei Huang 	/* start test */
1547d63899aSWei Huang 	for (cl = cfg->begin; cl <= cfg->end; cl += cfg->multi_cl) {
1557d63899aSWei Huang 		memset(ctx->dest_ptr, 0, CLS_TO_SIZE(cl));
1567d63899aSWei Huang 		memset(ctx->dsm_ptr, 0, DSM_SIZE);
1577d63899aSWei Huang 
1587d63899aSWei Huang 		ctl.csr = 0;
1597d63899aSWei Huang 		rte_write32(ctl.csr, ctx->addr + CSR_CTL);
1607d63899aSWei Huang 		ctl.reset = 1;
1617d63899aSWei Huang 		rte_write32(ctl.csr, ctx->addr + CSR_CTL);
1627d63899aSWei Huang 
1637d63899aSWei Huang 		rte_write32(cl, ctx->addr + CSR_NUM_LINES);
1647d63899aSWei Huang 
1657d63899aSWei Huang 		rte_delay_us(10);
1667d63899aSWei Huang 
1677d63899aSWei Huang 		ctl.start = 1;
1687d63899aSWei Huang 		rte_write32(ctl.csr, ctx->addr + CSR_CTL);
1697d63899aSWei Huang 
1707d63899aSWei Huang 		if (cfg->cont) {
1717d63899aSWei Huang 			rte_delay_ms(cfg->timeout * 1000);
1727d63899aSWei Huang 			ctl.force_completion = 1;
1737d63899aSWei Huang 			rte_write32(ctl.csr, ctx->addr + CSR_CTL);
1747d63899aSWei Huang 			ret = dsm_poll_timeout(&ctx->status_ptr->test_complete,
1757d63899aSWei Huang 				val, (val & 0x1) == 1, DSM_POLL_INTERVAL,
1767d63899aSWei Huang 				DSM_TIMEOUT);
1777d63899aSWei Huang 			if (ret) {
1787d63899aSWei Huang 				printf("DSM poll timeout\n");
1797d63899aSWei Huang 				goto end;
1807d63899aSWei Huang 			}
1817d63899aSWei Huang 		} else {
1827d63899aSWei Huang 			ret = dsm_poll_timeout(&ctx->status_ptr->test_complete,
1837d63899aSWei Huang 				val, (val & 0x1) == 1, DSM_POLL_INTERVAL,
1847d63899aSWei Huang 				DSM_TIMEOUT);
1857d63899aSWei Huang 			if (ret) {
1867d63899aSWei Huang 				printf("DSM poll timeout\n");
1877d63899aSWei Huang 				goto end;
1887d63899aSWei Huang 			}
1897d63899aSWei Huang 			ctl.force_completion = 1;
1907d63899aSWei Huang 			rte_write32(ctl.csr, ctx->addr + CSR_CTL);
1917d63899aSWei Huang 		}
1927d63899aSWei Huang 
1937d63899aSWei Huang 		nlb_afu_report(dev, cl);
1947d63899aSWei Huang 
1957d63899aSWei Huang 		i = 0;
1967d63899aSWei Huang 		while (i++ < 100) {
1977d63899aSWei Huang 			sval = rte_read64(ctx->addr + CSR_STATUS1);
1987d63899aSWei Huang 			if (sval == 0)
1997d63899aSWei Huang 				break;
2007d63899aSWei Huang 			rte_delay_us(1000);
2017d63899aSWei Huang 		}
2027d63899aSWei Huang 
2037d63899aSWei Huang 		ptr = (uint32_t *)ctx->dest_ptr;
2047d63899aSWei Huang 		j = CLS_TO_SIZE(cl) >> 2;
2057d63899aSWei Huang 		for (i = 0; i < j; i++) {
2067d63899aSWei Huang 			if (*ptr++ != i) {
2077d63899aSWei Huang 				IFPGA_RAWDEV_PMD_ERR("Data mismatch @ %u", i);
2087d63899aSWei Huang 				break;
2097d63899aSWei Huang 			}
2107d63899aSWei Huang 		}
2117d63899aSWei Huang 	}
2127d63899aSWei Huang 
2137d63899aSWei Huang end:
2147d63899aSWei Huang 	return ret;
2157d63899aSWei Huang }
2167d63899aSWei Huang 
2177d63899aSWei Huang static void dma_afu_buf_free(struct dma_afu_ctx *ctx)
2187d63899aSWei Huang {
2197d63899aSWei Huang 	int i = 0;
2207d63899aSWei Huang 
2217d63899aSWei Huang 	if (!ctx)
2227d63899aSWei Huang 		return;
2237d63899aSWei Huang 
2247d63899aSWei Huang 	for (i = 0; i < NUM_DMA_BUF; i++) {
2257d63899aSWei Huang 		rte_free(ctx->dma_buf[i]);
2267d63899aSWei Huang 		ctx->dma_buf[i] = NULL;
2277d63899aSWei Huang 	}
2287d63899aSWei Huang 
2297d63899aSWei Huang 	rte_free(ctx->data_buf);
2307d63899aSWei Huang 	ctx->data_buf = NULL;
2317d63899aSWei Huang 
2327d63899aSWei Huang 	rte_free(ctx->ref_buf);
2337d63899aSWei Huang 	ctx->ref_buf = NULL;
2347d63899aSWei Huang }
2357d63899aSWei Huang 
2367d63899aSWei Huang static int dma_afu_buf_alloc(struct dma_afu_ctx *ctx,
2377d63899aSWei Huang 	struct rte_pmd_afu_dma_cfg *cfg)
2387d63899aSWei Huang {
2397d63899aSWei Huang 	size_t page_sz = sysconf(_SC_PAGE_SIZE);
2407d63899aSWei Huang 	int i, ret = 0;
2417d63899aSWei Huang 
2427d63899aSWei Huang 	if (!ctx || !cfg)
2437d63899aSWei Huang 		return -EINVAL;
2447d63899aSWei Huang 
2457d63899aSWei Huang 	for (i = 0; i < NUM_DMA_BUF; i++) {
2467d63899aSWei Huang 		ctx->dma_buf[i] = (uint64_t *)rte_zmalloc(NULL, cfg->size,
2477d63899aSWei Huang 			TEST_MEM_ALIGN);
2487d63899aSWei Huang 		if (!ctx->dma_buf[i]) {
2497d63899aSWei Huang 			ret = -ENOMEM;
2507d63899aSWei Huang 			goto free_dma_buf;
2517d63899aSWei Huang 		}
2527d63899aSWei Huang 		ctx->dma_iova[i] = rte_malloc_virt2iova(ctx->dma_buf[i]);
2537d63899aSWei Huang 		if (ctx->dma_iova[i] == RTE_BAD_IOVA) {
2547d63899aSWei Huang 			ret = -ENOMEM;
2557d63899aSWei Huang 			goto free_dma_buf;
2567d63899aSWei Huang 		}
2577d63899aSWei Huang 	}
2587d63899aSWei Huang 
2597d63899aSWei Huang 	ctx->data_buf = rte_malloc(NULL, cfg->length, page_sz);
2607d63899aSWei Huang 	if (!ctx->data_buf) {
2617d63899aSWei Huang 		ret = -ENOMEM;
2627d63899aSWei Huang 		goto free_dma_buf;
2637d63899aSWei Huang 	}
2647d63899aSWei Huang 
2657d63899aSWei Huang 	ctx->ref_buf = rte_malloc(NULL, cfg->length, page_sz);
2667d63899aSWei Huang 	if (!ctx->ref_buf) {
2677d63899aSWei Huang 		ret = -ENOMEM;
2687d63899aSWei Huang 		goto free_data_buf;
2697d63899aSWei Huang 	}
2707d63899aSWei Huang 
2717d63899aSWei Huang 	return 0;
2727d63899aSWei Huang 
2737d63899aSWei Huang free_data_buf:
2747d63899aSWei Huang 	rte_free(ctx->data_buf);
2757d63899aSWei Huang 	ctx->data_buf = NULL;
2767d63899aSWei Huang free_dma_buf:
2777d63899aSWei Huang 	for (i = 0; i < NUM_DMA_BUF; i++) {
2787d63899aSWei Huang 		rte_free(ctx->dma_buf[i]);
2797d63899aSWei Huang 		ctx->dma_buf[i] = NULL;
2807d63899aSWei Huang 	}
2817d63899aSWei Huang 	return ret;
2827d63899aSWei Huang }
2837d63899aSWei Huang 
2847d63899aSWei Huang static void dma_afu_buf_init(struct dma_afu_ctx *ctx, size_t size)
2857d63899aSWei Huang {
2867d63899aSWei Huang 	int *ptr = NULL;
2877d63899aSWei Huang 	size_t i = 0;
2887d63899aSWei Huang 	size_t dword_size = 0;
2897d63899aSWei Huang 
2907d63899aSWei Huang 	if (!ctx || !size)
2917d63899aSWei Huang 		return;
2927d63899aSWei Huang 
2937d63899aSWei Huang 	ptr = (int *)ctx->ref_buf;
2947d63899aSWei Huang 
2957d63899aSWei Huang 	if (ctx->pattern) {
2967d63899aSWei Huang 		memset(ptr, ctx->pattern, size);
2977d63899aSWei Huang 	} else {
2987d63899aSWei Huang 		srand(99);
2997d63899aSWei Huang 		dword_size = size >> 2;
3007d63899aSWei Huang 		for (i = 0; i < dword_size; i++)
3017d63899aSWei Huang 			*ptr++ = rand();
3027d63899aSWei Huang 	}
3037d63899aSWei Huang 	rte_memcpy(ctx->data_buf, ctx->ref_buf, size);
3047d63899aSWei Huang }
3057d63899aSWei Huang 
3067d63899aSWei Huang static int dma_afu_buf_verify(struct dma_afu_ctx *ctx, size_t size)
3077d63899aSWei Huang {
3087d63899aSWei Huang 	uint8_t *src = NULL;
3097d63899aSWei Huang 	uint8_t *dst = NULL;
3107d63899aSWei Huang 	size_t i = 0;
3117d63899aSWei Huang 	int n = 0;
3127d63899aSWei Huang 
3137d63899aSWei Huang 	if (!ctx || !size)
3147d63899aSWei Huang 		return -EINVAL;
3157d63899aSWei Huang 
3167d63899aSWei Huang 	src = (uint8_t *)ctx->ref_buf;
3177d63899aSWei Huang 	dst = (uint8_t *)ctx->data_buf;
3187d63899aSWei Huang 
3197d63899aSWei Huang 	if (memcmp(src, dst, size)) {
3207d63899aSWei Huang 		printf("Transfer is corrupted\n");
3217d63899aSWei Huang 		if (ctx->verbose) {
3227d63899aSWei Huang 			for (i = 0; i < size; i++) {
3237d63899aSWei Huang 				if (*src != *dst) {
3247d63899aSWei Huang 					if (++n >= ERR_CHECK_LIMIT)
3257d63899aSWei Huang 						break;
3267d63899aSWei Huang 					printf("Mismatch at 0x%zx, "
3277d63899aSWei Huang 						"Expected %02x  Actual %02x\n",
3287d63899aSWei Huang 						i, *src, *dst);
3297d63899aSWei Huang 				}
3307d63899aSWei Huang 				src++;
3317d63899aSWei Huang 				dst++;
3327d63899aSWei Huang 			}
3337d63899aSWei Huang 			if (n < ERR_CHECK_LIMIT) {
3347d63899aSWei Huang 				printf("Found %d error bytes\n", n);
3357d63899aSWei Huang 			} else {
3367d63899aSWei Huang 				printf("......\n");
3377d63899aSWei Huang 				printf("Found more than %d error bytes\n", n);
3387d63899aSWei Huang 			}
3397d63899aSWei Huang 		}
3407d63899aSWei Huang 		return -1;
3417d63899aSWei Huang 	}
3427d63899aSWei Huang 
3437d63899aSWei Huang 	printf("Transfer is verified\n");
3447d63899aSWei Huang 	return 0;
3457d63899aSWei Huang }
3467d63899aSWei Huang 
3477d63899aSWei Huang static void blk_write64(uint64_t *dev_addr, uint64_t *host_addr, uint64_t bytes)
3487d63899aSWei Huang {
3497d63899aSWei Huang 	uint64_t qwords = bytes / sizeof(uint64_t);
3507d63899aSWei Huang 
3517d63899aSWei Huang 	if (!IS_ALIGNED_QWORD((uint64_t)dev_addr) ||
3527d63899aSWei Huang 		!IS_ALIGNED_QWORD((uint64_t)bytes))
3537d63899aSWei Huang 		return;
3547d63899aSWei Huang 
3557d63899aSWei Huang 	for (; qwords > 0; qwords--, host_addr++, dev_addr++)
3567d63899aSWei Huang 		rte_write64(*host_addr, dev_addr);
3577d63899aSWei Huang }
3587d63899aSWei Huang 
3597d63899aSWei Huang static void blk_read64(uint64_t *dev_addr, uint64_t *host_addr, uint64_t bytes)
3607d63899aSWei Huang {
3617d63899aSWei Huang 	uint64_t qwords = bytes / sizeof(uint64_t);
3627d63899aSWei Huang 
3637d63899aSWei Huang 	if (!IS_ALIGNED_QWORD((uint64_t)dev_addr) ||
3647d63899aSWei Huang 		!IS_ALIGNED_QWORD((uint64_t)bytes))
3657d63899aSWei Huang 		return;
3667d63899aSWei Huang 
3677d63899aSWei Huang 	for (; qwords > 0; qwords--, host_addr++, dev_addr++)
3687d63899aSWei Huang 		*host_addr = rte_read64(dev_addr);
3697d63899aSWei Huang }
3707d63899aSWei Huang 
3717d63899aSWei Huang static void switch_ase_page(struct dma_afu_ctx *ctx, uint64_t addr)
3727d63899aSWei Huang {
3737d63899aSWei Huang 	uint64_t requested_page = addr & ~DMA_ASE_WINDOW_MASK;
3747d63899aSWei Huang 
3757d63899aSWei Huang 	if (!ctx)
3767d63899aSWei Huang 		return;
3777d63899aSWei Huang 
3787d63899aSWei Huang 	if (requested_page != ctx->cur_ase_page) {
3797d63899aSWei Huang 		rte_write64(requested_page, ctx->ase_ctrl_addr);
3807d63899aSWei Huang 		ctx->cur_ase_page = requested_page;
3817d63899aSWei Huang 	}
3827d63899aSWei Huang }
3837d63899aSWei Huang 
3847d63899aSWei Huang static int ase_write_unaligned(struct dma_afu_ctx *ctx, uint64_t dev_addr,
3857d63899aSWei Huang 	uint64_t host_addr, uint32_t count)
3867d63899aSWei Huang {
3877d63899aSWei Huang 	uint64_t dev_aligned_addr = 0;
3887d63899aSWei Huang 	uint64_t shift = 0;
3897d63899aSWei Huang 	uint64_t val = 0;
3907d63899aSWei Huang 	uintptr_t addr = (uintptr_t)host_addr;  /* transfer to pointer size */
3917d63899aSWei Huang 
3927d63899aSWei Huang 	IFPGA_RAWDEV_PMD_DEBUG("0x%"PRIx64" --> 0x%"PRIx64" (0x%x)", host_addr,
3937d63899aSWei Huang 		dev_addr, count);
3947d63899aSWei Huang 
3957d63899aSWei Huang 	if (!ctx || (count >= QWORD_BYTES))
3967d63899aSWei Huang 		return -EINVAL;
3977d63899aSWei Huang 
3987d63899aSWei Huang 	if (!count)
3997d63899aSWei Huang 		return 0;
4007d63899aSWei Huang 
4017d63899aSWei Huang 	switch_ase_page(ctx, dev_addr);
4027d63899aSWei Huang 
4037d63899aSWei Huang 	shift = dev_addr % QWORD_BYTES;
4047d63899aSWei Huang 	dev_aligned_addr = (dev_addr - shift) & DMA_ASE_WINDOW_MASK;
4057d63899aSWei Huang 	val = rte_read64(ctx->ase_data_addr + dev_aligned_addr);
4067d63899aSWei Huang 	rte_memcpy(((char *)(&val)) + shift, (void *)addr, count);
4077d63899aSWei Huang 
4087d63899aSWei Huang 	/* write back to device */
4097d63899aSWei Huang 	rte_write64(val, ctx->ase_data_addr + dev_aligned_addr);
4107d63899aSWei Huang 
4117d63899aSWei Huang 	return 0;
4127d63899aSWei Huang }
4137d63899aSWei Huang 
4147d63899aSWei Huang static int ase_write(struct dma_afu_ctx *ctx, uint64_t *dst_ptr,
4157d63899aSWei Huang 	uint64_t *src_ptr, uint64_t *count)
4167d63899aSWei Huang {
4177d63899aSWei Huang 	uint64_t src = *src_ptr;
4187d63899aSWei Huang 	uint64_t dst = *dst_ptr;
4197d63899aSWei Huang 	uint64_t align_bytes = *count;
4207d63899aSWei Huang 	uint64_t offset = 0;
4217d63899aSWei Huang 	uint64_t left_in_page = DMA_ASE_WINDOW;
4227d63899aSWei Huang 	uint64_t size_to_copy = 0;
4237d63899aSWei Huang 
4247d63899aSWei Huang 	IFPGA_RAWDEV_PMD_DEBUG("0x%"PRIx64" --> 0x%"PRIx64" (0x%"PRIx64")", src, dst,
4257d63899aSWei Huang 		align_bytes);
4267d63899aSWei Huang 
4277d63899aSWei Huang 	if (!ctx || !IS_ALIGNED_DWORD(dst))
4287d63899aSWei Huang 		return -EINVAL;
4297d63899aSWei Huang 
4307d63899aSWei Huang 	if (align_bytes < DWORD_BYTES)
4317d63899aSWei Huang 		return 0;
4327d63899aSWei Huang 
4337d63899aSWei Huang 	if (!IS_ALIGNED_QWORD(dst)) {
4347d63899aSWei Huang 		/* Write out a single DWORD to get QWORD aligned */
4357d63899aSWei Huang 		switch_ase_page(ctx, dst);
4367d63899aSWei Huang 		offset = dst & DMA_ASE_WINDOW_MASK;
4377d63899aSWei Huang 
4387d63899aSWei Huang 		rte_write32(*(uint32_t *)(uintptr_t)src,
4397d63899aSWei Huang 			ctx->ase_data_addr + offset);
4407d63899aSWei Huang 		src += DWORD_BYTES;
4417d63899aSWei Huang 		dst += DWORD_BYTES;
4427d63899aSWei Huang 		align_bytes -= DWORD_BYTES;
4437d63899aSWei Huang 	}
4447d63899aSWei Huang 
4457d63899aSWei Huang 	if (!align_bytes)
4467d63899aSWei Huang 		return 0;
4477d63899aSWei Huang 
4487d63899aSWei Huang 	/* Write out blocks of 64-bit values */
4497d63899aSWei Huang 	while (align_bytes >= QWORD_BYTES) {
4507d63899aSWei Huang 		left_in_page -= dst & DMA_ASE_WINDOW_MASK;
4517d63899aSWei Huang 		size_to_copy =
4527d63899aSWei Huang 			MIN(left_in_page, (align_bytes & ~(QWORD_BYTES - 1)));
4537d63899aSWei Huang 		if (size_to_copy < QWORD_BYTES)
4547d63899aSWei Huang 			break;
4557d63899aSWei Huang 		switch_ase_page(ctx, dst);
4567d63899aSWei Huang 		offset = dst & DMA_ASE_WINDOW_MASK;
4577d63899aSWei Huang 		blk_write64((uint64_t *)(ctx->ase_data_addr + offset),
4587d63899aSWei Huang 			(uint64_t *)(uintptr_t)src, size_to_copy);
4597d63899aSWei Huang 		src += size_to_copy;
4607d63899aSWei Huang 		dst += size_to_copy;
4617d63899aSWei Huang 		align_bytes -= size_to_copy;
4627d63899aSWei Huang 	}
4637d63899aSWei Huang 
4647d63899aSWei Huang 	if (align_bytes >= DWORD_BYTES) {
4657d63899aSWei Huang 		/* Write out remaining DWORD */
4667d63899aSWei Huang 		switch_ase_page(ctx, dst);
4677d63899aSWei Huang 		offset = dst & DMA_ASE_WINDOW_MASK;
4687d63899aSWei Huang 		rte_write32(*(uint32_t *)(uintptr_t)src,
4697d63899aSWei Huang 			ctx->ase_data_addr + offset);
4707d63899aSWei Huang 		src += DWORD_BYTES;
4717d63899aSWei Huang 		dst += DWORD_BYTES;
4727d63899aSWei Huang 		align_bytes -= DWORD_BYTES;
4737d63899aSWei Huang 	}
4747d63899aSWei Huang 
4757d63899aSWei Huang 	*src_ptr = src;
4767d63899aSWei Huang 	*dst_ptr = dst;
4777d63899aSWei Huang 	*count = align_bytes;
4787d63899aSWei Huang 
4797d63899aSWei Huang 	return 0;
4807d63899aSWei Huang }
4817d63899aSWei Huang 
4827d63899aSWei Huang static int ase_host_to_fpga(struct dma_afu_ctx *ctx, uint64_t *dst_ptr,
4837d63899aSWei Huang 	uint64_t *src_ptr, uint64_t count)
4847d63899aSWei Huang {
4857d63899aSWei Huang 	uint64_t dst = *dst_ptr;
4867d63899aSWei Huang 	uint64_t src = *src_ptr;
4877d63899aSWei Huang 	uint64_t count_left = count;
4887d63899aSWei Huang 	uint64_t unaligned_size = 0;
4897d63899aSWei Huang 	int ret = 0;
4907d63899aSWei Huang 
4917d63899aSWei Huang 	IFPGA_RAWDEV_PMD_DEBUG("0x%"PRIx64" --> 0x%"PRIx64" (0x%"PRIx64")", src, dst,
4927d63899aSWei Huang 		count);
4937d63899aSWei Huang 
4947d63899aSWei Huang 	/* aligns address to 8 byte using dst masking method */
4957d63899aSWei Huang 	if (!IS_ALIGNED_DWORD(dst) && !IS_ALIGNED_QWORD(dst)) {
4967d63899aSWei Huang 		unaligned_size = QWORD_BYTES - (dst % QWORD_BYTES);
4977d63899aSWei Huang 		if (unaligned_size > count_left)
4987d63899aSWei Huang 			unaligned_size = count_left;
4997d63899aSWei Huang 		ret = ase_write_unaligned(ctx, dst, src, unaligned_size);
5007d63899aSWei Huang 		if (ret)
5017d63899aSWei Huang 			return ret;
5027d63899aSWei Huang 		count_left -= unaligned_size;
5037d63899aSWei Huang 		src += unaligned_size;
5047d63899aSWei Huang 		dst += unaligned_size;
5057d63899aSWei Huang 	}
5067d63899aSWei Huang 
5077d63899aSWei Huang 	/* Handles 8/4 byte MMIO transfer */
5087d63899aSWei Huang 	ret = ase_write(ctx, &dst, &src, &count_left);
5097d63899aSWei Huang 	if (ret)
5107d63899aSWei Huang 		return ret;
5117d63899aSWei Huang 
5127d63899aSWei Huang 	/* Left over unaligned bytes transferred using dst masking method */
5137d63899aSWei Huang 	unaligned_size = QWORD_BYTES - (dst % QWORD_BYTES);
5147d63899aSWei Huang 	if (unaligned_size > count_left)
5157d63899aSWei Huang 		unaligned_size = count_left;
5167d63899aSWei Huang 
5177d63899aSWei Huang 	ret = ase_write_unaligned(ctx, dst, src, unaligned_size);
5187d63899aSWei Huang 	if (ret)
5197d63899aSWei Huang 		return ret;
5207d63899aSWei Huang 
5217d63899aSWei Huang 	count_left -= unaligned_size;
5227d63899aSWei Huang 	*dst_ptr = dst + unaligned_size;
5237d63899aSWei Huang 	*src_ptr = src + unaligned_size;
5247d63899aSWei Huang 
5257d63899aSWei Huang 	return 0;
5267d63899aSWei Huang }
5277d63899aSWei Huang 
5287d63899aSWei Huang static int ase_read_unaligned(struct dma_afu_ctx *ctx, uint64_t dev_addr,
5297d63899aSWei Huang 	uint64_t host_addr, uint32_t count)
5307d63899aSWei Huang {
5317d63899aSWei Huang 	uint64_t dev_aligned_addr = 0;
5327d63899aSWei Huang 	uint64_t shift = 0;
5337d63899aSWei Huang 	uint64_t val = 0;
5347d63899aSWei Huang 	uintptr_t addr = (uintptr_t)host_addr;  /* transfer to pointer size */
5357d63899aSWei Huang 
5367d63899aSWei Huang 	IFPGA_RAWDEV_PMD_DEBUG("0x%"PRIx64" <-- 0x%"PRIx64" (0x%x)", host_addr,
5377d63899aSWei Huang 		dev_addr, count);
5387d63899aSWei Huang 
5397d63899aSWei Huang 	if (!ctx || (count >= QWORD_BYTES))
5407d63899aSWei Huang 		return -EINVAL;
5417d63899aSWei Huang 
5427d63899aSWei Huang 	if (!count)
5437d63899aSWei Huang 		return 0;
5447d63899aSWei Huang 
5457d63899aSWei Huang 	switch_ase_page(ctx, dev_addr);
5467d63899aSWei Huang 
5477d63899aSWei Huang 	shift = dev_addr % QWORD_BYTES;
5487d63899aSWei Huang 	dev_aligned_addr = (dev_addr - shift) & DMA_ASE_WINDOW_MASK;
5497d63899aSWei Huang 	val = rte_read64(ctx->ase_data_addr + dev_aligned_addr);
5507d63899aSWei Huang 	rte_memcpy((void *)addr, ((char *)(&val)) + shift, count);
5517d63899aSWei Huang 
5527d63899aSWei Huang 	return 0;
5537d63899aSWei Huang }
5547d63899aSWei Huang 
5557d63899aSWei Huang static int ase_read(struct dma_afu_ctx *ctx, uint64_t *src_ptr,
5567d63899aSWei Huang 	uint64_t *dst_ptr, uint64_t *count)
5577d63899aSWei Huang {
5587d63899aSWei Huang 	uint64_t src = *src_ptr;
5597d63899aSWei Huang 	uint64_t dst = *dst_ptr;
5607d63899aSWei Huang 	uint64_t align_bytes = *count;
5617d63899aSWei Huang 	uint64_t offset = 0;
5627d63899aSWei Huang 	uint64_t left_in_page = DMA_ASE_WINDOW;
5637d63899aSWei Huang 	uint64_t size_to_copy = 0;
5647d63899aSWei Huang 
5657d63899aSWei Huang 	IFPGA_RAWDEV_PMD_DEBUG("0x%"PRIx64" <-- 0x%"PRIx64" (0x%"PRIx64")", dst, src,
5667d63899aSWei Huang 		align_bytes);
5677d63899aSWei Huang 
5687d63899aSWei Huang 	if (!ctx || !IS_ALIGNED_DWORD(src))
5697d63899aSWei Huang 		return -EINVAL;
5707d63899aSWei Huang 
5717d63899aSWei Huang 	if (align_bytes < DWORD_BYTES)
5727d63899aSWei Huang 		return 0;
5737d63899aSWei Huang 
5747d63899aSWei Huang 	if (!IS_ALIGNED_QWORD(src)) {
5757d63899aSWei Huang 		/* Read a single DWORD to get QWORD aligned */
5767d63899aSWei Huang 		switch_ase_page(ctx, src);
5777d63899aSWei Huang 		offset = src & DMA_ASE_WINDOW_MASK;
5787d63899aSWei Huang 		*(uint32_t *)(uintptr_t)dst =
5797d63899aSWei Huang 			rte_read32(ctx->ase_data_addr + offset);
5807d63899aSWei Huang 		src += DWORD_BYTES;
5817d63899aSWei Huang 		dst += DWORD_BYTES;
5827d63899aSWei Huang 		align_bytes -= DWORD_BYTES;
5837d63899aSWei Huang 	}
5847d63899aSWei Huang 
5857d63899aSWei Huang 	if (!align_bytes)
5867d63899aSWei Huang 		return 0;
5877d63899aSWei Huang 
5887d63899aSWei Huang 	/* Read blocks of 64-bit values */
5897d63899aSWei Huang 	while (align_bytes >= QWORD_BYTES) {
5907d63899aSWei Huang 		left_in_page -= src & DMA_ASE_WINDOW_MASK;
5917d63899aSWei Huang 		size_to_copy =
5927d63899aSWei Huang 			MIN(left_in_page, (align_bytes & ~(QWORD_BYTES - 1)));
5937d63899aSWei Huang 		if (size_to_copy < QWORD_BYTES)
5947d63899aSWei Huang 			break;
5957d63899aSWei Huang 		switch_ase_page(ctx, src);
5967d63899aSWei Huang 		offset = src & DMA_ASE_WINDOW_MASK;
5977d63899aSWei Huang 		blk_read64((uint64_t *)(ctx->ase_data_addr + offset),
5987d63899aSWei Huang 			(uint64_t *)(uintptr_t)dst, size_to_copy);
5997d63899aSWei Huang 		src += size_to_copy;
6007d63899aSWei Huang 		dst += size_to_copy;
6017d63899aSWei Huang 		align_bytes -= size_to_copy;
6027d63899aSWei Huang 	}
6037d63899aSWei Huang 
6047d63899aSWei Huang 	if (align_bytes >= DWORD_BYTES) {
6057d63899aSWei Huang 		/* Read remaining DWORD */
6067d63899aSWei Huang 		switch_ase_page(ctx, src);
6077d63899aSWei Huang 		offset = src & DMA_ASE_WINDOW_MASK;
6087d63899aSWei Huang 		*(uint32_t *)(uintptr_t)dst =
6097d63899aSWei Huang 			rte_read32(ctx->ase_data_addr + offset);
6107d63899aSWei Huang 		src += DWORD_BYTES;
6117d63899aSWei Huang 		dst += DWORD_BYTES;
6127d63899aSWei Huang 		align_bytes -= DWORD_BYTES;
6137d63899aSWei Huang 	}
6147d63899aSWei Huang 
6157d63899aSWei Huang 	*src_ptr = src;
6167d63899aSWei Huang 	*dst_ptr = dst;
6177d63899aSWei Huang 	*count = align_bytes;
6187d63899aSWei Huang 
6197d63899aSWei Huang 	return 0;
6207d63899aSWei Huang }
6217d63899aSWei Huang 
6227d63899aSWei Huang static int ase_fpga_to_host(struct dma_afu_ctx *ctx, uint64_t *src_ptr,
6237d63899aSWei Huang 	uint64_t *dst_ptr, uint64_t count)
6247d63899aSWei Huang {
6257d63899aSWei Huang 	uint64_t src = *src_ptr;
6267d63899aSWei Huang 	uint64_t dst = *dst_ptr;
6277d63899aSWei Huang 	uint64_t count_left = count;
6287d63899aSWei Huang 	uint64_t unaligned_size = 0;
6297d63899aSWei Huang 	int ret = 0;
6307d63899aSWei Huang 
6317d63899aSWei Huang 	IFPGA_RAWDEV_PMD_DEBUG("0x%"PRIx64" --> 0x%"PRIx64" (0x%"PRIx64")", src, dst,
6327d63899aSWei Huang 		count);
6337d63899aSWei Huang 
6347d63899aSWei Huang 	/* Aligns address to 8 byte using src masking method */
6357d63899aSWei Huang 	if (!IS_ALIGNED_DWORD(src) && !IS_ALIGNED_QWORD(src)) {
6367d63899aSWei Huang 		unaligned_size = QWORD_BYTES - (src % QWORD_BYTES);
6377d63899aSWei Huang 		if (unaligned_size > count_left)
6387d63899aSWei Huang 			unaligned_size = count_left;
6397d63899aSWei Huang 		ret = ase_read_unaligned(ctx, src, dst, unaligned_size);
6407d63899aSWei Huang 		if (ret)
6417d63899aSWei Huang 			return ret;
6427d63899aSWei Huang 		count_left -= unaligned_size;
6437d63899aSWei Huang 		dst += unaligned_size;
6447d63899aSWei Huang 		src += unaligned_size;
6457d63899aSWei Huang 	}
6467d63899aSWei Huang 
6477d63899aSWei Huang 	/* Handles 8/4 byte MMIO transfer */
6487d63899aSWei Huang 	ret = ase_read(ctx, &src, &dst, &count_left);
6497d63899aSWei Huang 	if (ret)
6507d63899aSWei Huang 		return ret;
6517d63899aSWei Huang 
6527d63899aSWei Huang 	/* Left over unaligned bytes transferred using src masking method */
6537d63899aSWei Huang 	unaligned_size = QWORD_BYTES - (src % QWORD_BYTES);
6547d63899aSWei Huang 	if (unaligned_size > count_left)
6557d63899aSWei Huang 		unaligned_size = count_left;
6567d63899aSWei Huang 
6577d63899aSWei Huang 	ret = ase_read_unaligned(ctx, src, dst, unaligned_size);
6587d63899aSWei Huang 	if (ret)
6597d63899aSWei Huang 		return ret;
6607d63899aSWei Huang 
6617d63899aSWei Huang 	count_left -= unaligned_size;
6627d63899aSWei Huang 	*dst_ptr = dst + unaligned_size;
6637d63899aSWei Huang 	*src_ptr = src + unaligned_size;
6647d63899aSWei Huang 
6657d63899aSWei Huang 	return 0;
6667d63899aSWei Huang }
6677d63899aSWei Huang 
6687d63899aSWei Huang static void clear_interrupt(struct dma_afu_ctx *ctx)
6697d63899aSWei Huang {
6707d63899aSWei Huang 	/* clear interrupt by writing 1 to IRQ bit in status register */
6717d63899aSWei Huang 	msgdma_status status;
6727d63899aSWei Huang 
6737d63899aSWei Huang 	if (!ctx)
6747d63899aSWei Huang 		return;
6757d63899aSWei Huang 
6767d63899aSWei Huang 	status.csr = 0;
6777d63899aSWei Huang 	status.irq = 1;
6787d63899aSWei Huang 	rte_write32(status.csr, CSR_STATUS(ctx->csr_addr));
6797d63899aSWei Huang }
6807d63899aSWei Huang 
6817d63899aSWei Huang static int poll_interrupt(struct dma_afu_ctx *ctx)
6827d63899aSWei Huang {
6837d63899aSWei Huang 	struct pollfd pfd = {0};
6847d63899aSWei Huang 	uint64_t count = 0;
6857d63899aSWei Huang 	ssize_t bytes_read = 0;
6867d63899aSWei Huang 	int poll_ret = 0;
6877d63899aSWei Huang 	int ret = 0;
6887d63899aSWei Huang 
6897d63899aSWei Huang 	if (!ctx || (ctx->event_fd < 0))
6907d63899aSWei Huang 		return -EINVAL;
6917d63899aSWei Huang 
6927d63899aSWei Huang 	pfd.fd = ctx->event_fd;
6937d63899aSWei Huang 	pfd.events = POLLIN;
6947d63899aSWei Huang 	poll_ret = poll(&pfd, 1, DMA_TIMEOUT_MSEC);
6957d63899aSWei Huang 	if (poll_ret < 0) {
6967d63899aSWei Huang 		IFPGA_RAWDEV_PMD_ERR("Error %s", strerror(errno));
6977d63899aSWei Huang 		ret = -EFAULT;
6987d63899aSWei Huang 		goto out;
6997d63899aSWei Huang 	} else if (poll_ret == 0) {
7007d63899aSWei Huang 		IFPGA_RAWDEV_PMD_ERR("Timeout");
7017d63899aSWei Huang 		ret = -ETIMEDOUT;
7027d63899aSWei Huang 	} else {
7037d63899aSWei Huang 		bytes_read = read(pfd.fd, &count, sizeof(count));
7047d63899aSWei Huang 		if (bytes_read > 0) {
7057d63899aSWei Huang 			if (ctx->verbose)
7067d63899aSWei Huang 				IFPGA_RAWDEV_PMD_DEBUG("Successful, ret %d, cnt %"PRIu64,
7077d63899aSWei Huang 					poll_ret, count);
7087d63899aSWei Huang 			ret = 0;
7097d63899aSWei Huang 		} else {
7107d63899aSWei Huang 			IFPGA_RAWDEV_PMD_ERR("Failed %s", bytes_read > 0 ?
7117d63899aSWei Huang 				strerror(errno) : "zero bytes read");
7127d63899aSWei Huang 			ret = -EIO;
7137d63899aSWei Huang 		}
7147d63899aSWei Huang 	}
7157d63899aSWei Huang out:
7167d63899aSWei Huang 	clear_interrupt(ctx);
7177d63899aSWei Huang 	return ret;
7187d63899aSWei Huang }
7197d63899aSWei Huang 
7207d63899aSWei Huang static void send_descriptor(struct dma_afu_ctx *ctx, msgdma_ext_desc *desc)
7217d63899aSWei Huang {
7227d63899aSWei Huang 	msgdma_status status;
7237d63899aSWei Huang 	uint64_t fpga_queue_full = 0;
7247d63899aSWei Huang 
7257d63899aSWei Huang 	if (!ctx)
7267d63899aSWei Huang 		return;
7277d63899aSWei Huang 
7287d63899aSWei Huang 	if (ctx->verbose) {
7297d63899aSWei Huang 		IFPGA_RAWDEV_PMD_DEBUG("descriptor.rd_address = 0x%x%08x",
7307d63899aSWei Huang 			desc->rd_address_ext, desc->rd_address);
7317d63899aSWei Huang 		IFPGA_RAWDEV_PMD_DEBUG("descriptor.wr_address = 0x%x%08x",
7327d63899aSWei Huang 			desc->wr_address_ext, desc->wr_address);
7337d63899aSWei Huang 		IFPGA_RAWDEV_PMD_DEBUG("descriptor.len = %u", desc->len);
7347d63899aSWei Huang 		IFPGA_RAWDEV_PMD_DEBUG("descriptor.wr_burst_count = %u",
7357d63899aSWei Huang 			desc->wr_burst_count);
7367d63899aSWei Huang 		IFPGA_RAWDEV_PMD_DEBUG("descriptor.rd_burst_count = %u",
7377d63899aSWei Huang 			desc->rd_burst_count);
7387d63899aSWei Huang 		IFPGA_RAWDEV_PMD_DEBUG("descriptor.wr_stride %u", desc->wr_stride);
7397d63899aSWei Huang 		IFPGA_RAWDEV_PMD_DEBUG("descriptor.rd_stride %u", desc->rd_stride);
7407d63899aSWei Huang 	}
7417d63899aSWei Huang 
7427d63899aSWei Huang 	do {
7437d63899aSWei Huang 		status.csr = rte_read32(CSR_STATUS(ctx->csr_addr));
7447d63899aSWei Huang 		if (fpga_queue_full++ > 100000000) {
7457d63899aSWei Huang 			IFPGA_RAWDEV_PMD_DEBUG("DMA queue full retry");
7467d63899aSWei Huang 			fpga_queue_full = 0;
7477d63899aSWei Huang 		}
7487d63899aSWei Huang 	} while (status.desc_buf_full);
7497d63899aSWei Huang 
7507d63899aSWei Huang 	blk_write64((uint64_t *)ctx->desc_addr, (uint64_t *)desc,
7517d63899aSWei Huang 		sizeof(*desc));
7527d63899aSWei Huang }
7537d63899aSWei Huang 
7547d63899aSWei Huang static int do_dma(struct dma_afu_ctx *ctx, uint64_t dst, uint64_t src,
7557d63899aSWei Huang 	int count, int is_last_desc, fpga_dma_type type, int intr_en)
7567d63899aSWei Huang {
7577d63899aSWei Huang 	msgdma_ext_desc *desc = NULL;
7587d63899aSWei Huang 	int alignment_offset = 0;
7597d63899aSWei Huang 	int segment_size = 0;
7607d63899aSWei Huang 
7617d63899aSWei Huang 	if (!ctx)
7627d63899aSWei Huang 		return -EINVAL;
7637d63899aSWei Huang 
7647d63899aSWei Huang 	/* src, dst and count must be 64-byte aligned */
7657d63899aSWei Huang 	if (!IS_DMA_ALIGNED(src) || !IS_DMA_ALIGNED(dst) ||
7667d63899aSWei Huang 		!IS_DMA_ALIGNED(count))
7677d63899aSWei Huang 		return -EINVAL;
7687d63899aSWei Huang 	memset(ctx->desc_buf, 0, sizeof(msgdma_ext_desc));
7697d63899aSWei Huang 
7707d63899aSWei Huang 	/* these fields are fixed for all DMA transfers */
7717d63899aSWei Huang 	desc = ctx->desc_buf;
7727d63899aSWei Huang 	desc->seq_num = 0;
7737d63899aSWei Huang 	desc->wr_stride = 1;
7747d63899aSWei Huang 	desc->rd_stride = 1;
7757d63899aSWei Huang 	desc->control.go = 1;
7767d63899aSWei Huang 	if (intr_en)
7777d63899aSWei Huang 		desc->control.transfer_irq_en = 1;
7787d63899aSWei Huang 	else
7797d63899aSWei Huang 		desc->control.transfer_irq_en = 0;
7807d63899aSWei Huang 
7817d63899aSWei Huang 	if (!is_last_desc)
7827d63899aSWei Huang 		desc->control.early_done_en = 1;
7837d63899aSWei Huang 	else
7847d63899aSWei Huang 		desc->control.early_done_en = 0;
7857d63899aSWei Huang 
7867d63899aSWei Huang 	if (type == FPGA_TO_FPGA) {
7877d63899aSWei Huang 		desc->rd_address = src & DMA_MASK_32_BIT;
7887d63899aSWei Huang 		desc->wr_address = dst & DMA_MASK_32_BIT;
7897d63899aSWei Huang 		desc->len = count;
7907d63899aSWei Huang 		desc->wr_burst_count = 4;
7917d63899aSWei Huang 		desc->rd_burst_count = 4;
7927d63899aSWei Huang 		desc->rd_address_ext = (src >> 32) & DMA_MASK_32_BIT;
7937d63899aSWei Huang 		desc->wr_address_ext = (dst >> 32) & DMA_MASK_32_BIT;
7947d63899aSWei Huang 		send_descriptor(ctx, desc);
7957d63899aSWei Huang 	} else {
7967d63899aSWei Huang 		/* check CCIP (host) address is aligned to 4CL (256B) */
7977d63899aSWei Huang 		alignment_offset = (type == HOST_TO_FPGA)
7987d63899aSWei Huang 			? (src % CCIP_ALIGN_BYTES) : (dst % CCIP_ALIGN_BYTES);
7997d63899aSWei Huang 		/* performing a short transfer to get aligned */
8007d63899aSWei Huang 		if (alignment_offset != 0) {
8017d63899aSWei Huang 			desc->rd_address = src & DMA_MASK_32_BIT;
8027d63899aSWei Huang 			desc->wr_address = dst & DMA_MASK_32_BIT;
8037d63899aSWei Huang 			desc->wr_burst_count = 1;
8047d63899aSWei Huang 			desc->rd_burst_count = 1;
8057d63899aSWei Huang 			desc->rd_address_ext = (src >> 32) & DMA_MASK_32_BIT;
8067d63899aSWei Huang 			desc->wr_address_ext = (dst >> 32) & DMA_MASK_32_BIT;
8077d63899aSWei Huang 			/* count isn't large enough to hit next 4CL boundary */
8087d63899aSWei Huang 			if ((CCIP_ALIGN_BYTES - alignment_offset) >= count) {
8097d63899aSWei Huang 				segment_size = count;
8107d63899aSWei Huang 				count = 0;
8117d63899aSWei Huang 			} else {
8127d63899aSWei Huang 				segment_size = CCIP_ALIGN_BYTES
8137d63899aSWei Huang 					- alignment_offset;
8147d63899aSWei Huang 				src += segment_size;
8157d63899aSWei Huang 				dst += segment_size;
8167d63899aSWei Huang 				count -= segment_size;
8177d63899aSWei Huang 				desc->control.transfer_irq_en = 0;
8187d63899aSWei Huang 			}
8197d63899aSWei Huang 			/* post short transfer to align to a 4CL (256 byte) */
8207d63899aSWei Huang 			desc->len = segment_size;
8217d63899aSWei Huang 			send_descriptor(ctx, desc);
8227d63899aSWei Huang 		}
8237d63899aSWei Huang 		/* at this point we are 4CL (256 byte) aligned */
8247d63899aSWei Huang 		if (count >= CCIP_ALIGN_BYTES) {
8257d63899aSWei Huang 			desc->rd_address = src & DMA_MASK_32_BIT;
8267d63899aSWei Huang 			desc->wr_address = dst & DMA_MASK_32_BIT;
8277d63899aSWei Huang 			desc->wr_burst_count = 4;
8287d63899aSWei Huang 			desc->rd_burst_count = 4;
8297d63899aSWei Huang 			desc->rd_address_ext = (src >> 32) & DMA_MASK_32_BIT;
8307d63899aSWei Huang 			desc->wr_address_ext = (dst >> 32) & DMA_MASK_32_BIT;
8317d63899aSWei Huang 			/* buffer ends on 4CL boundary */
8327d63899aSWei Huang 			if ((count % CCIP_ALIGN_BYTES) == 0) {
8337d63899aSWei Huang 				segment_size = count;
8347d63899aSWei Huang 				count = 0;
8357d63899aSWei Huang 			} else {
8367d63899aSWei Huang 				segment_size = count
8377d63899aSWei Huang 					- (count % CCIP_ALIGN_BYTES);
8387d63899aSWei Huang 				src += segment_size;
8397d63899aSWei Huang 				dst += segment_size;
8407d63899aSWei Huang 				count -= segment_size;
8417d63899aSWei Huang 				desc->control.transfer_irq_en = 0;
8427d63899aSWei Huang 			}
8437d63899aSWei Huang 			desc->len = segment_size;
8447d63899aSWei Huang 			send_descriptor(ctx, desc);
8457d63899aSWei Huang 		}
8467d63899aSWei Huang 		/* post short transfer to handle the remainder */
8477d63899aSWei Huang 		if (count > 0) {
8487d63899aSWei Huang 			desc->rd_address = src & DMA_MASK_32_BIT;
8497d63899aSWei Huang 			desc->wr_address = dst & DMA_MASK_32_BIT;
8507d63899aSWei Huang 			desc->len = count;
8517d63899aSWei Huang 			desc->wr_burst_count = 1;
8527d63899aSWei Huang 			desc->rd_burst_count = 1;
8537d63899aSWei Huang 			desc->rd_address_ext = (src >> 32) & DMA_MASK_32_BIT;
8547d63899aSWei Huang 			desc->wr_address_ext = (dst >> 32) & DMA_MASK_32_BIT;
8557d63899aSWei Huang 			if (intr_en)
8567d63899aSWei Huang 				desc->control.transfer_irq_en = 1;
8577d63899aSWei Huang 			send_descriptor(ctx, desc);
8587d63899aSWei Huang 		}
8597d63899aSWei Huang 	}
8607d63899aSWei Huang 
8617d63899aSWei Huang 	return 0;
8627d63899aSWei Huang }
8637d63899aSWei Huang 
8647d63899aSWei Huang static int issue_magic(struct dma_afu_ctx *ctx)
8657d63899aSWei Huang {
8667d63899aSWei Huang 	*(ctx->magic_buf) = 0ULL;
8677d63899aSWei Huang 	return do_dma(ctx, DMA_WF_HOST_ADDR(ctx->magic_iova),
8687d63899aSWei Huang 		DMA_WF_MAGIC_ROM, 64, 1, FPGA_TO_HOST, 1);
8697d63899aSWei Huang }
8707d63899aSWei Huang 
8717d63899aSWei Huang static void wait_magic(struct dma_afu_ctx *ctx)
8727d63899aSWei Huang {
8737d63899aSWei Huang 	int magic_timeout = 0;
8747d63899aSWei Huang 
8757d63899aSWei Huang 	if (!ctx)
8767d63899aSWei Huang 		return;
8777d63899aSWei Huang 
8787d63899aSWei Huang 	poll_interrupt(ctx);
8797d63899aSWei Huang 	while (*(ctx->magic_buf) != DMA_WF_MAGIC) {
8807d63899aSWei Huang 		if (magic_timeout++ > 1000) {
8817d63899aSWei Huang 			IFPGA_RAWDEV_PMD_ERR("DMA magic operation timeout");
8827d63899aSWei Huang 			magic_timeout = 0;
8837d63899aSWei Huang 			break;
8847d63899aSWei Huang 		}
8857d63899aSWei Huang 	}
8867d63899aSWei Huang 	*(ctx->magic_buf) = 0ULL;
8877d63899aSWei Huang }
8887d63899aSWei Huang 
8897d63899aSWei Huang static int dma_tx_buf(struct dma_afu_ctx *ctx, uint64_t dst, uint64_t src,
8907d63899aSWei Huang 	uint64_t chunk, int is_last_chunk, int *intr_issued)
8917d63899aSWei Huang {
8927d63899aSWei Huang 	int intr_en = 0;
8937d63899aSWei Huang 	int ret = 0;
8947d63899aSWei Huang 
8957d63899aSWei Huang 	if (!ctx || !intr_issued)
8967d63899aSWei Huang 		return -EINVAL;
8977d63899aSWei Huang 
8987d63899aSWei Huang 	src += chunk * ctx->dma_buf_size;
8997d63899aSWei Huang 	dst += chunk * ctx->dma_buf_size;
9007d63899aSWei Huang 
9017d63899aSWei Huang 	if (((chunk % HALF_DMA_BUF) == (HALF_DMA_BUF - 1)) || is_last_chunk) {
9027d63899aSWei Huang 		if (*intr_issued) {
9037d63899aSWei Huang 			ret = poll_interrupt(ctx);
9047d63899aSWei Huang 			if (ret)
9057d63899aSWei Huang 				return ret;
9067d63899aSWei Huang 		}
9077d63899aSWei Huang 		intr_en = 1;
9087d63899aSWei Huang 	}
9097d63899aSWei Huang 
9107d63899aSWei Huang 	chunk %= NUM_DMA_BUF;
9117d63899aSWei Huang 	rte_memcpy(ctx->dma_buf[chunk], (void *)(uintptr_t)src,
9127d63899aSWei Huang 		ctx->dma_buf_size);
9137d63899aSWei Huang 	ret = do_dma(ctx, dst, DMA_HOST_ADDR(ctx->dma_iova[chunk]),
9147d63899aSWei Huang 			ctx->dma_buf_size, 0, HOST_TO_FPGA, intr_en);
9157d63899aSWei Huang 	if (intr_en)
9167d63899aSWei Huang 		*intr_issued = 1;
9177d63899aSWei Huang 
9187d63899aSWei Huang 	return ret;
9197d63899aSWei Huang }
9207d63899aSWei Huang 
9217d63899aSWei Huang static int dma_host_to_fpga(struct dma_afu_ctx *ctx, uint64_t dst, uint64_t src,
9227d63899aSWei Huang 	size_t count)
9237d63899aSWei Huang {
9247d63899aSWei Huang 	uint64_t i = 0;
9257d63899aSWei Huang 	uint64_t count_left = count;
9267d63899aSWei Huang 	uint64_t aligned_addr = 0;
9277d63899aSWei Huang 	uint64_t align_bytes = 0;
9287d63899aSWei Huang 	uint64_t dma_chunks = 0;
9297d63899aSWei Huang 	uint64_t dma_tx_bytes = 0;
9307d63899aSWei Huang 	uint64_t offset = 0;
9317d63899aSWei Huang 	int issued_intr = 0;
9327d63899aSWei Huang 	int ret = 0;
9337d63899aSWei Huang 
9347d63899aSWei Huang 	IFPGA_RAWDEV_PMD_DEBUG("0x%"PRIx64" ---> 0x%"PRIx64" (%zu)", src, dst,
9357d63899aSWei Huang 		count);
9367d63899aSWei Huang 
9377d63899aSWei Huang 	if (!ctx)
9387d63899aSWei Huang 		return -EINVAL;
9397d63899aSWei Huang 
9407d63899aSWei Huang 	if (!IS_DMA_ALIGNED(dst)) {
9417d63899aSWei Huang 		if (count_left < DMA_ALIGN_BYTES)
9427d63899aSWei Huang 			return ase_host_to_fpga(ctx, &dst, &src, count_left);
9437d63899aSWei Huang 
9447d63899aSWei Huang 		aligned_addr = ((dst / DMA_ALIGN_BYTES) + 1)
9457d63899aSWei Huang 			* DMA_ALIGN_BYTES;
9467d63899aSWei Huang 		align_bytes = aligned_addr - dst;
9477d63899aSWei Huang 		ret = ase_host_to_fpga(ctx, &dst, &src, align_bytes);
9487d63899aSWei Huang 		if (ret)
9497d63899aSWei Huang 			return ret;
9507d63899aSWei Huang 		count_left = count_left - align_bytes;
9517d63899aSWei Huang 	}
9527d63899aSWei Huang 
9537d63899aSWei Huang 	if (count_left) {
9547d63899aSWei Huang 		dma_chunks = count_left / ctx->dma_buf_size;
9557d63899aSWei Huang 		offset = dma_chunks * ctx->dma_buf_size;
9567d63899aSWei Huang 		count_left -= offset;
9577d63899aSWei Huang 		IFPGA_RAWDEV_PMD_DEBUG("0x%"PRIx64" ---> 0x%"PRIx64
9587d63899aSWei Huang 			" (%"PRIu64"...0x%"PRIx64")",
9597d63899aSWei Huang 			src, dst, dma_chunks, count_left);
9607d63899aSWei Huang 		for (i = 0; i < dma_chunks; i++) {
9617d63899aSWei Huang 			ret = dma_tx_buf(ctx, dst, src, i,
9627d63899aSWei Huang 				i == (dma_chunks - 1), &issued_intr);
9637d63899aSWei Huang 			if (ret)
9647d63899aSWei Huang 				return ret;
9657d63899aSWei Huang 		}
9667d63899aSWei Huang 
9677d63899aSWei Huang 		if (issued_intr) {
9687d63899aSWei Huang 			ret = poll_interrupt(ctx);
9697d63899aSWei Huang 			if (ret)
9707d63899aSWei Huang 				return ret;
9717d63899aSWei Huang 		}
9727d63899aSWei Huang 
9737d63899aSWei Huang 		if (count_left) {
9747d63899aSWei Huang 			i = count_left / DMA_ALIGN_BYTES;
9757d63899aSWei Huang 			if (i > 0) {
9767d63899aSWei Huang 				dma_tx_bytes = i * DMA_ALIGN_BYTES;
9777d63899aSWei Huang 				IFPGA_RAWDEV_PMD_DEBUG("left over 0x%"PRIx64" to DMA",
9787d63899aSWei Huang 					dma_tx_bytes);
9797d63899aSWei Huang 				rte_memcpy(ctx->dma_buf[0],
9807d63899aSWei Huang 					(void *)(uintptr_t)(src + offset),
9817d63899aSWei Huang 					dma_tx_bytes);
9827d63899aSWei Huang 				ret = do_dma(ctx, dst + offset,
9837d63899aSWei Huang 					DMA_HOST_ADDR(ctx->dma_iova[0]),
9847d63899aSWei Huang 					dma_tx_bytes, 1, HOST_TO_FPGA, 1);
9857d63899aSWei Huang 				if (ret)
9867d63899aSWei Huang 					return ret;
9877d63899aSWei Huang 				ret = poll_interrupt(ctx);
9887d63899aSWei Huang 				if (ret)
9897d63899aSWei Huang 					return ret;
9907d63899aSWei Huang 			}
9917d63899aSWei Huang 
9927d63899aSWei Huang 			count_left -= dma_tx_bytes;
9937d63899aSWei Huang 			if (count_left) {
9947d63899aSWei Huang 				IFPGA_RAWDEV_PMD_DEBUG("left over 0x%"PRIx64" to ASE",
9957d63899aSWei Huang 					count_left);
9967d63899aSWei Huang 				dst += offset + dma_tx_bytes;
9977d63899aSWei Huang 				src += offset + dma_tx_bytes;
9987d63899aSWei Huang 				ret = ase_host_to_fpga(ctx, &dst, &src,
9997d63899aSWei Huang 					count_left);
10007d63899aSWei Huang 			}
10017d63899aSWei Huang 		}
10027d63899aSWei Huang 	}
10037d63899aSWei Huang 
10047d63899aSWei Huang 	return ret;
10057d63899aSWei Huang }
10067d63899aSWei Huang 
10077d63899aSWei Huang static int dma_rx_buf(struct dma_afu_ctx *ctx, uint64_t dst, uint64_t src,
10087d63899aSWei Huang 	uint64_t chunk, int is_last_chunk, uint64_t *rx_count, int *wf_issued)
10097d63899aSWei Huang {
10107d63899aSWei Huang 	uint64_t i = chunk % NUM_DMA_BUF;
10117d63899aSWei Huang 	uint64_t n = *rx_count;
10127d63899aSWei Huang 	uint64_t num_pending = 0;
10137d63899aSWei Huang 	int ret = 0;
10147d63899aSWei Huang 
10157d63899aSWei Huang 	if (!ctx || !wf_issued)
10167d63899aSWei Huang 		return -EINVAL;
10177d63899aSWei Huang 
10187d63899aSWei Huang 	ret = do_dma(ctx, DMA_HOST_ADDR(ctx->dma_iova[i]),
10197d63899aSWei Huang 		src + chunk * ctx->dma_buf_size,
10207d63899aSWei Huang 		ctx->dma_buf_size, 1, FPGA_TO_HOST, 0);
10217d63899aSWei Huang 	if (ret)
10227d63899aSWei Huang 		return ret;
10237d63899aSWei Huang 
10247d63899aSWei Huang 	num_pending = chunk - n + 1;
10257d63899aSWei Huang 	if (num_pending == HALF_DMA_BUF) {
10267d63899aSWei Huang 		ret = issue_magic(ctx);
10277d63899aSWei Huang 		if (ret) {
10287d63899aSWei Huang 			IFPGA_RAWDEV_PMD_DEBUG("Magic issue failed");
10297d63899aSWei Huang 			return ret;
10307d63899aSWei Huang 		}
10317d63899aSWei Huang 		*wf_issued = 1;
10327d63899aSWei Huang 	}
10337d63899aSWei Huang 
10347d63899aSWei Huang 	if ((num_pending > (NUM_DMA_BUF - 1)) || is_last_chunk) {
10357d63899aSWei Huang 		if (*wf_issued) {
10367d63899aSWei Huang 			wait_magic(ctx);
10377d63899aSWei Huang 			for (i = 0; i < HALF_DMA_BUF; i++) {
10387d63899aSWei Huang 				rte_memcpy((void *)(uintptr_t)(dst +
10397d63899aSWei Huang 						n * ctx->dma_buf_size),
10407d63899aSWei Huang 					ctx->dma_buf[n % NUM_DMA_BUF],
10417d63899aSWei Huang 					ctx->dma_buf_size);
10427d63899aSWei Huang 				n++;
10437d63899aSWei Huang 			}
10447d63899aSWei Huang 			*wf_issued = 0;
10457d63899aSWei Huang 			*rx_count = n;
10467d63899aSWei Huang 		}
10477d63899aSWei Huang 		ret = issue_magic(ctx);
10487d63899aSWei Huang 		if (ret) {
10497d63899aSWei Huang 			IFPGA_RAWDEV_PMD_DEBUG("Magic issue failed");
10507d63899aSWei Huang 			return ret;
10517d63899aSWei Huang 		}
10527d63899aSWei Huang 		*wf_issued = 1;
10537d63899aSWei Huang 	}
10547d63899aSWei Huang 
10557d63899aSWei Huang 	return ret;
10567d63899aSWei Huang }
10577d63899aSWei Huang 
10587d63899aSWei Huang static int dma_fpga_to_host(struct dma_afu_ctx *ctx, uint64_t dst, uint64_t src,
10597d63899aSWei Huang 	size_t count)
10607d63899aSWei Huang {
10617d63899aSWei Huang 	uint64_t i = 0;
10627d63899aSWei Huang 	uint64_t count_left = count;
10637d63899aSWei Huang 	uint64_t aligned_addr = 0;
10647d63899aSWei Huang 	uint64_t align_bytes = 0;
10657d63899aSWei Huang 	uint64_t dma_chunks = 0;
10667d63899aSWei Huang 	uint64_t pending_buf = 0;
10677d63899aSWei Huang 	uint64_t dma_rx_bytes = 0;
10687d63899aSWei Huang 	uint64_t offset = 0;
10697d63899aSWei Huang 	int wf_issued = 0;
10707d63899aSWei Huang 	int ret = 0;
10717d63899aSWei Huang 
10727d63899aSWei Huang 	IFPGA_RAWDEV_PMD_DEBUG("0x%"PRIx64" ---> 0x%"PRIx64" (%zu)", src, dst,
10737d63899aSWei Huang 		count);
10747d63899aSWei Huang 
10757d63899aSWei Huang 	if (!ctx)
10767d63899aSWei Huang 		return -EINVAL;
10777d63899aSWei Huang 
10787d63899aSWei Huang 	if (!IS_DMA_ALIGNED(src)) {
10797d63899aSWei Huang 		if (count_left < DMA_ALIGN_BYTES)
10807d63899aSWei Huang 			return ase_fpga_to_host(ctx, &src, &dst, count_left);
10817d63899aSWei Huang 
10827d63899aSWei Huang 		aligned_addr = ((src / DMA_ALIGN_BYTES) + 1)
10837d63899aSWei Huang 			 * DMA_ALIGN_BYTES;
10847d63899aSWei Huang 		align_bytes = aligned_addr - src;
10857d63899aSWei Huang 		ret = ase_fpga_to_host(ctx, &src, &dst, align_bytes);
10867d63899aSWei Huang 		if (ret)
10877d63899aSWei Huang 			return ret;
10887d63899aSWei Huang 		count_left = count_left - align_bytes;
10897d63899aSWei Huang 	}
10907d63899aSWei Huang 
10917d63899aSWei Huang 	if (count_left) {
10927d63899aSWei Huang 		dma_chunks = count_left / ctx->dma_buf_size;
10937d63899aSWei Huang 		offset = dma_chunks * ctx->dma_buf_size;
10947d63899aSWei Huang 		count_left -= offset;
10957d63899aSWei Huang 		IFPGA_RAWDEV_PMD_DEBUG("0x%"PRIx64" ---> 0x%"PRIx64
10967d63899aSWei Huang 			" (%"PRIu64"...0x%"PRIx64")",
10977d63899aSWei Huang 			src, dst, dma_chunks, count_left);
10987d63899aSWei Huang 		for (i = 0; i < dma_chunks; i++) {
10997d63899aSWei Huang 			ret = dma_rx_buf(ctx, dst, src, i,
11007d63899aSWei Huang 				i == (dma_chunks - 1),
11017d63899aSWei Huang 				&pending_buf, &wf_issued);
11027d63899aSWei Huang 			if (ret)
11037d63899aSWei Huang 				return ret;
11047d63899aSWei Huang 		}
11057d63899aSWei Huang 
11067d63899aSWei Huang 		if (wf_issued)
11077d63899aSWei Huang 			wait_magic(ctx);
11087d63899aSWei Huang 
11097d63899aSWei Huang 		/* clear out final dma memcpy operations */
11107d63899aSWei Huang 		while (pending_buf < dma_chunks) {
11117d63899aSWei Huang 			/* constant size transfer; no length check required */
11127d63899aSWei Huang 			rte_memcpy((void *)(uintptr_t)(dst +
11137d63899aSWei Huang 					pending_buf * ctx->dma_buf_size),
11147d63899aSWei Huang 				ctx->dma_buf[pending_buf % NUM_DMA_BUF],
11157d63899aSWei Huang 				ctx->dma_buf_size);
11167d63899aSWei Huang 			pending_buf++;
11177d63899aSWei Huang 		}
11187d63899aSWei Huang 
11197d63899aSWei Huang 		if (count_left > 0) {
11207d63899aSWei Huang 			i = count_left / DMA_ALIGN_BYTES;
11217d63899aSWei Huang 			if (i > 0) {
11227d63899aSWei Huang 				dma_rx_bytes = i * DMA_ALIGN_BYTES;
11237d63899aSWei Huang 				IFPGA_RAWDEV_PMD_DEBUG("left over 0x%"PRIx64" to DMA",
11247d63899aSWei Huang 					dma_rx_bytes);
11257d63899aSWei Huang 				ret = do_dma(ctx,
11267d63899aSWei Huang 					DMA_HOST_ADDR(ctx->dma_iova[0]),
11277d63899aSWei Huang 					src + offset,
11287d63899aSWei Huang 					dma_rx_bytes, 1, FPGA_TO_HOST, 0);
11297d63899aSWei Huang 				if (ret)
11307d63899aSWei Huang 					return ret;
11317d63899aSWei Huang 				ret = issue_magic(ctx);
11327d63899aSWei Huang 				if (ret)
11337d63899aSWei Huang 					return ret;
11347d63899aSWei Huang 				wait_magic(ctx);
11357d63899aSWei Huang 				rte_memcpy((void *)(uintptr_t)(dst + offset),
11367d63899aSWei Huang 					ctx->dma_buf[0], dma_rx_bytes);
11377d63899aSWei Huang 			}
11387d63899aSWei Huang 
11397d63899aSWei Huang 			count_left -= dma_rx_bytes;
11407d63899aSWei Huang 			if (count_left) {
11417d63899aSWei Huang 				IFPGA_RAWDEV_PMD_DEBUG("left over 0x%"PRIx64" to ASE",
11427d63899aSWei Huang 					count_left);
11437d63899aSWei Huang 				dst += offset + dma_rx_bytes;
11447d63899aSWei Huang 				src += offset + dma_rx_bytes;
11457d63899aSWei Huang 				ret = ase_fpga_to_host(ctx, &src, &dst,
11467d63899aSWei Huang 							count_left);
11477d63899aSWei Huang 			}
11487d63899aSWei Huang 		}
11497d63899aSWei Huang 	}
11507d63899aSWei Huang 
11517d63899aSWei Huang 	return ret;
11527d63899aSWei Huang }
11537d63899aSWei Huang 
11547d63899aSWei Huang static int dma_fpga_to_fpga(struct dma_afu_ctx *ctx, uint64_t dst, uint64_t src,
11557d63899aSWei Huang 	size_t count)
11567d63899aSWei Huang {
11577d63899aSWei Huang 	uint64_t i = 0;
11587d63899aSWei Huang 	uint64_t count_left = count;
11597d63899aSWei Huang 	uint64_t dma_chunks = 0;
11607d63899aSWei Huang 	uint64_t offset = 0;
1161099da897SWei Huang 	uint64_t tx_chunks = 0;
11627d63899aSWei Huang 	uint64_t *tmp_buf = NULL;
11637d63899aSWei Huang 	int ret = 0;
11647d63899aSWei Huang 
11657d63899aSWei Huang 	IFPGA_RAWDEV_PMD_DEBUG("0x%"PRIx64" ---> 0x%"PRIx64" (%zu)", src, dst,
11667d63899aSWei Huang 		count);
11677d63899aSWei Huang 
11687d63899aSWei Huang 	if (!ctx)
11697d63899aSWei Huang 		return -EINVAL;
11707d63899aSWei Huang 
11717d63899aSWei Huang 	if (IS_DMA_ALIGNED(dst) && IS_DMA_ALIGNED(src)
11727d63899aSWei Huang 	    && IS_DMA_ALIGNED(count_left)) {
11737d63899aSWei Huang 		dma_chunks = count_left / ctx->dma_buf_size;
11747d63899aSWei Huang 		offset = dma_chunks * ctx->dma_buf_size;
11757d63899aSWei Huang 		count_left -= offset;
11767d63899aSWei Huang 		IFPGA_RAWDEV_PMD_DEBUG("0x%"PRIx64" ---> 0x%"PRIx64
11777d63899aSWei Huang 			" (%"PRIu64"...0x%"PRIx64")",
11787d63899aSWei Huang 			src, dst, dma_chunks, count_left);
11797d63899aSWei Huang 		for (i = 0; i < dma_chunks; i++) {
11807d63899aSWei Huang 			ret = do_dma(ctx, dst + i * ctx->dma_buf_size,
11817d63899aSWei Huang 				src + i * ctx->dma_buf_size,
11827d63899aSWei Huang 				ctx->dma_buf_size, 0, FPGA_TO_FPGA, 0);
11837d63899aSWei Huang 			if (ret)
11847d63899aSWei Huang 				return ret;
11857d63899aSWei Huang 			if ((((i + 1) % NUM_DMA_BUF) == 0) ||
11867d63899aSWei Huang 				(i == (dma_chunks - 1))) {
11877d63899aSWei Huang 				ret = issue_magic(ctx);
11887d63899aSWei Huang 				if (ret)
11897d63899aSWei Huang 					return ret;
11907d63899aSWei Huang 				wait_magic(ctx);
11917d63899aSWei Huang 			}
11927d63899aSWei Huang 		}
11937d63899aSWei Huang 
11947d63899aSWei Huang 		if (count_left > 0) {
11957d63899aSWei Huang 			IFPGA_RAWDEV_PMD_DEBUG("left over 0x%"PRIx64" to DMA", count_left);
11967d63899aSWei Huang 			ret = do_dma(ctx, dst + offset, src + offset,
11977d63899aSWei Huang 				count_left, 1, FPGA_TO_FPGA, 0);
11987d63899aSWei Huang 			if (ret)
11997d63899aSWei Huang 				return ret;
12007d63899aSWei Huang 			ret = issue_magic(ctx);
12017d63899aSWei Huang 			if (ret)
12027d63899aSWei Huang 				return ret;
12037d63899aSWei Huang 			wait_magic(ctx);
12047d63899aSWei Huang 		}
12057d63899aSWei Huang 	} else {
12067d63899aSWei Huang 		if ((src < dst) && (src + count_left > dst)) {
12077d63899aSWei Huang 			IFPGA_RAWDEV_PMD_ERR("Overlapping: 0x%"PRIx64
12087d63899aSWei Huang 				" -> 0x%"PRIx64" (0x%"PRIx64")",
12097d63899aSWei Huang 				src, dst, count_left);
12107d63899aSWei Huang 			return -EINVAL;
12117d63899aSWei Huang 		}
12127d63899aSWei Huang 		tx_chunks = count_left / ctx->dma_buf_size;
12137d63899aSWei Huang 		offset = tx_chunks * ctx->dma_buf_size;
12147d63899aSWei Huang 		count_left -= offset;
12157d63899aSWei Huang 		IFPGA_RAWDEV_PMD_DEBUG("0x%"PRIx64" --> 0x%"PRIx64
1216099da897SWei Huang 			" (%"PRIu64"...0x%"PRIx64")",
12177d63899aSWei Huang 			src, dst, tx_chunks, count_left);
12187d63899aSWei Huang 		tmp_buf = (uint64_t *)rte_malloc(NULL, ctx->dma_buf_size,
12197d63899aSWei Huang 			DMA_ALIGN_BYTES);
12207d63899aSWei Huang 		for (i = 0; i < tx_chunks; i++) {
12217d63899aSWei Huang 			ret = dma_fpga_to_host(ctx, (uint64_t)tmp_buf,
12227d63899aSWei Huang 				src + i * ctx->dma_buf_size,
12237d63899aSWei Huang 				ctx->dma_buf_size);
12247d63899aSWei Huang 			if (ret)
12257d63899aSWei Huang 				goto free_buf;
12267d63899aSWei Huang 			ret = dma_host_to_fpga(ctx,
12277d63899aSWei Huang 				dst + i * ctx->dma_buf_size,
12287d63899aSWei Huang 				(uint64_t)tmp_buf, ctx->dma_buf_size);
12297d63899aSWei Huang 			if (ret)
12307d63899aSWei Huang 				goto free_buf;
12317d63899aSWei Huang 		}
12327d63899aSWei Huang 
12337d63899aSWei Huang 		if (count_left > 0) {
12347d63899aSWei Huang 			ret = dma_fpga_to_host(ctx, (uint64_t)tmp_buf,
12357d63899aSWei Huang 				src + offset, count_left);
12367d63899aSWei Huang 			if (ret)
12377d63899aSWei Huang 				goto free_buf;
12387d63899aSWei Huang 			ret = dma_host_to_fpga(ctx, dst + offset,
12397d63899aSWei Huang 				(uint64_t)tmp_buf, count_left);
12407d63899aSWei Huang 			if (ret)
12417d63899aSWei Huang 				goto free_buf;
12427d63899aSWei Huang 		}
12437d63899aSWei Huang free_buf:
12447d63899aSWei Huang 		rte_free(tmp_buf);
12457d63899aSWei Huang 	}
12467d63899aSWei Huang 
12477d63899aSWei Huang 	return ret;
12487d63899aSWei Huang }
12497d63899aSWei Huang 
12507d63899aSWei Huang static int dma_transfer_sync(struct dma_afu_ctx *ctx, uint64_t dst,
12517d63899aSWei Huang 	uint64_t src, size_t count, fpga_dma_type type)
12527d63899aSWei Huang {
12537d63899aSWei Huang 	int ret = 0;
12547d63899aSWei Huang 
12557d63899aSWei Huang 	if (!ctx)
12567d63899aSWei Huang 		return -EINVAL;
12577d63899aSWei Huang 
12587d63899aSWei Huang 	if (type == HOST_TO_FPGA)
12597d63899aSWei Huang 		ret = dma_host_to_fpga(ctx, dst, src, count);
12607d63899aSWei Huang 	else if (type == FPGA_TO_HOST)
12617d63899aSWei Huang 		ret = dma_fpga_to_host(ctx, dst, src, count);
12627d63899aSWei Huang 	else if (type == FPGA_TO_FPGA)
12637d63899aSWei Huang 		ret = dma_fpga_to_fpga(ctx, dst, src, count);
12647d63899aSWei Huang 	else
12657d63899aSWei Huang 		return -EINVAL;
12667d63899aSWei Huang 
12677d63899aSWei Huang 	return ret;
12687d63899aSWei Huang }
12697d63899aSWei Huang 
12707d63899aSWei Huang static double get_duration(struct timespec start, struct timespec end)
12717d63899aSWei Huang {
12727d63899aSWei Huang 	uint64_t diff = 1000000000L * (end.tv_sec - start.tv_sec)
12737d63899aSWei Huang 		+ end.tv_nsec - start.tv_nsec;
12747d63899aSWei Huang 	return (double)diff / (double)1000000000L;
12757d63899aSWei Huang }
12767d63899aSWei Huang 
12777d63899aSWei Huang #define SWEEP_ITERS 1
12787d63899aSWei Huang static int sweep_test(struct dma_afu_ctx *ctx, uint32_t length,
12797d63899aSWei Huang 	uint64_t ddr_offset, uint64_t buf_offset, uint64_t size_decrement)
12807d63899aSWei Huang {
12817d63899aSWei Huang 	struct timespec start, end;
12827d63899aSWei Huang 	uint64_t test_size = 0;
12837d63899aSWei Huang 	uint64_t *dma_buf_ptr = NULL;
12847d63899aSWei Huang 	double throughput, total_time = 0.0;
12857d63899aSWei Huang 	int i = 0;
12867d63899aSWei Huang 	int ret = 0;
12877d63899aSWei Huang 
12887d63899aSWei Huang 	if (!ctx || !ctx->data_buf || !ctx->ref_buf) {
12897d63899aSWei Huang 		IFPGA_RAWDEV_PMD_ERR("Buffer for DMA test is not allocated");
12907d63899aSWei Huang 		return -EINVAL;
12917d63899aSWei Huang 	}
12927d63899aSWei Huang 
12937d63899aSWei Huang 	if (length < (buf_offset + size_decrement)) {
12947d63899aSWei Huang 		IFPGA_RAWDEV_PMD_ERR("Test length does not match unaligned parameter");
12957d63899aSWei Huang 		return -EINVAL;
12967d63899aSWei Huang 	}
12977d63899aSWei Huang 	test_size = length - (buf_offset + size_decrement);
12987d63899aSWei Huang 	if ((ddr_offset + test_size) > ctx->mem_size) {
12997d63899aSWei Huang 		IFPGA_RAWDEV_PMD_ERR("Test is out of DDR memory space");
13007d63899aSWei Huang 		return -EINVAL;
13017d63899aSWei Huang 	}
13027d63899aSWei Huang 
13037d63899aSWei Huang 	dma_buf_ptr = (uint64_t *)((uint8_t *)ctx->data_buf + buf_offset);
13047d63899aSWei Huang 	printf("Sweep Host %p to FPGA 0x%"PRIx64
13057d63899aSWei Huang 		" with 0x%"PRIx64" bytes ...\n",
13067d63899aSWei Huang 		(void *)dma_buf_ptr, ddr_offset, test_size);
13077d63899aSWei Huang 
13087d63899aSWei Huang 	for (i = 0; i < SWEEP_ITERS; i++) {
13097d63899aSWei Huang 		clock_gettime(CLOCK_MONOTONIC, &start);
13107d63899aSWei Huang 		ret = dma_transfer_sync(ctx, ddr_offset, (uint64_t)dma_buf_ptr,
13117d63899aSWei Huang 			test_size, HOST_TO_FPGA);
13127d63899aSWei Huang 		clock_gettime(CLOCK_MONOTONIC, &end);
13137d63899aSWei Huang 		if (ret) {
13147d63899aSWei Huang 			IFPGA_RAWDEV_PMD_ERR("Failed");
13157d63899aSWei Huang 			return ret;
13167d63899aSWei Huang 		}
13177d63899aSWei Huang 		total_time += get_duration(start, end);
13187d63899aSWei Huang 	}
13197d63899aSWei Huang 	throughput = (test_size * SWEEP_ITERS) / (total_time * 1000000);
13207d63899aSWei Huang 	printf("Measured bandwidth = %lf MB/s\n", throughput);
13217d63899aSWei Huang 
13227d63899aSWei Huang 	printf("Sweep FPGA 0x%"PRIx64" to Host %p with 0x%"PRIx64" bytes ...\n",
13237d63899aSWei Huang 		ddr_offset, (void *)dma_buf_ptr, test_size);
13247d63899aSWei Huang 
13257d63899aSWei Huang 	total_time = 0.0;
13267d63899aSWei Huang 	memset((char *)dma_buf_ptr, 0, test_size);
13277d63899aSWei Huang 	for (i = 0; i < SWEEP_ITERS; i++) {
13287d63899aSWei Huang 		clock_gettime(CLOCK_MONOTONIC, &start);
13297d63899aSWei Huang 		ret = dma_transfer_sync(ctx, (uint64_t)dma_buf_ptr, ddr_offset,
13307d63899aSWei Huang 			test_size, FPGA_TO_HOST);
13317d63899aSWei Huang 		clock_gettime(CLOCK_MONOTONIC, &end);
13327d63899aSWei Huang 		if (ret) {
13337d63899aSWei Huang 			IFPGA_RAWDEV_PMD_ERR("Failed");
13347d63899aSWei Huang 			return ret;
13357d63899aSWei Huang 		}
13367d63899aSWei Huang 		total_time += get_duration(start, end);
13377d63899aSWei Huang 	}
13387d63899aSWei Huang 	throughput = (test_size * SWEEP_ITERS) / (total_time * 1000000);
13397d63899aSWei Huang 	printf("Measured bandwidth = %lf MB/s\n", throughput);
13407d63899aSWei Huang 
13417d63899aSWei Huang 	printf("Verifying buffer ...\n");
13427d63899aSWei Huang 	return dma_afu_buf_verify(ctx, test_size);
13437d63899aSWei Huang }
13447d63899aSWei Huang 
13457d63899aSWei Huang static int dma_afu_test(struct afu_rawdev *dev)
13467d63899aSWei Huang {
13477d63899aSWei Huang 	struct n3000_afu_priv *priv = NULL;
13487d63899aSWei Huang 	struct dma_afu_ctx *ctx = NULL;
13497d63899aSWei Huang 	struct rte_pmd_afu_dma_cfg *cfg = NULL;
13507d63899aSWei Huang 	msgdma_ctrl ctrl;
13517d63899aSWei Huang 	uint64_t offset = 0;
13527d63899aSWei Huang 	uint32_t i = 0;
13537d63899aSWei Huang 	int ret = 0;
13547d63899aSWei Huang 
13557d63899aSWei Huang 	if (!dev)
13567d63899aSWei Huang 		return -EINVAL;
13577d63899aSWei Huang 
13587d63899aSWei Huang 	if (!dev->priv)
13597d63899aSWei Huang 		return -ENOENT;
13607d63899aSWei Huang 
13617d63899aSWei Huang 	priv = (struct n3000_afu_priv *)dev->priv;
13627d63899aSWei Huang 	cfg = &priv->dma_cfg;
13637d63899aSWei Huang 	if (cfg->index >= NUM_N3000_DMA)
13647d63899aSWei Huang 		return -EINVAL;
13657d63899aSWei Huang 	ctx = &priv->dma_ctx[cfg->index];
13667d63899aSWei Huang 
13677d63899aSWei Huang 	ctx->pattern = (int)cfg->pattern;
13687d63899aSWei Huang 	ctx->verbose = (int)cfg->verbose;
13697d63899aSWei Huang 	ctx->dma_buf_size = cfg->size;
13707d63899aSWei Huang 
13717d63899aSWei Huang 	ret = dma_afu_buf_alloc(ctx, cfg);
13727d63899aSWei Huang 	if (ret)
13737d63899aSWei Huang 		goto free;
13747d63899aSWei Huang 
13757d63899aSWei Huang 	printf("Initialize test buffer\n");
13767d63899aSWei Huang 	dma_afu_buf_init(ctx, cfg->length);
13777d63899aSWei Huang 
13787d63899aSWei Huang 	/* enable interrupt */
13797d63899aSWei Huang 	ctrl.csr = 0;
13807d63899aSWei Huang 	ctrl.global_intr_en_mask = 1;
13817d63899aSWei Huang 	rte_write32(ctrl.csr, CSR_CONTROL(ctx->csr_addr));
13827d63899aSWei Huang 
13837d63899aSWei Huang 	printf("Host %p to FPGA 0x%x with 0x%x bytes\n", ctx->data_buf,
13847d63899aSWei Huang 		cfg->offset, cfg->length);
13857d63899aSWei Huang 	ret = dma_transfer_sync(ctx, cfg->offset, (uint64_t)ctx->data_buf,
13867d63899aSWei Huang 		cfg->length, HOST_TO_FPGA);
13877d63899aSWei Huang 	if (ret) {
13887d63899aSWei Huang 		IFPGA_RAWDEV_PMD_ERR("Failed to transfer data from host to FPGA");
13897d63899aSWei Huang 		goto end;
13907d63899aSWei Huang 	}
13917d63899aSWei Huang 	memset(ctx->data_buf, 0, cfg->length);
13927d63899aSWei Huang 
13937d63899aSWei Huang 	printf("FPGA 0x%x to Host %p with 0x%x bytes\n", cfg->offset,
13947d63899aSWei Huang 		ctx->data_buf, cfg->length);
13957d63899aSWei Huang 	ret = dma_transfer_sync(ctx, (uint64_t)ctx->data_buf, cfg->offset,
13967d63899aSWei Huang 		cfg->length, FPGA_TO_HOST);
13977d63899aSWei Huang 	if (ret) {
13987d63899aSWei Huang 		IFPGA_RAWDEV_PMD_ERR("Failed to transfer data from FPGA to host");
13997d63899aSWei Huang 		goto end;
14007d63899aSWei Huang 	}
14017d63899aSWei Huang 	ret = dma_afu_buf_verify(ctx, cfg->length);
14027d63899aSWei Huang 	if (ret)
14037d63899aSWei Huang 		goto end;
14047d63899aSWei Huang 
14057d63899aSWei Huang 	if ((cfg->offset + cfg->length * 2) <= ctx->mem_size)
14067d63899aSWei Huang 		offset = cfg->offset + cfg->length;
14077d63899aSWei Huang 	else if (cfg->offset > cfg->length)
14087d63899aSWei Huang 		offset = 0;
14097d63899aSWei Huang 	else
14107d63899aSWei Huang 		goto end;
14117d63899aSWei Huang 
14127d63899aSWei Huang 	printf("FPGA 0x%x to FPGA 0x%"PRIx64" with 0x%x bytes\n",
14137d63899aSWei Huang 		cfg->offset, offset, cfg->length);
14147d63899aSWei Huang 	ret = dma_transfer_sync(ctx, offset, cfg->offset, cfg->length,
14157d63899aSWei Huang 		FPGA_TO_FPGA);
14167d63899aSWei Huang 	if (ret) {
14177d63899aSWei Huang 		IFPGA_RAWDEV_PMD_ERR("Failed to transfer data from FPGA to FPGA");
14187d63899aSWei Huang 		goto end;
14197d63899aSWei Huang 	}
14207d63899aSWei Huang 
14217d63899aSWei Huang 	printf("FPGA 0x%"PRIx64" to Host %p with 0x%x bytes\n", offset,
14227d63899aSWei Huang 		ctx->data_buf, cfg->length);
14237d63899aSWei Huang 	ret = dma_transfer_sync(ctx, (uint64_t)ctx->data_buf, offset,
14247d63899aSWei Huang 		cfg->length, FPGA_TO_HOST);
14257d63899aSWei Huang 	if (ret) {
14267d63899aSWei Huang 		IFPGA_RAWDEV_PMD_ERR("Failed to transfer data from FPGA to host");
14277d63899aSWei Huang 		goto end;
14287d63899aSWei Huang 	}
14297d63899aSWei Huang 	ret = dma_afu_buf_verify(ctx, cfg->length);
14307d63899aSWei Huang 	if (ret)
14317d63899aSWei Huang 		goto end;
14327d63899aSWei Huang 
14337d63899aSWei Huang 	printf("Sweep with aligned address and size\n");
14347d63899aSWei Huang 	ret = sweep_test(ctx, cfg->length, cfg->offset, 0, 0);
14357d63899aSWei Huang 	if (ret)
14367d63899aSWei Huang 		goto end;
14377d63899aSWei Huang 
14387d63899aSWei Huang 	if (cfg->unaligned) {
14397d63899aSWei Huang 		printf("Sweep with unaligned address and size\n");
14407d63899aSWei Huang 		struct unaligned_set {
14417d63899aSWei Huang 			uint64_t addr_offset;
14427d63899aSWei Huang 			uint64_t size_dec;
14437d63899aSWei Huang 		} param[] = {{61, 5}, {3, 0}, {7, 3}, {0, 3}, {0, 61}, {0, 7}};
14447d63899aSWei Huang 		for (i = 0; i < ARRAY_SIZE(param); i++) {
14457d63899aSWei Huang 			ret = sweep_test(ctx, cfg->length, cfg->offset,
14467d63899aSWei Huang 				param[i].addr_offset, param[i].size_dec);
14477d63899aSWei Huang 			if (ret)
14487d63899aSWei Huang 				break;
14497d63899aSWei Huang 		}
14507d63899aSWei Huang 	}
14517d63899aSWei Huang 
14527d63899aSWei Huang end:
14537d63899aSWei Huang 	/* disable interrupt */
14547d63899aSWei Huang 	ctrl.global_intr_en_mask = 0;
14557d63899aSWei Huang 	rte_write32(ctrl.csr, CSR_CONTROL(ctx->csr_addr));
14567d63899aSWei Huang 
14577d63899aSWei Huang free:
14587d63899aSWei Huang 	dma_afu_buf_free(ctx);
14597d63899aSWei Huang 	return ret;
14607d63899aSWei Huang }
14617d63899aSWei Huang 
14627d63899aSWei Huang static struct rte_pci_device *n3000_afu_get_pci_dev(struct afu_rawdev *dev)
14637d63899aSWei Huang {
14647d63899aSWei Huang 	struct rte_afu_device *afudev = NULL;
14657d63899aSWei Huang 
14667d63899aSWei Huang 	if (!dev || !dev->rawdev || !dev->rawdev->device)
14677d63899aSWei Huang 		return NULL;
14687d63899aSWei Huang 
14697d63899aSWei Huang 	afudev = RTE_DEV_TO_AFU(dev->rawdev->device);
14707d63899aSWei Huang 	if (!afudev->rawdev || !afudev->rawdev->device)
14717d63899aSWei Huang 		return NULL;
14727d63899aSWei Huang 
14737d63899aSWei Huang 	return RTE_DEV_TO_PCI(afudev->rawdev->device);
14747d63899aSWei Huang }
14757d63899aSWei Huang 
14767d63899aSWei Huang #ifdef VFIO_PRESENT
14777d63899aSWei Huang static int dma_afu_set_irqs(struct afu_rawdev *dev, uint32_t vec_start,
14787d63899aSWei Huang 	uint32_t count, int *efds)
14797d63899aSWei Huang {
14807d63899aSWei Huang 	struct rte_pci_device *pci_dev = NULL;
14817d63899aSWei Huang 	struct vfio_irq_set *irq_set = NULL;
14827d63899aSWei Huang 	int vfio_dev_fd = 0;
14837d63899aSWei Huang 	size_t sz = 0;
14847d63899aSWei Huang 	int ret = 0;
14857d63899aSWei Huang 
14867d63899aSWei Huang 	if (!dev || !efds || (count == 0) || (count > MAX_MSIX_VEC))
14877d63899aSWei Huang 		return -EINVAL;
14887d63899aSWei Huang 
14897d63899aSWei Huang 	pci_dev = n3000_afu_get_pci_dev(dev);
14907d63899aSWei Huang 	if (!pci_dev)
14917d63899aSWei Huang 		return -ENODEV;
14927d63899aSWei Huang 	vfio_dev_fd = rte_intr_dev_fd_get(pci_dev->intr_handle);
14937d63899aSWei Huang 
14947d63899aSWei Huang 	sz = sizeof(*irq_set) + sizeof(*efds) * count;
14957d63899aSWei Huang 	irq_set = rte_zmalloc(NULL, sz, 0);
14967d63899aSWei Huang 	if (!irq_set)
14977d63899aSWei Huang 		return -ENOMEM;
14987d63899aSWei Huang 
14997d63899aSWei Huang 	irq_set->argsz = (uint32_t)sz;
15007d63899aSWei Huang 	irq_set->count = count;
15017d63899aSWei Huang 	irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
15027d63899aSWei Huang 		VFIO_IRQ_SET_ACTION_TRIGGER;
15037d63899aSWei Huang 	irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
15047d63899aSWei Huang 	irq_set->start = vec_start;
15057d63899aSWei Huang 
15067d63899aSWei Huang 	rte_memcpy(&irq_set->data, efds, sizeof(*efds) * count);
15077d63899aSWei Huang 	ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
15087d63899aSWei Huang 	if (ret)
1509*f665790aSDavid Marchand 		IFPGA_RAWDEV_PMD_ERR("Error enabling MSI-X interrupts");
15107d63899aSWei Huang 
15117d63899aSWei Huang 	rte_free(irq_set);
15127d63899aSWei Huang 	return ret;
15137d63899aSWei Huang }
15147d63899aSWei Huang #endif
15157d63899aSWei Huang 
15167d63899aSWei Huang static void *n3000_afu_get_port_addr(struct afu_rawdev *dev)
15177d63899aSWei Huang {
15187d63899aSWei Huang 	struct rte_pci_device *pci_dev = NULL;
15197d63899aSWei Huang 	uint8_t *addr = NULL;
15207d63899aSWei Huang 	uint64_t val = 0;
15217d63899aSWei Huang 	uint32_t bar = 0;
15227d63899aSWei Huang 
15237d63899aSWei Huang 	pci_dev = n3000_afu_get_pci_dev(dev);
15247d63899aSWei Huang 	if (!pci_dev)
15257d63899aSWei Huang 		return NULL;
15267d63899aSWei Huang 
15277d63899aSWei Huang 	addr = (uint8_t *)pci_dev->mem_resource[0].addr;
15287d63899aSWei Huang 	val = rte_read64(addr + PORT_ATTR_REG(dev->port));
15297d63899aSWei Huang 	if (!PORT_IMPLEMENTED(val)) {
15307d63899aSWei Huang 		IFPGA_RAWDEV_PMD_INFO("FIU port %d is not implemented", dev->port);
15317d63899aSWei Huang 		return NULL;
15327d63899aSWei Huang 	}
15337d63899aSWei Huang 
15347d63899aSWei Huang 	bar = PORT_BAR(val);
15357d63899aSWei Huang 	if (bar >= PCI_MAX_RESOURCE) {
15367d63899aSWei Huang 		IFPGA_RAWDEV_PMD_ERR("BAR index %u is out of limit", bar);
15377d63899aSWei Huang 		return NULL;
15387d63899aSWei Huang 	}
15397d63899aSWei Huang 
15407d63899aSWei Huang 	addr = (uint8_t *)pci_dev->mem_resource[bar].addr + PORT_OFFSET(val);
15417d63899aSWei Huang 	return addr;
15427d63899aSWei Huang }
15437d63899aSWei Huang 
15447d63899aSWei Huang static int n3000_afu_get_irq_capability(struct afu_rawdev *dev,
15457d63899aSWei Huang 	uint32_t *vec_start, uint32_t *vec_count)
15467d63899aSWei Huang {
15477d63899aSWei Huang 	uint8_t *addr = NULL;
15487d63899aSWei Huang 	uint64_t val = 0;
15497d63899aSWei Huang 	uint64_t header = 0;
15507d63899aSWei Huang 	uint64_t next_offset = 0;
15517d63899aSWei Huang 
15527d63899aSWei Huang 	addr = (uint8_t *)n3000_afu_get_port_addr(dev);
15537d63899aSWei Huang 	if (!addr)
15547d63899aSWei Huang 		return -ENOENT;
15557d63899aSWei Huang 
15567d63899aSWei Huang 	do {
15577d63899aSWei Huang 		addr += next_offset;
15587d63899aSWei Huang 		header = rte_read64(addr);
15597d63899aSWei Huang 		if ((DFH_TYPE(header) == DFH_TYPE_PRIVATE) &&
15607d63899aSWei Huang 			(DFH_FEATURE_ID(header) == PORT_FEATURE_UINT_ID)) {
15617d63899aSWei Huang 			val = rte_read64(addr + PORT_UINT_CAP_REG);
15627d63899aSWei Huang 			if (vec_start)
15637d63899aSWei Huang 				*vec_start = PORT_VEC_START(val);
15647d63899aSWei Huang 			if (vec_count)
15657d63899aSWei Huang 				*vec_count = PORT_VEC_COUNT(val);
15667d63899aSWei Huang 			return 0;
15677d63899aSWei Huang 		}
15687d63899aSWei Huang 		next_offset = DFH_NEXT_OFFSET(header);
15697d63899aSWei Huang 		if (((next_offset & 0xffff) == 0xffff) || (next_offset == 0))
15707d63899aSWei Huang 			break;
15717d63899aSWei Huang 	} while (!DFH_EOL(header));
15727d63899aSWei Huang 
15737d63899aSWei Huang 	return -ENOENT;
15747d63899aSWei Huang }
15757d63899aSWei Huang 
15767d63899aSWei Huang static int nlb_afu_ctx_release(struct afu_rawdev *dev)
15777d63899aSWei Huang {
15787d63899aSWei Huang 	struct n3000_afu_priv *priv = NULL;
15797d63899aSWei Huang 	struct nlb_afu_ctx *ctx = NULL;
15807d63899aSWei Huang 
15817d63899aSWei Huang 	if (!dev)
15827d63899aSWei Huang 		return -EINVAL;
15837d63899aSWei Huang 
15847d63899aSWei Huang 	priv = (struct n3000_afu_priv *)dev->priv;
15857d63899aSWei Huang 	if (!priv)
15867d63899aSWei Huang 		return -ENOENT;
15877d63899aSWei Huang 
15887d63899aSWei Huang 	ctx = &priv->nlb_ctx;
15897d63899aSWei Huang 
15907d63899aSWei Huang 	rte_free(ctx->dsm_ptr);
15917d63899aSWei Huang 	ctx->dsm_ptr = NULL;
15927d63899aSWei Huang 	ctx->status_ptr = NULL;
15937d63899aSWei Huang 
15947d63899aSWei Huang 	rte_free(ctx->src_ptr);
15957d63899aSWei Huang 	ctx->src_ptr = NULL;
15967d63899aSWei Huang 
15977d63899aSWei Huang 	rte_free(ctx->dest_ptr);
15987d63899aSWei Huang 	ctx->dest_ptr = NULL;
15997d63899aSWei Huang 
16007d63899aSWei Huang 	return 0;
16017d63899aSWei Huang }
16027d63899aSWei Huang 
16037d63899aSWei Huang static int nlb_afu_ctx_init(struct afu_rawdev *dev, uint8_t *addr)
16047d63899aSWei Huang {
16057d63899aSWei Huang 	struct n3000_afu_priv *priv = NULL;
16067d63899aSWei Huang 	struct nlb_afu_ctx *ctx = NULL;
16077d63899aSWei Huang 	int ret = 0;
16087d63899aSWei Huang 
16097d63899aSWei Huang 	if (!dev || !addr)
16107d63899aSWei Huang 		return -EINVAL;
16117d63899aSWei Huang 
16127d63899aSWei Huang 	priv = (struct n3000_afu_priv *)dev->priv;
16137d63899aSWei Huang 	if (!priv)
16147d63899aSWei Huang 		return -ENOENT;
16157d63899aSWei Huang 
16167d63899aSWei Huang 	ctx = &priv->nlb_ctx;
16177d63899aSWei Huang 	ctx->addr = addr;
16187d63899aSWei Huang 
16197d63899aSWei Huang 	ctx->dsm_ptr = (uint8_t *)rte_zmalloc(NULL, DSM_SIZE, TEST_MEM_ALIGN);
16207d63899aSWei Huang 	if (!ctx->dsm_ptr)
16217d63899aSWei Huang 		return -ENOMEM;
16227d63899aSWei Huang 
16237d63899aSWei Huang 	ctx->dsm_iova = rte_malloc_virt2iova(ctx->dsm_ptr);
16247d63899aSWei Huang 	if (ctx->dsm_iova == RTE_BAD_IOVA) {
16257d63899aSWei Huang 		ret = -ENOMEM;
16267d63899aSWei Huang 		goto release_dsm;
16277d63899aSWei Huang 	}
16287d63899aSWei Huang 
16297d63899aSWei Huang 	ctx->src_ptr = (uint8_t *)rte_zmalloc(NULL, NLB_BUF_SIZE,
16307d63899aSWei Huang 		TEST_MEM_ALIGN);
16317d63899aSWei Huang 	if (!ctx->src_ptr) {
16327d63899aSWei Huang 		ret = -ENOMEM;
16337d63899aSWei Huang 		goto release_dsm;
16347d63899aSWei Huang 	}
16357d63899aSWei Huang 	ctx->src_iova = rte_malloc_virt2iova(ctx->src_ptr);
16367d63899aSWei Huang 	if (ctx->src_iova == RTE_BAD_IOVA) {
16377d63899aSWei Huang 		ret = -ENOMEM;
16387d63899aSWei Huang 		goto release_src;
16397d63899aSWei Huang 	}
16407d63899aSWei Huang 
16417d63899aSWei Huang 	ctx->dest_ptr = (uint8_t *)rte_zmalloc(NULL, NLB_BUF_SIZE,
16427d63899aSWei Huang 		TEST_MEM_ALIGN);
16437d63899aSWei Huang 	if (!ctx->dest_ptr) {
16447d63899aSWei Huang 		ret = -ENOMEM;
16457d63899aSWei Huang 		goto release_src;
16467d63899aSWei Huang 	}
16477d63899aSWei Huang 	ctx->dest_iova = rte_malloc_virt2iova(ctx->dest_ptr);
16487d63899aSWei Huang 	if (ctx->dest_iova == RTE_BAD_IOVA) {
16497d63899aSWei Huang 		ret = -ENOMEM;
16507d63899aSWei Huang 		goto release_dest;
16517d63899aSWei Huang 	}
16527d63899aSWei Huang 
16537d63899aSWei Huang 	ctx->status_ptr = (struct nlb_dsm_status *)(ctx->dsm_ptr + DSM_STATUS);
16547d63899aSWei Huang 	return 0;
16557d63899aSWei Huang 
16567d63899aSWei Huang release_dest:
16577d63899aSWei Huang 	rte_free(ctx->dest_ptr);
16587d63899aSWei Huang 	ctx->dest_ptr = NULL;
16597d63899aSWei Huang release_src:
16607d63899aSWei Huang 	rte_free(ctx->src_ptr);
16617d63899aSWei Huang 	ctx->src_ptr = NULL;
16627d63899aSWei Huang release_dsm:
16637d63899aSWei Huang 	rte_free(ctx->dsm_ptr);
16647d63899aSWei Huang 	ctx->dsm_ptr = NULL;
16657d63899aSWei Huang 	return ret;
16667d63899aSWei Huang }
16677d63899aSWei Huang 
16687d63899aSWei Huang static int dma_afu_ctx_release(struct afu_rawdev *dev)
16697d63899aSWei Huang {
16707d63899aSWei Huang 	struct n3000_afu_priv *priv = NULL;
16717d63899aSWei Huang 	struct dma_afu_ctx *ctx = NULL;
16727d63899aSWei Huang 
16737d63899aSWei Huang 	if (!dev)
16747d63899aSWei Huang 		return -EINVAL;
16757d63899aSWei Huang 
16767d63899aSWei Huang 	priv = (struct n3000_afu_priv *)dev->priv;
16777d63899aSWei Huang 	if (!priv)
16787d63899aSWei Huang 		return -ENOENT;
16797d63899aSWei Huang 
16807d63899aSWei Huang 	ctx = &priv->dma_ctx[0];
16817d63899aSWei Huang 
16827d63899aSWei Huang 	rte_free(ctx->desc_buf);
16837d63899aSWei Huang 	ctx->desc_buf = NULL;
16847d63899aSWei Huang 
16857d63899aSWei Huang 	rte_free(ctx->magic_buf);
16867d63899aSWei Huang 	ctx->magic_buf = NULL;
16877d63899aSWei Huang 
16887d63899aSWei Huang 	close(ctx->event_fd);
16897d63899aSWei Huang 	return 0;
16907d63899aSWei Huang }
16917d63899aSWei Huang 
16927d63899aSWei Huang static int dma_afu_ctx_init(struct afu_rawdev *dev, int index, uint8_t *addr)
16937d63899aSWei Huang {
16947d63899aSWei Huang 	struct n3000_afu_priv *priv = NULL;
16957d63899aSWei Huang 	struct dma_afu_ctx *ctx = NULL;
16967d63899aSWei Huang 	uint64_t mem_sz[] = {0x100000000, 0x100000000, 0x40000000, 0x1000000};
16977d63899aSWei Huang 	static int efds[1] = {0};
16987d63899aSWei Huang 	uint32_t vec_start = 0;
16997d63899aSWei Huang 	int ret = 0;
17007d63899aSWei Huang 
17017d63899aSWei Huang 	if (!dev || (index < 0) || (index >= NUM_N3000_DMA) || !addr)
17027d63899aSWei Huang 		return -EINVAL;
17037d63899aSWei Huang 
17047d63899aSWei Huang 	priv = (struct n3000_afu_priv *)dev->priv;
17057d63899aSWei Huang 	if (!priv)
17067d63899aSWei Huang 		return -ENOENT;
17077d63899aSWei Huang 
17087d63899aSWei Huang 	ctx = &priv->dma_ctx[index];
17097d63899aSWei Huang 	ctx->index = index;
17107d63899aSWei Huang 	ctx->addr = addr;
17117d63899aSWei Huang 	ctx->csr_addr = addr + DMA_CSR;
17127d63899aSWei Huang 	ctx->desc_addr = addr + DMA_DESC;
17137d63899aSWei Huang 	ctx->ase_ctrl_addr = addr + DMA_ASE_CTRL;
17147d63899aSWei Huang 	ctx->ase_data_addr = addr + DMA_ASE_DATA;
17157d63899aSWei Huang 	ctx->mem_size = mem_sz[ctx->index];
17167d63899aSWei Huang 	ctx->cur_ase_page = INVALID_ASE_PAGE;
17177d63899aSWei Huang 	if (ctx->index == 0) {
17187d63899aSWei Huang 		ret = n3000_afu_get_irq_capability(dev, &vec_start, NULL);
17197d63899aSWei Huang 		if (ret)
17207d63899aSWei Huang 			return ret;
17217d63899aSWei Huang 
17227d63899aSWei Huang 		efds[0] = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
17237d63899aSWei Huang 		if (efds[0] < 0) {
17247d63899aSWei Huang 			IFPGA_RAWDEV_PMD_ERR("eventfd create failed");
17257d63899aSWei Huang 			return -EBADF;
17267d63899aSWei Huang 		}
17277d63899aSWei Huang #ifdef VFIO_PRESENT
17287d63899aSWei Huang 		if (dma_afu_set_irqs(dev, vec_start, 1, efds))
17297d63899aSWei Huang 			IFPGA_RAWDEV_PMD_ERR("DMA interrupt setup failed");
17307d63899aSWei Huang #endif
17317d63899aSWei Huang 	}
17327d63899aSWei Huang 	ctx->event_fd = efds[0];
17337d63899aSWei Huang 
17347d63899aSWei Huang 	ctx->desc_buf = (msgdma_ext_desc *)rte_zmalloc(NULL,
17357d63899aSWei Huang 		sizeof(msgdma_ext_desc), DMA_ALIGN_BYTES);
17367d63899aSWei Huang 	if (!ctx->desc_buf) {
17377d63899aSWei Huang 		ret = -ENOMEM;
17387d63899aSWei Huang 		goto release;
17397d63899aSWei Huang 	}
17407d63899aSWei Huang 
17417d63899aSWei Huang 	ctx->magic_buf = (uint64_t *)rte_zmalloc(NULL, MAGIC_BUF_SIZE,
17427d63899aSWei Huang 		TEST_MEM_ALIGN);
17437d63899aSWei Huang 	if (!ctx->magic_buf) {
17447d63899aSWei Huang 		ret = -ENOMEM;
17457d63899aSWei Huang 		goto release;
17467d63899aSWei Huang 	}
17477d63899aSWei Huang 	ctx->magic_iova = rte_malloc_virt2iova(ctx->magic_buf);
17487d63899aSWei Huang 	if (ctx->magic_iova == RTE_BAD_IOVA) {
17497d63899aSWei Huang 		ret = -ENOMEM;
17507d63899aSWei Huang 		goto release;
17517d63899aSWei Huang 	}
17527d63899aSWei Huang 
17537d63899aSWei Huang 	return 0;
17547d63899aSWei Huang 
17557d63899aSWei Huang release:
17567d63899aSWei Huang 	dma_afu_ctx_release(dev);
17577d63899aSWei Huang 	return ret;
17587d63899aSWei Huang }
17597d63899aSWei Huang 
17607d63899aSWei Huang static int n3000_afu_ctx_init(struct afu_rawdev *dev)
17617d63899aSWei Huang {
17627d63899aSWei Huang 	struct n3000_afu_priv *priv = NULL;
17637d63899aSWei Huang 	uint8_t *addr = NULL;
17647d63899aSWei Huang 	uint64_t header = 0;
17657d63899aSWei Huang 	uint64_t uuid_hi = 0;
17667d63899aSWei Huang 	uint64_t uuid_lo = 0;
17677d63899aSWei Huang 	uint64_t next_offset = 0;
17687d63899aSWei Huang 	int ret = 0;
17697d63899aSWei Huang 
17707d63899aSWei Huang 	if (!dev)
17717d63899aSWei Huang 		return -EINVAL;
17727d63899aSWei Huang 
17737d63899aSWei Huang 	priv = (struct n3000_afu_priv *)dev->priv;
17747d63899aSWei Huang 	if (!priv)
17757d63899aSWei Huang 		return -ENOENT;
17767d63899aSWei Huang 
17777d63899aSWei Huang 	addr = (uint8_t *)dev->addr;
17787d63899aSWei Huang 	do {
17797d63899aSWei Huang 		addr += next_offset;
17807d63899aSWei Huang 		header = rte_read64(addr);
17817d63899aSWei Huang 		uuid_lo = rte_read64(addr + DFH_UUID_L_OFFSET);
17827d63899aSWei Huang 		uuid_hi = rte_read64(addr + DFH_UUID_H_OFFSET);
17837d63899aSWei Huang 
17847d63899aSWei Huang 		if ((DFH_TYPE(header) == DFH_TYPE_AFU) &&
17857d63899aSWei Huang 			(uuid_lo == N3000_NLB0_UUID_L) &&
17867d63899aSWei Huang 			(uuid_hi == N3000_NLB0_UUID_H)) {
17877d63899aSWei Huang 			IFPGA_RAWDEV_PMD_INFO("AFU NLB0 found @ %p", (void *)addr);
17887d63899aSWei Huang 			ret = nlb_afu_ctx_init(dev, addr);
17897d63899aSWei Huang 			if (ret)
17907d63899aSWei Huang 				return ret;
17917d63899aSWei Huang 		} else if ((DFH_TYPE(header) == DFH_TYPE_BBB) &&
17927d63899aSWei Huang 			(uuid_lo == N3000_DMA_UUID_L) &&
17937d63899aSWei Huang 			(uuid_hi == N3000_DMA_UUID_H) &&
17947d63899aSWei Huang 			(priv->num_dma < NUM_N3000_DMA)) {
17957d63899aSWei Huang 			IFPGA_RAWDEV_PMD_INFO("AFU DMA%d found @ %p",
17967d63899aSWei Huang 				priv->num_dma, (void *)addr);
17977d63899aSWei Huang 			ret = dma_afu_ctx_init(dev, priv->num_dma, addr);
17987d63899aSWei Huang 			if (ret)
17997d63899aSWei Huang 				return ret;
18007d63899aSWei Huang 			priv->num_dma++;
18017d63899aSWei Huang 		} else {
18027d63899aSWei Huang 			IFPGA_RAWDEV_PMD_DEBUG("DFH: type %"PRIu64
18037d63899aSWei Huang 				", uuid %016"PRIx64"%016"PRIx64,
18047d63899aSWei Huang 				DFH_TYPE(header), uuid_hi, uuid_lo);
18057d63899aSWei Huang 		}
18067d63899aSWei Huang 
18077d63899aSWei Huang 		next_offset = DFH_NEXT_OFFSET(header);
18087d63899aSWei Huang 		if (((next_offset & 0xffff) == 0xffff) || (next_offset == 0))
18097d63899aSWei Huang 			break;
18107d63899aSWei Huang 	} while (!DFH_EOL(header));
18117d63899aSWei Huang 
18127d63899aSWei Huang 	return 0;
18137d63899aSWei Huang }
18147d63899aSWei Huang 
18157d63899aSWei Huang static int n3000_afu_init(struct afu_rawdev *dev)
18167d63899aSWei Huang {
18177d63899aSWei Huang 	if (!dev)
18187d63899aSWei Huang 		return -EINVAL;
18197d63899aSWei Huang 
18207d63899aSWei Huang 	if (!dev->priv) {
18217d63899aSWei Huang 		dev->priv = rte_zmalloc(NULL, sizeof(struct n3000_afu_priv), 0);
18227d63899aSWei Huang 		if (!dev->priv)
18237d63899aSWei Huang 			return -ENOMEM;
18247d63899aSWei Huang 	}
18257d63899aSWei Huang 
18267d63899aSWei Huang 	return n3000_afu_ctx_init(dev);
18277d63899aSWei Huang }
18287d63899aSWei Huang 
18297d63899aSWei Huang static int n3000_afu_config(struct afu_rawdev *dev, void *config,
18307d63899aSWei Huang 	size_t config_size)
18317d63899aSWei Huang {
18327d63899aSWei Huang 	struct n3000_afu_priv *priv = NULL;
18337d63899aSWei Huang 	struct rte_pmd_afu_n3000_cfg *cfg = NULL;
18347d63899aSWei Huang 	int i = 0;
18357d63899aSWei Huang 	uint64_t top = 0;
18367d63899aSWei Huang 
18377d63899aSWei Huang 	if (!dev || !config || !config_size)
18387d63899aSWei Huang 		return -EINVAL;
18397d63899aSWei Huang 
18407d63899aSWei Huang 	priv = (struct n3000_afu_priv *)dev->priv;
18417d63899aSWei Huang 	if (!priv)
18427d63899aSWei Huang 		return -ENOENT;
18437d63899aSWei Huang 
18447d63899aSWei Huang 	if (config_size != sizeof(struct rte_pmd_afu_n3000_cfg))
18457d63899aSWei Huang 		return -EINVAL;
18467d63899aSWei Huang 
18477d63899aSWei Huang 	cfg = (struct rte_pmd_afu_n3000_cfg *)config;
18487d63899aSWei Huang 	if (cfg->type == RTE_PMD_AFU_N3000_NLB) {
18497d63899aSWei Huang 		if (cfg->nlb_cfg.mode != NLB_MODE_LPBK)
18507d63899aSWei Huang 			return -EINVAL;
18517d63899aSWei Huang 		if ((cfg->nlb_cfg.read_vc > NLB_VC_RANDOM) ||
18527d63899aSWei Huang 			(cfg->nlb_cfg.write_vc > NLB_VC_RANDOM))
18537d63899aSWei Huang 			return -EINVAL;
18547d63899aSWei Huang 		if (cfg->nlb_cfg.wrfence_vc > NLB_VC_VH1)
18557d63899aSWei Huang 			return -EINVAL;
18567d63899aSWei Huang 		if (cfg->nlb_cfg.cache_hint > NLB_RDLINE_MIXED)
18577d63899aSWei Huang 			return -EINVAL;
18587d63899aSWei Huang 		if (cfg->nlb_cfg.cache_policy > NLB_WRPUSH_I)
18597d63899aSWei Huang 			return -EINVAL;
18607d63899aSWei Huang 		if ((cfg->nlb_cfg.multi_cl != 1) &&
18617d63899aSWei Huang 			(cfg->nlb_cfg.multi_cl != 2) &&
18627d63899aSWei Huang 			(cfg->nlb_cfg.multi_cl != 4))
18637d63899aSWei Huang 			return -EINVAL;
18647d63899aSWei Huang 		if ((cfg->nlb_cfg.begin < MIN_CACHE_LINES) ||
18657d63899aSWei Huang 			(cfg->nlb_cfg.begin > MAX_CACHE_LINES))
18667d63899aSWei Huang 			return -EINVAL;
18677d63899aSWei Huang 		if ((cfg->nlb_cfg.end < cfg->nlb_cfg.begin) ||
18687d63899aSWei Huang 			(cfg->nlb_cfg.end > MAX_CACHE_LINES))
18697d63899aSWei Huang 			return -EINVAL;
18707d63899aSWei Huang 		rte_memcpy(&priv->nlb_cfg, &cfg->nlb_cfg,
18717d63899aSWei Huang 			sizeof(struct rte_pmd_afu_nlb_cfg));
18727d63899aSWei Huang 	} else if (cfg->type == RTE_PMD_AFU_N3000_DMA) {
18737d63899aSWei Huang 		if (cfg->dma_cfg.index >= NUM_N3000_DMA)
18747d63899aSWei Huang 			return -EINVAL;
18757d63899aSWei Huang 		i = cfg->dma_cfg.index;
18767d63899aSWei Huang 		if (cfg->dma_cfg.length > priv->dma_ctx[i].mem_size)
18777d63899aSWei Huang 			return -EINVAL;
18787d63899aSWei Huang 		if (cfg->dma_cfg.offset >= priv->dma_ctx[i].mem_size)
18797d63899aSWei Huang 			return -EINVAL;
18807d63899aSWei Huang 		top = cfg->dma_cfg.length + cfg->dma_cfg.offset;
18817d63899aSWei Huang 		if ((top == 0) || (top > priv->dma_ctx[i].mem_size))
18827d63899aSWei Huang 			return -EINVAL;
18837d63899aSWei Huang 		if (i == 3) {  /* QDR connected to DMA3 */
18847d63899aSWei Huang 			if (cfg->dma_cfg.length & 0x3f) {
18857d63899aSWei Huang 				cfg->dma_cfg.length &= ~0x3f;
18867d63899aSWei Huang 				IFPGA_RAWDEV_PMD_INFO("Round size to %x for QDR",
18877d63899aSWei Huang 					cfg->dma_cfg.length);
18887d63899aSWei Huang 			}
18897d63899aSWei Huang 		}
18907d63899aSWei Huang 		rte_memcpy(&priv->dma_cfg, &cfg->dma_cfg,
18917d63899aSWei Huang 			sizeof(struct rte_pmd_afu_dma_cfg));
18927d63899aSWei Huang 	} else {
18937d63899aSWei Huang 		IFPGA_RAWDEV_PMD_ERR("Invalid type of N3000 AFU");
18947d63899aSWei Huang 		return -EINVAL;
18957d63899aSWei Huang 	}
18967d63899aSWei Huang 
18977d63899aSWei Huang 	priv->cfg_type = cfg->type;
18987d63899aSWei Huang 	return 0;
18997d63899aSWei Huang }
19007d63899aSWei Huang 
19017d63899aSWei Huang static int n3000_afu_test(struct afu_rawdev *dev)
19027d63899aSWei Huang {
19037d63899aSWei Huang 	struct n3000_afu_priv *priv = NULL;
19047d63899aSWei Huang 	int ret = 0;
19057d63899aSWei Huang 
19067d63899aSWei Huang 	if (!dev)
19077d63899aSWei Huang 		return -EINVAL;
19087d63899aSWei Huang 
19097d63899aSWei Huang 	if (!dev->priv)
19107d63899aSWei Huang 		return -ENOENT;
19117d63899aSWei Huang 
19127d63899aSWei Huang 	priv = (struct n3000_afu_priv *)dev->priv;
19137d63899aSWei Huang 
19147d63899aSWei Huang 	if (priv->cfg_type == RTE_PMD_AFU_N3000_NLB) {
19157d63899aSWei Huang 		IFPGA_RAWDEV_PMD_INFO("Test NLB");
19167d63899aSWei Huang 		ret = nlb_afu_test(dev);
19177d63899aSWei Huang 	} else if (priv->cfg_type == RTE_PMD_AFU_N3000_DMA) {
19187d63899aSWei Huang 		IFPGA_RAWDEV_PMD_INFO("Test DMA%u", priv->dma_cfg.index);
19197d63899aSWei Huang 		ret = dma_afu_test(dev);
19207d63899aSWei Huang 	} else {
19217d63899aSWei Huang 		IFPGA_RAWDEV_PMD_ERR("Please configure AFU before test");
19227d63899aSWei Huang 		ret = -EINVAL;
19237d63899aSWei Huang 	}
19247d63899aSWei Huang 
19257d63899aSWei Huang 	return ret;
19267d63899aSWei Huang }
19277d63899aSWei Huang 
19287d63899aSWei Huang static int n3000_afu_close(struct afu_rawdev *dev)
19297d63899aSWei Huang {
19307d63899aSWei Huang 	if (!dev)
19317d63899aSWei Huang 		return -EINVAL;
19327d63899aSWei Huang 
19337d63899aSWei Huang 	nlb_afu_ctx_release(dev);
19347d63899aSWei Huang 	dma_afu_ctx_release(dev);
19357d63899aSWei Huang 
19367d63899aSWei Huang 	rte_free(dev->priv);
19377d63899aSWei Huang 	dev->priv = NULL;
19387d63899aSWei Huang 
19397d63899aSWei Huang 	return 0;
19407d63899aSWei Huang }
19417d63899aSWei Huang 
19427d63899aSWei Huang static int n3000_afu_dump(struct afu_rawdev *dev, FILE *f)
19437d63899aSWei Huang {
19447d63899aSWei Huang 	struct n3000_afu_priv *priv = NULL;
19457d63899aSWei Huang 
19467d63899aSWei Huang 	if (!dev)
19477d63899aSWei Huang 		return -EINVAL;
19487d63899aSWei Huang 
19497d63899aSWei Huang 	priv = (struct n3000_afu_priv *)dev->priv;
19507d63899aSWei Huang 	if (!priv)
19517d63899aSWei Huang 		return -ENOENT;
19527d63899aSWei Huang 
19537d63899aSWei Huang 	if (!f)
19547d63899aSWei Huang 		f = stdout;
19557d63899aSWei Huang 
19567d63899aSWei Huang 	if (priv->cfg_type == RTE_PMD_AFU_N3000_NLB) {
19577d63899aSWei Huang 		struct nlb_afu_ctx *ctx = &priv->nlb_ctx;
19587d63899aSWei Huang 		fprintf(f, "addr:\t\t%p\n", (void *)ctx->addr);
19597d63899aSWei Huang 		fprintf(f, "dsm_ptr:\t%p\n", (void *)ctx->dsm_ptr);
19607d63899aSWei Huang 		fprintf(f, "dsm_iova:\t0x%"PRIx64"\n", ctx->dsm_iova);
19617d63899aSWei Huang 		fprintf(f, "src_ptr:\t%p\n", (void *)ctx->src_ptr);
19627d63899aSWei Huang 		fprintf(f, "src_iova:\t0x%"PRIx64"\n", ctx->src_iova);
19637d63899aSWei Huang 		fprintf(f, "dest_ptr:\t%p\n", (void *)ctx->dest_ptr);
19647d63899aSWei Huang 		fprintf(f, "dest_iova:\t0x%"PRIx64"\n", ctx->dest_iova);
19657d63899aSWei Huang 		fprintf(f, "status_ptr:\t%p\n", (void *)ctx->status_ptr);
19667d63899aSWei Huang 	} else if (priv->cfg_type == RTE_PMD_AFU_N3000_DMA) {
19677d63899aSWei Huang 		struct dma_afu_ctx *ctx = &priv->dma_ctx[priv->dma_cfg.index];
19687d63899aSWei Huang 		fprintf(f, "index:\t\t%d\n", ctx->index);
19697d63899aSWei Huang 		fprintf(f, "addr:\t\t%p\n", (void *)ctx->addr);
19707d63899aSWei Huang 		fprintf(f, "csr_addr:\t%p\n", (void *)ctx->csr_addr);
19717d63899aSWei Huang 		fprintf(f, "desc_addr:\t%p\n", (void *)ctx->desc_addr);
19727d63899aSWei Huang 		fprintf(f, "ase_ctrl_addr:\t%p\n", (void *)ctx->ase_ctrl_addr);
19737d63899aSWei Huang 		fprintf(f, "ase_data_addr:\t%p\n", (void *)ctx->ase_data_addr);
19747d63899aSWei Huang 		fprintf(f, "desc_buf:\t%p\n", (void *)ctx->desc_buf);
19757d63899aSWei Huang 		fprintf(f, "magic_buf:\t%p\n", (void *)ctx->magic_buf);
19767d63899aSWei Huang 		fprintf(f, "magic_iova:\t0x%"PRIx64"\n", ctx->magic_iova);
19777d63899aSWei Huang 	} else {
19787d63899aSWei Huang 		return -EINVAL;
19797d63899aSWei Huang 	}
19807d63899aSWei Huang 
19817d63899aSWei Huang 	return 0;
19827d63899aSWei Huang }
19837d63899aSWei Huang 
19847d63899aSWei Huang static int n3000_afu_reset(struct afu_rawdev *dev)
19857d63899aSWei Huang {
19867d63899aSWei Huang 	uint8_t *addr = NULL;
19877d63899aSWei Huang 	uint64_t val = 0;
19887d63899aSWei Huang 
19897d63899aSWei Huang 	addr = (uint8_t *)n3000_afu_get_port_addr(dev);
19907d63899aSWei Huang 	if (!addr)
19917d63899aSWei Huang 		return -ENOENT;
19927d63899aSWei Huang 
19937d63899aSWei Huang 	val = rte_read64(addr + PORT_CTRL_REG);
19947d63899aSWei Huang 	val |= PORT_SOFT_RESET;
19957d63899aSWei Huang 	rte_write64(val, addr + PORT_CTRL_REG);
19967d63899aSWei Huang 	rte_delay_us(100);
19977d63899aSWei Huang 	val &= ~PORT_SOFT_RESET;
19987d63899aSWei Huang 	rte_write64(val, addr + PORT_CTRL_REG);
19997d63899aSWei Huang 
20007d63899aSWei Huang 	return 0;
20017d63899aSWei Huang }
20027d63899aSWei Huang 
20037d63899aSWei Huang static struct afu_ops n3000_afu_ops = {
20047d63899aSWei Huang 	.init = n3000_afu_init,
20057d63899aSWei Huang 	.config = n3000_afu_config,
20067d63899aSWei Huang 	.start = NULL,
20077d63899aSWei Huang 	.stop = NULL,
20087d63899aSWei Huang 	.test = n3000_afu_test,
20097d63899aSWei Huang 	.close = n3000_afu_close,
20107d63899aSWei Huang 	.dump = n3000_afu_dump,
20117d63899aSWei Huang 	.reset = n3000_afu_reset
20127d63899aSWei Huang };
20137d63899aSWei Huang 
20147d63899aSWei Huang static struct afu_rawdev_drv n3000_afu_drv = {
20157d63899aSWei Huang 	.uuid = { N3000_AFU_UUID_L, N3000_AFU_UUID_H },
20167d63899aSWei Huang 	.ops = &n3000_afu_ops
20177d63899aSWei Huang };
20187d63899aSWei Huang 
20197d63899aSWei Huang AFU_PMD_REGISTER(n3000_afu_drv);
2020