[v1,3/3] dma/idxd: add API to create and attach to window

Message ID f91003785ebd4c1075629b3b3e654db6f77f61e9.1691768110.git.anatoly.burakov@intel.com (mailing list archive)
State New
Delegated to: Thomas Monjalon
Headers
Series Add support for inter-domain DMA operations |

Checks

Context Check Description
ci/checkpatch warning coding style issues
ci/loongarch-compilation success Compilation OK
ci/loongarch-unit-testing success Unit Testing PASS
ci/Intel-compilation success Compilation OK
ci/intel-Testing success Testing PASS
ci/intel-Functional success Functional PASS
ci/github-robot: build fail github build: failed
ci/iol-unit-amd64-testing success Testing PASS
ci/iol-unit-arm64-testing success Testing PASS
ci/iol-compile-arm64-testing success Testing PASS
ci/iol-sample-apps-testing success Testing PASS
ci/iol-broadcom-Performance success Performance Testing PASS
ci/iol-intel-Functional success Functional Testing PASS
ci/iol-broadcom-Functional success Functional Testing PASS
ci/iol-intel-Performance success Performance Testing PASS
ci/iol-compile-amd64-testing fail Testing issues

Commit Message

Burakov, Anatoly Aug. 11, 2023, 4:14 p.m. UTC
  This commit implements functions necessary to use inter-domain
operations with idxd driver.

The process is as follows:

1. Process A that wishes to share its memory with others, shall call
   `rte_idxd_window_create()`, which will return a file descriptor
2. Process A is to send above mentioned file descriptor to any
   recipient process (usually over kernel IPC) that wishes to attach to
   that window
3. Process B, after receiving above mentioned file descriptor from
   process A over IPC, shall call `rte_idxd_window_attach()` and
   receive an inter-pasid handle
4. Process B shall use this handle as an argument for inter-domain
   operations using DMA device API

Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
Signed-off-by: Anatoly Burakov <anatoly.burakov@intel.com>
---
 doc/guides/dmadevs/idxd.rst           |  52 ++++++++
 drivers/dma/idxd/idxd_inter_dom.c     | 166 ++++++++++++++++++++++++++
 drivers/dma/idxd/meson.build          |   7 +-
 drivers/dma/idxd/rte_idxd_inter_dom.h |  79 ++++++++++++
 drivers/dma/idxd/version.map          |  11 ++
 5 files changed, 314 insertions(+), 1 deletion(-)
 create mode 100644 drivers/dma/idxd/idxd_inter_dom.c
 create mode 100644 drivers/dma/idxd/rte_idxd_inter_dom.h
 create mode 100644 drivers/dma/idxd/version.map
  

Comments

Jerin Jacob Aug. 14, 2023, 4:39 a.m. UTC | #1
On Fri, Aug 11, 2023 at 9:45 PM Anatoly Burakov
<anatoly.burakov@intel.com> wrote:
>
> This commit implements functions necessary to use inter-domain
> operations with idxd driver.
>
> The process is as follows:
>
> 1. Process A that wishes to share its memory with others, shall call
>    `rte_idxd_window_create()`, which will return a file descriptor
> 2. Process A is to send above mentioned file descriptor to any
>    recipient process (usually over kernel IPC) that wishes to attach to
>    that window
> 3. Process B, after receiving above mentioned file descriptor from
>    process A over IPC, shall call `rte_idxd_window_attach()` and
>    receive an inter-pasid handle
> 4. Process B shall use this handle as an argument for inter-domain
>    operations using DMA device API

> +};
> +
> +
> +EXPERIMENTAL {
> +       global:
> +
> +       rte_idxd_window_create;
> +       rte_idxd_window_attach;

PMD specific API starts with rte_pmd_

> +};
> --
> 2.37.2
>
  
Burakov, Anatoly Aug. 14, 2023, 9:55 a.m. UTC | #2
On 8/14/2023 5:39 AM, Jerin Jacob wrote:
> On Fri, Aug 11, 2023 at 9:45 PM Anatoly Burakov
> <anatoly.burakov@intel.com> wrote:
>>
>> This commit implements functions necessary to use inter-domain
>> operations with idxd driver.
>>
>> The process is as follows:
>>
>> 1. Process A that wishes to share its memory with others, shall call
>>     `rte_idxd_window_create()`, which will return a file descriptor
>> 2. Process A is to send above mentioned file descriptor to any
>>     recipient process (usually over kernel IPC) that wishes to attach to
>>     that window
>> 3. Process B, after receiving above mentioned file descriptor from
>>     process A over IPC, shall call `rte_idxd_window_attach()` and
>>     receive an inter-pasid handle
>> 4. Process B shall use this handle as an argument for inter-domain
>>     operations using DMA device API
> 
>> +};
>> +
>> +
>> +EXPERIMENTAL {
>> +       global:
>> +
>> +       rte_idxd_window_create;
>> +       rte_idxd_window_attach;
> 
> PMD specific API starts with rte_pmd_

Thanks, will fix in next revisions.

> 
>> +};
>> --
>> 2.37.2
>>
  

Patch

diff --git a/doc/guides/dmadevs/idxd.rst b/doc/guides/dmadevs/idxd.rst
index cb8f1fe729..b0439377f8 100644
--- a/doc/guides/dmadevs/idxd.rst
+++ b/doc/guides/dmadevs/idxd.rst
@@ -225,3 +225,55 @@  which operation failed and kick off the device to continue processing operations
    if (error){
       status_count = rte_dma_completed_status(dev_id, vchan, COMP_BURST_SZ, &idx, status);
    }
+
+Performing Inter-Domain operations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Refer to the :ref:`Enqueue / Dequeue APIs <dmadev_enqueue_dequeue>` section of the dmadev library
+documentation for details on operation enqueue, submission and completion API usage.
+
+Refer to the :ref:`Inter-domain operations <dmadev_inter_dom>` section of the dmadev library
+documentation for details on inter-domain operations.
+
+Intel(R) IDXD currently supports the following inter-domain operations:
+
+* Copy operation
+* Fill operation
+
+To use these operations with the IDXD driver, the following program flow should
+be adhered to:
+
+* Process A that wishes to share its memory with others, shall call
+  ``rte_idxd_window_create()``, which will return a file descriptor
+* Process A is to send above mentioned file descriptor to any recipient process
+  (usually over IPC) that wishes to attach to that window
+* Process B, after receiving above mentioned file descriptor from process A over
+  IPC, shall call ``rte_idxd_window_attach()`` and receive an inter-pasid handle
+* Process B shall use this handle as an argument for inter-domain operations
+  using DMA device API
+
+The controller ID parameter for create/attach functions in this case would be
+the controller ID of configured DSA2 devices (located under ``rte_dma_info``
+structure), but which can also be read from ``accel-config`` tool, or from the
+DSA2 work queue name (e.g. work queue ``wq0.3`` would have ``0`` as its
+controller ID).
+
+The ``rte_idxd_window_create()`` call will accept a ``flags`` argument, which
+can contain the following bits:
+
+* ``RTE_IDXD_WIN_FLAGS_PROT_READ`` - allow other process to read from memory
+  region to be shared
+  - In this case, the remote process will be using the resulting inter-pasid
+    handle as source handle for inter-domain DMA operations (and set the
+    ``RTE_DMA_OP_FLAG_SRC_HANDLE`` DMA operation flag)
+* ``RTE_IDXD_WIN_FLAGS_PROT_WRITE`` - allow other process to write into memory
+  region to be shared
+  - In this case, the remote process will be using the resulting inter-pasid
+    handle as destination handle for inter-domain DMA operations (and set the
+    ``RTE_DMA_OP_FLAG_DST_HANDLE`` DMA operation flag)
+* ``RTE_IDXD_WIN_FLAGS_WIN_CHECK`` - if this flag is not set, the remote process
+  will be allowed unrestricted access to entire memory space of the owner
+  process
+* ``RTE_IDXD_WIN_FLAGS_OFFSET_MODE`` - addresses for DMA operations will have to
+  be specified as offsets from base address of the memory region to be shared
+* ``RTE_IDXD_WIN_FLAGS_TYPE_SAMS`` - enable multi-submitter mode.
diff --git a/drivers/dma/idxd/idxd_inter_dom.c b/drivers/dma/idxd/idxd_inter_dom.c
new file mode 100644
index 0000000000..21dcd6980d
--- /dev/null
+++ b/drivers/dma/idxd/idxd_inter_dom.c
@@ -0,0 +1,166 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include <rte_common.h>
+#include <rte_errno.h>
+#include <rte_idxd_inter_dom.h>
+
+#include "idxd_internal.h"
+
+#define IDXD_TYPE       ('d')
+#define IDXD_IOC_BASE   100
+#define IDXD_WIN_BASE   200
+
+enum idxd_win_type {
+	IDXD_WIN_TYPE_SA_SS = 0,
+	IDXD_WIN_TYPE_SA_MS,
+};
+
+#define IDXD_WIN_FLAGS_MASK (RTE_IDXD_WIN_FLAGS_PROT_READ | RTE_IDXD_WIN_FLAGS_PROT_WRITE |\
+		RTE_IDXD_WIN_FLAGS_WIN_CHECK | RTE_IDXD_WIN_FLAGS_OFFSET_MODE|\
+		RTE_IDXD_WIN_FLAGS_TYPE_SAMS)
+
+struct idxd_win_param {
+	uint64_t base;          /* Window base */
+	uint64_t size;          /* Window size */
+	uint32_t type;          /* Window type, see enum idxd_win_type */
+	uint16_t flags;         /* See IDXD windows flags */
+	uint16_t handle;        /* Window handle returned by driver */
+} __attribute__((packed));
+
+struct idxd_win_attach {
+	uint32_t fd;            /* Window file descriptor returned by IDXD_WIN_CREATE */
+	uint16_t handle;        /* Window handle returned by driver */
+} __attribute__((packed));
+
+struct idxd_win_fault {
+	uint64_t offset;        /* Window offset of faulting address */
+	uint64_t len;           /* Faulting range */
+	uint32_t write_fault;   /* Fault generated on write */
+} __attribute__((packed));
+
+#define IDXD_WIN_CREATE         _IOWR(IDXD_TYPE, IDXD_IOC_BASE + 1, struct idxd_win_param)
+#define IDXD_WIN_ATTACH         _IOR(IDXD_TYPE, IDXD_IOC_BASE + 2, struct idxd_win_attach)
+#define IDXD_WIN_FAULT          _IOR(IDXD_TYPE, IDXD_WIN_BASE + 1, struct idxd_win_fault)
+#define DSA_DEV_PATH "/dev/dsa"
+
+static inline const char *
+dsa_get_dev_path(void)
+{
+	const char *path = getenv("DSA_DEV_PATH");
+	return path ? path : DSA_DEV_PATH;
+}
+
+static int
+dsa_find_work_queue(int controller_id)
+{
+	char dev_templ[PATH_MAX], path_templ[PATH_MAX];
+	const char *path = dsa_get_dev_path();
+	struct dirent *wq;
+	DIR *dev_dir;
+	int fd = -1;
+
+	/* construct work queue path template */
+	snprintf(dev_templ, sizeof(dev_templ), "wq%d.", controller_id);
+
+	/* open the DSA device directory */
+	dev_dir = opendir(path);
+	if (dev_dir == NULL)
+		return -1;
+
+	/* find any available work queue */
+	while ((wq = readdir(dev_dir)) != NULL) {
+		/* skip things that aren't work queues */
+		if (strncmp(wq->d_name, dev_templ, strlen(dev_templ)) != 0)
+			continue;
+
+		/* try this work queue */
+		snprintf(path_templ, sizeof(path_templ), "%s/%s", path, wq->d_name);
+
+		fd = open(path_templ, O_RDWR);
+		if (fd < 0)
+			continue;
+
+		break;
+	}
+
+	return fd;
+}
+
+int
+rte_idxd_window_create(int controller_id, void *win_addr,
+	unsigned int win_len, int flags)
+{
+	struct idxd_win_param param = {0};
+	int idpte_fd, fd;
+
+	fd = dsa_find_work_queue(controller_id);
+
+	/* did we find anything? */
+	if (fd < 0) {
+		IDXD_PMD_ERR("%s(): creatomg idpt window failed", __func__);
+		return -1;
+	}
+
+	/* create a wormhole into a parallel reality... */
+	param.base = (uint64_t)win_addr;
+	param.size = win_len;
+	param.flags = flags & IDXD_WIN_FLAGS_MASK;
+	param.type = (flags & RTE_IDXD_WIN_FLAGS_TYPE_SAMS) ?
+		IDXD_WIN_TYPE_SA_MS : IDXD_WIN_TYPE_SA_SS;
+
+	idpte_fd = ioctl(fd, IDXD_WIN_CREATE, &param);
+
+	close(fd);
+
+	if (idpte_fd < 0)
+		rte_errno = idpte_fd;
+
+	return idpte_fd;
+}
+
+int
+rte_idxd_window_attach(int controller_id, int idpte_fd,
+	uint16_t *handle)
+{
+
+	struct idxd_win_attach win_attach = {0};
+	int ret, fd;
+
+	if (handle == NULL) {
+		rte_errno = EINVAL;
+		return -1;
+	}
+
+	fd = dsa_find_work_queue(controller_id);
+
+	/* did we find anything? */
+	if (fd < 0) {
+		IDXD_PMD_ERR("%s(): creatomg idpt window failed", __func__);
+		rte_errno = ENOENT;
+		return -1;
+	}
+
+	/* get access to someone else's wormhole */
+	win_attach.fd = idpte_fd;
+
+	ret = ioctl(fd, IDXD_WIN_ATTACH, &win_attach);
+	if (ret != 0) {
+		IDXD_PMD_ERR("%s(): attaching idpt window failed: %s",
+				__func__, strerror(ret));
+		rte_errno = ret;
+		return -1;
+	}
+
+	*handle = win_attach.handle;
+
+	return 0;
+}
diff --git a/drivers/dma/idxd/meson.build b/drivers/dma/idxd/meson.build
index c5403b431c..da73ab340c 100644
--- a/drivers/dma/idxd/meson.build
+++ b/drivers/dma/idxd/meson.build
@@ -22,5 +22,10 @@  sources = files(
 )
 
 if is_linux
-    sources += files('idxd_bus.c')
+    sources += files(
+    'idxd_bus.c',
+    'idxd_inter_dom.c',
+)
 endif
+
+headers = files('rte_idxd_inter_dom.h')
diff --git a/drivers/dma/idxd/rte_idxd_inter_dom.h b/drivers/dma/idxd/rte_idxd_inter_dom.h
new file mode 100644
index 0000000000..c31f3777c9
--- /dev/null
+++ b/drivers/dma/idxd/rte_idxd_inter_dom.h
@@ -0,0 +1,79 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Intel Corporation
+ */
+
+#ifndef _RTE_IDXD_INTER_DOM_H_
+#define _RTE_IDXD_INTER_DOM_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#include <rte_compat.h>
+
+/** Allow reading from address space. */
+#define RTE_IDXD_WIN_FLAGS_PROT_READ    0x0001
+/** Allow writing to address space. */
+#define RTE_IDXD_WIN_FLAGS_PROT_WRITE   0x0002
+/** If this flag not set, the entire address space will be accessible. */
+#define RTE_IDXD_WIN_FLAGS_WIN_CHECK    0x0004
+/** Destination addresses are offsets from window base address. */
+#define RTE_IDXD_WIN_FLAGS_OFFSET_MODE  0x0008
+/* multiple submitter flag. If not set - single submitter type will be used. */
+#define RTE_IDXD_WIN_FLAGS_TYPE_SAMS    0x0010
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Create an inter-pasid window to allow another process to access this process'
+ * memory. This function returns a file descriptor for the window, that can be
+ * used by another process to access this window.
+ *
+ * @param controller_id
+ *   IDXD controller device ID.
+ * @param win_addr
+ *   Base address of memory chunk being shared (ignored if
+ *   `RTE_IDXD_WIN_FLAGS_WIN_CHECK` is not set).
+ * @param win_len
+ *   Length of memory chunk being shared (ignored if
+ *   `RTE_IDXD_WIN_FLAGS_WIN_CHECK` is not set).
+ * @param flags
+ *   Flags to configure the window.
+ * @return
+ *   Non-negative on success.
+ *   Negative on error.
+ */
+__rte_experimental
+int rte_idxd_window_create(int controller_id, void *win_addr,
+	unsigned int win_len, int flags);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Attach to an inter-pasid window of another process. This function expects a
+ * file descriptor returned by `rte_idxd_window_create()`, and will set the
+ * value pointed to by `handle`. This handle can then be used to perform
+ * inter-domain DMA operations.
+ *
+ * @param controller_id
+ *   IDXD controller device ID.
+ * @param idpte_fd
+ *   File descriptor for another process's window
+ * @param handle
+ *   Pointer to a variable to receive the handle.
+ * @return
+ *   0 on success.
+ *   Negative on error.
+ */
+__rte_experimental
+int rte_idxd_window_attach(int controller_id, int idpte_fd, uint16_t *handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_IDXD_INTER_DOM_H_ */
diff --git a/drivers/dma/idxd/version.map b/drivers/dma/idxd/version.map
new file mode 100644
index 0000000000..e091bb7c09
--- /dev/null
+++ b/drivers/dma/idxd/version.map
@@ -0,0 +1,11 @@ 
+DPDK_23 {
+	local: *;
+};
+
+
+EXPERIMENTAL {
+	global:
+
+	rte_idxd_window_create;
+	rte_idxd_window_attach;
+};