xref: /dpdk/drivers/dma/skeleton/skeleton_dmadev.c (revision 2b843cac232eb3f2fa79e4254e21766817e2019f)
105d5fc66SChengwen Feng /* SPDX-License-Identifier: BSD-3-Clause
2e1d7b79aSChengwen Feng  * Copyright(c) 2021-2024 HiSilicon Limited
305d5fc66SChengwen Feng  */
405d5fc66SChengwen Feng 
505d5fc66SChengwen Feng #include <inttypes.h>
672b452c5SDmitry Kozlyuk #include <stdlib.h>
705d5fc66SChengwen Feng 
8f241553bSTyler Retzlaff #include <pthread.h>
9f241553bSTyler Retzlaff 
104851ef2bSDavid Marchand #include <bus_vdev_driver.h>
1105d5fc66SChengwen Feng #include <rte_cycles.h>
1205d5fc66SChengwen Feng #include <rte_eal.h>
1305d5fc66SChengwen Feng #include <rte_kvargs.h>
1405d5fc66SChengwen Feng #include <rte_lcore.h>
1505d5fc66SChengwen Feng #include <rte_log.h>
1605d5fc66SChengwen Feng #include <rte_malloc.h>
1705d5fc66SChengwen Feng #include <rte_memcpy.h>
1805d5fc66SChengwen Feng 
1905d5fc66SChengwen Feng #include <rte_dmadev_pmd.h>
2005d5fc66SChengwen Feng 
2105d5fc66SChengwen Feng #include "skeleton_dmadev.h"
2205d5fc66SChengwen Feng 
2305d5fc66SChengwen Feng RTE_LOG_REGISTER_DEFAULT(skeldma_logtype, INFO);
24*2b843cacSDavid Marchand #define RTE_LOGTYPE_SKELDMA skeldma_logtype
25*2b843cacSDavid Marchand #define SKELDMA_LOG(level, ...) \
26*2b843cacSDavid Marchand 	RTE_LOG_LINE_PREFIX(level, SKELDMA, "%s(): ", __func__, __VA_ARGS__)
2705d5fc66SChengwen Feng 
2805d5fc66SChengwen Feng static int
2905d5fc66SChengwen Feng skeldma_info_get(const struct rte_dma_dev *dev, struct rte_dma_info *dev_info,
3005d5fc66SChengwen Feng 		 uint32_t info_sz)
3105d5fc66SChengwen Feng {
3205d5fc66SChengwen Feng #define SKELDMA_MAX_DESC	8192
3305d5fc66SChengwen Feng #define SKELDMA_MIN_DESC	32
3405d5fc66SChengwen Feng 
3505d5fc66SChengwen Feng 	RTE_SET_USED(dev);
3605d5fc66SChengwen Feng 	RTE_SET_USED(info_sz);
3705d5fc66SChengwen Feng 
3805d5fc66SChengwen Feng 	dev_info->dev_capa = RTE_DMA_CAPA_MEM_TO_MEM |
3905d5fc66SChengwen Feng 			     RTE_DMA_CAPA_SVA |
40e1d7b79aSChengwen Feng 			     RTE_DMA_CAPA_OPS_COPY |
410335480fSChengwen Feng 			     RTE_DMA_CAPA_OPS_COPY_SG |
420335480fSChengwen Feng 			     RTE_DMA_CAPA_OPS_FILL;
4305d5fc66SChengwen Feng 	dev_info->max_vchans = 1;
4405d5fc66SChengwen Feng 	dev_info->max_desc = SKELDMA_MAX_DESC;
4505d5fc66SChengwen Feng 	dev_info->min_desc = SKELDMA_MIN_DESC;
46e1d7b79aSChengwen Feng 	dev_info->max_sges = SKELDMA_MAX_SGES;
4705d5fc66SChengwen Feng 
4805d5fc66SChengwen Feng 	return 0;
4905d5fc66SChengwen Feng }
5005d5fc66SChengwen Feng 
5105d5fc66SChengwen Feng static int
5205d5fc66SChengwen Feng skeldma_configure(struct rte_dma_dev *dev, const struct rte_dma_conf *conf,
5305d5fc66SChengwen Feng 		  uint32_t conf_sz)
5405d5fc66SChengwen Feng {
5505d5fc66SChengwen Feng 	RTE_SET_USED(dev);
5605d5fc66SChengwen Feng 	RTE_SET_USED(conf);
5705d5fc66SChengwen Feng 	RTE_SET_USED(conf_sz);
5805d5fc66SChengwen Feng 	return 0;
5905d5fc66SChengwen Feng }
6005d5fc66SChengwen Feng 
61e1d7b79aSChengwen Feng static inline void
62e1d7b79aSChengwen Feng do_copy_sg_one(struct rte_dma_sge *src, struct rte_dma_sge *dst, uint16_t nb_dst, uint64_t offset)
63e1d7b79aSChengwen Feng {
64e1d7b79aSChengwen Feng 	uint32_t src_off = 0, dst_off = 0;
65e1d7b79aSChengwen Feng 	uint32_t copy_len = 0;
66e1d7b79aSChengwen Feng 	uint64_t tmp = 0;
67e1d7b79aSChengwen Feng 	uint16_t i;
68e1d7b79aSChengwen Feng 
69e1d7b79aSChengwen Feng 	/* Locate the segment from which the copy is started. */
70e1d7b79aSChengwen Feng 	for (i = 0; i < nb_dst; i++) {
71e1d7b79aSChengwen Feng 		tmp += dst[i].length;
72e1d7b79aSChengwen Feng 		if (offset < tmp) {
73e1d7b79aSChengwen Feng 			copy_len = tmp - offset;
74e1d7b79aSChengwen Feng 			dst_off = dst[i].length - copy_len;
75e1d7b79aSChengwen Feng 			break;
76e1d7b79aSChengwen Feng 		}
77e1d7b79aSChengwen Feng 	}
78e1d7b79aSChengwen Feng 
79e1d7b79aSChengwen Feng 	for (/* Use the above index */; i < nb_dst; i++, copy_len = dst[i].length) {
80e1d7b79aSChengwen Feng 		copy_len = RTE_MIN(copy_len, src->length - src_off);
81e1d7b79aSChengwen Feng 		rte_memcpy((uint8_t *)(uintptr_t)dst[i].addr + dst_off,
82e1d7b79aSChengwen Feng 			   (uint8_t *)(uintptr_t)src->addr + src_off,
83e1d7b79aSChengwen Feng 			   copy_len);
84e1d7b79aSChengwen Feng 		src_off += copy_len;
85e1d7b79aSChengwen Feng 		if (src_off >= src->length)
86e1d7b79aSChengwen Feng 			break;
87e1d7b79aSChengwen Feng 		dst_off = 0;
88e1d7b79aSChengwen Feng 	}
89e1d7b79aSChengwen Feng }
90e1d7b79aSChengwen Feng 
91e1d7b79aSChengwen Feng static inline void
92e1d7b79aSChengwen Feng do_copy_sg(struct skeldma_desc *desc)
93e1d7b79aSChengwen Feng {
94e1d7b79aSChengwen Feng 	uint64_t offset = 0;
95e1d7b79aSChengwen Feng 	uint16_t i;
96e1d7b79aSChengwen Feng 
97e1d7b79aSChengwen Feng 	for (i = 0; i < desc->copy_sg.nb_src; i++) {
98e1d7b79aSChengwen Feng 		do_copy_sg_one(&desc->copy_sg.src[i], desc->copy_sg.dst,
99e1d7b79aSChengwen Feng 			       desc->copy_sg.nb_dst, offset);
100e1d7b79aSChengwen Feng 		offset += desc->copy_sg.src[i].length;
101e1d7b79aSChengwen Feng 	}
102e1d7b79aSChengwen Feng }
103e1d7b79aSChengwen Feng 
1040335480fSChengwen Feng static inline void
1050335480fSChengwen Feng do_fill(struct skeldma_desc *desc)
1060335480fSChengwen Feng {
1070335480fSChengwen Feng 	uint8_t *fills = (uint8_t *)&desc->fill.pattern;
1080335480fSChengwen Feng 	uint8_t *dst = (uint8_t *)desc->fill.dst;
1090335480fSChengwen Feng 	uint32_t i;
1100335480fSChengwen Feng 
1110335480fSChengwen Feng 	for (i = 0; i < desc->fill.len; i++)
1120335480fSChengwen Feng 		dst[i] = fills[i % 8];
1130335480fSChengwen Feng }
1140335480fSChengwen Feng 
115f241553bSTyler Retzlaff static uint32_t
1160335480fSChengwen Feng cpuwork_thread(void *param)
11705d5fc66SChengwen Feng {
11805d5fc66SChengwen Feng #define SLEEP_THRESHOLD		10000
11905d5fc66SChengwen Feng #define SLEEP_US_VAL		10
12005d5fc66SChengwen Feng 
12105d5fc66SChengwen Feng 	struct rte_dma_dev *dev = param;
12205d5fc66SChengwen Feng 	struct skeldma_hw *hw = dev->data->dev_private;
12305d5fc66SChengwen Feng 	struct skeldma_desc *desc = NULL;
12405d5fc66SChengwen Feng 	int ret;
12505d5fc66SChengwen Feng 
12605d5fc66SChengwen Feng 	while (!hw->exit_flag) {
12705d5fc66SChengwen Feng 		ret = rte_ring_dequeue(hw->desc_running, (void **)&desc);
12805d5fc66SChengwen Feng 		if (ret) {
12905d5fc66SChengwen Feng 			hw->zero_req_count++;
13005d5fc66SChengwen Feng 			if (hw->zero_req_count == 0)
13105d5fc66SChengwen Feng 				hw->zero_req_count = SLEEP_THRESHOLD;
13205d5fc66SChengwen Feng 			if (hw->zero_req_count >= SLEEP_THRESHOLD)
13305d5fc66SChengwen Feng 				rte_delay_us_sleep(SLEEP_US_VAL);
13405d5fc66SChengwen Feng 			continue;
13505d5fc66SChengwen Feng 		}
13605d5fc66SChengwen Feng 		hw->zero_req_count = 0;
137e1d7b79aSChengwen Feng 
138e1d7b79aSChengwen Feng 		if (desc->op == SKELDMA_OP_COPY)
139e1d7b79aSChengwen Feng 			rte_memcpy(desc->copy.dst, desc->copy.src, desc->copy.len);
140e1d7b79aSChengwen Feng 		else if (desc->op == SKELDMA_OP_COPY_SG)
141e1d7b79aSChengwen Feng 			do_copy_sg(desc);
1420335480fSChengwen Feng 		else if (desc->op == SKELDMA_OP_FILL)
1430335480fSChengwen Feng 			do_fill(desc);
144e1d7b79aSChengwen Feng 
145e12a0166STyler Retzlaff 		rte_atomic_fetch_add_explicit(&hw->completed_count, 1, rte_memory_order_release);
14605d5fc66SChengwen Feng 		(void)rte_ring_enqueue(hw->desc_completed, (void *)desc);
14705d5fc66SChengwen Feng 	}
14805d5fc66SChengwen Feng 
149f241553bSTyler Retzlaff 	return 0;
15005d5fc66SChengwen Feng }
15105d5fc66SChengwen Feng 
15205d5fc66SChengwen Feng static void
15305d5fc66SChengwen Feng fflush_ring(struct skeldma_hw *hw, struct rte_ring *ring)
15405d5fc66SChengwen Feng {
15505d5fc66SChengwen Feng 	struct skeldma_desc *desc = NULL;
15605d5fc66SChengwen Feng 	while (rte_ring_count(ring) > 0) {
15705d5fc66SChengwen Feng 		(void)rte_ring_dequeue(ring, (void **)&desc);
15805d5fc66SChengwen Feng 		(void)rte_ring_enqueue(hw->desc_empty, (void *)desc);
15905d5fc66SChengwen Feng 	}
16005d5fc66SChengwen Feng }
16105d5fc66SChengwen Feng 
16205d5fc66SChengwen Feng static int
16305d5fc66SChengwen Feng skeldma_start(struct rte_dma_dev *dev)
16405d5fc66SChengwen Feng {
16505d5fc66SChengwen Feng 	struct skeldma_hw *hw = dev->data->dev_private;
166a7ba40b2SThomas Monjalon 	char name[RTE_THREAD_INTERNAL_NAME_SIZE];
16705d5fc66SChengwen Feng 	rte_cpuset_t cpuset;
16805d5fc66SChengwen Feng 	int ret;
16905d5fc66SChengwen Feng 
17005d5fc66SChengwen Feng 	if (hw->desc_mem == NULL) {
17105d5fc66SChengwen Feng 		SKELDMA_LOG(ERR, "Vchan was not setup, start fail!");
17205d5fc66SChengwen Feng 		return -EINVAL;
17305d5fc66SChengwen Feng 	}
17405d5fc66SChengwen Feng 
17505d5fc66SChengwen Feng 	/* Reset the dmadev to a known state, include:
17605d5fc66SChengwen Feng 	 * 1) fflush pending/running/completed ring to empty ring.
17705d5fc66SChengwen Feng 	 * 2) init ring idx to zero.
17805d5fc66SChengwen Feng 	 * 3) init running statistics.
1790335480fSChengwen Feng 	 * 4) mark cpuwork task exit_flag to false.
18005d5fc66SChengwen Feng 	 */
18105d5fc66SChengwen Feng 	fflush_ring(hw, hw->desc_pending);
18205d5fc66SChengwen Feng 	fflush_ring(hw, hw->desc_running);
18305d5fc66SChengwen Feng 	fflush_ring(hw, hw->desc_completed);
18405d5fc66SChengwen Feng 	hw->ridx = 0;
185618a40a0SChengwen Feng 	hw->last_ridx = hw->ridx - 1;
18605d5fc66SChengwen Feng 	hw->submitted_count = 0;
18705d5fc66SChengwen Feng 	hw->zero_req_count = 0;
18805d5fc66SChengwen Feng 	hw->completed_count = 0;
18905d5fc66SChengwen Feng 	hw->exit_flag = false;
19005d5fc66SChengwen Feng 
19105d5fc66SChengwen Feng 	rte_mb();
19205d5fc66SChengwen Feng 
193a7ba40b2SThomas Monjalon 	snprintf(name, sizeof(name), "dma-skel%d", dev->data->dev_id);
194a7ba40b2SThomas Monjalon 	ret = rte_thread_create_internal_control(&hw->thread, name,
1950335480fSChengwen Feng 			cpuwork_thread, dev);
19605d5fc66SChengwen Feng 	if (ret) {
1970335480fSChengwen Feng 		SKELDMA_LOG(ERR, "Start cpuwork thread fail!");
19805d5fc66SChengwen Feng 		return -EINVAL;
19905d5fc66SChengwen Feng 	}
20005d5fc66SChengwen Feng 
20105d5fc66SChengwen Feng 	if (hw->lcore_id != -1) {
20205d5fc66SChengwen Feng 		cpuset = rte_lcore_cpuset(hw->lcore_id);
2032f9afbe4SVipin Varghese 		ret = rte_thread_set_affinity_by_id(hw->thread, &cpuset);
20405d5fc66SChengwen Feng 		if (ret)
20505d5fc66SChengwen Feng 			SKELDMA_LOG(WARNING,
20605d5fc66SChengwen Feng 				"Set thread affinity lcore = %d fail!",
20705d5fc66SChengwen Feng 				hw->lcore_id);
20805d5fc66SChengwen Feng 	}
20905d5fc66SChengwen Feng 
21005d5fc66SChengwen Feng 	return 0;
21105d5fc66SChengwen Feng }
21205d5fc66SChengwen Feng 
21305d5fc66SChengwen Feng static int
21405d5fc66SChengwen Feng skeldma_stop(struct rte_dma_dev *dev)
21505d5fc66SChengwen Feng {
21605d5fc66SChengwen Feng 	struct skeldma_hw *hw = dev->data->dev_private;
21705d5fc66SChengwen Feng 
21805d5fc66SChengwen Feng 	hw->exit_flag = true;
21905d5fc66SChengwen Feng 	rte_delay_ms(1);
22005d5fc66SChengwen Feng 
221f241553bSTyler Retzlaff 	(void)pthread_cancel((pthread_t)hw->thread.opaque_id);
222f241553bSTyler Retzlaff 	rte_thread_join(hw->thread, NULL);
22305d5fc66SChengwen Feng 
22405d5fc66SChengwen Feng 	return 0;
22505d5fc66SChengwen Feng }
22605d5fc66SChengwen Feng 
22705d5fc66SChengwen Feng static int
228674c4f2dSSivaprasad Tummala vchan_setup(struct skeldma_hw *hw, int16_t dev_id, uint16_t nb_desc)
22905d5fc66SChengwen Feng {
230674c4f2dSSivaprasad Tummala 	char name[RTE_RING_NAMESIZE];
23105d5fc66SChengwen Feng 	struct skeldma_desc *desc;
23205d5fc66SChengwen Feng 	struct rte_ring *empty;
23305d5fc66SChengwen Feng 	struct rte_ring *pending;
23405d5fc66SChengwen Feng 	struct rte_ring *running;
23505d5fc66SChengwen Feng 	struct rte_ring *completed;
23605d5fc66SChengwen Feng 	uint16_t i;
23705d5fc66SChengwen Feng 
238674c4f2dSSivaprasad Tummala 	desc = rte_zmalloc_socket(NULL, nb_desc * sizeof(struct skeldma_desc),
23905d5fc66SChengwen Feng 				  RTE_CACHE_LINE_SIZE, hw->socket_id);
24005d5fc66SChengwen Feng 	if (desc == NULL) {
24105d5fc66SChengwen Feng 		SKELDMA_LOG(ERR, "Malloc dma skeleton desc fail!");
24205d5fc66SChengwen Feng 		return -ENOMEM;
24305d5fc66SChengwen Feng 	}
24405d5fc66SChengwen Feng 
245674c4f2dSSivaprasad Tummala 	snprintf(name, RTE_RING_NAMESIZE, "dma_skel_desc_empty_%d", dev_id);
246674c4f2dSSivaprasad Tummala 	empty = rte_ring_create(name, nb_desc, hw->socket_id,
247674c4f2dSSivaprasad Tummala 				RING_F_SP_ENQ | RING_F_SC_DEQ);
248674c4f2dSSivaprasad Tummala 	snprintf(name, RTE_RING_NAMESIZE, "dma_skel_desc_pend_%d", dev_id);
249674c4f2dSSivaprasad Tummala 	pending = rte_ring_create(name, nb_desc, hw->socket_id,
250674c4f2dSSivaprasad Tummala 				  RING_F_SP_ENQ | RING_F_SC_DEQ);
251674c4f2dSSivaprasad Tummala 	snprintf(name, RTE_RING_NAMESIZE, "dma_skel_desc_run_%d", dev_id);
252674c4f2dSSivaprasad Tummala 	running = rte_ring_create(name, nb_desc, hw->socket_id,
253674c4f2dSSivaprasad Tummala 				  RING_F_SP_ENQ | RING_F_SC_DEQ);
254674c4f2dSSivaprasad Tummala 	snprintf(name, RTE_RING_NAMESIZE, "dma_skel_desc_comp_%d", dev_id);
255674c4f2dSSivaprasad Tummala 	completed = rte_ring_create(name, nb_desc, hw->socket_id,
256674c4f2dSSivaprasad Tummala 				    RING_F_SP_ENQ | RING_F_SC_DEQ);
25705d5fc66SChengwen Feng 	if (empty == NULL || pending == NULL || running == NULL ||
25805d5fc66SChengwen Feng 	    completed == NULL) {
25905d5fc66SChengwen Feng 		SKELDMA_LOG(ERR, "Create dma skeleton desc ring fail!");
26005d5fc66SChengwen Feng 		rte_ring_free(empty);
26105d5fc66SChengwen Feng 		rte_ring_free(pending);
26205d5fc66SChengwen Feng 		rte_ring_free(running);
26305d5fc66SChengwen Feng 		rte_ring_free(completed);
26405d5fc66SChengwen Feng 		rte_free(desc);
26505d5fc66SChengwen Feng 		return -ENOMEM;
26605d5fc66SChengwen Feng 	}
26705d5fc66SChengwen Feng 
26805d5fc66SChengwen Feng 	/* The real usable ring size is *count-1* instead of *count* to
26905d5fc66SChengwen Feng 	 * differentiate a free ring from an empty ring.
27005d5fc66SChengwen Feng 	 * @see rte_ring_create
27105d5fc66SChengwen Feng 	 */
27205d5fc66SChengwen Feng 	for (i = 0; i < nb_desc - 1; i++)
27305d5fc66SChengwen Feng 		(void)rte_ring_enqueue(empty, (void *)(desc + i));
27405d5fc66SChengwen Feng 
27505d5fc66SChengwen Feng 	hw->desc_mem = desc;
27605d5fc66SChengwen Feng 	hw->desc_empty = empty;
27705d5fc66SChengwen Feng 	hw->desc_pending = pending;
27805d5fc66SChengwen Feng 	hw->desc_running = running;
27905d5fc66SChengwen Feng 	hw->desc_completed = completed;
28005d5fc66SChengwen Feng 
28105d5fc66SChengwen Feng 	return 0;
28205d5fc66SChengwen Feng }
28305d5fc66SChengwen Feng 
28405d5fc66SChengwen Feng static void
28505d5fc66SChengwen Feng vchan_release(struct skeldma_hw *hw)
28605d5fc66SChengwen Feng {
28705d5fc66SChengwen Feng 	if (hw->desc_mem == NULL)
28805d5fc66SChengwen Feng 		return;
28905d5fc66SChengwen Feng 
29005d5fc66SChengwen Feng 	rte_free(hw->desc_mem);
29105d5fc66SChengwen Feng 	hw->desc_mem = NULL;
29205d5fc66SChengwen Feng 	rte_ring_free(hw->desc_empty);
29305d5fc66SChengwen Feng 	hw->desc_empty = NULL;
29405d5fc66SChengwen Feng 	rte_ring_free(hw->desc_pending);
29505d5fc66SChengwen Feng 	hw->desc_pending = NULL;
29605d5fc66SChengwen Feng 	rte_ring_free(hw->desc_running);
29705d5fc66SChengwen Feng 	hw->desc_running = NULL;
29805d5fc66SChengwen Feng 	rte_ring_free(hw->desc_completed);
29905d5fc66SChengwen Feng 	hw->desc_completed = NULL;
30005d5fc66SChengwen Feng }
30105d5fc66SChengwen Feng 
30205d5fc66SChengwen Feng static int
30305d5fc66SChengwen Feng skeldma_close(struct rte_dma_dev *dev)
30405d5fc66SChengwen Feng {
30505d5fc66SChengwen Feng 	/* The device already stopped */
30605d5fc66SChengwen Feng 	vchan_release(dev->data->dev_private);
30705d5fc66SChengwen Feng 	return 0;
30805d5fc66SChengwen Feng }
30905d5fc66SChengwen Feng 
31005d5fc66SChengwen Feng static int
31105d5fc66SChengwen Feng skeldma_vchan_setup(struct rte_dma_dev *dev, uint16_t vchan,
31205d5fc66SChengwen Feng 		    const struct rte_dma_vchan_conf *conf,
31305d5fc66SChengwen Feng 		    uint32_t conf_sz)
31405d5fc66SChengwen Feng {
31505d5fc66SChengwen Feng 	struct skeldma_hw *hw = dev->data->dev_private;
31605d5fc66SChengwen Feng 
31705d5fc66SChengwen Feng 	RTE_SET_USED(vchan);
31805d5fc66SChengwen Feng 	RTE_SET_USED(conf_sz);
31905d5fc66SChengwen Feng 
32005d5fc66SChengwen Feng 	if (!rte_is_power_of_2(conf->nb_desc)) {
32105d5fc66SChengwen Feng 		SKELDMA_LOG(ERR, "Number of desc must be power of 2!");
32205d5fc66SChengwen Feng 		return -EINVAL;
32305d5fc66SChengwen Feng 	}
32405d5fc66SChengwen Feng 
32505d5fc66SChengwen Feng 	vchan_release(hw);
326674c4f2dSSivaprasad Tummala 	return vchan_setup(hw, dev->data->dev_id, conf->nb_desc);
32705d5fc66SChengwen Feng }
32805d5fc66SChengwen Feng 
32905d5fc66SChengwen Feng static int
3305e0f8591SBruce Richardson skeldma_vchan_status(const struct rte_dma_dev *dev,
3315e0f8591SBruce Richardson 		uint16_t vchan, enum rte_dma_vchan_status *status)
3325e0f8591SBruce Richardson {
3335e0f8591SBruce Richardson 	struct skeldma_hw *hw = dev->data->dev_private;
3345e0f8591SBruce Richardson 
3355e0f8591SBruce Richardson 	RTE_SET_USED(vchan);
3365e0f8591SBruce Richardson 
3375e0f8591SBruce Richardson 	*status = RTE_DMA_VCHAN_IDLE;
338e12a0166STyler Retzlaff 	if (hw->submitted_count != rte_atomic_load_explicit(&hw->completed_count,
339e12a0166STyler Retzlaff 			rte_memory_order_acquire)
3405e0f8591SBruce Richardson 			|| hw->zero_req_count == 0)
3415e0f8591SBruce Richardson 		*status = RTE_DMA_VCHAN_ACTIVE;
3425e0f8591SBruce Richardson 	return 0;
3435e0f8591SBruce Richardson }
3445e0f8591SBruce Richardson 
3455e0f8591SBruce Richardson static int
34605d5fc66SChengwen Feng skeldma_stats_get(const struct rte_dma_dev *dev, uint16_t vchan,
34705d5fc66SChengwen Feng 		  struct rte_dma_stats *stats, uint32_t stats_sz)
34805d5fc66SChengwen Feng {
34905d5fc66SChengwen Feng 	struct skeldma_hw *hw = dev->data->dev_private;
35005d5fc66SChengwen Feng 
35105d5fc66SChengwen Feng 	RTE_SET_USED(vchan);
35205d5fc66SChengwen Feng 	RTE_SET_USED(stats_sz);
35305d5fc66SChengwen Feng 
35405d5fc66SChengwen Feng 	stats->submitted = hw->submitted_count;
35505d5fc66SChengwen Feng 	stats->completed = hw->completed_count;
35605d5fc66SChengwen Feng 	stats->errors = 0;
35705d5fc66SChengwen Feng 
35805d5fc66SChengwen Feng 	return 0;
35905d5fc66SChengwen Feng }
36005d5fc66SChengwen Feng 
36105d5fc66SChengwen Feng static int
36205d5fc66SChengwen Feng skeldma_stats_reset(struct rte_dma_dev *dev, uint16_t vchan)
36305d5fc66SChengwen Feng {
36405d5fc66SChengwen Feng 	struct skeldma_hw *hw = dev->data->dev_private;
36505d5fc66SChengwen Feng 
36605d5fc66SChengwen Feng 	RTE_SET_USED(vchan);
36705d5fc66SChengwen Feng 
36805d5fc66SChengwen Feng 	hw->submitted_count = 0;
36905d5fc66SChengwen Feng 	hw->completed_count = 0;
37005d5fc66SChengwen Feng 
37105d5fc66SChengwen Feng 	return 0;
37205d5fc66SChengwen Feng }
37305d5fc66SChengwen Feng 
37405d5fc66SChengwen Feng static int
37505d5fc66SChengwen Feng skeldma_dump(const struct rte_dma_dev *dev, FILE *f)
37605d5fc66SChengwen Feng {
37705d5fc66SChengwen Feng #define GET_RING_COUNT(ring)	((ring) ? (rte_ring_count(ring)) : 0)
37805d5fc66SChengwen Feng 
37905d5fc66SChengwen Feng 	struct skeldma_hw *hw = dev->data->dev_private;
38005d5fc66SChengwen Feng 
38105d5fc66SChengwen Feng 	(void)fprintf(f,
38205d5fc66SChengwen Feng 		"    lcore_id: %d\n"
38305d5fc66SChengwen Feng 		"    socket_id: %d\n"
38405d5fc66SChengwen Feng 		"    desc_empty_ring_count: %u\n"
38505d5fc66SChengwen Feng 		"    desc_pending_ring_count: %u\n"
38605d5fc66SChengwen Feng 		"    desc_running_ring_count: %u\n"
38705d5fc66SChengwen Feng 		"    desc_completed_ring_count: %u\n",
38805d5fc66SChengwen Feng 		hw->lcore_id, hw->socket_id,
38905d5fc66SChengwen Feng 		GET_RING_COUNT(hw->desc_empty),
39005d5fc66SChengwen Feng 		GET_RING_COUNT(hw->desc_pending),
39105d5fc66SChengwen Feng 		GET_RING_COUNT(hw->desc_running),
39205d5fc66SChengwen Feng 		GET_RING_COUNT(hw->desc_completed));
39305d5fc66SChengwen Feng 	(void)fprintf(f,
39405d5fc66SChengwen Feng 		"    next_ring_idx: %u\n"
395618a40a0SChengwen Feng 		"    last_ring_idx: %u\n"
39605d5fc66SChengwen Feng 		"    submitted_count: %" PRIu64 "\n"
39705d5fc66SChengwen Feng 		"    completed_count: %" PRIu64 "\n",
398618a40a0SChengwen Feng 		hw->ridx, hw->last_ridx,
399618a40a0SChengwen Feng 		hw->submitted_count, hw->completed_count);
40005d5fc66SChengwen Feng 
40105d5fc66SChengwen Feng 	return 0;
40205d5fc66SChengwen Feng }
40305d5fc66SChengwen Feng 
40405d5fc66SChengwen Feng static inline void
40505d5fc66SChengwen Feng submit(struct skeldma_hw *hw, struct skeldma_desc *desc)
40605d5fc66SChengwen Feng {
40705d5fc66SChengwen Feng 	uint16_t count = rte_ring_count(hw->desc_pending);
40805d5fc66SChengwen Feng 	struct skeldma_desc *pend_desc = NULL;
40905d5fc66SChengwen Feng 
41005d5fc66SChengwen Feng 	while (count > 0) {
41105d5fc66SChengwen Feng 		(void)rte_ring_dequeue(hw->desc_pending, (void **)&pend_desc);
41205d5fc66SChengwen Feng 		(void)rte_ring_enqueue(hw->desc_running, (void *)pend_desc);
41305d5fc66SChengwen Feng 		count--;
41405d5fc66SChengwen Feng 	}
41505d5fc66SChengwen Feng 
41605d5fc66SChengwen Feng 	if (desc)
41705d5fc66SChengwen Feng 		(void)rte_ring_enqueue(hw->desc_running, (void *)desc);
41805d5fc66SChengwen Feng }
41905d5fc66SChengwen Feng 
42005d5fc66SChengwen Feng static int
42105d5fc66SChengwen Feng skeldma_copy(void *dev_private, uint16_t vchan,
42205d5fc66SChengwen Feng 	     rte_iova_t src, rte_iova_t dst,
42305d5fc66SChengwen Feng 	     uint32_t length, uint64_t flags)
42405d5fc66SChengwen Feng {
42505d5fc66SChengwen Feng 	struct skeldma_hw *hw = dev_private;
42605d5fc66SChengwen Feng 	struct skeldma_desc *desc;
42705d5fc66SChengwen Feng 	int ret;
42805d5fc66SChengwen Feng 
42905d5fc66SChengwen Feng 	RTE_SET_USED(vchan);
43005d5fc66SChengwen Feng 	RTE_SET_USED(flags);
43105d5fc66SChengwen Feng 
43205d5fc66SChengwen Feng 	ret = rte_ring_dequeue(hw->desc_empty, (void **)&desc);
43305d5fc66SChengwen Feng 	if (ret)
43405d5fc66SChengwen Feng 		return -ENOSPC;
435e1d7b79aSChengwen Feng 	desc->op = SKELDMA_OP_COPY;
43605d5fc66SChengwen Feng 	desc->ridx = hw->ridx;
437e1d7b79aSChengwen Feng 	desc->copy.src = (void *)(uintptr_t)src;
438e1d7b79aSChengwen Feng 	desc->copy.dst = (void *)(uintptr_t)dst;
439e1d7b79aSChengwen Feng 	desc->copy.len = length;
440e1d7b79aSChengwen Feng 	if (flags & RTE_DMA_OP_FLAG_SUBMIT)
441e1d7b79aSChengwen Feng 		submit(hw, desc);
442e1d7b79aSChengwen Feng 	else
443e1d7b79aSChengwen Feng 		(void)rte_ring_enqueue(hw->desc_pending, (void *)desc);
444e1d7b79aSChengwen Feng 	hw->submitted_count++;
445e1d7b79aSChengwen Feng 
446e1d7b79aSChengwen Feng 	return hw->ridx++;
447e1d7b79aSChengwen Feng }
448e1d7b79aSChengwen Feng 
449e1d7b79aSChengwen Feng static int
450e1d7b79aSChengwen Feng skeldma_copy_sg(void *dev_private, uint16_t vchan,
451e1d7b79aSChengwen Feng 		const struct rte_dma_sge *src,
452e1d7b79aSChengwen Feng 		const struct rte_dma_sge *dst,
453e1d7b79aSChengwen Feng 		uint16_t nb_src, uint16_t nb_dst,
454e1d7b79aSChengwen Feng 		uint64_t flags)
455e1d7b79aSChengwen Feng {
456e1d7b79aSChengwen Feng 	struct skeldma_hw *hw = dev_private;
457e1d7b79aSChengwen Feng 	struct skeldma_desc *desc;
458e1d7b79aSChengwen Feng 	int ret;
459e1d7b79aSChengwen Feng 
460e1d7b79aSChengwen Feng 	RTE_SET_USED(vchan);
461e1d7b79aSChengwen Feng 
462e1d7b79aSChengwen Feng 	ret = rte_ring_dequeue(hw->desc_empty, (void **)&desc);
463e1d7b79aSChengwen Feng 	if (ret)
464e1d7b79aSChengwen Feng 		return -ENOSPC;
465e1d7b79aSChengwen Feng 	desc->op = SKELDMA_OP_COPY_SG;
466e1d7b79aSChengwen Feng 	desc->ridx = hw->ridx;
467e1d7b79aSChengwen Feng 	memcpy(desc->copy_sg.src, src, sizeof(*src) * nb_src);
468e1d7b79aSChengwen Feng 	memcpy(desc->copy_sg.dst, dst, sizeof(*dst) * nb_dst);
469e1d7b79aSChengwen Feng 	desc->copy_sg.nb_src = nb_src;
470e1d7b79aSChengwen Feng 	desc->copy_sg.nb_dst = nb_dst;
47105d5fc66SChengwen Feng 	if (flags & RTE_DMA_OP_FLAG_SUBMIT)
47205d5fc66SChengwen Feng 		submit(hw, desc);
47305d5fc66SChengwen Feng 	else
47405d5fc66SChengwen Feng 		(void)rte_ring_enqueue(hw->desc_pending, (void *)desc);
47505d5fc66SChengwen Feng 	hw->submitted_count++;
47605d5fc66SChengwen Feng 
47705d5fc66SChengwen Feng 	return hw->ridx++;
47805d5fc66SChengwen Feng }
47905d5fc66SChengwen Feng 
48005d5fc66SChengwen Feng static int
4810335480fSChengwen Feng skeldma_fill(void *dev_private, uint16_t vchan,
4820335480fSChengwen Feng 	     uint64_t pattern, rte_iova_t dst,
4830335480fSChengwen Feng 	     uint32_t length, uint64_t flags)
4840335480fSChengwen Feng {
4850335480fSChengwen Feng 	struct skeldma_hw *hw = dev_private;
4860335480fSChengwen Feng 	struct skeldma_desc *desc;
4870335480fSChengwen Feng 	int ret;
4880335480fSChengwen Feng 
4890335480fSChengwen Feng 	RTE_SET_USED(vchan);
4900335480fSChengwen Feng 
4910335480fSChengwen Feng 	ret = rte_ring_dequeue(hw->desc_empty, (void **)&desc);
4920335480fSChengwen Feng 	if (ret)
4930335480fSChengwen Feng 		return -ENOSPC;
4940335480fSChengwen Feng 	desc->op = SKELDMA_OP_FILL;
4950335480fSChengwen Feng 	desc->ridx = hw->ridx;
4960335480fSChengwen Feng 	desc->fill.dst = (void *)(uintptr_t)dst;
4970335480fSChengwen Feng 	desc->fill.len = length;
4980335480fSChengwen Feng 	desc->fill.pattern = pattern;
4990335480fSChengwen Feng 	if (flags & RTE_DMA_OP_FLAG_SUBMIT)
5000335480fSChengwen Feng 		submit(hw, desc);
5010335480fSChengwen Feng 	else
5020335480fSChengwen Feng 		(void)rte_ring_enqueue(hw->desc_pending, (void *)desc);
5030335480fSChengwen Feng 	hw->submitted_count++;
5040335480fSChengwen Feng 
5050335480fSChengwen Feng 	return hw->ridx++;
5060335480fSChengwen Feng }
5070335480fSChengwen Feng 
5080335480fSChengwen Feng static int
50905d5fc66SChengwen Feng skeldma_submit(void *dev_private, uint16_t vchan)
51005d5fc66SChengwen Feng {
51105d5fc66SChengwen Feng 	struct skeldma_hw *hw = dev_private;
51205d5fc66SChengwen Feng 	RTE_SET_USED(vchan);
51305d5fc66SChengwen Feng 	submit(hw, NULL);
51405d5fc66SChengwen Feng 	return 0;
51505d5fc66SChengwen Feng }
51605d5fc66SChengwen Feng 
51705d5fc66SChengwen Feng static uint16_t
51805d5fc66SChengwen Feng skeldma_completed(void *dev_private,
51905d5fc66SChengwen Feng 		  uint16_t vchan, const uint16_t nb_cpls,
52005d5fc66SChengwen Feng 		  uint16_t *last_idx, bool *has_error)
52105d5fc66SChengwen Feng {
52205d5fc66SChengwen Feng 	struct skeldma_hw *hw = dev_private;
52305d5fc66SChengwen Feng 	struct skeldma_desc *desc = NULL;
52405d5fc66SChengwen Feng 	uint16_t index = 0;
52505d5fc66SChengwen Feng 	uint16_t count;
52605d5fc66SChengwen Feng 
52705d5fc66SChengwen Feng 	RTE_SET_USED(vchan);
52805d5fc66SChengwen Feng 	RTE_SET_USED(has_error);
52905d5fc66SChengwen Feng 
53005d5fc66SChengwen Feng 	count = RTE_MIN(nb_cpls, rte_ring_count(hw->desc_completed));
53105d5fc66SChengwen Feng 	while (index < count) {
53205d5fc66SChengwen Feng 		(void)rte_ring_dequeue(hw->desc_completed, (void **)&desc);
533618a40a0SChengwen Feng 		if (index == count - 1) {
534618a40a0SChengwen Feng 			hw->last_ridx = desc->ridx;
53505d5fc66SChengwen Feng 			*last_idx = desc->ridx;
536618a40a0SChengwen Feng 		}
53705d5fc66SChengwen Feng 		index++;
53805d5fc66SChengwen Feng 		(void)rte_ring_enqueue(hw->desc_empty, (void *)desc);
53905d5fc66SChengwen Feng 	}
540618a40a0SChengwen Feng 	if (unlikely(count == 0))
541618a40a0SChengwen Feng 		*last_idx = hw->last_ridx;
54205d5fc66SChengwen Feng 
54305d5fc66SChengwen Feng 	return count;
54405d5fc66SChengwen Feng }
54505d5fc66SChengwen Feng 
54605d5fc66SChengwen Feng static uint16_t
54705d5fc66SChengwen Feng skeldma_completed_status(void *dev_private,
54805d5fc66SChengwen Feng 			 uint16_t vchan, const uint16_t nb_cpls,
54905d5fc66SChengwen Feng 			 uint16_t *last_idx, enum rte_dma_status_code *status)
55005d5fc66SChengwen Feng {
55105d5fc66SChengwen Feng 	struct skeldma_hw *hw = dev_private;
55205d5fc66SChengwen Feng 	struct skeldma_desc *desc = NULL;
55305d5fc66SChengwen Feng 	uint16_t index = 0;
55405d5fc66SChengwen Feng 	uint16_t count;
55505d5fc66SChengwen Feng 
55605d5fc66SChengwen Feng 	RTE_SET_USED(vchan);
55705d5fc66SChengwen Feng 
55805d5fc66SChengwen Feng 	count = RTE_MIN(nb_cpls, rte_ring_count(hw->desc_completed));
55905d5fc66SChengwen Feng 	while (index < count) {
56005d5fc66SChengwen Feng 		(void)rte_ring_dequeue(hw->desc_completed, (void **)&desc);
561618a40a0SChengwen Feng 		if (index == count - 1) {
562618a40a0SChengwen Feng 			hw->last_ridx = desc->ridx;
56305d5fc66SChengwen Feng 			*last_idx = desc->ridx;
564618a40a0SChengwen Feng 		}
56505d5fc66SChengwen Feng 		status[index++] = RTE_DMA_STATUS_SUCCESSFUL;
56605d5fc66SChengwen Feng 		(void)rte_ring_enqueue(hw->desc_empty, (void *)desc);
56705d5fc66SChengwen Feng 	}
568618a40a0SChengwen Feng 	if (unlikely(count == 0))
569618a40a0SChengwen Feng 		*last_idx = hw->last_ridx;
57005d5fc66SChengwen Feng 
57105d5fc66SChengwen Feng 	return count;
57205d5fc66SChengwen Feng }
57305d5fc66SChengwen Feng 
574ea8cf0f8SKevin Laatz static uint16_t
575ea8cf0f8SKevin Laatz skeldma_burst_capacity(const void *dev_private, uint16_t vchan)
576ea8cf0f8SKevin Laatz {
577ea8cf0f8SKevin Laatz 	const struct skeldma_hw *hw = dev_private;
578ea8cf0f8SKevin Laatz 
579ea8cf0f8SKevin Laatz 	RTE_SET_USED(vchan);
580ea8cf0f8SKevin Laatz 	return rte_ring_count(hw->desc_empty);
581ea8cf0f8SKevin Laatz }
582ea8cf0f8SKevin Laatz 
58305d5fc66SChengwen Feng static const struct rte_dma_dev_ops skeldma_ops = {
58405d5fc66SChengwen Feng 	.dev_info_get     = skeldma_info_get,
58505d5fc66SChengwen Feng 	.dev_configure    = skeldma_configure,
58605d5fc66SChengwen Feng 	.dev_start        = skeldma_start,
58705d5fc66SChengwen Feng 	.dev_stop         = skeldma_stop,
58805d5fc66SChengwen Feng 	.dev_close        = skeldma_close,
58905d5fc66SChengwen Feng 
59005d5fc66SChengwen Feng 	.vchan_setup      = skeldma_vchan_setup,
5915e0f8591SBruce Richardson 	.vchan_status     = skeldma_vchan_status,
59205d5fc66SChengwen Feng 
59305d5fc66SChengwen Feng 	.stats_get        = skeldma_stats_get,
59405d5fc66SChengwen Feng 	.stats_reset      = skeldma_stats_reset,
59505d5fc66SChengwen Feng 
59605d5fc66SChengwen Feng 	.dev_dump         = skeldma_dump,
59705d5fc66SChengwen Feng };
59805d5fc66SChengwen Feng 
59905d5fc66SChengwen Feng static int
60005d5fc66SChengwen Feng skeldma_create(const char *name, struct rte_vdev_device *vdev, int lcore_id)
60105d5fc66SChengwen Feng {
60205d5fc66SChengwen Feng 	struct rte_dma_dev *dev;
60305d5fc66SChengwen Feng 	struct skeldma_hw *hw;
60405d5fc66SChengwen Feng 	int socket_id;
60505d5fc66SChengwen Feng 
60605d5fc66SChengwen Feng 	socket_id = (lcore_id < 0) ? rte_socket_id() :
60705d5fc66SChengwen Feng 				     rte_lcore_to_socket_id(lcore_id);
60805d5fc66SChengwen Feng 	dev = rte_dma_pmd_allocate(name, socket_id, sizeof(struct skeldma_hw));
60905d5fc66SChengwen Feng 	if (dev == NULL) {
61005d5fc66SChengwen Feng 		SKELDMA_LOG(ERR, "Unable to allocate dmadev: %s", name);
61105d5fc66SChengwen Feng 		return -EINVAL;
61205d5fc66SChengwen Feng 	}
61305d5fc66SChengwen Feng 
61405d5fc66SChengwen Feng 	dev->device = &vdev->device;
61505d5fc66SChengwen Feng 	dev->dev_ops = &skeldma_ops;
61605d5fc66SChengwen Feng 	dev->fp_obj->dev_private = dev->data->dev_private;
61705d5fc66SChengwen Feng 	dev->fp_obj->copy = skeldma_copy;
618e1d7b79aSChengwen Feng 	dev->fp_obj->copy_sg = skeldma_copy_sg;
6190335480fSChengwen Feng 	dev->fp_obj->fill = skeldma_fill;
62005d5fc66SChengwen Feng 	dev->fp_obj->submit = skeldma_submit;
62105d5fc66SChengwen Feng 	dev->fp_obj->completed = skeldma_completed;
62205d5fc66SChengwen Feng 	dev->fp_obj->completed_status = skeldma_completed_status;
623ea8cf0f8SKevin Laatz 	dev->fp_obj->burst_capacity = skeldma_burst_capacity;
62405d5fc66SChengwen Feng 
62505d5fc66SChengwen Feng 	hw = dev->data->dev_private;
62605d5fc66SChengwen Feng 	hw->lcore_id = lcore_id;
62705d5fc66SChengwen Feng 	hw->socket_id = socket_id;
62805d5fc66SChengwen Feng 
62905d5fc66SChengwen Feng 	dev->state = RTE_DMA_DEV_READY;
63005d5fc66SChengwen Feng 
63105d5fc66SChengwen Feng 	return dev->data->dev_id;
63205d5fc66SChengwen Feng }
63305d5fc66SChengwen Feng 
63405d5fc66SChengwen Feng static int
63505d5fc66SChengwen Feng skeldma_destroy(const char *name)
63605d5fc66SChengwen Feng {
63705d5fc66SChengwen Feng 	return rte_dma_pmd_release(name);
63805d5fc66SChengwen Feng }
63905d5fc66SChengwen Feng 
64005d5fc66SChengwen Feng static int
64105d5fc66SChengwen Feng skeldma_parse_lcore(const char *key __rte_unused,
64205d5fc66SChengwen Feng 		    const char *value,
64305d5fc66SChengwen Feng 		    void *opaque)
64405d5fc66SChengwen Feng {
645e0e5dd04SChengwen Feng 	int lcore_id;
646e0e5dd04SChengwen Feng 
647e0e5dd04SChengwen Feng 	if (value == NULL || opaque == NULL)
648e0e5dd04SChengwen Feng 		return -EINVAL;
649e0e5dd04SChengwen Feng 
650e0e5dd04SChengwen Feng 	lcore_id = atoi(value);
65105d5fc66SChengwen Feng 	if (lcore_id >= 0 && lcore_id < RTE_MAX_LCORE)
65205d5fc66SChengwen Feng 		*(int *)opaque = lcore_id;
653e0e5dd04SChengwen Feng 
65405d5fc66SChengwen Feng 	return 0;
65505d5fc66SChengwen Feng }
65605d5fc66SChengwen Feng 
65705d5fc66SChengwen Feng static void
65805d5fc66SChengwen Feng skeldma_parse_vdev_args(struct rte_vdev_device *vdev, int *lcore_id)
65905d5fc66SChengwen Feng {
66005d5fc66SChengwen Feng 	static const char *const args[] = {
66105d5fc66SChengwen Feng 		SKELDMA_ARG_LCORE,
66205d5fc66SChengwen Feng 		NULL
66305d5fc66SChengwen Feng 	};
66405d5fc66SChengwen Feng 
66505d5fc66SChengwen Feng 	struct rte_kvargs *kvlist;
66605d5fc66SChengwen Feng 	const char *params;
66705d5fc66SChengwen Feng 
66805d5fc66SChengwen Feng 	params = rte_vdev_device_args(vdev);
66905d5fc66SChengwen Feng 	if (params == NULL || params[0] == '\0')
67005d5fc66SChengwen Feng 		return;
67105d5fc66SChengwen Feng 
67205d5fc66SChengwen Feng 	kvlist = rte_kvargs_parse(params, args);
67305d5fc66SChengwen Feng 	if (!kvlist)
67405d5fc66SChengwen Feng 		return;
67505d5fc66SChengwen Feng 
67605d5fc66SChengwen Feng 	(void)rte_kvargs_process(kvlist, SKELDMA_ARG_LCORE,
67705d5fc66SChengwen Feng 				 skeldma_parse_lcore, lcore_id);
67805d5fc66SChengwen Feng 	SKELDMA_LOG(INFO, "Parse lcore_id = %d", *lcore_id);
67905d5fc66SChengwen Feng 
68005d5fc66SChengwen Feng 	rte_kvargs_free(kvlist);
68105d5fc66SChengwen Feng }
68205d5fc66SChengwen Feng 
68305d5fc66SChengwen Feng static int
68405d5fc66SChengwen Feng skeldma_probe(struct rte_vdev_device *vdev)
68505d5fc66SChengwen Feng {
68605d5fc66SChengwen Feng 	const char *name;
68705d5fc66SChengwen Feng 	int lcore_id = -1;
68805d5fc66SChengwen Feng 	int ret;
68905d5fc66SChengwen Feng 
69005d5fc66SChengwen Feng 	name = rte_vdev_device_name(vdev);
69105d5fc66SChengwen Feng 	if (name == NULL)
69205d5fc66SChengwen Feng 		return -EINVAL;
69305d5fc66SChengwen Feng 
69405d5fc66SChengwen Feng 	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
69505d5fc66SChengwen Feng 		SKELDMA_LOG(ERR, "Multiple process not supported for %s", name);
69605d5fc66SChengwen Feng 		return -EINVAL;
69705d5fc66SChengwen Feng 	}
69805d5fc66SChengwen Feng 
69905d5fc66SChengwen Feng 	skeldma_parse_vdev_args(vdev, &lcore_id);
70005d5fc66SChengwen Feng 
70105d5fc66SChengwen Feng 	ret = skeldma_create(name, vdev, lcore_id);
702674c4f2dSSivaprasad Tummala 	if (ret >= 0)
70305d5fc66SChengwen Feng 		SKELDMA_LOG(INFO, "Create %s dmadev with lcore-id %d",
70405d5fc66SChengwen Feng 			name, lcore_id);
70505d5fc66SChengwen Feng 
70605d5fc66SChengwen Feng 	return ret < 0 ? ret : 0;
70705d5fc66SChengwen Feng }
70805d5fc66SChengwen Feng 
70905d5fc66SChengwen Feng static int
71005d5fc66SChengwen Feng skeldma_remove(struct rte_vdev_device *vdev)
71105d5fc66SChengwen Feng {
71205d5fc66SChengwen Feng 	const char *name;
71305d5fc66SChengwen Feng 	int ret;
71405d5fc66SChengwen Feng 
71505d5fc66SChengwen Feng 	name = rte_vdev_device_name(vdev);
71605d5fc66SChengwen Feng 	if (name == NULL)
71705d5fc66SChengwen Feng 		return -1;
71805d5fc66SChengwen Feng 
71905d5fc66SChengwen Feng 	ret = skeldma_destroy(name);
720674c4f2dSSivaprasad Tummala 	if (!ret)
72105d5fc66SChengwen Feng 		SKELDMA_LOG(INFO, "Remove %s dmadev", name);
72205d5fc66SChengwen Feng 
72305d5fc66SChengwen Feng 	return ret;
72405d5fc66SChengwen Feng }
72505d5fc66SChengwen Feng 
72605d5fc66SChengwen Feng static struct rte_vdev_driver skeldma_pmd_drv = {
72705d5fc66SChengwen Feng 	.probe = skeldma_probe,
72805d5fc66SChengwen Feng 	.remove = skeldma_remove,
72905d5fc66SChengwen Feng 	.drv_flags = RTE_VDEV_DRV_NEED_IOVA_AS_VA,
73005d5fc66SChengwen Feng };
73105d5fc66SChengwen Feng 
73205d5fc66SChengwen Feng RTE_PMD_REGISTER_VDEV(dma_skeleton, skeldma_pmd_drv);
73305d5fc66SChengwen Feng RTE_PMD_REGISTER_PARAM_STRING(dma_skeleton,
73405d5fc66SChengwen Feng 		SKELDMA_ARG_LCORE "=<uint16> ");
735