[dpdk-dev] [RFC PATCH v2 5/7] hcdev: add memory API

Thomas Monjalon thomas at monjalon.net
Fri Jul 30 15:55:31 CEST 2021


From: Elena Agostini <eagostini at nvidia.com>

In heterogeneous computing system, processing is not only in the CPU.
Some tasks can be delegated to devices working in parallel.
Such workload distribution can be achieved by sharing some memory.

As a first step, the features are focused on memory management.
A function allows to allocate memory inside the device,
or in the main (CPU) memory while making it visible for the device.
This memory may be used to save packets or for synchronization data.

The next step should focus on GPU processing task control.

Signed-off-by: Elena Agostini <eagostini at nvidia.com>
Signed-off-by: Thomas Monjalon <thomas at monjalon.net>
---
 doc/guides/hcdevs/features/default.ini |  3 +
 doc/guides/rel_notes/release_21_08.rst |  1 +
 lib/hcdev/hcdev.c                      | 88 ++++++++++++++++++++++++++
 lib/hcdev/hcdev_driver.h               |  9 +++
 lib/hcdev/rte_hcdev.h                  | 53 ++++++++++++++++
 lib/hcdev/version.map                  |  2 +
 6 files changed, 156 insertions(+)

diff --git a/doc/guides/hcdevs/features/default.ini b/doc/guides/hcdevs/features/default.ini
index f988ee73d4..ee32753d94 100644
--- a/doc/guides/hcdevs/features/default.ini
+++ b/doc/guides/hcdevs/features/default.ini
@@ -8,3 +8,6 @@
 ;
 [Features]
 Get device info                =
+Share CPU memory with device   =
+Allocate device memory         =
+Free memory                    =
diff --git a/doc/guides/rel_notes/release_21_08.rst b/doc/guides/rel_notes/release_21_08.rst
index fb350b4706..e955a331a6 100644
--- a/doc/guides/rel_notes/release_21_08.rst
+++ b/doc/guides/rel_notes/release_21_08.rst
@@ -58,6 +58,7 @@ New Features
 * **Introduced Heterogeneous Computing Device library with first features:**
 
   * Device information
+  * Memory management
 
 * **Added auxiliary bus support.**
 
diff --git a/lib/hcdev/hcdev.c b/lib/hcdev/hcdev.c
index a7badd122b..621e0b99bd 100644
--- a/lib/hcdev/hcdev.c
+++ b/lib/hcdev/hcdev.c
@@ -6,6 +6,7 @@
 #include <rte_tailq.h>
 #include <rte_string_fns.h>
 #include <rte_memzone.h>
+#include <rte_malloc.h>
 #include <rte_errno.h>
 #include <rte_log.h>
 
@@ -501,3 +502,90 @@ rte_hcdev_info_get(int16_t dev_id, struct rte_hcdev_info *info)
 	}
 	return HCDEV_DRV_RET(dev->ops.dev_info_get(dev, info));
 }
+
+#define RTE_HCDEV_MALLOC_FLAGS_ALL \
+	RTE_HCDEV_MALLOC_REGISTER_FROM_CPU
+#define RTE_HCDEV_MALLOC_FLAGS_RESERVED ~RTE_HCDEV_MALLOC_FLAGS_ALL
+
+void *
+rte_hcdev_malloc(int16_t dev_id, size_t size, uint32_t flags)
+{
+	struct rte_hcdev *dev;
+	void *ptr;
+	int ret;
+
+	dev = hcdev_get_by_id(dev_id);
+	if (dev == NULL) {
+		HCDEV_LOG(ERR, "alloc mem for invalid device ID %d", dev_id);
+		rte_errno = ENODEV;
+		return NULL;
+	}
+	if (flags & RTE_HCDEV_MALLOC_FLAGS_RESERVED) {
+		HCDEV_LOG(ERR, "alloc mem with reserved flag 0x%x",
+				flags & RTE_HCDEV_MALLOC_FLAGS_RESERVED);
+		rte_errno = EINVAL;
+		return NULL;
+	}
+
+	if (flags & RTE_HCDEV_MALLOC_REGISTER_FROM_CPU) {
+		if (dev->ops.mem_register == NULL) {
+			HCDEV_LOG(ERR, "mem registration not supported");
+			rte_errno = ENOTSUP;
+			return NULL;
+		}
+	} else {
+		if (dev->ops.mem_alloc == NULL) {
+			HCDEV_LOG(ERR, "mem allocation not supported");
+			rte_errno = ENOTSUP;
+			return NULL;
+		}
+	}
+
+	if (size == 0) /* dry-run */
+		return NULL;
+
+	if (flags & RTE_HCDEV_MALLOC_REGISTER_FROM_CPU) {
+		ptr = rte_zmalloc(NULL, size, 0);
+		if (ptr == NULL) {
+			HCDEV_LOG(ERR, "cannot allocate CPU memory");
+			rte_errno = ENOMEM;
+			return NULL;
+		}
+		ret = dev->ops.mem_register(dev, size, ptr);
+	} else {
+		ret = dev->ops.mem_alloc(dev, size, &ptr);
+	}
+	/* TODO maintain a table of chunks registered/allocated */
+	switch (ret) {
+	case 0:
+		return ptr;
+	case -ENOMEM:
+	case -E2BIG:
+		rte_errno = -ret;
+		return NULL;
+	default:
+		rte_errno = EPERM;
+		return NULL;
+	}
+}
+
+int
+rte_hcdev_free(int16_t dev_id, void *ptr)
+{
+	struct rte_hcdev *dev;
+
+	dev = hcdev_get_by_id(dev_id);
+	if (dev == NULL) {
+		HCDEV_LOG(ERR, "free mem for invalid device ID %d", dev_id);
+		rte_errno = ENODEV;
+		return -rte_errno;
+	}
+
+	if (dev->ops.mem_free == NULL) {
+		rte_errno = ENOTSUP;
+		return -rte_errno;
+	}
+	return HCDEV_DRV_RET(dev->ops.mem_free(dev, ptr));
+	/* TODO unregister callback */
+	/* TODO rte_free CPU memory */
+}
diff --git a/lib/hcdev/hcdev_driver.h b/lib/hcdev/hcdev_driver.h
index f33b56947b..f42f08508f 100644
--- a/lib/hcdev/hcdev_driver.h
+++ b/lib/hcdev/hcdev_driver.h
@@ -27,12 +27,21 @@ enum rte_hcdev_state {
 struct rte_hcdev;
 typedef int (rte_hcdev_close_t)(struct rte_hcdev *dev);
 typedef int (rte_hcdev_info_get_t)(struct rte_hcdev *dev, struct rte_hcdev_info *info);
+typedef int (rte_hcdev_mem_alloc_t)(struct rte_hcdev *dev, size_t size, void **ptr);
+typedef int (rte_hcdev_mem_register_t)(struct rte_hcdev *dev, size_t size, void *ptr);
+typedef int (rte_hcdev_free_t)(struct rte_hcdev *dev, void *ptr);
 
 struct rte_hcdev_ops {
 	/* Get device info. If NULL, info is just copied. */
 	rte_hcdev_info_get_t *dev_info_get;
 	/* Close device or child context. */
 	rte_hcdev_close_t *dev_close;
+	/* Allocate memory in device. */
+	rte_hcdev_mem_alloc_t *mem_alloc;
+	/* Register CPU memory in device. */
+	rte_hcdev_mem_register_t *mem_register;
+	/* Free memory allocated or registered in device. */
+	rte_hcdev_free_t *mem_free;
 };
 
 struct rte_hcdev_mpshared {
diff --git a/lib/hcdev/rte_hcdev.h b/lib/hcdev/rte_hcdev.h
index c95f37063d..11895d9486 100644
--- a/lib/hcdev/rte_hcdev.h
+++ b/lib/hcdev/rte_hcdev.h
@@ -9,6 +9,7 @@
 #include <stdint.h>
 #include <stdbool.h>
 
+#include <rte_bitops.h>
 #include <rte_compat.h>
 
 /**
@@ -293,6 +294,58 @@ int rte_hcdev_callback_unregister(int16_t dev_id, enum rte_hcdev_event event,
 __rte_experimental
 int rte_hcdev_info_get(int16_t dev_id, struct rte_hcdev_info *info);
 
+/** Memory allocated on a CPU node and visible by the device. */
+#define RTE_HCDEV_MALLOC_REGISTER_FROM_CPU RTE_BIT32(0)
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Allocate a chunk of memory usable by the device.
+ *
+ * @param dev_id
+ *   Device ID requiring allocated memory.
+ * @param size
+ *   Number of bytes to allocate.
+ *   Requesting 0 will do nothing.
+ * @param flags
+ *   If 0, the default is to allocate in the device memory.
+ *   See flags RTE_HCDEV_MALLOC_*
+ *
+ * @return
+ *   A pointer to the allocated memory, otherwise NULL and rte_errno is set:
+ *   - ENODEV if invalid dev_id
+ *   - EINVAL if reserved flags
+ *   - ENOTSUP if operation not supported by the driver
+ *   - E2BIG if size is higher than limit
+ *   - ENOMEM if out of space
+ *   - EPERM if driver error
+ */
+__rte_experimental
+void *rte_hcdev_malloc(int16_t dev_id, size_t size, uint32_t flags)
+__rte_alloc_size(2);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Deallocate a chunk of memory allocated with rte_hcdev_malloc().
+ *
+ * @param dev_id
+ *   Reference device ID.
+ * @param ptr
+ *   Pointer to the memory area to be deallocated.
+ *   NULL is a no-op accepted value.
+ *
+ * @return
+ *   0 on success, -rte_errno otherwise:
+ *   - ENODEV if invalid dev_id
+ *   - ENOTSUP if operation not supported by the driver
+ *   - EPERM if driver error
+ */
+__rte_experimental
+int rte_hcdev_free(int16_t dev_id, void *ptr);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/hcdev/version.map b/lib/hcdev/version.map
index 450c256527..9195f4f747 100644
--- a/lib/hcdev/version.map
+++ b/lib/hcdev/version.map
@@ -8,9 +8,11 @@ EXPERIMENTAL {
 	rte_hcdev_close;
 	rte_hcdev_count_avail;
 	rte_hcdev_find_next;
+	rte_hcdev_free;
 	rte_hcdev_info_get;
 	rte_hcdev_init;
 	rte_hcdev_is_valid;
+	rte_hcdev_malloc;
 };
 
 INTERNAL {
-- 
2.31.1



More information about the dev mailing list