DPDK patches and discussions
 help / color / mirror / Atom feed
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


  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).