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',
