DPDK patches and discussions
 help / color / mirror / Atom feed
* [RFC] lib/dma: introduce inter-process and inter-OS DMA
@ 2025-09-01 12:33 Vamsi Krishna
  0 siblings, 0 replies; only message in thread
From: Vamsi Krishna @ 2025-09-01 12:33 UTC (permalink / raw)
  To: dev
  Cc: fengchengwen, thomas, bruce.richardson, vladimir.medvedkin,
	anatoly.burakov, kevin.laatz, jerinj, vattunuru

From: Vamsi Attunuru <vattunuru@marvell.com>

Modern DMA hardware supports data transfers between multiple DMA
devices, facilitating data communication across isolated domains,
containers, or operating systems. These DMA transfers function as
standard memory-to-memory operations, but with source or destination
addresses residing in different process or OS address space. The
exchange of these addresses between processes is handled through
private driver mechanism, which are beyond the scope of this
specification change.

This commit introduces new capability flags to advertise driver support
for inter-process or inter-OS DMA transfers. It provides two mechanisms
for specifying source and destination handlers: either through the vchan
configuration or via the flags parameter in DMA enqueue APIs. This commit
also adds a controller ID field to specify the device hierarchy details
when applicable.

To ensure secure and controlled DMA transfers, this commit adds a set
of APIs for creating and managing access groups. Devices can create or
join an access group using token-based authentication, and only devices
within the same group are permitted to perform DMA transfers across
processes or OS domains. This approach enhances security and flexibility
for advanced DMA use cases in multi-tenant or virtualized environments.

The following flow demonstrates how two processes (a group creator and a
group joiner) use the DMA access group APIs to securely set up and
manage inter-process DMA transfers:

1) Process 1 (Group Creator):
   Calls rte_dma_access_group_create(group_token, &group_id) to create a
   new access group.
   Shares group_id and group_token with Process 2 via IPC.
2) Process 2 (Group Joiner):
   Receives group_id and group_token from Process 1.
   Calls rte_dma_access_group_join(group_id, group_token) to join the
   group.
3) Both Processes:
   Use rte_dma_access_group_size_get() to check the number of devices in
   the group.
   Use rte_dma_access_group_get() to retrieve the group table and
   handler information.

   Perform DMA transfers as needed.

4) Process 2 (when done):
   Calls rte_dma_access_group_leave(group_id) to leave the group.
5) Process 1:
   Receives RTE_DMA_EVENT_ACCESS_TABLE_UPDATE to be notified of group
   changes.
   Uses rte_dma_access_group_size_get() to confirm the group size.

This flow ensures only authenticated and authorized devices can
participate in inter-process or inter-OS DMA transfers, enhancing
security and isolation.

Signed-off-by: Vamsi Attunuru <vattunuru@marvell.com>
---
 lib/dmadev/rte_dmadev.c       | 320 ++++++++++++++++++++++++++++++++++
 lib/dmadev/rte_dmadev.h       | 255 +++++++++++++++++++++++++++
 lib/dmadev/rte_dmadev_pmd.h   |  48 +++++
 lib/dmadev/rte_dmadev_trace.h |  51 ++++++
 4 files changed, 674 insertions(+)

diff --git a/lib/dmadev/rte_dmadev.c b/lib/dmadev/rte_dmadev.c
index 17ee0808a9..a6e5e4071d 100644
--- a/lib/dmadev/rte_dmadev.c
+++ b/lib/dmadev/rte_dmadev.c
@@ -9,11 +9,13 @@
 
 #include <eal_export.h>
 #include <rte_eal.h>
+#include <rte_errno.h>
 #include <rte_lcore.h>
 #include <rte_log.h>
 #include <rte_malloc.h>
 #include <rte_memzone.h>
 #include <rte_string_fns.h>
+#include <rte_tailq.h>
 #include <rte_telemetry.h>
 
 #include "rte_dmadev.h"
@@ -33,6 +35,14 @@ static struct {
 	struct rte_dma_dev_data data[0];
 } *dma_devices_shared_data;
 
+/** List of callback functions registered by an application */
+struct rte_dma_dev_callback {
+	TAILQ_ENTRY(rte_dma_dev_callback) next;  /** Callbacks list */
+	rte_dma_event_callback cb_fn; /** Callback address */
+	void *cb_arg;  /** Parameter for callback */
+	enum rte_dma_event event; /** Interrupt event type */
+};
+
 RTE_LOG_REGISTER_DEFAULT(rte_dma_logtype, INFO);
 #define RTE_LOGTYPE_DMADEV rte_dma_logtype
 
@@ -789,6 +799,310 @@ rte_dma_vchan_status(int16_t dev_id, uint16_t vchan, enum rte_dma_vchan_status *
 	return dev->dev_ops->vchan_status(dev, vchan, status);
 }
 
+int
+rte_dma_access_group_create(int16_t dev_id, rte_uuid_t token, uint16_t *group_id)
+{
+	struct rte_dma_info dev_info;
+	struct rte_dma_dev *dev;
+
+	if (!rte_dma_is_valid(dev_id) || group_id == NULL)
+		return -EINVAL;
+	dev = &rte_dma_devices[dev_id];
+
+	if (rte_dma_info_get(dev_id, &dev_info)) {
+		RTE_DMA_LOG(ERR, "Device %d get device info fail", dev_id);
+		return -EINVAL;
+	}
+
+	if (!((dev_info.dev_capa & RTE_DMA_CAPA_INTER_PROCESS_DOMAIN) ||
+	    (dev_info.dev_capa & RTE_DMA_CAPA_INTER_OS_DOMAIN))) {
+		RTE_DMA_LOG(ERR, "Device %d don't support inter-process or inter-os transfers",
+			    dev_id);
+		return -EINVAL;
+	}
+	if (*dev->dev_ops->access_group_create == NULL)
+		return -ENOTSUP;
+	return (*dev->dev_ops->access_group_create)(dev, token, group_id);
+}
+
+int
+rte_dma_access_group_destroy(int16_t dev_id, uint16_t group_id)
+{
+	struct rte_dma_info dev_info;
+	struct rte_dma_dev *dev;
+
+	if (!rte_dma_is_valid(dev_id))
+		return -EINVAL;
+	dev = &rte_dma_devices[dev_id];
+
+	if (rte_dma_info_get(dev_id, &dev_info)) {
+		RTE_DMA_LOG(ERR, "Device %d get device info fail", dev_id);
+		return -EINVAL;
+	}
+
+	if (!((dev_info.dev_capa & RTE_DMA_CAPA_INTER_PROCESS_DOMAIN) ||
+	    (dev_info.dev_capa & RTE_DMA_CAPA_INTER_OS_DOMAIN))) {
+		RTE_DMA_LOG(ERR, "Device %d don't support inter-process or inter-os transfers",
+			    dev_id);
+		return -EINVAL;
+	}
+
+	if (dev_info.nb_access_groups <= group_id) {
+		RTE_DMA_LOG(ERR, "Group id should be < %u for device %d",
+			    dev_info.nb_access_groups, dev_id);
+		return -EINVAL;
+	}
+	if (*dev->dev_ops->access_group_destroy == NULL)
+		return -ENOTSUP;
+	return (*dev->dev_ops->access_group_destroy)(dev, group_id);
+}
+
+int
+rte_dma_access_group_join(int16_t dev_id, uint16_t group_id, rte_uuid_t token)
+{
+	struct rte_dma_info dev_info;
+	struct rte_dma_dev *dev;
+
+	if (!rte_dma_is_valid(dev_id))
+		return -EINVAL;
+	dev = &rte_dma_devices[dev_id];
+
+	if (rte_dma_info_get(dev_id, &dev_info)) {
+		RTE_DMA_LOG(ERR, "Device %d get device info fail", dev_id);
+		return -EINVAL;
+	}
+
+	if (!((dev_info.dev_capa & RTE_DMA_CAPA_INTER_PROCESS_DOMAIN) ||
+	    (dev_info.dev_capa & RTE_DMA_CAPA_INTER_OS_DOMAIN))) {
+		RTE_DMA_LOG(ERR, "Device %d don't support inter-process or inter-os transfers",
+			    dev_id);
+		return -EINVAL;
+	}
+
+	if (dev_info.nb_access_groups <= group_id) {
+		RTE_DMA_LOG(ERR, "Group id should be < %u for device %d",
+			    dev_info.nb_access_groups, dev_id);
+		return -EINVAL;
+	}
+	if (*dev->dev_ops->access_group_join == NULL)
+		return -ENOTSUP;
+	return (*dev->dev_ops->access_group_join)(dev, group_id, token);
+}
+
+int
+rte_dma_access_group_leave(int16_t dev_id, uint16_t group_id)
+{
+	struct rte_dma_info dev_info;
+	struct rte_dma_dev *dev;
+
+	if (!rte_dma_is_valid(dev_id))
+		return -EINVAL;
+	dev = &rte_dma_devices[dev_id];
+
+	if (rte_dma_info_get(dev_id, &dev_info)) {
+		RTE_DMA_LOG(ERR, "Device %d get device info fail", dev_id);
+		return -EINVAL;
+	}
+
+	if (!((dev_info.dev_capa & RTE_DMA_CAPA_INTER_PROCESS_DOMAIN) ||
+	    (dev_info.dev_capa & RTE_DMA_CAPA_INTER_OS_DOMAIN))) {
+		RTE_DMA_LOG(ERR, "Device %d don't support inter-process or inter-os transfers",
+			    dev_id);
+		return -EINVAL;
+	}
+
+	if (dev_info.nb_access_groups <= group_id) {
+		RTE_DMA_LOG(ERR, "Group id should be < %u for device %d",
+			    dev_info.nb_access_groups, dev_id);
+		return -EINVAL;
+	}
+	if (*dev->dev_ops->access_group_leave == NULL)
+		return -ENOTSUP;
+	return (*dev->dev_ops->access_group_leave)(dev, group_id);
+}
+
+uint16_t
+rte_dma_access_group_size_get(int16_t dev_id, uint16_t group_id)
+{
+	struct rte_dma_info dev_info;
+	struct rte_dma_dev *dev;
+
+	if (!rte_dma_is_valid(dev_id))
+		return -EINVAL;
+	dev = &rte_dma_devices[dev_id];
+
+	if (rte_dma_info_get(dev_id, &dev_info)) {
+		RTE_DMA_LOG(ERR, "Device %d get device info fail", dev_id);
+		return -EINVAL;
+	}
+
+	if (!((dev_info.dev_capa & RTE_DMA_CAPA_INTER_PROCESS_DOMAIN) ||
+	    (dev_info.dev_capa & RTE_DMA_CAPA_INTER_OS_DOMAIN))) {
+		RTE_DMA_LOG(ERR, "Device %d don't support inter-process or inter-os transfers",
+			    dev_id);
+		return -EINVAL;
+	}
+
+	if (dev_info.nb_access_groups <= group_id) {
+		RTE_DMA_LOG(ERR, "Group id should be < %u for device %d",
+			    dev_info.nb_access_groups, dev_id);
+		return -EINVAL;
+	}
+	if (*dev->dev_ops->access_group_size_get == NULL)
+		return -ENOTSUP;
+	return (*dev->dev_ops->access_group_size_get)(dev, group_id);
+}
+
+int
+rte_dma_access_group_get(int16_t dev_id, uint16_t group_id, uint64_t *group_tbl, uint16_t size)
+{
+	struct rte_dma_info dev_info;
+	struct rte_dma_dev *dev;
+
+	if (!rte_dma_is_valid(dev_id) || group_tbl == NULL)
+		return -EINVAL;
+	dev = &rte_dma_devices[dev_id];
+
+	if (rte_dma_info_get(dev_id, &dev_info)) {
+		RTE_DMA_LOG(ERR, "Device %d get device info fail", dev_id);
+		return -EINVAL;
+	}
+
+	if (!((dev_info.dev_capa & RTE_DMA_CAPA_INTER_PROCESS_DOMAIN) ||
+	    (dev_info.dev_capa & RTE_DMA_CAPA_INTER_OS_DOMAIN))) {
+		RTE_DMA_LOG(ERR, "Device %d don't support inter-process or inter-os transfers",
+			    dev_id);
+		return -EINVAL;
+	}
+
+	if (dev_info.nb_access_groups <= group_id) {
+		RTE_DMA_LOG(ERR, "Group id should be < %u for device %d",
+			    dev_info.nb_access_groups, dev_id);
+		return -EINVAL;
+	}
+	if (*dev->dev_ops->access_group_get == NULL)
+		return -ENOTSUP;
+	return (*dev->dev_ops->access_group_get)(dev, group_id, group_tbl, size);
+}
+
+int
+rte_dma_event_callback_register(uint16_t dev_id, enum rte_dma_event event,
+				rte_dma_event_callback cb_fn, void *cb_arg)
+{
+	struct rte_dma_dev_callback *user_cb;
+	struct rte_dma_dev *dev;
+	int ret = 0;
+
+	if (!rte_dma_is_valid(dev_id))
+		return -EINVAL;
+
+	dev = &rte_dma_devices[dev_id];
+
+	if (event >= RTE_DMA_EVENT_MAX) {
+		RTE_DMA_LOG(ERR, "Invalid event type (%u), should be less than %u", event,
+			    RTE_DMA_EVENT_MAX);
+		return -EINVAL;
+	}
+
+	if (cb_fn == NULL) {
+		RTE_DMA_LOG(ERR, "NULL callback function");
+		return -EINVAL;
+	}
+
+	rte_mcfg_tailq_write_lock();
+	TAILQ_FOREACH(user_cb, &(dev->list_cbs), next) {
+		if (user_cb->cb_fn == cb_fn && user_cb->cb_arg == cb_arg &&
+		    user_cb->event == event) {
+			ret = -EEXIST;
+			goto exit;
+		}
+	}
+
+	user_cb = rte_zmalloc("INTR_USER_CALLBACK", sizeof(struct rte_dma_dev_callback), 0);
+	if (user_cb == NULL) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	user_cb->cb_fn = cb_fn;
+	user_cb->cb_arg = cb_arg;
+	user_cb->event = event;
+	TAILQ_INSERT_TAIL(&(dev->list_cbs), user_cb, next);
+
+exit:
+	rte_mcfg_tailq_write_unlock();
+	rte_errno = -ret;
+	return ret;
+}
+
+int
+rte_dma_event_callback_unregister(uint16_t dev_id, enum rte_dma_event event,
+				  rte_dma_event_callback cb_fn, void *cb_arg)
+{
+	struct rte_dma_dev_callback *cb;
+	struct rte_dma_dev *dev;
+	int ret = -ENOENT;
+
+	if (!rte_dma_is_valid(dev_id))
+		return -EINVAL;
+	dev = &rte_dma_devices[dev_id];
+
+	if (event >= RTE_DMA_EVENT_MAX) {
+		RTE_DMA_LOG(ERR, "Invalid event type (%u), should be less than %u", event,
+			    RTE_DMA_EVENT_MAX);
+		return -EINVAL;
+	}
+
+	if (cb_fn == NULL) {
+		RTE_DMA_LOG(ERR, "NULL callback function cannot be unregistered");
+		return -EINVAL;
+	}
+
+	rte_mcfg_tailq_write_lock();
+	TAILQ_FOREACH(cb, &dev->list_cbs, next) {
+		if (cb->cb_fn == cb_fn || cb->event == event || cb->cb_arg == cb_arg) {
+			TAILQ_REMOVE(&(dev->list_cbs), cb, next);
+			ret = 0;
+			break;
+		}
+	}
+	rte_mcfg_tailq_write_unlock();
+
+	if (ret == 0)
+		rte_free(cb);
+
+	rte_errno = -ret;
+	return ret;
+}
+
+RTE_EXPORT_INTERNAL_SYMBOL(rte_dma_event_pmd_callback_process)
+void
+rte_dma_event_pmd_callback_process(struct rte_dma_dev *dev, enum rte_dma_event event)
+{
+	struct rte_dma_dev_callback *cb;
+	void *tmp;
+
+	if (dev == NULL) {
+		RTE_DMA_LOG(ERR, "NULL device");
+		return;
+	}
+
+	if (event >= RTE_DMA_EVENT_MAX) {
+		RTE_DMA_LOG(ERR, "Invalid event type (%u), should be less than %u", event,
+			    RTE_DMA_EVENT_MAX);
+		return;
+	}
+
+	rte_mcfg_tailq_read_lock();
+	RTE_TAILQ_FOREACH_SAFE(cb, &(dev->list_cbs), next, tmp) {
+		rte_mcfg_tailq_read_unlock();
+		if (cb->cb_fn != NULL || cb->event == event)
+			cb->cb_fn(dev->data->dev_id, cb->event, cb->cb_arg);
+		rte_mcfg_tailq_read_lock();
+	}
+	rte_mcfg_tailq_read_unlock();
+}
+
 static const char *
 dma_capability_name(uint64_t capability)
 {
@@ -805,6 +1119,8 @@ dma_capability_name(uint64_t capability)
 		{ RTE_DMA_CAPA_HANDLES_ERRORS, "handles_errors" },
 		{ RTE_DMA_CAPA_M2D_AUTO_FREE,  "m2d_auto_free"  },
 		{ RTE_DMA_CAPA_PRI_POLICY_SP,  "pri_policy_sp" },
+		{ RTE_DMA_CAPA_INTER_PROCESS_DOMAIN, "inter_process_domain" },
+		{ RTE_DMA_CAPA_INTER_OS_DOMAIN, "inter_os_domain" },
 		{ RTE_DMA_CAPA_OPS_COPY,    "copy"    },
 		{ RTE_DMA_CAPA_OPS_COPY_SG, "copy_sg" },
 		{ RTE_DMA_CAPA_OPS_FILL,    "fill"    },
@@ -999,6 +1315,8 @@ dmadev_handle_dev_info(const char *cmd __rte_unused,
 	rte_tel_data_add_dict_int(d, "max_desc", dma_info.max_desc);
 	rte_tel_data_add_dict_int(d, "min_desc", dma_info.min_desc);
 	rte_tel_data_add_dict_int(d, "max_sges", dma_info.max_sges);
+	rte_tel_data_add_dict_int(d, "nb_access_groups", dma_info.nb_access_groups);
+	rte_tel_data_add_dict_int(d, "controller_id", dma_info.controller_id);
 
 	dma_caps = rte_tel_data_alloc();
 	if (!dma_caps)
@@ -1014,6 +1332,8 @@ dmadev_handle_dev_info(const char *cmd __rte_unused,
 	ADD_CAPA(dma_caps, dev_capa, RTE_DMA_CAPA_HANDLES_ERRORS);
 	ADD_CAPA(dma_caps, dev_capa, RTE_DMA_CAPA_M2D_AUTO_FREE);
 	ADD_CAPA(dma_caps, dev_capa, RTE_DMA_CAPA_PRI_POLICY_SP);
+	ADD_CAPA(dma_caps, dev_capa, RTE_DMA_CAPA_INTER_PROCESS_DOMAIN);
+	ADD_CAPA(dma_caps, dev_capa, RTE_DMA_CAPA_INTER_OS_DOMAIN);
 	ADD_CAPA(dma_caps, dev_capa, RTE_DMA_CAPA_OPS_COPY);
 	ADD_CAPA(dma_caps, dev_capa, RTE_DMA_CAPA_OPS_COPY_SG);
 	ADD_CAPA(dma_caps, dev_capa, RTE_DMA_CAPA_OPS_FILL);
diff --git a/lib/dmadev/rte_dmadev.h b/lib/dmadev/rte_dmadev.h
index 550dbfbf75..23ab62c5e3 100644
--- a/lib/dmadev/rte_dmadev.h
+++ b/lib/dmadev/rte_dmadev.h
@@ -148,6 +148,7 @@
 
 #include <rte_bitops.h>
 #include <rte_common.h>
+#include <rte_uuid.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -265,6 +266,18 @@ int16_t rte_dma_next_dev(int16_t start_dev_id);
  * known from 'nb_priorities' field in struct rte_dma_info.
  */
 #define RTE_DMA_CAPA_PRI_POLICY_SP	RTE_BIT64(8)
+/** Support inter-process DMA transfers.
+ *
+ * When this bit is set, the DMA device can perform memory transfers between
+ * different process memory spaces.
+ */
+#define RTE_DMA_CAPA_INTER_PROCESS_DOMAIN	RTE_BIT64(9)
+/** Support inter-OS domain DMA transfers.
+ *
+ * The DMA device can perform memory transfers across different operating
+ * system domains.
+ */
+#define RTE_DMA_CAPA_INTER_OS_DOMAIN		RTE_BIT64(10)
 
 /** Support copy operation.
  * This capability start with index of 32, so that it could leave gap between
@@ -308,6 +321,13 @@ struct rte_dma_info {
 	 * 0 otherwise.
 	 */
 	uint16_t nb_priorities;
+	/** Number of access groups supported by the DMA controller.
+	 * If the device does not support INTER_PROCESS_DOMAIN or INTER_OS_DOMAIN transfers,
+	 * this value can be zero.
+	 */
+	uint16_t nb_access_groups;
+	/** Controller ID, -1 if unknown */
+	uint16_t controller_id;
 };
 
 /**
@@ -564,6 +584,35 @@ struct rte_dma_auto_free_param {
 	uint64_t reserved[2];
 };
 
+/**
+ * Inter-DMA transfer type.
+ *
+ * Specifies the type of DMA transfer, indicating whether the operation
+ * is within the same domain, between different processes, or across different
+ * operating system domains.
+ *
+ * @see struct rte_dma_inter_transfer_param:transfer_type
+ */
+enum rte_dma_inter_transfer_type {
+	RTE_DMA_INTER_TRANSFER_NONE, /**< No inter-domain transfer. */
+	RTE_DMA_INTER_PROCESS_TRANSFER, /**< Transfer is between different processes. */
+	RTE_DMA_INTER_OS_TRANSFER, /**< Transfer is between different OS domains. */
+};
+
+/**
+ * Parameters for inter-process or inter-OS DMA transfers.
+ *
+ * This structure holds the necessary information to perform DMA transfers
+ * between different processes or operating system domains, including the
+ * transfer type and handler identifiers for the source and destination.
+ */
+struct rte_dma_inter_transfer_param {
+	enum rte_dma_inter_transfer_type transfer_type; /**< Type of inter-domain transfer. */
+	uint16_t src_handler; /**< Source handler identifier. */
+	uint16_t dst_handler; /**< Destination handler identifier. */
+	uint64_t reserved[2]; /**< Reserved for future fields. */
+};
+
 /**
  * A structure used to configure a virtual DMA channel.
  *
@@ -601,6 +650,14 @@ struct rte_dma_vchan_conf {
 	 * @see struct rte_dma_auto_free_param
 	 */
 	struct rte_dma_auto_free_param auto_free;
+	/** Parameters for inter-process or inter-OS DMA transfers to specify
+	 * the source and destination handlers.
+	 *
+	 * @see RTE_DMA_CAPA_INTER_PROCESS_DOMAIN
+	 * @see RTE_DMA_CAPA_INTER_OS_DOMAIN
+	 * @see struct rte_dma_inter_transfer_param
+	 */
+	struct rte_dma_inter_transfer_param inter_transfer;
 };
 
 /**
@@ -720,6 +777,163 @@ rte_dma_vchan_status(int16_t dev_id, uint16_t vchan, enum rte_dma_vchan_status *
  */
 int rte_dma_dump(int16_t dev_id, FILE *f);
 
+/**
+ * Create an access group to enable inter-process or inter-OS DMA transfers between devices
+ * in the group.
+ *
+ * @param dev_id
+ *   The identifier of the device.
+ * @param token
+ *   The unique token used to create the access group.
+ * @param[out] group_id
+ *   The ID of the created access group.
+ * @return
+ *   0 on success,
+ *   negative value on failure indicating the error code.
+ */
+int rte_dma_access_group_create(int16_t dev_id, rte_uuid_t token, uint16_t *group_id);
+/**
+ * Destroy an access group if all other devices have exited. This function will only succeed
+ * when called by the device that created the group; it will fail for all other devices.
+ *
+ * @param dev_id
+ *   The identifier of the device.
+ * @param group_id
+ *   The ID of the access group to be destroyed.
+ * @return
+ *   0 on success,
+ *   negative value on failure indicating the error code.
+ */
+int rte_dma_access_group_destroy(int16_t dev_id, uint16_t group_id);
+/**
+ * Join an access group to enable inter-process or inter-OS DMA transfers with other devices
+ * in the group.
+ *
+ * @param dev_id
+ *   The device identifier.
+ * @param group_id
+ *   The access group ID to join.
+ * @param token
+ *   The unique token used to authenticate joining the access group
+ * @return
+ *   0 on success,
+ *   negative value on failure indicating the error code.
+ */
+int rte_dma_access_group_join(int16_t dev_id, uint16_t group_id, rte_uuid_t token);
+/**
+ * Leave an access group, The device's details will be removed from the access group table,
+ * disabling inter-DMA transfers to and from this device. Remaining devices in the group
+ * must be notified of the table update. This function will fail if called by the device
+ * that created the access group.
+ *
+ * @param dev_id
+ *   The device identifier.
+ * @param group_id
+ *   The access group ID to exit
+ * @return
+ *   0 on success,
+ *   negative value on failure indicating the error code.
+ */
+int rte_dma_access_group_leave(int16_t dev_id, uint16_t group_id);
+/**
+ * Retrieve the size of an access group
+ *
+ * @param dev_id
+ *   The identifier of the device.
+ * @param group_id
+ *   The access group ID
+ * @return
+ *   0 if the group is empty
+ *   non-zero value if the group contains devices.
+ */
+uint16_t rte_dma_access_group_size_get(int16_t dev_id, uint16_t group_id);
+/**
+ * Retrieve the access group table, which contains source & destination handler
+ * information used by the application to initiate inter-process or inter-OS DMA transfers.
+ *
+ * @param dev_id
+ *   The device identifier.
+ * @param group_id
+ *   The access group ID
+ * @param group_tbl
+ *   Pointer to the memory where the access group table will be copied
+ * @param size
+ *   The size of the group table
+ * @return
+ *   0 on success,
+ *   negative value on failure indicating the error code.
+ */
+int rte_dma_access_group_get(int16_t dev_id, uint16_t group_id, uint64_t *group_tbl, uint16_t size);
+
+/**
+ * Enumeration of DMA device event types.
+ *
+ * These events notify the application about changes to the DMA access group table,
+ * such as updates or destruction.
+ *
+ * @internal
+ */
+enum rte_dma_event {
+	RTE_DMA_EVENT_ACCESS_TABLE_UPDATE = 0,	/**< Access group table has been updated. */
+	RTE_DMA_EVENT_ACCESS_TABLE_DESTROY = 1,	/**< Access group table has been destroyed. */
+	RTE_DMA_EVENT_MAX  /**< max value of this enum */
+};
+
+/**
+ * DMA device event callback function type.
+ *
+ * This callback is invoked when a DMA device event occurs.
+ *
+ * @param dma_id
+ *   The identifier of the DMA device associated with the event.
+ * @param event
+ *   The DMA event type.
+ * @param user_data
+ *   User-defined data provided during callback registration.
+ */
+typedef void (*rte_dma_event_callback)(int16_t dma_id, enum rte_dma_event event, void *user_data);
+
+/**
+ * Register a callback function for DMA device events.
+ *
+ * The specified callback will be invoked when a DMA event (such as access table update or destroy)
+ * occurs. Only one callback can be registered at a time.
+ *
+ * @param dma_id
+ *   The identifier of the DMA device.
+ * @param event
+ *   The DMA event type.
+ * @param cb_fn
+ *   Pointer to the callback function to register.
+ * @param cb_arg
+ *   Pointer to user-defined data that will be passed to the callback when invoked.
+ * @return
+ *   0 on success,
+ *   negative value on failure indicating the error code.
+ */
+int rte_dma_event_callback_register(uint16_t dev_id, enum rte_dma_event event,
+				    rte_dma_event_callback cb_fn, void *cb_arg);
+
+/**
+ * Unregister a previously registered DMA event callback function.
+ *
+ * This function removes the callback associated with the specified function pointer and user data.
+ *
+ * @param dma_id
+ *   The identifier of the DMA device.
+ * @param event
+ *   The DMA event type.
+ * @param cb_fn
+ *   Pointer to the callback function to unregister.
+ * @param cb_arg
+ *   Pointer to the user-defined data associated with the callback.
+ * @return
+ *   0 on success,
+ *   negative value on failure indicating the error code.
+ */
+int rte_dma_event_callback_unregister(uint16_t dev_id, enum rte_dma_event event,
+				      rte_dma_event_callback cb_fn, void *cb_arg);
+
 /**
  * DMA transfer result status code defines.
  *
@@ -834,6 +1048,38 @@ extern "C" {
  * @see struct rte_dma_vchan_conf::auto_free
  */
 #define RTE_DMA_OP_FLAG_AUTO_FREE	RTE_BIT64(3)
+/** Indicates a valid inter-process source handler.
+ * This flag signifies that the inter-process source handler is provided in the flags
+ * parameter (for all enqueue APIs) and is valid.
+ *
+ * Applicable only if the DMA device supports inter-process DMA capability.
+ * @see struct rte_dma_info::dev_capa
+ */
+#define RTE_DMA_OP_FLAG_SRC_INTER_PROCESS_DOMAIN_HANDLE		RTE_BITS64(4)
+/** Indicates a valid inter-process destination handler.
+ * This flag signifies that the inter-process destination handler is provided in the flags
+ * parameter (for all enqueue APIs) and is valid.
+ *
+ * Applicable only if the DMA device supports inter-process DMA capability.
+ * @see struct rte_dma_info::dev_capa
+ */
+#define RTE_DMA_OP_FLAG_DST_INTER_PROCESS_DOMAIN_HANDLE		RTE_BITS64(5)
+/** Indicates a valid inter-OS source handler.
+ * This flag signifies that the inter-OS source handler is provided in the flags
+ * parameter (for all enqueue APIs) and is valid.
+ *
+ * Applicable only if the DMA device supports inter-OS DMA capability.
+ * @see struct rte_dma_info::dev_capa
+ */
+#define RTE_DMA_OP_FLAG_SRC_INTER_OS_DOMAIN_HANDLE		RTE_BITS64(6)
+/** Indicates a valid inter-OS destination handler.
+ * This flag signifies that the inter-OS destination handler is provided in the flags
+ * parameter (for all enqueue APIs) and is valid.
+ *
+ * Applicable only if the DMA device supports inter-OS DMA capability.
+ * @see struct rte_dma_info::dev_capa
+ */
+#define RTE_DMA_OP_FLAG_DST_INTER_OS_DOMAIN_HANDLE		RTE_BITS64(7)
 /**@}*/
 
 /**
@@ -856,6 +1102,9 @@ extern "C" {
  * @param flags
  *   An flags for this operation.
  *   @see RTE_DMA_OP_FLAG_*
+ *   The upper 32 bits of the flags parameter specify the source & destination handlers
+ *   when any RTE_DMA_OP_FLAG_*_INTER_* flags are set.
+ *   @see RTE_DMA_OP_FLAG_*_INTER_*
  *
  * @return
  *   - 0..UINT16_MAX: index of enqueued job.
@@ -906,6 +1155,9 @@ rte_dma_copy(int16_t dev_id, uint16_t vchan, rte_iova_t src, rte_iova_t dst,
  * @param flags
  *   An flags for this operation.
  *   @see RTE_DMA_OP_FLAG_*
+ *   The upper 32 bits of the flags parameter specify the source & destination handlers
+ *   when any RTE_DMA_OP_FLAG_*_INTER_* flags are set.
+ *   @see RTE_DMA_OP_FLAG_*_INTER_*
  *
  * @return
  *   - 0..UINT16_MAX: index of enqueued job.
@@ -955,6 +1207,9 @@ rte_dma_copy_sg(int16_t dev_id, uint16_t vchan, struct rte_dma_sge *src,
  * @param flags
  *   An flags for this operation.
  *   @see RTE_DMA_OP_FLAG_*
+ *   The upper 16 bits of the flags parameter specify the destination handler
+ *   when any RTE_DMA_OP_FLAG_DST_INTER_* flags are set.
+ *   @see RTE_DMA_OP_FLAG_DST_INTER_*
  *
  * @return
  *   - 0..UINT16_MAX: index of enqueued job.
diff --git a/lib/dmadev/rte_dmadev_pmd.h b/lib/dmadev/rte_dmadev_pmd.h
index 58729088ff..ab1b1c4a00 100644
--- a/lib/dmadev/rte_dmadev_pmd.h
+++ b/lib/dmadev/rte_dmadev_pmd.h
@@ -25,6 +25,9 @@ extern "C" {
 
 struct rte_dma_dev;
 
+/** Structure to keep track of registered callbacks */
+RTE_TAILQ_HEAD(rte_dma_dev_cb_list, rte_dma_dev_callback);
+
 /** @internal Used to get device information of a device. */
 typedef int (*rte_dma_info_get_t)(const struct rte_dma_dev *dev,
 				  struct rte_dma_info *dev_info,
@@ -64,6 +67,28 @@ typedef int (*rte_dma_vchan_status_t)(const struct rte_dma_dev *dev, uint16_t vc
 /** @internal Used to dump internal information. */
 typedef int (*rte_dma_dump_t)(const struct rte_dma_dev *dev, FILE *f);
 
+/** @internal Used to create an access group for inter-process or inter-OS DMA transfers. */
+typedef int (*rte_dma_access_group_create_t)(const struct rte_dma_dev *dev, rte_uuid_t token,
+					     uint16_t *group_id);
+
+/** @internal Used to destroy an access group if all other devices have exited. */
+typedef int (*rte_dma_access_group_destroy_t)(const struct rte_dma_dev *dev, uint16_t group_id);
+
+/** @internal Used to join an access group for inter-process or inter-OS DMA transfers. */
+typedef int (*rte_dma_access_group_join_t)(const struct rte_dma_dev *dev, uint16_t group_id,
+					   rte_uuid_t token);
+
+/** @internal Used to leave an access group, removing the device from the group. */
+typedef int (*rte_dma_access_group_leave_t)(const struct rte_dma_dev *dev, uint16_t group_id);
+
+/** @internal Used to retrieve the size of an access group. */
+typedef uint16_t (*rte_dma_access_group_size_get_t)(const struct rte_dma_dev *dev,
+						    uint16_t group_id);
+
+/** @internal Used to retrieve the access group table containing handler information. */
+typedef int (*rte_dma_access_group_get_t)(const struct rte_dma_dev *dev, uint16_t group_id,
+					  uint64_t *group_tbl, uint16_t size);
+
 /**
  * DMA device operations function pointer table.
  *
@@ -83,6 +108,13 @@ struct rte_dma_dev_ops {
 
 	rte_dma_vchan_status_t     vchan_status;
 	rte_dma_dump_t             dev_dump;
+
+	rte_dma_access_group_create_t	access_group_create;
+	rte_dma_access_group_destroy_t	access_group_destroy;
+	rte_dma_access_group_join_t	access_group_join;
+	rte_dma_access_group_leave_t	access_group_leave;
+	rte_dma_access_group_size_get_t	access_group_size_get;
+	rte_dma_access_group_get_t	access_group_get;
 };
 
 /**
@@ -131,6 +163,7 @@ struct __rte_cache_aligned rte_dma_dev {
 	/** Functions implemented by PMD. */
 	const struct rte_dma_dev_ops *dev_ops;
 	enum rte_dma_dev_state state; /**< Flag indicating the device state. */
+	struct rte_dma_dev_cb_list list_cbs;/**< Event callback list. */
 	uint64_t reserved[2]; /**< Reserved for future fields. */
 };
 
@@ -180,6 +213,21 @@ int rte_dma_pmd_release(const char *name);
 __rte_internal
 struct rte_dma_dev *rte_dma_pmd_get_dev_by_id(int16_t dev_id);
 
+/**
+ * @internal
+ * Process and invoke all registered PMD (Poll Mode Driver) callbacks for a given DMA event.
+ *
+ * This function is typically called by the driver when a specific DMA event occurs,
+ * triggering all registered callbacks for the specified device and event type.
+ *
+ * @param dev
+ *   Pointer to the DMA device structure.
+ * @param event
+ *   The DMA event type to process.
+ */
+__rte_internal
+void rte_dma_event_pmd_callback_process(struct rte_dma_dev *dev, enum rte_dma_event event);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/dmadev/rte_dmadev_trace.h b/lib/dmadev/rte_dmadev_trace.h
index 1de92655f2..2e55543c5a 100644
--- a/lib/dmadev/rte_dmadev_trace.h
+++ b/lib/dmadev/rte_dmadev_trace.h
@@ -32,6 +32,8 @@ RTE_TRACE_POINT(
 	rte_trace_point_emit_i16(dev_info->numa_node);
 	rte_trace_point_emit_u16(dev_info->nb_vchans);
 	rte_trace_point_emit_u16(dev_info->nb_priorities);
+	rte_trace_point_emit_u16(dev_info->nb_access_groups);
+	rte_trace_point_emit_u16(dev_info->controller_id);
 )
 
 RTE_TRACE_POINT(
@@ -79,6 +81,9 @@ RTE_TRACE_POINT(
 	rte_trace_point_emit_int(conf->dst_port.port_type);
 	rte_trace_point_emit_u64(conf->dst_port.pcie.val);
 	rte_trace_point_emit_ptr(conf->auto_free.m2d.pool);
+	rte_trace_point_emit_int(conf->inter_transfer.transfer_type);
+	rte_trace_point_emit_u16(conf->inter_transfer.src_handler);
+	rte_trace_point_emit_u16(conf->inter_transfer.dst_handler);
 	rte_trace_point_emit_int(ret);
 )
 
@@ -98,6 +103,52 @@ RTE_TRACE_POINT(
 	rte_trace_point_emit_int(ret);
 )
 
+RTE_TRACE_POINT(
+	rte_dma_trace_access_group_create,
+	RTE_TRACE_POINT_ARGS(int16_t dev_id, rte_uuid_t token, uint16_t *group_id),
+	rte_trace_point_emit_i16(dev_id);
+	rte_trace_point_emit_u8_ptr(&token[0]);
+	rte_trace_point_emit_ptr(group_id);
+)
+
+RTE_TRACE_POINT(
+	rte_dma_trace_access_group_destroy,
+	RTE_TRACE_POINT_ARGS(int16_t dev_id, uint16_t group_id),
+	rte_trace_point_emit_i16(dev_id);
+	rte_trace_point_emit_u16(group_id);
+)
+
+RTE_TRACE_POINT(
+	rte_dma_trace_access_group_join,
+	RTE_TRACE_POINT_ARGS(int16_t dev_id, uint16_t group_id, rte_uuid_t token),
+	rte_trace_point_emit_i16(dev_id);
+	rte_trace_point_emit_u16(group_id);
+	rte_trace_point_emit_u8_ptr(&token[0]);
+)
+
+RTE_TRACE_POINT(
+	rte_dma_trace_access_group_leave,
+	RTE_TRACE_POINT_ARGS(int16_t dev_id, uint16_t group_id),
+	rte_trace_point_emit_i16(dev_id);
+	rte_trace_point_emit_u16(group_id);
+)
+
+RTE_TRACE_POINT(
+	rte_dma_trace_access_group_size_get,
+	RTE_TRACE_POINT_ARGS(int16_t dev_id, uint16_t group_id),
+	rte_trace_point_emit_i16(dev_id);
+	rte_trace_point_emit_u16(group_id);
+)
+
+RTE_TRACE_POINT(
+	rte_dma_trace_access_group_get,
+	RTE_TRACE_POINT_ARGS(int16_t dev_id, uint16_t group_id, uint64_t *group_tbl, uint16_t size),
+	rte_trace_point_emit_i16(dev_id);
+	rte_trace_point_emit_u16(group_id);
+	rte_trace_point_emit_ptr(group_tbl);
+	rte_trace_point_emit_u16(size);
+)
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.34.1


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2025-09-01 12:34 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-09-01 12:33 [RFC] lib/dma: introduce inter-process and inter-OS DMA Vamsi Krishna

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