From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-21.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,MENTIONS_GIT_HOSTING,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6EEFBC433EF for ; Thu, 16 Sep 2021 03:46:22 +0000 (UTC) Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by mail.kernel.org (Postfix) with ESMTP id D19BB6112E for ; Thu, 16 Sep 2021 03:46:21 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org D19BB6112E Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=huawei.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=dpdk.org Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 46B5E410FF; Thu, 16 Sep 2021 05:46:03 +0200 (CEST) Received: from szxga02-in.huawei.com (szxga02-in.huawei.com [45.249.212.188]) by mails.dpdk.org (Postfix) with ESMTP id 14F5F407FF for ; Thu, 16 Sep 2021 05:45:57 +0200 (CEST) Received: from dggemv711-chm.china.huawei.com (unknown [172.30.72.56]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4H92vJ4qT1zR5sg; Thu, 16 Sep 2021 11:41:48 +0800 (CST) Received: from dggpeml500024.china.huawei.com (7.185.36.10) by dggemv711-chm.china.huawei.com (10.1.198.66) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2308.8; Thu, 16 Sep 2021 11:45:54 +0800 Received: from localhost.localdomain (10.67.165.24) by dggpeml500024.china.huawei.com (7.185.36.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2308.8; Thu, 16 Sep 2021 11:45:54 +0800 From: Chengwen Feng To: , , , , , CC: , , , , , , , , , , , Date: Thu, 16 Sep 2021 11:41:41 +0800 Message-ID: <20210916034145.51561-2-fengchengwen@huawei.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20210916034145.51561-1-fengchengwen@huawei.com> References: <1625231891-2963-1-git-send-email-fengchengwen@huawei.com> <20210916034145.51561-1-fengchengwen@huawei.com> MIME-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 8bit X-Originating-IP: [10.67.165.24] X-ClientProxiedBy: dggems704-chm.china.huawei.com (10.3.19.181) To dggpeml500024.china.huawei.com (7.185.36.10) X-CFilter-Loop: Reflected Subject: [dpdk-dev] [PATCH v22 1/5] dmadev: introduce DMA device library X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" The 'dmadevice' is a generic type of DMA device. This patch introduce the 'dmadevice' device allocation APIs and it's multi-process support. The infrastructure is prepared to welcome drivers in drivers/dma/ Signed-off-by: Chengwen Feng Acked-by: Bruce Richardson Acked-by: Morten Brørup Acked-by: Jerin Jacob Reviewed-by: Kevin Laatz Reviewed-by: Conor Walsh --- MAINTAINERS | 5 + config/rte_config.h | 3 + doc/api/doxy-api-index.md | 1 + doc/api/doxy-api.conf.in | 1 + doc/guides/dmadevs/index.rst | 12 + doc/guides/index.rst | 1 + doc/guides/prog_guide/dmadev.rst | 62 +++++ doc/guides/prog_guide/img/dmadev.svg | 283 +++++++++++++++++++ doc/guides/prog_guide/index.rst | 1 + doc/guides/rel_notes/release_21_11.rst | 4 + drivers/dma/meson.build | 4 + drivers/meson.build | 1 + lib/dmadev/meson.build | 7 + lib/dmadev/rte_dmadev.c | 358 +++++++++++++++++++++++++ lib/dmadev/rte_dmadev.h | 133 +++++++++ lib/dmadev/rte_dmadev_core.h | 83 ++++++ lib/dmadev/rte_dmadev_pmd.h | 60 +++++ lib/dmadev/version.map | 20 ++ lib/meson.build | 1 + 19 files changed, 1040 insertions(+) create mode 100644 doc/guides/dmadevs/index.rst create mode 100644 doc/guides/prog_guide/dmadev.rst create mode 100644 doc/guides/prog_guide/img/dmadev.svg create mode 100644 drivers/dma/meson.build create mode 100644 lib/dmadev/meson.build create mode 100644 lib/dmadev/rte_dmadev.c create mode 100644 lib/dmadev/rte_dmadev.h create mode 100644 lib/dmadev/rte_dmadev_core.h create mode 100644 lib/dmadev/rte_dmadev_pmd.h create mode 100644 lib/dmadev/version.map diff --git a/MAINTAINERS b/MAINTAINERS index 1e0d303394..8af9522a5a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -452,6 +452,11 @@ F: app/test-regex/ F: doc/guides/prog_guide/regexdev.rst F: doc/guides/regexdevs/features/default.ini +DMA device API - EXPERIMENTAL +M: Chengwen Feng +F: lib/dmadev/ +F: doc/guides/prog_guide/dmadev.rst + Eventdev API M: Jerin Jacob T: git://dpdk.org/next/dpdk-next-eventdev diff --git a/config/rte_config.h b/config/rte_config.h index 590903c07d..6e397a62ab 100644 --- a/config/rte_config.h +++ b/config/rte_config.h @@ -70,6 +70,9 @@ /* regexdev defines */ #define RTE_MAX_REGEXDEV_DEVS 32 +/* dmadev defines */ +#define RTE_DMADEV_DEFAULT_MAX_DEVS 64 + /* eventdev defines */ #define RTE_EVENT_MAX_DEVS 16 #define RTE_EVENT_MAX_QUEUES_PER_DEV 255 diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md index 1992107a03..2939050431 100644 --- a/doc/api/doxy-api-index.md +++ b/doc/api/doxy-api-index.md @@ -21,6 +21,7 @@ The public API headers are grouped by topics: [compressdev] (@ref rte_compressdev.h), [compress] (@ref rte_comp.h), [regexdev] (@ref rte_regexdev.h), + [dmadev] (@ref rte_dmadev.h), [eventdev] (@ref rte_eventdev.h), [event_eth_rx_adapter] (@ref rte_event_eth_rx_adapter.h), [event_eth_tx_adapter] (@ref rte_event_eth_tx_adapter.h), diff --git a/doc/api/doxy-api.conf.in b/doc/api/doxy-api.conf.in index 325a0195c6..109ec1f682 100644 --- a/doc/api/doxy-api.conf.in +++ b/doc/api/doxy-api.conf.in @@ -35,6 +35,7 @@ INPUT = @TOPDIR@/doc/api/doxy-api-index.md \ @TOPDIR@/lib/compressdev \ @TOPDIR@/lib/cryptodev \ @TOPDIR@/lib/distributor \ + @TOPDIR@/lib/dmadev \ @TOPDIR@/lib/efd \ @TOPDIR@/lib/ethdev \ @TOPDIR@/lib/eventdev \ diff --git a/doc/guides/dmadevs/index.rst b/doc/guides/dmadevs/index.rst new file mode 100644 index 0000000000..0bce29d766 --- /dev/null +++ b/doc/guides/dmadevs/index.rst @@ -0,0 +1,12 @@ +.. SPDX-License-Identifier: BSD-3-Clause + Copyright 2021 HiSilicon Limited + +DMA Device Drivers +================== + +The following are a list of DMA device drivers, which can be used from +an application through DMA API. + +.. toctree:: + :maxdepth: 2 + :numbered: diff --git a/doc/guides/index.rst b/doc/guides/index.rst index 857f0363d3..919825992e 100644 --- a/doc/guides/index.rst +++ b/doc/guides/index.rst @@ -21,6 +21,7 @@ DPDK documentation compressdevs/index vdpadevs/index regexdevs/index + dmadevs/index eventdevs/index rawdevs/index mempool/index diff --git a/doc/guides/prog_guide/dmadev.rst b/doc/guides/prog_guide/dmadev.rst new file mode 100644 index 0000000000..c1c7579107 --- /dev/null +++ b/doc/guides/prog_guide/dmadev.rst @@ -0,0 +1,62 @@ +.. SPDX-License-Identifier: BSD-3-Clause + Copyright 2021 HiSilicon Limited + +DMA Device Library +================== + +The DMA library provides a DMA device framework for management and provisioning +of hardware and software DMA poll mode drivers, defining generic APIs which +support a number of different DMA operations. + + +Design Principles +----------------- + +The DMA library follows the same basic principles as those used in DPDK's +Ethernet Device framework and the RegEx framework. The DMA framework provides +a generic DMA device framework which supports both physical (hardware) +and virtual (software) DMA devices as well as a generic DMA API which allows +DMA devices to be managed and configured and supports DMA operations to be +provisioned on DMA poll mode driver. + +.. _figure_dmadev: + +.. figure:: img/dmadev.* + +The above figure shows the model on which the DMA framework is built on: + + * The DMA controller could have multiple hardware DMA channels (aka. hardware + DMA queues), each hardware DMA channel should be represented by a dmadev. + * The dmadev could create multiple virtual DMA channels, each virtual DMA + channel represents a different transfer context. The DMA operation request + must be submitted to the virtual DMA channel. e.g. Application could create + virtual DMA channel 0 for memory-to-memory transfer scenario, and create + virtual DMA channel 1 for memory-to-device transfer scenario. + + +Device Management +----------------- + +Device Creation +~~~~~~~~~~~~~~~ + +Physical DMA controllers are discovered during the PCI probe/enumeration of the +EAL function which is executed at DPDK initialization, this is based on their +PCI BDF (bus/bridge, device, function). Specific physical DMA controllers, like +other physical devices in DPDK can be listed using the EAL command line options. + +The dmadevs are dynamically allocated by using the API +``rte_dma_pmd_allocate`` based on the number of hardware DMA channels. + + +Device Identification +~~~~~~~~~~~~~~~~~~~~~ + +Each DMA device, whether physical or virtual is uniquely designated by two +identifiers: + +- A unique device index used to designate the DMA device in all functions + exported by the DMA API. + +- A device name used to designate the DMA device in console messages, for + administration or debugging purposes. diff --git a/doc/guides/prog_guide/img/dmadev.svg b/doc/guides/prog_guide/img/dmadev.svg new file mode 100644 index 0000000000..157d7eb7dc --- /dev/null +++ b/doc/guides/prog_guide/img/dmadev.svg @@ -0,0 +1,283 @@ + + + + + + + + + + + + + + virtual DMA channel + + virtual DMA channel + + virtual DMA channel + + + dmadev + + hardware DMA channel + + hardware DMA channel + + hardware DMA controller + + dmadev + + + + + + + + + diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst index 2dce507f46..89af28dacb 100644 --- a/doc/guides/prog_guide/index.rst +++ b/doc/guides/prog_guide/index.rst @@ -27,6 +27,7 @@ Programmer's Guide cryptodev_lib compressdev regexdev + dmadev rte_security rawdev link_bonding_poll_mode_drv_lib diff --git a/doc/guides/rel_notes/release_21_11.rst b/doc/guides/rel_notes/release_21_11.rst index 43d367bcad..5a85198e0d 100644 --- a/doc/guides/rel_notes/release_21_11.rst +++ b/doc/guides/rel_notes/release_21_11.rst @@ -87,6 +87,10 @@ New Features Added command-line options to specify total number of processes and current process ID. Each process owns subset of Rx and Tx queues. +* **Introduced dmadev library with:** + + * Device allocation and it's multi-process support. + Removed Items ------------- diff --git a/drivers/dma/meson.build b/drivers/dma/meson.build new file mode 100644 index 0000000000..a24c56d8ff --- /dev/null +++ b/drivers/dma/meson.build @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2021 HiSilicon Limited + +drivers = [] diff --git a/drivers/meson.build b/drivers/meson.build index d9e331ec85..a390787d6a 100644 --- a/drivers/meson.build +++ b/drivers/meson.build @@ -18,6 +18,7 @@ subdirs = [ 'vdpa', # depends on common, bus and mempool. 'event', # depends on common, bus, mempool and net. 'baseband', # depends on common and bus. + 'dma', # depends on common and bus. ] if meson.is_cross_build() diff --git a/lib/dmadev/meson.build b/lib/dmadev/meson.build new file mode 100644 index 0000000000..d2fc85e8c7 --- /dev/null +++ b/lib/dmadev/meson.build @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2021 HiSilicon Limited. + +sources = files('rte_dmadev.c') +headers = files('rte_dmadev.h') +indirect_headers += files('rte_dmadev_core.h') +driver_sdk_headers += files('rte_dmadev_pmd.h') diff --git a/lib/dmadev/rte_dmadev.c b/lib/dmadev/rte_dmadev.c new file mode 100644 index 0000000000..12d8302f15 --- /dev/null +++ b/lib/dmadev/rte_dmadev.c @@ -0,0 +1,358 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 HiSilicon Limited + * Copyright(c) 2021 Intel Corporation + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "rte_dmadev.h" +#include "rte_dmadev_pmd.h" + +struct rte_dma_dev *rte_dma_devices; +static int16_t dma_devices_max; +static struct { + /* Hold the dev_max information of the primary process. This field is + * set by the primary process and is read by the secondary process. + */ + int16_t dev_max; + struct rte_dma_dev_data data[0]; +} *dma_devices_shared_data; + +RTE_LOG_REGISTER_DEFAULT(rte_dma_logtype, INFO); +#define RTE_DMA_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, rte_dma_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +/* Macros to check for valid device id */ +#define RTE_DMA_VALID_DEV_ID_OR_ERR_RET(dev_id, retval) do { \ + if (!rte_dma_is_valid(dev_id)) { \ + RTE_DMA_LOG(ERR, "Invalid dev_id=%d", dev_id); \ + return retval; \ + } \ +} while (0) + +int +rte_dma_dev_max(size_t dev_max) +{ + /* This function may be called before rte_eal_init(), so no rte library + * function can be called in this function. + */ + if (dev_max == 0 || dev_max > INT16_MAX) + return -EINVAL; + + if (dma_devices_max > 0) + return -EINVAL; + + dma_devices_max = dev_max; + + return 0; +} + +static int +dma_check_name(const char *name) +{ + size_t name_len; + + if (name == NULL) { + RTE_DMA_LOG(ERR, "Name can't be NULL"); + return -EINVAL; + } + + name_len = strnlen(name, RTE_DEV_NAME_MAX_LEN); + if (name_len == 0) { + RTE_DMA_LOG(ERR, "Zero length DMA device name"); + return -EINVAL; + } + if (name_len >= RTE_DEV_NAME_MAX_LEN) { + RTE_DMA_LOG(ERR, "DMA device name is too long"); + return -EINVAL; + } + + return 0; +} + +static int16_t +dma_find_free_dev(void) +{ + int16_t i; + + for (i = 0; i < dma_devices_max; i++) { + if (dma_devices_shared_data->data[i].dev_name[0] == '\0') + return i; + } + + return -1; +} + +static struct rte_dma_dev* +dma_find(const char *name) +{ + int16_t i; + + for (i = 0; i < dma_devices_max; i++) { + if ((rte_dma_devices[i].state != RTE_DMA_DEV_UNUSED) && + (!strcmp(name, rte_dma_devices[i].data->dev_name))) + return &rte_dma_devices[i]; + } + + return NULL; +} + +static int +dma_process_data_prepare(void) +{ + size_t size; + void *ptr; + + if (rte_dma_devices != NULL) + return 0; + + /* The return value of malloc may not be aligned to the cache line. + * Therefore, extra memory is applied for realignment. + * note: We do not call posix_memalign/aligned_alloc because it is + * version dependent on libc. + */ + size = dma_devices_max * sizeof(struct rte_dma_dev) + + RTE_CACHE_LINE_SIZE; + ptr = malloc(size); + if (ptr == NULL) + return -ENOMEM; + memset(ptr, 0, size); + + rte_dma_devices = RTE_PTR_ALIGN(ptr, RTE_CACHE_LINE_SIZE); + + return 0; +} + +static int +dma_shared_data_prepare(void) +{ + const char *mz_name = "rte_dma_dev_data"; + const struct rte_memzone *mz; + size_t size; + + if (dma_devices_shared_data != NULL) + return 0; + + size = sizeof(*dma_devices_shared_data) + + sizeof(struct rte_dma_dev_data) * dma_devices_max; + + if (rte_eal_process_type() == RTE_PROC_PRIMARY) + mz = rte_memzone_reserve(mz_name, size, rte_socket_id(), 0); + else + mz = rte_memzone_lookup(mz_name); + if (mz == NULL) + return -ENOMEM; + + dma_devices_shared_data = mz->addr; + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + memset(dma_devices_shared_data, 0, size); + dma_devices_shared_data->dev_max = dma_devices_max; + } else { + dma_devices_max = dma_devices_shared_data->dev_max; + } + + return 0; +} + +static int +dma_data_prepare(void) +{ + int ret; + + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + if (dma_devices_max == 0) + dma_devices_max = RTE_DMADEV_DEFAULT_MAX_DEVS; + ret = dma_process_data_prepare(); + if (ret) + return ret; + ret = dma_shared_data_prepare(); + if (ret) + return ret; + } else { + ret = dma_shared_data_prepare(); + if (ret) + return ret; + ret = dma_process_data_prepare(); + if (ret) + return ret; + } + + return 0; +} + +static struct rte_dma_dev * +dma_allocate_primary(const char *name, int numa_node, size_t private_data_size) +{ + struct rte_dma_dev *dev; + void *dev_private; + int16_t dev_id; + int ret; + + ret = dma_data_prepare(); + if (ret < 0) { + RTE_DMA_LOG(ERR, "Cannot initialize dmadevs data"); + return NULL; + } + + dev = dma_find(name); + if (dev != NULL) { + RTE_DMA_LOG(ERR, "DMA device already allocated"); + return NULL; + } + + dev_private = rte_zmalloc_socket(name, private_data_size, + RTE_CACHE_LINE_SIZE, numa_node); + if (dev_private == NULL) { + RTE_DMA_LOG(ERR, "Cannot allocate private data"); + return NULL; + } + + dev_id = dma_find_free_dev(); + if (dev_id < 0) { + RTE_DMA_LOG(ERR, "Reached maximum number of DMA devices"); + rte_free(dev_private); + return NULL; + } + + dev = &rte_dma_devices[dev_id]; + dev->dev_private = dev_private; + dev->data = &dma_devices_shared_data->data[dev_id]; + rte_strscpy(dev->data->dev_name, name, sizeof(dev->data->dev_name)); + dev->data->dev_id = dev_id; + dev->data->numa_node = numa_node; + dev->data->dev_private = dev_private; + + return dev; +} + +static struct rte_dma_dev * +dma_attach_secondary(const char *name) +{ + struct rte_dma_dev *dev; + int16_t i; + int ret; + + ret = dma_data_prepare(); + if (ret < 0) { + RTE_DMA_LOG(ERR, "Cannot initialize dmadevs data"); + return NULL; + } + + for (i = 0; i < dma_devices_max; i++) { + if (!strcmp(dma_devices_shared_data->data[i].dev_name, name)) + break; + } + if (i == dma_devices_max) { + RTE_DMA_LOG(ERR, + "Device %s is not driven by the primary process", + name); + return NULL; + } + + dev = &rte_dma_devices[i]; + dev->data = &dma_devices_shared_data->data[i]; + dev->dev_private = dev->data->dev_private; + + return dev; +} + +static struct rte_dma_dev * +dma_allocate(const char *name, int numa_node, size_t private_data_size) +{ + struct rte_dma_dev *dev; + + if (rte_eal_process_type() == RTE_PROC_PRIMARY) + dev = dma_allocate_primary(name, numa_node, private_data_size); + else + dev = dma_attach_secondary(name); + + return dev; +} + +static void +dma_release(struct rte_dma_dev *dev) +{ + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + memset(dev->data, 0, sizeof(struct rte_dma_dev_data)); + rte_free(dev->dev_private); + } + + memset(dev, 0, sizeof(struct rte_dma_dev)); +} + +struct rte_dma_dev * +rte_dma_pmd_allocate(const char *name, int numa_node, size_t private_data_size) +{ + struct rte_dma_dev *dev; + + if (dma_check_name(name) != 0 || private_data_size == 0) + return NULL; + + dev = dma_allocate(name, numa_node, private_data_size); + if (dev == NULL) + return NULL; + + dev->state = RTE_DMA_DEV_REGISTERED; + + return dev; +} + +int +rte_dma_pmd_release(const char *name) +{ + struct rte_dma_dev *dev; + + if (dma_check_name(name) != 0) + return -EINVAL; + + dev = dma_find(name); + if (dev == NULL) + return -EINVAL; + + dma_release(dev); + return 0; +} + +int +rte_dma_get_dev_id(const char *name) +{ + struct rte_dma_dev *dev; + + if (dma_check_name(name) != 0) + return -EINVAL; + + dev = dma_find(name); + if (dev == NULL) + return -EINVAL; + + return dev->data->dev_id; +} + +bool +rte_dma_is_valid(int16_t dev_id) +{ + return (dev_id >= 0) && (dev_id < dma_devices_max) && + rte_dma_devices[dev_id].state != RTE_DMA_DEV_UNUSED; +} + +uint16_t +rte_dma_count_avail(void) +{ + uint16_t count = 0; + uint16_t i; + + for (i = 0; i < dma_devices_max; i++) { + if (rte_dma_devices[i].state != RTE_DMA_DEV_UNUSED) + count++; + } + + return count; +} diff --git a/lib/dmadev/rte_dmadev.h b/lib/dmadev/rte_dmadev.h new file mode 100644 index 0000000000..6074bae25d --- /dev/null +++ b/lib/dmadev/rte_dmadev.h @@ -0,0 +1,133 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 HiSilicon Limited + * Copyright(c) 2021 Intel Corporation + * Copyright(c) 2021 Marvell International Ltd + * Copyright(c) 2021 SmartShare Systems + */ + +#ifndef RTE_DMADEV_H +#define RTE_DMADEV_H + +/** + * @file rte_dmadev.h + * + * DMA (Direct Memory Access) device API. + * + * The DMA framework is built on the following model: + * + * --------------- --------------- --------------- + * | virtual DMA | | virtual DMA | | virtual DMA | + * | channel | | channel | | channel | + * --------------- --------------- --------------- + * | | | + * ------------------ | + * | | + * ------------ ------------ + * | dmadev | | dmadev | + * ------------ ------------ + * | | + * ------------------ ------------------ + * | HW DMA channel | | HW DMA channel | + * ------------------ ------------------ + * | | + * -------------------------------- + * | + * --------------------- + * | HW DMA Controller | + * --------------------- + * + * The DMA controller could have multiple HW-DMA-channels (aka. HW-DMA-queues), + * each HW-DMA-channel should be represented by a dmadev. + * + * The dmadev could create multiple virtual DMA channels, each virtual DMA + * channel represents a different transfer context. The DMA operation request + * must be submitted to the virtual DMA channel. e.g. Application could create + * virtual DMA channel 0 for memory-to-memory transfer scenario, and create + * virtual DMA channel 1 for memory-to-device transfer scenario. + * + * The dmadev are dynamically allocated by rte_dma_pmd_allocate() during the + * PCI/SoC device probing phase performed at EAL initialization time. And could + * be released by rte_dma_pmd_release() during the PCI/SoC device removing + * phase. + * + * This framework uses 'int16_t dev_id' as the device identifier of a dmadev, + * and 'uint16_t vchan' as the virtual DMA channel identifier in one dmadev. + * + */ + +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Configure the maximum number of dmadevs. + * @note This function can be invoked before the primary process rte_eal_init() + * to change the maximum number of dmadevs. + * + * @param dev_max + * maximum number of dmadevs. + * + * @return + * 0 on success. Otherwise negative value is returned. + */ +__rte_experimental +int rte_dma_dev_max(size_t dev_max); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Get the device identifier for the named DMA device. + * + * @param name + * DMA device name. + * + * @return + * Returns DMA device identifier on success. + * - <0: Failure to find named DMA device. + */ +__rte_experimental +int rte_dma_get_dev_id(const char *name); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * @param dev_id + * DMA device index. + * + * @return + * - If the device index is valid (true) or not (false). + */ +__rte_experimental +bool rte_dma_is_valid(int16_t dev_id); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Get the total number of DMA devices that have been successfully + * initialised. + * + * @return + * The total number of usable DMA devices. + */ +__rte_experimental +uint16_t rte_dma_count_avail(void); + +#include "rte_dmadev_core.h" + +#ifdef __cplusplus +} +#endif + +#endif /* RTE_DMADEV_H */ diff --git a/lib/dmadev/rte_dmadev_core.h b/lib/dmadev/rte_dmadev_core.h new file mode 100644 index 0000000000..1ce2cf0bf1 --- /dev/null +++ b/lib/dmadev/rte_dmadev_core.h @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 HiSilicon Limited + * Copyright(c) 2021 Intel Corporation + */ + +#ifndef RTE_DMADEV_CORE_H +#define RTE_DMADEV_CORE_H + +/** + * @file + * + * DMA Device internal header. + * + * This header contains internal data types, that are used by the DMA devices + * in order to expose their ops to the class. + * + * Applications should not use these API directly. + * + */ + +#include + +/** + * Possible states of a DMA device. + * + * @see struct rte_dmadev::state + */ +enum rte_dma_dev_state { + RTE_DMA_DEV_UNUSED = 0, /**< Device is unused. */ + /** Device is registered, but not ready to be used. */ + RTE_DMA_DEV_REGISTERED, + /** Device is ready for use. This is set by the PMD. */ + RTE_DMA_DEV_READY, + +}; + +/** + * @internal + * The data part, with no function pointers, associated with each DMA device. + * + * This structure is safe to place in shared memory to be common among different + * processes in a multi-process configuration. + * + * @see struct rte_dmadev::data + */ +struct rte_dma_dev_data { + char dev_name[RTE_DEV_NAME_MAX_LEN]; /**< Unique identifier name */ + int16_t dev_id; /**< Device [external] identifier. */ + int16_t numa_node; /**< Local NUMA memory ID. -1 if unknown. */ + /** PMD-specific private data. + * This is a copy of the 'dev_private' field in the 'struct rte_dmadev' + * from primary process, it is used by the secondary process to get + * dev_private information. + */ + void *dev_private; + uint8_t dev_started : 1; /**< Device state: STARTED(1)/STOPPED(0). */ + uint64_t reserved[2]; /**< Reserved for future fields */ +} __rte_cache_aligned; + +/** + * @internal + * The generic data structure associated with each DMA device. + * + * The dataplane APIs are located at the beginning of the structure, along + * with the pointer to where all the data elements for the particular device + * are stored in shared memory. This split scheme allows the function pointer + * and driver data to be per-process, while the actual configuration data for + * the device is shared. + * And the 'dev_private' field was placed in the first cache line to optimize + * performance because the PMD driver mainly depends on this field. + */ +struct rte_dma_dev { + void *dev_private; /**< PMD-specific private data. */ + struct rte_dma_dev_data *data; /**< Pointer to device data. */ + /** Device info which supplied during device initialization. */ + struct rte_device *device; + enum rte_dma_dev_state state; /**< Flag indicating the device state. */ + uint64_t reserved[2]; /**< Reserved for future fields. */ +} __rte_cache_aligned; + +extern struct rte_dma_dev *rte_dma_devices; + +#endif /* RTE_DMADEV_CORE_H */ diff --git a/lib/dmadev/rte_dmadev_pmd.h b/lib/dmadev/rte_dmadev_pmd.h new file mode 100644 index 0000000000..02281c74fd --- /dev/null +++ b/lib/dmadev/rte_dmadev_pmd.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 HiSilicon Limited + */ + +#ifndef RTE_DMADEV_PMD_H +#define RTE_DMADEV_PMD_H + +/** + * @file + * + * DMA Device PMD APIs + * + * Driver facing APIs for a DMA device. These are not to be called directly by + * any application. + */ + +#include "rte_dmadev.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @internal + * Allocates a new dmadev slot for an DMA device and returns the pointer + * to that slot for the driver to use. + * + * @param name + * DMA device name. + * @param numa_node + * Driver's private data's numa node. + * @param private_data_size + * Driver's private data size. + * + * @return + * A pointer to the DMA device slot case of success, + * NULL otherwise. + */ +__rte_internal +struct rte_dma_dev *rte_dma_pmd_allocate(const char *name, int numa_node, + size_t private_data_size); + +/** + * @internal + * Release the specified dmadev. + * + * @param name + * DMA device name. + * + * @return + * - 0 on success, negative on error. + */ +__rte_internal +int rte_dma_pmd_release(const char *name); + +#ifdef __cplusplus +} +#endif + +#endif /* RTE_DMADEV_PMD_H */ diff --git a/lib/dmadev/version.map b/lib/dmadev/version.map new file mode 100644 index 0000000000..56ea0332cb --- /dev/null +++ b/lib/dmadev/version.map @@ -0,0 +1,20 @@ +EXPERIMENTAL { + global: + + rte_dma_count_avail; + rte_dma_dev_max; + rte_dma_get_dev_id; + rte_dma_is_valid; + + local: *; +}; + +INTERNAL { + global: + + rte_dma_devices; + rte_dma_pmd_allocate; + rte_dma_pmd_release; + + local: *; +}; diff --git a/lib/meson.build b/lib/meson.build index 1673ca4323..3dd920f5c5 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -45,6 +45,7 @@ libraries = [ 'pdump', 'rawdev', 'regexdev', + 'dmadev', 'rib', 'reorder', 'sched', -- 2.33.0