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