From: Chengwen Feng <fengchengwen@huawei.com>
To: <thomas@monjalon.net>, <liuyonglong@huawei.com>
Cc: <dev@dpdk.org>
Subject: [PATCH 1/4] dma/acc: add probe and remove
Date: Wed, 27 Aug 2025 17:27:26 +0800 [thread overview]
Message-ID: <20250827092729.10719-2-fengchengwen@huawei.com> (raw)
In-Reply-To: <20250827092729.10719-1-fengchengwen@huawei.com>
This patch adds probe and remove operation for accelerator DMA driver.
Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
MAINTAINERS | 4 +
drivers/dma/acc/acc_dmadev.c | 281 +++++++++++++++++++++++++++++++++++
drivers/dma/acc/acc_dmadev.h | 53 +++++++
drivers/dma/acc/meson.build | 21 +++
drivers/dma/meson.build | 1 +
5 files changed, 360 insertions(+)
create mode 100644 drivers/dma/acc/acc_dmadev.c
create mode 100644 drivers/dma/acc/acc_dmadev.h
create mode 100644 drivers/dma/acc/meson.build
diff --git a/MAINTAINERS b/MAINTAINERS
index 7aca98c537..42717363a0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1363,6 +1363,10 @@ M: Chengwen Feng <fengchengwen@huawei.com>
F: drivers/dma/hisilicon/
F: doc/guides/dmadevs/hisilicon.rst
+HiSilicon Accelerator DMA
+M: Chengwen Feng <fengchengwen@huawei.com>
+F: drivers/dma/acc/
+
Marvell CNXK DPI DMA
M: Vamsi Attunuru <vattunuru@marvell.com>
T: git://dpdk.org/next/dpdk-next-net-mrvl
diff --git a/drivers/dma/acc/acc_dmadev.c b/drivers/dma/acc/acc_dmadev.c
new file mode 100644
index 0000000000..b479d52c91
--- /dev/null
+++ b/drivers/dma/acc/acc_dmadev.c
@@ -0,0 +1,281 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved.
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include <rte_byteorder.h>
+#include <rte_eal.h>
+#include <rte_io.h>
+#include <rte_kvargs.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+
+#include <rte_dmadev_pmd.h>
+
+#include "acc_dmadev.h"
+
+RTE_LOG_REGISTER_DEFAULT(acc_dma_logtype, INFO);
+#define RTE_LOGTYPE_ACC_DMA acc_dma_logtype
+#define ACC_DMA_LOG(level, ...) \
+ RTE_LOG_LINE_PREFIX(level, ACC_DMA, "%s(): ", __func__, __VA_ARGS__)
+#define ACC_DMA_DEV_LOG(hw, level, ...) \
+ RTE_LOG_LINE_PREFIX(level, ACC_DMA, "%s %s(): ", \
+ (hw)->data->dev_name RTE_LOG_COMMA __func__, __VA_ARGS__)
+#define ACC_DMA_DEBUG(hw, ...) \
+ ACC_DMA_DEV_LOG(hw, DEBUG, __VA_ARGS__)
+#define ACC_DMA_INFO(hw, ...) \
+ ACC_DMA_DEV_LOG(hw, INFO, __VA_ARGS__)
+#define ACC_DMA_WARN(hw, ...) \
+ ACC_DMA_DEV_LOG(hw, WARNING, __VA_ARGS__)
+#define ACC_DMA_ERR(hw, ...) \
+ ACC_DMA_DEV_LOG(hw, ERR, __VA_ARGS__)
+
+static void
+acc_dma_gen_dev_name(const struct rte_uacce_device *uacce_dev,
+ uint16_t queue_id, char *dev_name, size_t size)
+{
+ memset(dev_name, 0, size);
+ (void)snprintf(dev_name, size, "%s-dma%u", uacce_dev->device.name, queue_id);
+}
+
+static int
+acc_dma_get_qp_info(struct acc_dma_dev *hw)
+{
+#define CMD_QM_GET_QP_CTX _IOWR('H', 10, struct acc_dma_qp_contex)
+#define CMD_QM_GET_QP_INFO _IOWR('H', 11, struct acc_dma_qp_info)
+#define QP_ALG_TYPE 2
+ struct acc_dma_qp_contex {
+ uint16_t id;
+ uint16_t qc_type;
+ } qp_ctx;
+ struct acc_dma_qp_info {
+ uint32_t sqe_size;
+ uint16_t sq_depth;
+ uint16_t cq_depth;
+ uint64_t reserved;
+ } qp_info;
+ int ret;
+
+ memset(&qp_ctx, 0, sizeof(qp_ctx));
+ qp_ctx.qc_type = QP_ALG_TYPE;
+ ret = rte_uacce_queue_ioctl(&hw->qctx, CMD_QM_GET_QP_CTX, &qp_ctx);
+ if (ret != 0) {
+ ACC_DMA_ERR(hw, "get qm qp context fail!");
+ return -EINVAL;
+ }
+ hw->sqn = qp_ctx.id;
+
+ memset(&qp_info, 0, sizeof(qp_info));
+ ret = rte_uacce_queue_ioctl(&hw->qctx, CMD_QM_GET_QP_INFO, &qp_info);
+ if (ret != 0) {
+ ACC_DMA_ERR(hw, "get qm qp info fail!");
+ return -EINVAL;
+ }
+ if ((qp_info.sq_depth & (qp_info.sq_depth - 1)) != 0) {
+ ACC_DMA_ERR(hw, "sq depth is not 2's power!");
+ return -EINVAL;
+ }
+ hw->sqe_size = qp_info.sqe_size;
+ hw->sq_depth = qp_info.sq_depth;
+ hw->cq_depth = qp_info.cq_depth;
+ hw->sq_depth_mask = hw->sq_depth - 1;
+
+ return 0;
+}
+
+static int
+acc_dma_create(struct rte_uacce_device *uacce_dev, uint16_t queue_id)
+{
+ char name[RTE_DEV_NAME_MAX_LEN];
+ struct rte_dma_dev *dev;
+ struct acc_dma_dev *hw;
+ int ret;
+
+ acc_dma_gen_dev_name(uacce_dev, queue_id, name, sizeof(name));
+ dev = rte_dma_pmd_allocate(name, uacce_dev->device.numa_node,
+ sizeof(struct acc_dma_dev));
+ if (dev == NULL) {
+ ACC_DMA_LOG(ERR, "%s allocate dmadev fail!", name);
+ return -EINVAL;
+ }
+
+ dev->device = &uacce_dev->device;
+ dev->fp_obj->dev_private = dev->data->dev_private;
+
+ hw = dev->data->dev_private;
+ hw->data = dev->data; /* make sure ACC_DMA_DEBUG/INFO/WARN/ERR was available. */
+
+ ret = rte_uacce_queue_alloc(uacce_dev, &hw->qctx);
+ if (ret != 0) {
+ ACC_DMA_ERR(hw, "alloc queue fail!");
+ goto release_dma_pmd;
+ }
+
+ ret = acc_dma_get_qp_info(hw);
+ if (ret != 0)
+ goto free_uacce_queue;
+
+ hw->io_base = rte_uacce_queue_mmap(&hw->qctx, RTE_UACCE_QFRT_MMIO);
+ if (hw->io_base == NULL) {
+ ACC_DMA_ERR(hw, "mmap MMIO region fail!");
+ ret = -EINVAL;
+ goto free_uacce_queue;
+ }
+ hw->doorbell_reg = (void *)((uintptr_t)hw->io_base + 0x1000);
+
+ hw->dus_base = rte_uacce_queue_mmap(&hw->qctx, RTE_UACCE_QFRT_DUS);
+ if (hw->dus_base == NULL) {
+ ACC_DMA_ERR(hw, "mmap DUS region fail!");
+ ret = -EINVAL;
+ goto unmap_mmio;
+ }
+ hw->sqe = hw->dus_base;
+ hw->cqe = (void *)((uintptr_t)hw->dus_base + hw->sqe_size * hw->sq_depth);
+ hw->sq_status = (uint32_t *)((uintptr_t)hw->dus_base +
+ uacce_dev->qfrt_sz[RTE_UACCE_QFRT_DUS] - sizeof(uint32_t));
+ hw->cq_status = hw->sq_status - 1;
+
+ hw->status = rte_zmalloc_socket(NULL, sizeof(uint16_t) * hw->sq_depth,
+ RTE_CACHE_LINE_SIZE, uacce_dev->numa_node);
+ if (hw->status == NULL) {
+ ACC_DMA_ERR(hw, "malloc status region fail!");
+ ret = -ENOMEM;
+ goto unmap_dus;
+ }
+
+ dev->state = RTE_DMA_DEV_READY;
+ ACC_DMA_DEBUG(hw, "create dmadev %s success!", name);
+
+ return 0;
+
+unmap_dus:
+ rte_uacce_queue_unmap(&hw->qctx, RTE_UACCE_QFRT_DUS);
+unmap_mmio:
+ rte_uacce_queue_unmap(&hw->qctx, RTE_UACCE_QFRT_MMIO);
+free_uacce_queue:
+ rte_uacce_queue_free(&hw->qctx);
+release_dma_pmd:
+ rte_dma_pmd_release(name);
+ return ret;
+}
+
+static int
+acc_dma_parse_queues(const char *key, const char *value, void *extra_args)
+{
+ struct acc_dma_config *config = extra_args;
+ uint64_t val;
+ char *end;
+
+ RTE_SET_USED(key);
+
+ errno = 0;
+ val = strtoull(value, &end, 0);
+ if (errno == ERANGE || value == end || *end != '\0' || val == 0) {
+ ACC_DMA_LOG(ERR, "%s invalid queues! set to default one queue!",
+ config->dev->name);
+ config->queues = ACC_DMA_DEFAULT_QUEUES;
+ } else if (val > config->avail_queues) {
+ ACC_DMA_LOG(WARNING, "%s exceed available queues! set to available queues",
+ config->dev->name);
+ config->queues = config->avail_queues;
+ } else {
+ config->queues = val;
+ }
+
+ return 0;
+}
+
+static int
+acc_dma_parse_devargs(struct rte_uacce_device *uacce_dev, struct acc_dma_config *config)
+{
+ struct rte_kvargs *kvlist;
+ int avail_queues;
+
+ avail_queues = rte_uacce_avail_queues(uacce_dev);
+ if (avail_queues <= 0) {
+ ACC_DMA_LOG(ERR, "%s don't have available queues!", uacce_dev->name);
+ return -1;
+ }
+ config->dev = uacce_dev;
+ config->avail_queues = avail_queues <= UINT16_MAX ? avail_queues : UINT16_MAX;
+
+ if (uacce_dev->device.devargs == NULL)
+ return 0;
+
+ kvlist = rte_kvargs_parse(uacce_dev->device.devargs->args, NULL);
+ if (kvlist == NULL)
+ return 0;
+
+ (void)rte_kvargs_process(kvlist, ACC_DMA_DEVARG_QUEUES, &acc_dma_parse_queues, config);
+
+ rte_kvargs_free(kvlist);
+
+ return 0;
+}
+
+static int
+acc_dma_probe(struct rte_uacce_driver *dr, struct rte_uacce_device *uacce_dev)
+{
+ struct acc_dma_config config = { .queues = ACC_DMA_DEFAULT_QUEUES };
+ int ret = 0;
+ uint32_t i;
+
+ RTE_SET_USED(dr);
+
+ ret = acc_dma_parse_devargs(uacce_dev, &config);
+ if (ret != 0)
+ return ret;
+
+ for (i = 0; i < config.queues; i++) {
+ ret = acc_dma_create(uacce_dev, i);
+ if (ret != 0) {
+ ACC_DMA_LOG(ERR, "%s create dmadev No.%u failed!", uacce_dev->name, i);
+ break;
+ }
+ }
+
+ if (ret != 0 && i > 0) {
+ ACC_DMA_LOG(WARNING, "%s probed %u dmadev, can't probe more!", uacce_dev->name, i);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int
+acc_dma_remove(struct rte_uacce_device *uacce_dev)
+{
+ struct rte_dma_info info;
+ int i = 0;
+ int ret;
+
+ RTE_DMA_FOREACH_DEV(i) {
+ ret = rte_dma_info_get(i, &info);
+ if (ret != 0)
+ continue;
+ if (strncmp(info.dev_name, uacce_dev->device.name,
+ strlen(uacce_dev->device.name)) == 0)
+ rte_dma_pmd_release(info.dev_name);
+ }
+
+ return 0;
+}
+
+static const struct rte_uacce_id acc_dma_id_table[] = {
+ { "hisi_qm_v5", "udma" },
+ { .dev_api = NULL, },
+};
+
+static struct rte_uacce_driver acc_dma_pmd_drv = {
+ .id_table = acc_dma_id_table,
+ .probe = acc_dma_probe,
+ .remove = acc_dma_remove,
+};
+
+RTE_PMD_REGISTER_UACCE(dma_acc, acc_dma_pmd_drv);
+RTE_PMD_REGISTER_PARAM_STRING(dma_acc,
+ ACC_DMA_DEVARG_QUEUES "=<uint16> ");
diff --git a/drivers/dma/acc/acc_dmadev.h b/drivers/dma/acc/acc_dmadev.h
new file mode 100644
index 0000000000..ce613541c0
--- /dev/null
+++ b/drivers/dma/acc/acc_dmadev.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved.
+ */
+
+#ifndef ACC_DMADEV_H
+#define ACC_DMADEV_H
+
+#include <bus_uacce_driver.h>
+#include <rte_bitops.h>
+#include <rte_common.h>
+#include <rte_dmadev_pmd.h>
+
+#define ACC_DMA_DEVARG_QUEUES "queues"
+#define ACC_DMA_DEFAULT_QUEUES 1
+
+struct acc_dma_config {
+ uint16_t queues;
+
+ /* The following fields are config contexts. */
+ struct rte_uacce_device *dev;
+ uint16_t avail_queues;
+};
+
+struct acc_dma_sqe {};
+struct acc_dma_cqe {};
+
+struct acc_dma_dev {
+ struct acc_dma_sqe *sqe;
+ struct acc_dma_cqe *cqe;
+ uint16_t *status; /* the completion status array of SQEs. */
+
+ volatile void *doorbell_reg; /**< register address for doorbell. */
+ volatile uint32_t *sq_status; /**< SQ status pointer. */
+ volatile uint32_t *cq_status; /**< CQ status pointer. */
+
+ uint16_t sqn; /**< SQ global number, inited when created. */
+ uint16_t sq_depth_mask; /**< SQ depth - 1, the SQ depth is power of 2. */
+
+ uint16_t cq_depth; /**< CQ depth, inited when created. */
+
+ /**
+ * The following fields are not accessed in the I/O path, so they are
+ * placed at the end.
+ */
+ struct rte_dma_dev_data *data;
+ struct rte_uacce_qcontex qctx;
+ void *io_base;
+ void *dus_base;
+ uint32_t sqe_size;
+ uint16_t sq_depth;
+};
+
+#endif /* ACC_DMADEV_H */
diff --git a/drivers/dma/acc/meson.build b/drivers/dma/acc/meson.build
new file mode 100644
index 0000000000..8a1bad5281
--- /dev/null
+++ b/drivers/dma/acc/meson.build
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright (c) 2025 HiSilicon Technologies Co., Ltd. All rights reserved.
+
+if not is_linux
+ build = false
+ reason = 'only supported on Linux'
+ subdir_done()
+endif
+
+if (arch_subdir != 'x86' and arch_subdir != 'arm') or (not dpdk_conf.get('RTE_ARCH_64'))
+ build = false
+ reason = 'only supported on x86_64 and aarch64'
+ subdir_done()
+endif
+
+deps += ['bus_uacce', 'dmadev']
+sources = files(
+ 'acc_dmadev.c',
+)
+
+require_iova_in_mbuf = false
diff --git a/drivers/dma/meson.build b/drivers/dma/meson.build
index 358132759a..eeab0ec361 100644
--- a/drivers/dma/meson.build
+++ b/drivers/dma/meson.build
@@ -2,6 +2,7 @@
# Copyright 2021 HiSilicon Limited
drivers = [
+ 'acc',
'cnxk',
'dpaa',
'dpaa2',
--
2.17.1
next prev parent reply other threads:[~2025-08-27 9:27 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-27 9:27 [PATCH 0/4] add Hisilicon accelerator DMA driver Chengwen Feng
2025-08-27 9:27 ` Chengwen Feng [this message]
2025-08-27 9:27 ` [PATCH 2/4] dma/acc: add control path ops Chengwen Feng
2025-08-27 9:27 ` [PATCH 3/4] dma/acc: add data " Chengwen Feng
2025-08-27 9:27 ` [PATCH 4/4] dma/acc: add doc Chengwen Feng
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250827092729.10719-2-fengchengwen@huawei.com \
--to=fengchengwen@huawei.com \
--cc=dev@dpdk.org \
--cc=liuyonglong@huawei.com \
--cc=thomas@monjalon.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).