diff mbox series

[RFC,v2,1/7] hcdev: introduce heterogeneous computing device library

Message ID 20210730135533.417611-2-thomas@monjalon.net (mailing list archive)
State New
Delegated to: Thomas Monjalon
Headers show
Series heterogeneous computing library | expand

Checks

Context Check Description
ci/checkpatch warning coding style issues

Commit Message

Thomas Monjalon July 30, 2021, 1:55 p.m. UTC
From: Elena Agostini <eagostini@nvidia.com>

In heterogeneous computing system, processing is not only in the CPU.
Some tasks can be delegated to devices working in parallel.

The new library hcdev is for dealing with computing devices
from a DPDK application running on the CPU.

The infrastructure is prepared to welcome drivers in drivers/hc/.

Signed-off-by: Elena Agostini <eagostini@nvidia.com>
Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
---
 .gitignore                             |   1 +
 MAINTAINERS                            |   6 +
 doc/api/doxy-api-index.md              |   1 +
 doc/api/doxy-api.conf.in               |   1 +
 doc/guides/conf.py                     |   8 +
 doc/guides/hcdevs/features/default.ini |  10 +
 doc/guides/hcdevs/index.rst            |  11 ++
 doc/guides/hcdevs/overview.rst         |  11 ++
 doc/guides/index.rst                   |   1 +
 doc/guides/prog_guide/hcdev.rst        |   5 +
 doc/guides/prog_guide/index.rst        |   1 +
 doc/guides/rel_notes/release_21_08.rst |   4 +
 drivers/hc/meson.build                 |   4 +
 drivers/meson.build                    |   1 +
 lib/hcdev/hcdev.c                      | 249 +++++++++++++++++++++++++
 lib/hcdev/hcdev_driver.h               |  67 +++++++
 lib/hcdev/meson.build                  |  10 +
 lib/hcdev/rte_hcdev.h                  | 169 +++++++++++++++++
 lib/hcdev/version.map                  |  20 ++
 lib/meson.build                        |   1 +
 20 files changed, 581 insertions(+)
 create mode 100644 doc/guides/hcdevs/features/default.ini
 create mode 100644 doc/guides/hcdevs/index.rst
 create mode 100644 doc/guides/hcdevs/overview.rst
 create mode 100644 doc/guides/prog_guide/hcdev.rst
 create mode 100644 drivers/hc/meson.build
 create mode 100644 lib/hcdev/hcdev.c
 create mode 100644 lib/hcdev/hcdev_driver.h
 create mode 100644 lib/hcdev/meson.build
 create mode 100644 lib/hcdev/rte_hcdev.h
 create mode 100644 lib/hcdev/version.map
diff mbox series

Patch

diff --git a/.gitignore b/.gitignore
index b19c0717e6..97e57e5897 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,7 @@  doc/guides/compressdevs/overview_feature_table.txt
 doc/guides/regexdevs/overview_feature_table.txt
 doc/guides/vdpadevs/overview_feature_table.txt
 doc/guides/bbdevs/overview_feature_table.txt
+doc/guides/hcdevs/overview_feature_table.txt
 
 # ignore generated ctags/cscope files
 cscope.out.po
diff --git a/MAINTAINERS b/MAINTAINERS
index 8013ba1f14..71e850ae44 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -452,6 +452,12 @@  F: app/test-regex/
 F: doc/guides/prog_guide/regexdev.rst
 F: doc/guides/regexdevs/features/default.ini
 
+Heterogeneous Computing API - EXPERIMENTAL
+M: Elena Agostini <eagostini@nvidia.com>
+F: lib/hcdev/
+F: doc/guides/prog_guide/hcdev.rst
+F: doc/guides/hcdevs/features/default.ini
+
 Eventdev API
 M: Jerin Jacob <jerinj@marvell.com>
 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..2e5256ccc1 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),
+  [hcdev]              (@ref rte_hcdev.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..549f373b8a 100644
--- a/doc/api/doxy-api.conf.in
+++ b/doc/api/doxy-api.conf.in
@@ -44,6 +44,7 @@  INPUT                   = @TOPDIR@/doc/api/doxy-api-index.md \
                           @TOPDIR@/lib/gro \
                           @TOPDIR@/lib/gso \
                           @TOPDIR@/lib/hash \
+                          @TOPDIR@/lib/hcdev \
                           @TOPDIR@/lib/ip_frag \
                           @TOPDIR@/lib/ipsec \
                           @TOPDIR@/lib/jobstats \
diff --git a/doc/guides/conf.py b/doc/guides/conf.py
index 67d2dd62c7..67ad2c8090 100644
--- a/doc/guides/conf.py
+++ b/doc/guides/conf.py
@@ -152,6 +152,9 @@  def generate_overview_table(output_filename, table_id, section, table_name, titl
         name = ini_filename[:-4]
         name = name.replace('_vf', 'vf')
         pmd_names.append(name)
+    if not pmd_names:
+        # Add an empty column if table is empty (required by RST syntax)
+        pmd_names.append(' ')
 
     # Pad the table header names.
     max_header_len = len(max(pmd_names, key=len))
@@ -388,6 +391,11 @@  def setup(app):
                             'Features',
                             'Features availability in bbdev drivers',
                             'Feature')
+    table_file = dirname(__file__) + '/hcdevs/overview_feature_table.txt'
+    generate_overview_table(table_file, 1,
+                            'Features',
+                            'Features availability in hcdev drivers',
+                            'Feature')
 
     if LooseVersion(sphinx_version) < LooseVersion('1.3.1'):
         print('Upgrade sphinx to version >= 1.3.1 for '
diff --git a/doc/guides/hcdevs/features/default.ini b/doc/guides/hcdevs/features/default.ini
new file mode 100644
index 0000000000..f988ee73d4
--- /dev/null
+++ b/doc/guides/hcdevs/features/default.ini
@@ -0,0 +1,10 @@ 
+;
+; Features of heterogeneous device driver.
+;
+; This file defines the features that are valid for inclusion in
+; the other driver files and also the order that they appear in
+; the features table in the documentation. The feature description
+; string should not exceed feature_str_len defined in conf.py.
+;
+[Features]
+Get device info                =
diff --git a/doc/guides/hcdevs/index.rst b/doc/guides/hcdevs/index.rst
new file mode 100644
index 0000000000..4c217ec0c2
--- /dev/null
+++ b/doc/guides/hcdevs/index.rst
@@ -0,0 +1,11 @@ 
+.. SPDX-License-Identifier: BSD-3-Clause
+   Copyright (c) 2021 NVIDIA Corporation & Affiliates
+
+Heterogeneous Computing Device Drivers
+======================================
+
+.. toctree::
+   :maxdepth: 2
+   :numbered:
+
+   overview
diff --git a/doc/guides/hcdevs/overview.rst b/doc/guides/hcdevs/overview.rst
new file mode 100644
index 0000000000..aedce33792
--- /dev/null
+++ b/doc/guides/hcdevs/overview.rst
@@ -0,0 +1,11 @@ 
+.. SPDX-License-Identifier: BSD-3-Clause
+   Copyright (c) 2021 NVIDIA Corporation & Affiliates
+
+Overview of Heterogeneous Computing Drivers
+===========================================
+
+Heterogeneous computing device may refer to any computing unit
+able to process data and to share some memory with the CPU.
+Examples are GPU or specialized processor in a SoC.
+
+.. include:: overview_feature_table.txt
diff --git a/doc/guides/index.rst b/doc/guides/index.rst
index 857f0363d3..643c52d8f9 100644
--- a/doc/guides/index.rst
+++ b/doc/guides/index.rst
@@ -21,6 +21,7 @@  DPDK documentation
    compressdevs/index
    vdpadevs/index
    regexdevs/index
+   hcdevs/index
    eventdevs/index
    rawdevs/index
    mempool/index
diff --git a/doc/guides/prog_guide/hcdev.rst b/doc/guides/prog_guide/hcdev.rst
new file mode 100644
index 0000000000..0b5bd3cb1c
--- /dev/null
+++ b/doc/guides/prog_guide/hcdev.rst
@@ -0,0 +1,5 @@ 
+.. SPDX-License-Identifier: BSD-3-Clause
+   Copyright (c) 2021 NVIDIA Corporation & Affiliates
+
+Heterogeneous Computing Device Library
+======================================
diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst
index 2dce507f46..12e7ea3e20 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
+    hcdev
     rte_security
     rawdev
     link_bonding_poll_mode_drv_lib
diff --git a/doc/guides/rel_notes/release_21_08.rst b/doc/guides/rel_notes/release_21_08.rst
index 16bb9ce19e..fb350b4706 100644
--- a/doc/guides/rel_notes/release_21_08.rst
+++ b/doc/guides/rel_notes/release_21_08.rst
@@ -55,6 +55,10 @@  New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **Introduced Heterogeneous Computing Device library with first features:**
+
+  * Device information
+
 * **Added auxiliary bus support.**
 
   Auxiliary bus provides a way to split function into child-devices
diff --git a/drivers/hc/meson.build b/drivers/hc/meson.build
new file mode 100644
index 0000000000..e51ad3381b
--- /dev/null
+++ b/drivers/hc/meson.build
@@ -0,0 +1,4 @@ 
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright (c) 2021 NVIDIA Corporation & Affiliates
+
+drivers = []
diff --git a/drivers/meson.build b/drivers/meson.build
index bc6f4f567f..b0dbee1b54 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.
+        'hc',             # depends on common and bus.
 ]
 
 if meson.is_cross_build()
diff --git a/lib/hcdev/hcdev.c b/lib/hcdev/hcdev.c
new file mode 100644
index 0000000000..ea587b3713
--- /dev/null
+++ b/lib/hcdev/hcdev.c
@@ -0,0 +1,249 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2021 NVIDIA Corporation & Affiliates
+ */
+
+#include <rte_eal.h>
+#include <rte_string_fns.h>
+#include <rte_errno.h>
+#include <rte_log.h>
+
+#include "rte_hcdev.h"
+#include "hcdev_driver.h"
+
+/* Logging */
+RTE_LOG_REGISTER_DEFAULT(hcdev_logtype, NOTICE);
+#define HCDEV_LOG(level, ...) \
+	rte_log(RTE_LOG_ ## level, hcdev_logtype, RTE_FMT("hcdev: " \
+		RTE_FMT_HEAD(__VA_ARGS__,) "\n", RTE_FMT_TAIL(__VA_ARGS__,)))
+
+/* Set any driver error as EPERM */
+#define HCDEV_DRV_RET(function) \
+	((function != 0) ? -(rte_errno = EPERM) : (rte_errno = 0))
+
+/* Array of devices */
+static struct rte_hcdev *hcdevs;
+/* Number of currently valid devices */
+static int16_t hcdev_max;
+/* Number of currently valid devices */
+static int16_t hcdev_count;
+
+int
+rte_hcdev_init(size_t dev_max)
+{
+	if (dev_max == 0 || dev_max > INT16_MAX) {
+		HCDEV_LOG(ERR, "invalid array size");
+		rte_errno = EINVAL;
+		return -rte_errno;
+	}
+
+	/* No lock, it must be called before or during first probing. */
+	if (hcdevs != NULL) {
+		HCDEV_LOG(ERR, "already initialized");
+		rte_errno = EBUSY;
+		return -rte_errno;
+	}
+
+	hcdevs = calloc(dev_max, sizeof(struct rte_hcdev));
+	if (hcdevs == NULL) {
+		HCDEV_LOG(ERR, "cannot initialize library");
+		rte_errno = ENOMEM;
+		return -rte_errno;
+	}
+
+	hcdev_max = dev_max;
+	return 0;
+}
+
+uint16_t
+rte_hcdev_count_avail(void)
+{
+	return hcdev_count;
+}
+
+bool
+rte_hcdev_is_valid(int16_t dev_id)
+{
+	if (dev_id >= 0 && dev_id < hcdev_max &&
+		hcdevs[dev_id].state == RTE_HCDEV_STATE_INITIALIZED)
+		return true;
+	return false;
+}
+
+int16_t
+rte_hcdev_find_next(int16_t dev_id)
+{
+	if (dev_id < 0)
+		dev_id = 0;
+	while (dev_id < hcdev_max &&
+			hcdevs[dev_id].state == RTE_HCDEV_STATE_UNUSED)
+		dev_id++;
+
+	if (dev_id >= hcdev_max)
+		return RTE_HCDEV_ID_NONE;
+	return dev_id;
+}
+
+static int16_t
+hcdev_find_free_id(void)
+{
+	int16_t dev_id;
+
+	for (dev_id = 0; dev_id < hcdev_max; dev_id++) {
+		if (hcdevs[dev_id].state == RTE_HCDEV_STATE_UNUSED)
+			return dev_id;
+	}
+	return RTE_HCDEV_ID_NONE;
+}
+
+static struct rte_hcdev *
+hcdev_get_by_id(int16_t dev_id)
+{
+	if (!rte_hcdev_is_valid(dev_id))
+		return NULL;
+	return &hcdevs[dev_id];
+}
+
+struct rte_hcdev *
+rte_hcdev_get_by_name(const char *name)
+{
+	int16_t dev_id;
+	struct rte_hcdev *dev;
+
+	if (name == NULL) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+
+	RTE_HCDEV_FOREACH(dev_id) {
+		dev = &hcdevs[dev_id];
+		if (strncmp(name, dev->name, RTE_DEV_NAME_MAX_LEN) == 0)
+			return dev;
+	}
+	return NULL;
+}
+
+struct rte_hcdev *
+rte_hcdev_allocate(const char *name)
+{
+	int16_t dev_id;
+	struct rte_hcdev *dev;
+
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
+		HCDEV_LOG(ERR, "only primary process can allocate device");
+		rte_errno = EPERM;
+		return NULL;
+	}
+	if (name == NULL) {
+		HCDEV_LOG(ERR, "allocate device without a name");
+		rte_errno = EINVAL;
+		return NULL;
+	}
+
+	/* implicit initialization of library before adding first device */
+	if (hcdevs == NULL && rte_hcdev_init(RTE_HCDEV_DEFAULT_MAX) < 0)
+		return NULL;
+
+	if (rte_hcdev_get_by_name(name) != NULL) {
+		HCDEV_LOG(ERR, "device with name %s already exists", name);
+		rte_errno = EEXIST;
+		return NULL;
+	}
+	dev_id = hcdev_find_free_id();
+	if (dev_id == RTE_HCDEV_ID_NONE) {
+		HCDEV_LOG(ERR, "reached maximum number of devices");
+		rte_errno = ENOENT;
+		return NULL;
+	}
+
+	dev = &hcdevs[dev_id];
+	memset(dev, 0, sizeof(*dev));
+
+	if (rte_strscpy(dev->name, name, RTE_DEV_NAME_MAX_LEN) < 0) {
+		HCDEV_LOG(ERR, "device name too long: %s", name);
+		rte_errno = ENAMETOOLONG;
+		return NULL;
+	}
+	dev->info.name = dev->name;
+	dev->info.dev_id = dev_id;
+	dev->info.numa_node = -1;
+
+	hcdev_count++;
+	HCDEV_LOG(DEBUG, "new device %s (id %d) of total %d",
+			name, dev_id, hcdev_count);
+	return dev;
+}
+
+void
+rte_hcdev_complete_new(struct rte_hcdev *dev)
+{
+	if (dev == NULL)
+		return;
+
+	dev->state = RTE_HCDEV_STATE_INITIALIZED;
+}
+
+int
+rte_hcdev_release(struct rte_hcdev *dev)
+{
+	if (dev == NULL) {
+		rte_errno = ENODEV;
+		return -rte_errno;
+	}
+
+	HCDEV_LOG(DEBUG, "free device %s (id %d)",
+			dev->info.name, dev->info.dev_id);
+	dev->state = RTE_HCDEV_STATE_UNUSED;
+	hcdev_count--;
+
+	return 0;
+}
+
+int
+rte_hcdev_close(int16_t dev_id)
+{
+	int firsterr, binerr;
+	int *lasterr = &firsterr;
+	struct rte_hcdev *dev;
+
+	dev = hcdev_get_by_id(dev_id);
+	if (dev == NULL) {
+		HCDEV_LOG(ERR, "close invalid device ID %d", dev_id);
+		rte_errno = ENODEV;
+		return -rte_errno;
+	}
+
+	if (dev->ops.dev_close != NULL) {
+		*lasterr = HCDEV_DRV_RET(dev->ops.dev_close(dev));
+		if (*lasterr != 0)
+			lasterr = &binerr;
+	}
+
+	*lasterr = rte_hcdev_release(dev);
+
+	rte_errno = -firsterr;
+	return firsterr;
+}
+
+int
+rte_hcdev_info_get(int16_t dev_id, struct rte_hcdev_info *info)
+{
+	struct rte_hcdev *dev;
+
+	dev = hcdev_get_by_id(dev_id);
+	if (dev == NULL) {
+		HCDEV_LOG(ERR, "query invalid device ID %d", dev_id);
+		rte_errno = ENODEV;
+		return -rte_errno;
+	}
+	if (info == NULL) {
+		HCDEV_LOG(ERR, "query without storage");
+		rte_errno = EINVAL;
+		return -rte_errno;
+	}
+
+	if (dev->ops.dev_info_get == NULL) {
+		*info = dev->info;
+		return 0;
+	}
+	return HCDEV_DRV_RET(dev->ops.dev_info_get(dev, info));
+}
diff --git a/lib/hcdev/hcdev_driver.h b/lib/hcdev/hcdev_driver.h
new file mode 100644
index 0000000000..ca23cb9b9f
--- /dev/null
+++ b/lib/hcdev/hcdev_driver.h
@@ -0,0 +1,67 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2021 NVIDIA Corporation & Affiliates
+ */
+
+/*
+ * This header file must be included only by drivers.
+ * It is considered internal, i.e. hidden for the application.
+ * The prefix rte_ is used to avoid namespace clash in drivers.
+ */
+
+#ifndef RTE_HCDEV_DRIVER_H
+#define RTE_HCDEV_DRIVER_H
+
+#include <stdint.h>
+
+#include <rte_dev.h>
+
+#include "rte_hcdev.h"
+
+/* Flags indicate current state of device. */
+enum rte_hcdev_state {
+	RTE_HCDEV_STATE_UNUSED,        /* not initialized */
+	RTE_HCDEV_STATE_INITIALIZED,   /* initialized */
+};
+
+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);
+
+struct rte_hcdev_ops {
+	/* Get device info. If NULL, info is just copied. */
+	rte_hcdev_info_get_t *dev_info_get;
+	/* Close device. */
+	rte_hcdev_close_t *dev_close;
+};
+
+struct rte_hcdev {
+	/* Backing device. */
+	struct rte_device *device;
+	/* Unique identifier name. */
+	char name[RTE_DEV_NAME_MAX_LEN]; /* Updated by this library. */
+	/* Device info structure. */
+	struct rte_hcdev_info info;
+	/* Driver functions. */
+	struct rte_hcdev_ops ops;
+	/* Current state (used or not) in the running process. */
+	enum rte_hcdev_state state; /* Updated by this library. */
+	/* Driver-specific private data for the running process. */
+	void *process_private;
+} __rte_cache_aligned;
+
+__rte_internal
+struct rte_hcdev *rte_hcdev_get_by_name(const char *name);
+
+/* First step of initialization */
+__rte_internal
+struct rte_hcdev *rte_hcdev_allocate(const char *name);
+
+/* Last step of initialization. */
+__rte_internal
+void rte_hcdev_complete_new(struct rte_hcdev *dev);
+
+/* Last step of removal. */
+__rte_internal
+int rte_hcdev_release(struct rte_hcdev *dev);
+
+#endif /* RTE_HCDEV_DRIVER_H */
diff --git a/lib/hcdev/meson.build b/lib/hcdev/meson.build
new file mode 100644
index 0000000000..565c3cb623
--- /dev/null
+++ b/lib/hcdev/meson.build
@@ -0,0 +1,10 @@ 
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright (c) 2021 NVIDIA Corporation & Affiliates
+
+headers = files(
+        'rte_hcdev.h',
+)
+
+sources = files(
+        'hcdev.c',
+)
diff --git a/lib/hcdev/rte_hcdev.h b/lib/hcdev/rte_hcdev.h
new file mode 100644
index 0000000000..83f58193c1
--- /dev/null
+++ b/lib/hcdev/rte_hcdev.h
@@ -0,0 +1,169 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2021 NVIDIA Corporation & Affiliates
+ */
+
+#ifndef RTE_HCDEV_H
+#define RTE_HCDEV_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <rte_compat.h>
+
+/**
+ * @file
+ * Generic library to interact with heterogeneous computing device.
+ *
+ * The API is not thread-safe.
+ * Device management must be done by a single thread.
+ *
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Maximum number of devices if rte_hcdev_init() is not called. */
+#define RTE_HCDEV_DEFAULT_MAX 32
+
+/** Empty device ID. */
+#define RTE_HCDEV_ID_NONE -1
+
+/** Store device info. */
+struct rte_hcdev_info {
+	/** Unique identifier name. */
+	const char *name;
+	/** Device ID. */
+	int16_t dev_id;
+	/** Total processors available on device. */
+	uint32_t processor_count;
+	/** Total memory available on device. */
+	size_t total_memory;
+	/* Local NUMA memory ID. -1 if unknown. */
+	int16_t numa_node;
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Initialize the device array before probing devices.
+ * If not called, the maximum of probed devices is RTE_HCDEV_DEFAULT_MAX.
+ *
+ * @param dev_max
+ *   Maximum number of devices.
+ *
+ * @return
+ *   0 on success, -rte_errno otherwise:
+ *   - ENOMEM if out of memory
+ *   - EINVAL if 0 size
+ *   - EBUSY if already initialized
+ */
+__rte_experimental
+int rte_hcdev_init(size_t dev_max);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Return the number of heterogeneous computing devices detected
+ * and associated to DPDK.
+ *
+ * @return
+ *   The number of available computing devices.
+ */
+__rte_experimental
+uint16_t rte_hcdev_count_avail(void);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Check if the device is valid and initialized in DPDK.
+ *
+ * @param dev_id
+ *   The input device ID.
+ *
+ * @return
+ *   - True if dev_id is a valid and initialized computing device.
+ *   - False otherwise.
+ */
+__rte_experimental
+bool rte_hcdev_is_valid(int16_t dev_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Get the ID of the next valid computing device initialized in DPDK.
+ *
+ * @param dev_id
+ *   The initial device ID to start the research.
+ *
+ * @return
+ *   Next device ID corresponding to a valid and initialized computing device,
+ *   RTE_HCDEV_ID_NONE if there is none.
+ */
+__rte_experimental
+int16_t rte_hcdev_find_next(int16_t dev_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Macro to iterate over all valid computing devices.
+ *
+ * @param dev_id
+ *   The ID of the next possible valid device, usually 0 to iterate all.
+ */
+#define RTE_HCDEV_FOREACH(dev_id) \
+	for (dev_id = rte_hcdev_find_next(0); \
+	     dev_id > 0; \
+	     dev_id = rte_hcdev_find_next(dev_id + 1))
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Close device.
+ * All resources are released.
+ *
+ * @param dev_id
+ *   Device ID to close.
+ *
+ * @return
+ *   0 on success, -rte_errno otherwise:
+ *   - ENODEV if invalid dev_id
+ *   - EPERM if driver error
+ */
+__rte_experimental
+int rte_hcdev_close(int16_t dev_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Return device specific info.
+ *
+ * @param dev_id
+ *   Device ID to get info.
+ * @param info
+ *   Memory structure to fill with the info.
+ *
+ * @return
+ *   0 on success, -rte_errno otherwise:
+ *   - ENODEV if invalid dev_id
+ *   - EINVAL if NULL info
+ *   - EPERM if driver error
+ */
+__rte_experimental
+int rte_hcdev_info_get(int16_t dev_id, struct rte_hcdev_info *info);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RTE_HCDEV_H */
diff --git a/lib/hcdev/version.map b/lib/hcdev/version.map
new file mode 100644
index 0000000000..bc6dae6de7
--- /dev/null
+++ b/lib/hcdev/version.map
@@ -0,0 +1,20 @@ 
+EXPERIMENTAL {
+	global:
+
+	# added in 21.11
+	rte_hcdev_close;
+	rte_hcdev_count_avail;
+	rte_hcdev_find_next;
+	rte_hcdev_info_get;
+	rte_hcdev_init;
+	rte_hcdev_is_valid;
+};
+
+INTERNAL {
+	global:
+
+	rte_hcdev_allocate;
+	rte_hcdev_complete_new;
+	rte_hcdev_get_by_name;
+	rte_hcdev_release;
+};
diff --git a/lib/meson.build b/lib/meson.build
index 1673ca4323..3239182c03 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -35,6 +35,7 @@  libraries = [
         'eventdev',
         'gro',
         'gso',
+        'hcdev',
         'ip_frag',
         'jobstats',
         'kni',