From: Chengwen Feng Date: Wed, 13 Oct 2021 12:24:55 +0000 (+0800) Subject: dmadev: introduce DMA device library X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=b36970f2e13eadd34aef0c5b611a10e345a6f5b0;p=dpdk.git dmadev: introduce DMA device library The 'dmadev' is a generic type of DMA device. This patch introduce the 'dmadev' device allocation functions. 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 --- diff --git a/MAINTAINERS b/MAINTAINERS index ed8becce85..52648fcde6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -454,6 +454,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/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..46b85ce217 --- /dev/null +++ b/doc/guides/prog_guide/dmadev.rst @@ -0,0 +1,58 @@ +.. 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 API which +support a number of different DMA operations. + + +Design Principles +----------------- + +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. + + +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 function +``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 4c56cdfeaa..28ad1ea3ee 100644 --- a/doc/guides/rel_notes/release_21_11.rst +++ b/doc/guides/rel_notes/release_21_11.rst @@ -67,6 +67,11 @@ New Features * Modified to allow ``--huge-dir`` option to specify a sub-directory within a hugetlbfs mountpoint. +* **Added dmadev library.** + + * Added a DMA device framework for management and provision of + hardware and software DMA devices. + * **Added new RSS offload types for IPv4/L4 checksum in RSS flow.** Added macros ETH_RSS_IPV4_CHKSUM and ETH_RSS_L4_CHKSUM, now IPv4 and 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 3d08540581..b7d680868a 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..f8d54c6e74 --- /dev/null +++ b/lib/dmadev/meson.build @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2021 HiSilicon Limited. + +sources = files('rte_dmadev.c') +headers = files('rte_dmadev.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..42a4693bd9 --- /dev/null +++ b/lib/dmadev/rte_dmadev.c @@ -0,0 +1,246 @@ +/* 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" + +static int16_t dma_devices_max; + +struct rte_dma_dev *rte_dma_devices; + +RTE_LOG_REGISTER_DEFAULT(rte_dma_logtype, INFO); +#define RTE_DMA_LOG(level, ...) \ + rte_log(RTE_LOG_ ## level, rte_dma_logtype, RTE_FMT("dma: " \ + RTE_FMT_HEAD(__VA_ARGS__,) "\n", RTE_FMT_TAIL(__VA_ARGS__,))) + +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_id(void) +{ + int16_t i; + + if (rte_dma_devices == NULL) + return -1; + + for (i = 0; i < dma_devices_max; i++) { + if (rte_dma_devices[i].state == RTE_DMA_DEV_UNUSED) + return i; + } + + return -1; +} + +static struct rte_dma_dev* +dma_find_by_name(const char *name) +{ + int16_t i; + + if (rte_dma_devices == NULL) + return NULL; + + for (i = 0; i < dma_devices_max; i++) { + if ((rte_dma_devices[i].state != RTE_DMA_DEV_UNUSED) && + (!strcmp(name, rte_dma_devices[i].dev_name))) + return &rte_dma_devices[i]; + } + + return NULL; +} + +static int +dma_dev_data_prepare(void) +{ + size_t size; + + if (rte_dma_devices != NULL) + return 0; + + size = dma_devices_max * sizeof(struct rte_dma_dev); + rte_dma_devices = malloc(size); + if (rte_dma_devices == NULL) + return -ENOMEM; + memset(rte_dma_devices, 0, size); + + return 0; +} + +static int +dma_data_prepare(void) +{ + if (dma_devices_max == 0) + dma_devices_max = RTE_DMADEV_DEFAULT_MAX; + return dma_dev_data_prepare(); +} + +static struct rte_dma_dev * +dma_allocate(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_by_name(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_id(); + 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]; + rte_strscpy(dev->dev_name, name, sizeof(dev->dev_name)); + dev->dev_id = dev_id; + dev->numa_node = numa_node; + dev->dev_private = dev_private; + + return dev; +} + +static void +dma_release(struct rte_dma_dev *dev) +{ + 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_by_name(name); + if (dev == NULL) + return -EINVAL; + + dma_release(dev); + return 0; +} + +int +rte_dma_get_dev_id_by_name(const char *name) +{ + struct rte_dma_dev *dev; + + if (dma_check_name(name) != 0) + return -EINVAL; + + dev = dma_find_by_name(name); + if (dev == NULL) + return -EINVAL; + + return dev->dev_id; +} + +bool +rte_dma_is_valid(int16_t dev_id) +{ + return (dev_id >= 0) && (dev_id < dma_devices_max) && + rte_dma_devices != NULL && + rte_dma_devices[dev_id].state != RTE_DMA_DEV_UNUSED; +} + +uint16_t +rte_dma_count_avail(void) +{ + uint16_t count = 0; + uint16_t i; + + if (rte_dma_devices == NULL) + return count; + + 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..87810f2f08 --- /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. + * + * 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 +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Maximum number of devices if rte_dma_dev_max() is not called. */ +#define RTE_DMADEV_DEFAULT_MAX 64 + +/** + * @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. If not invoked, the maximum number + * of dmadevs is @see RTE_DMADEV_DEFAULT_MAX + * + * @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_by_name(const char *name); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Check whether the dev_id is valid. + * + * @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); + +#ifdef __cplusplus +} +#endif + +#endif /* RTE_DMADEV_H */ diff --git a/lib/dmadev/rte_dmadev_pmd.h b/lib/dmadev/rte_dmadev_pmd.h new file mode 100644 index 0000000000..bb09382dce --- /dev/null +++ b/lib/dmadev/rte_dmadev_pmd.h @@ -0,0 +1,90 @@ +/* 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 interface + * + * Driver facing interface for a DMA device. These are not to be called directly + * by any application. + */ + +#include "rte_dmadev.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Possible states of a DMA device. + * + * @see struct rte_dma_dev::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 generic data structure associated with each DMA device. + */ +struct rte_dma_dev { + 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. */ + void *dev_private; /**< PMD-specific private 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; + +/** + * @internal + * Allocate a new dmadev slot for an DMA device and return 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..f8a0076468 --- /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_by_name; + 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 b2ba7258d8..3b8b099820 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -45,6 +45,7 @@ libraries = [ 'pdump', 'rawdev', 'regexdev', + 'dmadev', 'rib', 'reorder', 'sched',