From patchwork Fri Jul 30 13:55:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Monjalon X-Patchwork-Id: 96461 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 19FE8A0A0C; Fri, 30 Jul 2021 15:56:02 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id F3B1D40DDC; Fri, 30 Jul 2021 15:56:01 +0200 (CEST) Received: from new3-smtp.messagingengine.com (new3-smtp.messagingengine.com [66.111.4.229]) by mails.dpdk.org (Postfix) with ESMTP id 13DE34003F for ; Fri, 30 Jul 2021 15:56:01 +0200 (CEST) Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailnew.nyi.internal (Postfix) with ESMTP id 74260580B57; Fri, 30 Jul 2021 09:56:00 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Fri, 30 Jul 2021 09:56:00 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=monjalon.net; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm1; bh=K8i8dm1sDmZTc ocXfM5rBLJqtqZvru1/YJey02esa0E=; b=wRSVvgPByGKZCs8yeqi03jhvQWtcu rMdAUWvgOIQZrpB0d2Wu+/cwED73NbqRasOA66SMYTJtNCENvNWtmUQmw02s/RFQ AIWj3Otj3MCb+1MHhuquJfwqg5zdJqWBntTWI71OELKfGAFimfqL+/ZAGCxkDnFS jzMZ24xa/uMr9vFFSuvnLPUHgZoPuiX/y7ljcEaaK+Wr2afuazSm0lvPHLCgGqpj PQLV1vwf5jyboGGutBOXlAC6nEwMZDYTMgBB7txMjRi/W0q5rmMtF1Mh0/qH+514 qgWbQ3BQi0KdWZ4Jn8mUACsKud9P4G+/shU+UechNsDRSf9KBf3w/2l9w== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; bh=K8i8dm1sDmZTcocXfM5rBLJqtqZvru1/YJey02esa0E=; b=rKg5/TVn RXkdr2jhfCuhWSsV0jbhl1KZl3yvuEmszEF8/oNCttgTiSGr7Quo0COZddw2VewK rCe1To3bAZ3431yOSCUjvXrTJY4ZuY/NIcG1+aBY5caCh0rVNZbIb3vIagwd596g /vxEEzSfVBPrAL/nsw0WZsOzGfGyRqc/pBw+lXIZ0nVwCaTiuL+gYHNPkDm6/cUr iE4Awu70YcXZZHtVVePbQZEd8UGknbUK+0gqMTGrg2nbbeSRsyNjFatlTOzt/R1F Rd+HzRSi51pVk/qdq9aRdNi3RnyK3aymZThfo8e5wUlDuBNzCupyMMocB6zAVz4A kd1Nr1666mUEuA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvtddrheehgdeiiecutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomhepvfhhohhmrghs ucfoohhnjhgrlhhonhcuoehthhhomhgrshesmhhonhhjrghlohhnrdhnvghtqeenucggtf frrghtthgvrhhnpeeghfeuteeutedthffgteejuefgudeukeejlefgheeiffdtfeffjedv feduiefhtdenucffohhmrghinheptghonhhfrdhinhdpughpughkrdhorhhgnecuvehluh hsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepthhhohhmrghssehm ohhnjhgrlhhonhdrnhgvth X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 30 Jul 2021 09:55:58 -0400 (EDT) From: Thomas Monjalon To: dev@dpdk.org Cc: Stephen Hemminger , David Marchand , Andrew Rybchenko , Haiyue Wang , Honnappa Nagarahalli , Jerin Jacob , Ferruh Yigit , Elena Agostini , Ray Kinsella , Anatoly Burakov Date: Fri, 30 Jul 2021 15:55:27 +0200 Message-Id: <20210730135533.417611-2-thomas@monjalon.net> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210730135533.417611-1-thomas@monjalon.net> References: <20210602203531.2288645-1-thomas@monjalon.net> <20210730135533.417611-1-thomas@monjalon.net> MIME-Version: 1.0 Subject: [dpdk-dev] [RFC PATCH v2 1/7] hcdev: introduce heterogeneous computing device library X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Elena Agostini 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 Signed-off-by: Thomas Monjalon --- .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 --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 +F: lib/hcdev/ +F: doc/guides/prog_guide/hcdev.rst +F: doc/guides/hcdevs/features/default.ini + Eventdev API M: Jerin Jacob 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 +#include +#include +#include + +#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 + +#include + +#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 +#include +#include + +#include + +/** + * @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', From patchwork Fri Jul 30 13:55:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Monjalon X-Patchwork-Id: 96462 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 9862AA0A0C; Fri, 30 Jul 2021 15:56:11 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 859D040DFB; Fri, 30 Jul 2021 15:56:11 +0200 (CEST) Received: from out1-smtp.messagingengine.com (out1-smtp.messagingengine.com [66.111.4.25]) by mails.dpdk.org (Postfix) with ESMTP id A35DF40141 for ; Fri, 30 Jul 2021 15:56:09 +0200 (CEST) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailout.nyi.internal (Postfix) with ESMTP id 3F8CC5C00C9; Fri, 30 Jul 2021 09:56:09 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute1.internal (MEProxy); Fri, 30 Jul 2021 09:56:09 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=monjalon.net; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm1; bh=5MuYWuqW+Onhk OmI7Q44MmKORIH5WFAbRVmCJmlMpOE=; b=lEzzUl2EvBkV7+ecADa4RUKKM8t9p fiV1ulbfbvowtVmV+oa1HDk1VmLSmMoxp0c16bSibJ8jAG2yeAl6QBubWsF7W9W2 oNhuuTzi6CnHHU4XDGfIHaDrVyHQelaczqDkYs3XbeS9WXM16uGH4XkUfy/jbtwm rSMMJZFcK9RPsXjjPqL4zxNuF955Ibkgg9s0Il1HYmAMDxRais4IUTnwn1KfpxTO ACYcXalB+AfNlLiD5IxqC+uEOmpE5jiM5C6W9UoGCgn9N8Ow+9KO/y+k1SuU2ARt x2F/ppi4vaHlnaRV22vhpBPAtrq8UXz7Ate7uf/pwsfd0O9ZwCIV7DILg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; bh=5MuYWuqW+OnhkOmI7Q44MmKORIH5WFAbRVmCJmlMpOE=; b=Kq3ahXVc 33fCs+mGJCU6bhStyMidSWZtwBkx1zLtfOBnos2HEcrGzcBKG7xF/qR9HoRWWAAZ soFI7+C0usMGoVdWJUgn5fAwWIDPh2J6Y/bf8UiNjojNLfYVFb8pOOl7BlGCrsVu t0ea6rgNtlu0IaZvjklUdJr2G5066PlBRW5DrrJ7t/DjqSGRnU+E3FKKQM+6I4u0 kindZRWgri00U113wQhOc/x7MEk4jgRXqYSG3EqPN/WJrZlHPjsLEPDJ885gyK1Q soIOBJuc0cS1JCX0QuIACJG0iOyzfNYxBl9BsEYMYWqrTfp75qOo3YpK1b1+JL2y khi53NZgUFTdYQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvtddrheehgdeiiecutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomhepvfhhohhmrghs ucfoohhnjhgrlhhonhcuoehthhhomhgrshesmhhonhhjrghlohhnrdhnvghtqeenucggtf frrghtthgvrhhnpedvhefgiedvjeegtdevheefhfetleefgfeivefgffevfeejgedtgfeu tdehtdegveenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhroh hmpehthhhomhgrshesmhhonhhjrghlohhnrdhnvght X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 30 Jul 2021 09:56:06 -0400 (EDT) From: Thomas Monjalon To: dev@dpdk.org Cc: Stephen Hemminger , David Marchand , Andrew Rybchenko , Haiyue Wang , Honnappa Nagarahalli , Jerin Jacob , Ferruh Yigit , Elena Agostini , Ray Kinsella Date: Fri, 30 Jul 2021 15:55:28 +0200 Message-Id: <20210730135533.417611-3-thomas@monjalon.net> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210730135533.417611-1-thomas@monjalon.net> References: <20210602203531.2288645-1-thomas@monjalon.net> <20210730135533.417611-1-thomas@monjalon.net> MIME-Version: 1.0 Subject: [dpdk-dev] [RFC PATCH v2 2/7] hcdev: add event notification X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Callback functions may be registered for a device event. Callback management is per-process and not thread-safe. The events RTE_HCDEV_EVENT_NEW and RTE_HCDEV_EVENT_DEL are notified respectively after creation and before removal of a device, as part of the library functions. Some future events may be emitted from drivers. Signed-off-by: Thomas Monjalon --- lib/hcdev/hcdev.c | 137 +++++++++++++++++++++++++++++++++++++++ lib/hcdev/hcdev_driver.h | 7 ++ lib/hcdev/rte_hcdev.h | 71 ++++++++++++++++++++ lib/hcdev/version.map | 3 + 4 files changed, 218 insertions(+) diff --git a/lib/hcdev/hcdev.c b/lib/hcdev/hcdev.c index ea587b3713..2a7ce1ccd8 100644 --- a/lib/hcdev/hcdev.c +++ b/lib/hcdev/hcdev.c @@ -3,6 +3,7 @@ */ #include +#include #include #include #include @@ -27,6 +28,15 @@ static int16_t hcdev_max; /* Number of currently valid devices */ static int16_t hcdev_count; +/* Event callback object */ +struct rte_hcdev_callback { + TAILQ_ENTRY(rte_hcdev_callback) next; + rte_hcdev_callback_t *function; + void *user_data; + enum rte_hcdev_event event; +}; +static void hcdev_free_callbacks(struct rte_hcdev *dev); + int rte_hcdev_init(size_t dev_max) { @@ -166,6 +176,7 @@ rte_hcdev_allocate(const char *name) dev->info.name = dev->name; dev->info.dev_id = dev_id; dev->info.numa_node = -1; + TAILQ_INIT(&dev->callbacks); hcdev_count++; HCDEV_LOG(DEBUG, "new device %s (id %d) of total %d", @@ -180,6 +191,7 @@ rte_hcdev_complete_new(struct rte_hcdev *dev) return; dev->state = RTE_HCDEV_STATE_INITIALIZED; + rte_hcdev_notify(dev, RTE_HCDEV_EVENT_NEW); } int @@ -192,6 +204,9 @@ rte_hcdev_release(struct rte_hcdev *dev) HCDEV_LOG(DEBUG, "free device %s (id %d)", dev->info.name, dev->info.dev_id); + rte_hcdev_notify(dev, RTE_HCDEV_EVENT_DEL); + + hcdev_free_callbacks(dev); dev->state = RTE_HCDEV_STATE_UNUSED; hcdev_count--; @@ -224,6 +239,128 @@ rte_hcdev_close(int16_t dev_id) return firsterr; } +int +rte_hcdev_callback_register(int16_t dev_id, enum rte_hcdev_event event, + rte_hcdev_callback_t *function, void *user_data) +{ + int16_t next_dev, last_dev; + struct rte_hcdev_callback_list *callbacks; + struct rte_hcdev_callback *callback; + + if (!rte_hcdev_is_valid(dev_id) && dev_id != RTE_HCDEV_ID_ANY) { + HCDEV_LOG(ERR, "register callback of invalid ID %d", dev_id); + rte_errno = ENODEV; + return -rte_errno; + } + if (function == NULL) { + HCDEV_LOG(ERR, "cannot register callback without function"); + rte_errno = EINVAL; + return -rte_errno; + } + + if (dev_id == RTE_HCDEV_ID_ANY) { + next_dev = 0; + last_dev = hcdev_max - 1; + } else { + next_dev = last_dev = dev_id; + } + do { + callbacks = &hcdevs[next_dev].callbacks; + + /* check if not already registered */ + TAILQ_FOREACH(callback, callbacks, next) { + if (callback->event == event && + callback->function == function && + callback->user_data == user_data) { + HCDEV_LOG(INFO, "callback already registered"); + return 0; + } + } + + callback = malloc(sizeof(*callback)); + if (callback == NULL) { + HCDEV_LOG(ERR, "cannot allocate callback"); + return -ENOMEM; + } + callback->function = function; + callback->user_data = user_data; + callback->event = event; + TAILQ_INSERT_TAIL(callbacks, callback, next); + + } while (++next_dev <= last_dev); + + return 0; +} + +int +rte_hcdev_callback_unregister(int16_t dev_id, enum rte_hcdev_event event, + rte_hcdev_callback_t *function, void *user_data) +{ + int16_t next_dev, last_dev; + struct rte_hcdev_callback_list *callbacks; + struct rte_hcdev_callback *callback, *next_callback; + + if (!rte_hcdev_is_valid(dev_id) && dev_id != RTE_HCDEV_ID_ANY) { + HCDEV_LOG(ERR, "unregister callback of invalid ID %d", dev_id); + rte_errno = ENODEV; + return -rte_errno; + } + if (function == NULL) { + HCDEV_LOG(ERR, "cannot unregister callback without function"); + rte_errno = EINVAL; + return -rte_errno; + } + + if (dev_id == RTE_HCDEV_ID_ANY) { + next_dev = 0; + last_dev = hcdev_max - 1; + } else { + next_dev = last_dev = dev_id; + } + + do { + callbacks = &hcdevs[next_dev].callbacks; + TAILQ_FOREACH_SAFE(callback, callbacks, next, next_callback) { + if (callback->event != event || + callback->function != function || + (callback->user_data != user_data && + user_data != (void *)-1)) + continue; + TAILQ_REMOVE(callbacks, callback, next); + free(callback); + } + } while (++next_dev <= last_dev); + + return 0; +} + +static void +hcdev_free_callbacks(struct rte_hcdev *dev) +{ + struct rte_hcdev_callback_list *callbacks; + struct rte_hcdev_callback *callback, *next_callback; + + callbacks = &dev->callbacks; + TAILQ_FOREACH_SAFE(callback, callbacks, next, next_callback) { + TAILQ_REMOVE(callbacks, callback, next); + free(callback); + } +} + +void +rte_hcdev_notify(struct rte_hcdev *dev, enum rte_hcdev_event event) +{ + int16_t dev_id; + struct rte_hcdev_callback *callback; + + dev_id = dev->info.dev_id; + TAILQ_FOREACH(callback, &dev->callbacks, next) { + if (callback->event != event || callback->function == NULL) + continue; + callback->function(dev_id, event, callback->user_data); + } +} + int rte_hcdev_info_get(int16_t dev_id, struct rte_hcdev_info *info) { diff --git a/lib/hcdev/hcdev_driver.h b/lib/hcdev/hcdev_driver.h index ca23cb9b9f..80d11bd612 100644 --- a/lib/hcdev/hcdev_driver.h +++ b/lib/hcdev/hcdev_driver.h @@ -12,6 +12,7 @@ #define RTE_HCDEV_DRIVER_H #include +#include #include @@ -43,6 +44,8 @@ struct rte_hcdev { struct rte_hcdev_info info; /* Driver functions. */ struct rte_hcdev_ops ops; + /* Event callback list. */ + TAILQ_HEAD(rte_hcdev_callback_list, rte_hcdev_callback) callbacks; /* 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. */ @@ -64,4 +67,8 @@ void rte_hcdev_complete_new(struct rte_hcdev *dev); __rte_internal int rte_hcdev_release(struct rte_hcdev *dev); +/* Call registered callbacks. No multi-process event. */ +__rte_internal +void rte_hcdev_notify(struct rte_hcdev *dev, enum rte_hcdev_event); + #endif /* RTE_HCDEV_DRIVER_H */ diff --git a/lib/hcdev/rte_hcdev.h b/lib/hcdev/rte_hcdev.h index 83f58193c1..8131e4045a 100644 --- a/lib/hcdev/rte_hcdev.h +++ b/lib/hcdev/rte_hcdev.h @@ -17,6 +17,7 @@ * * The API is not thread-safe. * Device management must be done by a single thread. + * TODO device rwlock for callback list * * @warning * @b EXPERIMENTAL: this API may change without prior notice. @@ -31,6 +32,11 @@ extern "C" { /** Empty device ID. */ #define RTE_HCDEV_ID_NONE -1 +/** Catch-all device ID. */ +#define RTE_HCDEV_ID_ANY INT16_MIN + +/** Catch-all callback data. */ +#define RTE_HCDEV_CALLBACK_ANY_DATA ((void *)-1) /** Store device info. */ struct rte_hcdev_info { @@ -46,6 +52,18 @@ struct rte_hcdev_info { int16_t numa_node; }; +/** Flags passed in notification callback. */ +enum rte_hcdev_event { + /** Device is just initialized. */ + RTE_HCDEV_EVENT_NEW, + /** Device is going to be released. */ + RTE_HCDEV_EVENT_DEL, +}; + +/** Prototype of event callback function. */ +typedef void (rte_hcdev_callback_t)(int16_t dev_id, + enum rte_hcdev_event event, void *user_data); + /** * @warning * @b EXPERIMENTAL: this API may change without prior notice. @@ -142,6 +160,59 @@ int16_t rte_hcdev_find_next(int16_t dev_id); __rte_experimental int rte_hcdev_close(int16_t dev_id); +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Register a function as event callback. + * A function may be registered multiple times for different events. + * + * @param dev_id + * Device ID to get notified about. + * RTE_HCDEV_ID_ANY means all devices. + * @param event + * Device event to be registered for. + * @param function + * Callback function to be called on event. + * @param user_data + * Optional parameter passed in the callback. + * + * @return + * 0 on success, -rte_errno otherwise: + * - ENODEV if invalid dev_id + * - EINVAL if NULL function + * - ENOMEM if out of memory + */ +__rte_experimental +int rte_hcdev_callback_register(int16_t dev_id, enum rte_hcdev_event event, + rte_hcdev_callback_t *function, void *user_data); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Unregister for an event. + * + * @param dev_id + * Device ID to be silenced. + * RTE_HCDEV_ID_ANY means all devices. + * @param event + * Registered event. + * @param function + * Registered function. + * @param user_data + * Optional parameter as registered. + * RTE_HCDEV_CALLBACK_ANY_DATA is a catch-all. + * + * @return + * 0 on success, -rte_errno otherwise: + * - ENODEV if invalid dev_id + * - EINVAL if NULL function + */ +__rte_experimental +int rte_hcdev_callback_unregister(int16_t dev_id, enum rte_hcdev_event event, + rte_hcdev_callback_t *function, void *user_data); + /** * @warning * @b EXPERIMENTAL: this API may change without prior notice. diff --git a/lib/hcdev/version.map b/lib/hcdev/version.map index bc6dae6de7..24a5a5a7c4 100644 --- a/lib/hcdev/version.map +++ b/lib/hcdev/version.map @@ -2,6 +2,8 @@ EXPERIMENTAL { global: # added in 21.11 + rte_hcdev_callback_register; + rte_hcdev_callback_unregister; rte_hcdev_close; rte_hcdev_count_avail; rte_hcdev_find_next; @@ -16,5 +18,6 @@ INTERNAL { rte_hcdev_allocate; rte_hcdev_complete_new; rte_hcdev_get_by_name; + rte_hcdev_notify; rte_hcdev_release; }; From patchwork Fri Jul 30 13:55:29 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Monjalon X-Patchwork-Id: 96463 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id EA94AA0A0C; Fri, 30 Jul 2021 15:56:16 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id B19C54067A; Fri, 30 Jul 2021 15:56:14 +0200 (CEST) Received: from out1-smtp.messagingengine.com (out1-smtp.messagingengine.com [66.111.4.25]) by mails.dpdk.org (Postfix) with ESMTP id 69ABA410FB for ; Fri, 30 Jul 2021 15:56:13 +0200 (CEST) Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id 203FA5C00C9; Fri, 30 Jul 2021 09:56:13 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Fri, 30 Jul 2021 09:56:13 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=monjalon.net; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm1; bh=hPce/qfuIG4LU gLU2qhBPlHU0uGEJzBN53FnbAns2ns=; b=wJelnuyNyVb0bW5/AYkPIjxlZzi6h nFmix5UIK3h9eJOj2/BflxfexMv2zEGmClpLDVBj3LC/WmR/7H+LxIm3b7Iqu4nb uHEvoil62qhY5f3nsQlblMmF+sICCGjeBRDREKVBS1AwfqMVsxoRUXey3bWKnSuH pp+p8cXohoBCDtZPEzZ9EiokIBTmGH/PIEXkZVrUJAl0mmNyDWcnq+2iLtoDXyxS JXFduFLbL3Dmm5WBihEUGgpl7In8LUaAzTV09tVlguDsLkeIWWuuiTKAwLvfUkt0 p2kcUuTfiDOx5Yrl9rAMJ75+KPvMtQLRzarQrugYCOh9kctPCMwQ722Fg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; bh=hPce/qfuIG4LUgLU2qhBPlHU0uGEJzBN53FnbAns2ns=; b=SL0rJ4N5 D0BcbRMVeYndb+Juu8inNEAN0s+GoDBawqDr+pu6asiQ2M5SZm4LIrTHcgDYMx/e /R2ERY50chaEma8/96k1qGU7RVsyX70sP0DW7dSpVl863KYekkgKZn1Dj9PTffY7 1G2XD6S4ubornVyc9NHhEcizmKsilr0keGwAuKHH8dhEu1WXxtHjidNR0D4k9iR7 Jr14pB2eSwHZbB5s+7rYVB+iiE3t0TDUJ3G1qf705SCigJsAIRQ9ofTTF/Rrtpzt aFahECVeCvTtJVPaoomNlCu0vCY1m1dXYn+yfYwZi+wacRcaBYS7wf49n7H7Ktu9 2zYqz/c1n5cyog== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvtddrheehgdeiiecutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomhepvfhhohhmrghs ucfoohhnjhgrlhhonhcuoehthhhomhgrshesmhhonhhjrghlohhnrdhnvghtqeenucggtf frrghtthgvrhhnpedvhefgiedvjeegtdevheefhfetleefgfeivefgffevfeejgedtgfeu tdehtdegveenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhroh hmpehthhhomhgrshesmhhonhhjrghlohhnrdhnvght X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 30 Jul 2021 09:56:11 -0400 (EDT) From: Thomas Monjalon To: dev@dpdk.org Cc: Stephen Hemminger , David Marchand , Andrew Rybchenko , Haiyue Wang , Honnappa Nagarahalli , Jerin Jacob , Ferruh Yigit , Elena Agostini , Ray Kinsella Date: Fri, 30 Jul 2021 15:55:29 +0200 Message-Id: <20210730135533.417611-4-thomas@monjalon.net> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210730135533.417611-1-thomas@monjalon.net> References: <20210602203531.2288645-1-thomas@monjalon.net> <20210730135533.417611-1-thomas@monjalon.net> MIME-Version: 1.0 Subject: [dpdk-dev] [RFC PATCH v2 3/7] hcdev: add child device representing a device context X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" The computing device may operate in some isolated contexts. Memory and processing are isolated in a silo represented by a child device. The context is provided as an opaque by the caller of rte_hcdev_add_child(). Signed-off-by: Thomas Monjalon --- lib/hcdev/hcdev.c | 45 ++++++++++++++++++++++++-- lib/hcdev/hcdev_driver.h | 2 +- lib/hcdev/rte_hcdev.h | 69 +++++++++++++++++++++++++++++++++++++--- lib/hcdev/version.map | 1 + 4 files changed, 110 insertions(+), 7 deletions(-) diff --git a/lib/hcdev/hcdev.c b/lib/hcdev/hcdev.c index 2a7ce1ccd8..d40010749a 100644 --- a/lib/hcdev/hcdev.c +++ b/lib/hcdev/hcdev.c @@ -79,13 +79,22 @@ rte_hcdev_is_valid(int16_t dev_id) return false; } +static bool +hcdev_match_parent(int16_t dev_id, int16_t parent) +{ + if (parent == RTE_HCDEV_ID_ANY) + return true; + return hcdevs[dev_id].info.parent == parent; +} + int16_t -rte_hcdev_find_next(int16_t dev_id) +rte_hcdev_find_next(int16_t dev_id, int16_t parent) { if (dev_id < 0) dev_id = 0; while (dev_id < hcdev_max && - hcdevs[dev_id].state == RTE_HCDEV_STATE_UNUSED) + (hcdevs[dev_id].state == RTE_HCDEV_STATE_UNUSED || + !hcdev_match_parent(dev_id, parent))) dev_id++; if (dev_id >= hcdev_max) @@ -176,6 +185,7 @@ rte_hcdev_allocate(const char *name) dev->info.name = dev->name; dev->info.dev_id = dev_id; dev->info.numa_node = -1; + dev->info.parent = RTE_HCDEV_ID_NONE; TAILQ_INIT(&dev->callbacks); hcdev_count++; @@ -184,6 +194,28 @@ rte_hcdev_allocate(const char *name) return dev; } +int16_t +rte_hcdev_add_child(const char *name, int16_t parent, uint64_t child_context) +{ + struct rte_hcdev *dev; + + if (!rte_hcdev_is_valid(parent)) { + HCDEV_LOG(ERR, "add child to invalid parent ID %d", parent); + rte_errno = ENODEV; + return -rte_errno; + } + + dev = rte_hcdev_allocate(name); + if (dev == NULL) + return -rte_errno; + + dev->info.parent = parent; + dev->info.context = child_context; + + rte_hcdev_complete_new(dev); + return dev->info.dev_id; +} + void rte_hcdev_complete_new(struct rte_hcdev *dev) { @@ -197,10 +229,19 @@ rte_hcdev_complete_new(struct rte_hcdev *dev) int rte_hcdev_release(struct rte_hcdev *dev) { + int16_t dev_id, child; + if (dev == NULL) { rte_errno = ENODEV; return -rte_errno; } + dev_id = dev->info.dev_id; + RTE_HCDEV_FOREACH_CHILD(child, dev_id) { + HCDEV_LOG(ERR, "cannot release device %d with child %d", + dev_id, child); + rte_errno = EBUSY; + return -rte_errno; + } HCDEV_LOG(DEBUG, "free device %s (id %d)", dev->info.name, dev->info.dev_id); diff --git a/lib/hcdev/hcdev_driver.h b/lib/hcdev/hcdev_driver.h index 80d11bd612..39f6fc57ab 100644 --- a/lib/hcdev/hcdev_driver.h +++ b/lib/hcdev/hcdev_driver.h @@ -31,7 +31,7 @@ typedef int (rte_hcdev_info_get_t)(struct rte_hcdev *dev, struct rte_hcdev_info struct rte_hcdev_ops { /* Get device info. If NULL, info is just copied. */ rte_hcdev_info_get_t *dev_info_get; - /* Close device. */ + /* Close device or child context. */ rte_hcdev_close_t *dev_close; }; diff --git a/lib/hcdev/rte_hcdev.h b/lib/hcdev/rte_hcdev.h index 8131e4045a..518020fd2f 100644 --- a/lib/hcdev/rte_hcdev.h +++ b/lib/hcdev/rte_hcdev.h @@ -42,8 +42,12 @@ extern "C" { struct rte_hcdev_info { /** Unique identifier name. */ const char *name; + /** Opaque handler of the device context. */ + uint64_t context; /** Device ID. */ int16_t dev_id; + /** ID of the parent device, RTE_HCDEV_ID_NONE if no parent */ + int16_t parent; /** Total processors available on device. */ uint32_t processor_count; /** Total memory available on device. */ @@ -112,6 +116,33 @@ uint16_t rte_hcdev_count_avail(void); __rte_experimental bool rte_hcdev_is_valid(int16_t dev_id); +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Create a virtual device representing a context in the parent device. + * + * @param name + * Unique string to identify the device. + * @param parent + * Device ID of the parent. + * @param child_context + * Opaque context handler. + * + * @return + * Device ID of the new created child, -rte_errno otherwise: + * - EINVAL if empty name + * - ENAMETOOLONG if long name + * - EEXIST if existing device name + * - ENODEV if invalid parent + * - EPERM if secondary process + * - ENOENT if too many devices + * - ENOMEM if out of space + */ +__rte_experimental +int16_t rte_hcdev_add_child(const char *name, + int16_t parent, uint64_t child_context); + /** * @warning * @b EXPERIMENTAL: this API may change without prior notice. @@ -120,13 +151,17 @@ bool rte_hcdev_is_valid(int16_t dev_id); * * @param dev_id * The initial device ID to start the research. + * @param parent + * The device ID of the parent. + * RTE_HCDEV_ID_NONE means no parent. + * RTE_HCDEV_ID_ANY means no or any parent. * * @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); +int16_t rte_hcdev_find_next(int16_t dev_id, int16_t parent); /** * @warning @@ -138,15 +173,41 @@ int16_t rte_hcdev_find_next(int16_t 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); \ + RTE_HCDEV_FOREACH_CHILD(dev_id, RTE_HCDEV_ID_ANY) + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Macro to iterate over all valid computing devices having no parent. + * + * @param dev_id + * The ID of the next possible valid device, usually 0 to iterate all. + */ +#define RTE_HCDEV_FOREACH_PARENT(dev_id) \ + RTE_HCDEV_FOREACH_CHILD(dev_id, RTE_HCDEV_ID_NONE) + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Macro to iterate over all valid children of a computing device parent. + * + * @param dev_id + * The ID of the next possible valid device, usually 0 to iterate all. + * @param parent + * The device ID of the parent. + */ +#define RTE_HCDEV_FOREACH_CHILD(dev_id, parent) \ + for (dev_id = rte_hcdev_find_next(0, parent); \ dev_id > 0; \ - dev_id = rte_hcdev_find_next(dev_id + 1)) + dev_id = rte_hcdev_find_next(dev_id + 1, parent)) /** * @warning * @b EXPERIMENTAL: this API may change without prior notice. * - * Close device. + * Close device or child context. * All resources are released. * * @param dev_id diff --git a/lib/hcdev/version.map b/lib/hcdev/version.map index 24a5a5a7c4..6d1a1ab1c9 100644 --- a/lib/hcdev/version.map +++ b/lib/hcdev/version.map @@ -2,6 +2,7 @@ EXPERIMENTAL { global: # added in 21.11 + rte_hcdev_add_child; rte_hcdev_callback_register; rte_hcdev_callback_unregister; rte_hcdev_close; From patchwork Fri Jul 30 13:55:30 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Monjalon X-Patchwork-Id: 96464 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 00656A0A0C; Fri, 30 Jul 2021 15:56:26 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id E102E40042; Fri, 30 Jul 2021 15:56:26 +0200 (CEST) Received: from new3-smtp.messagingengine.com (new3-smtp.messagingengine.com [66.111.4.229]) by mails.dpdk.org (Postfix) with ESMTP id B828B40042 for ; Fri, 30 Jul 2021 15:56:24 +0200 (CEST) Received: from compute6.internal (compute6.nyi.internal [10.202.2.46]) by mailnew.nyi.internal (Postfix) with ESMTP id 2E950580B58; Fri, 30 Jul 2021 09:56:24 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute6.internal (MEProxy); Fri, 30 Jul 2021 09:56:24 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=monjalon.net; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm1; bh=2OM+Tyxhvm5/2 ES2ktr/06yWh18g26sBU2kMwzlPuUM=; b=d2NR46AdcvxT3Vk3gw5GqPsA4yfEO DYktMPeb8Z2XeBs/yg9Ex3yxdEL7Cr4qSC/DGwTf7PFqgrJmWJTWhaL28ueJ6ZA+ yQ8+dNxPhC2CGq2v45nBhZoPW8SHtbAgXauh/CPVy9yywJxUiyktHIf5apbS/ZKE /9962pg9PDN/cXu+7FSLfKDCBvBOIswRess9xNd7lMmNtggk+dmXjsc1onX0iwXe sU8tB7QrwCVQzQDc9K9L85g66uSVCHB5MeoQL6RphbR4M0I/E/ERDDgf2rrkoxe9 FJaBLz7+LBhtNKegE+jN4QkseQpouFuftXRFIVg1NBUEc8IxwmvowepTQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; bh=2OM+Tyxhvm5/2ES2ktr/06yWh18g26sBU2kMwzlPuUM=; b=ORivtDnJ ClvyoMgUYggQQQXpVnHUtIXnA3gnGuRItFIX1vgkQ33n8PPtvBCgEobodhyu4v5f dQQkvJ6w6i4HhtZ+5MdqLtgXVZS2Pxbnvvn86xClSljMYpLyDhfaESeKwPiXCyir Dt02fAcjjQxl1S30RwXOQdsc4C802wFb5g7oy1/eF/mRtxjpukEbyBEd1V4ZQ2D6 Sjh0ku2AXmVYuc0wOJh4VkPre+DyUObrfnitjrNLizhEisl8pIOU8+AOrSn+6N2W XOq9Hh8btw6kGOPA4M9zhuIsC2ChXCrXamk34LpX2BIxBvg/d3TEQBRsjQom+JHV S8fyTeKZlEcmSQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvtddrheehgdeijecutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomhepvfhhohhmrghs ucfoohhnjhgrlhhonhcuoehthhhomhgrshesmhhonhhjrghlohhnrdhnvghtqeenucggtf frrghtthgvrhhnpedvhefgiedvjeegtdevheefhfetleefgfeivefgffevfeejgedtgfeu tdehtdegveenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhroh hmpehthhhomhgrshesmhhonhhjrghlohhnrdhnvght X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 30 Jul 2021 09:56:20 -0400 (EDT) From: Thomas Monjalon To: dev@dpdk.org Cc: Stephen Hemminger , David Marchand , Andrew Rybchenko , Haiyue Wang , Honnappa Nagarahalli , Jerin Jacob , Ferruh Yigit , Elena Agostini , Ray Kinsella , Anatoly Burakov Date: Fri, 30 Jul 2021 15:55:30 +0200 Message-Id: <20210730135533.417611-5-thomas@monjalon.net> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210730135533.417611-1-thomas@monjalon.net> References: <20210602203531.2288645-1-thomas@monjalon.net> <20210730135533.417611-1-thomas@monjalon.net> MIME-Version: 1.0 Subject: [dpdk-dev] [RFC PATCH v2 4/7] hcdev: support multi-process X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" The device data shared between processes are moved in a struct allocated in a shared memory (a new memzone for all hcdevs). The main struct rte_hcdev references the shared memory via the pointer mpshared. The API function rte_hcdev_attach() is added to attach a device from the secondary process. The function rte_hcdev_allocate() can be used only by primary process. Signed-off-by: Thomas Monjalon --- lib/hcdev/hcdev.c | 114 ++++++++++++++++++++++++++++++++------- lib/hcdev/hcdev_driver.h | 23 ++++++-- lib/hcdev/rte_hcdev.h | 3 +- lib/hcdev/version.map | 1 + 4 files changed, 115 insertions(+), 26 deletions(-) diff --git a/lib/hcdev/hcdev.c b/lib/hcdev/hcdev.c index d40010749a..a7badd122b 100644 --- a/lib/hcdev/hcdev.c +++ b/lib/hcdev/hcdev.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -28,6 +29,12 @@ static int16_t hcdev_max; /* Number of currently valid devices */ static int16_t hcdev_count; +/* Shared memory between processes. */ +static const char *HCDEV_MEMZONE = "rte_hcdev_shared"; +static struct { + __extension__ struct rte_hcdev_mpshared hcdevs[0]; +} *hcdev_shared_mem; + /* Event callback object */ struct rte_hcdev_callback { TAILQ_ENTRY(rte_hcdev_callback) next; @@ -40,6 +47,8 @@ static void hcdev_free_callbacks(struct rte_hcdev *dev); int rte_hcdev_init(size_t dev_max) { + const struct rte_memzone *memzone; + if (dev_max == 0 || dev_max > INT16_MAX) { HCDEV_LOG(ERR, "invalid array size"); rte_errno = EINVAL; @@ -60,6 +69,23 @@ rte_hcdev_init(size_t dev_max) return -rte_errno; } + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + memzone = rte_memzone_reserve(HCDEV_MEMZONE, + sizeof(*hcdev_shared_mem) + + sizeof(*hcdev_shared_mem->hcdevs) * dev_max, + SOCKET_ID_ANY, 0); + } else { + memzone = rte_memzone_lookup(HCDEV_MEMZONE); + } + if (memzone == NULL) { + HCDEV_LOG(ERR, "cannot initialize shared memory"); + free(hcdevs); + hcdevs = NULL; + rte_errno = ENOMEM; + return -rte_errno; + } + hcdev_shared_mem = memzone->addr; + hcdev_max = dev_max; return 0; } @@ -74,7 +100,7 @@ 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) + hcdevs[dev_id].process_state == RTE_HCDEV_STATE_INITIALIZED) return true; return false; } @@ -84,7 +110,7 @@ hcdev_match_parent(int16_t dev_id, int16_t parent) { if (parent == RTE_HCDEV_ID_ANY) return true; - return hcdevs[dev_id].info.parent == parent; + return hcdevs[dev_id].mpshared->info.parent == parent; } int16_t @@ -93,7 +119,7 @@ rte_hcdev_find_next(int16_t dev_id, int16_t parent) if (dev_id < 0) dev_id = 0; while (dev_id < hcdev_max && - (hcdevs[dev_id].state == RTE_HCDEV_STATE_UNUSED || + (hcdevs[dev_id].process_state == RTE_HCDEV_STATE_UNUSED || !hcdev_match_parent(dev_id, parent))) dev_id++; @@ -108,7 +134,7 @@ 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) + if (hcdevs[dev_id].process_state == RTE_HCDEV_STATE_UNUSED) return dev_id; } return RTE_HCDEV_ID_NONE; @@ -135,7 +161,7 @@ rte_hcdev_get_by_name(const char *name) RTE_HCDEV_FOREACH(dev_id) { dev = &hcdevs[dev_id]; - if (strncmp(name, dev->name, RTE_DEV_NAME_MAX_LEN) == 0) + if (strncmp(name, dev->mpshared->name, RTE_DEV_NAME_MAX_LEN) == 0) return dev; } return NULL; @@ -177,16 +203,20 @@ rte_hcdev_allocate(const char *name) dev = &hcdevs[dev_id]; memset(dev, 0, sizeof(*dev)); - if (rte_strscpy(dev->name, name, RTE_DEV_NAME_MAX_LEN) < 0) { + dev->mpshared = &hcdev_shared_mem->hcdevs[dev_id]; + memset(dev->mpshared, 0, sizeof(*dev->mpshared)); + + if (rte_strscpy(dev->mpshared->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; - dev->info.parent = RTE_HCDEV_ID_NONE; + dev->mpshared->info.name = dev->mpshared->name; + dev->mpshared->info.dev_id = dev_id; + dev->mpshared->info.numa_node = -1; + dev->mpshared->info.parent = RTE_HCDEV_ID_NONE; TAILQ_INIT(&dev->callbacks); + __atomic_fetch_add(&dev->mpshared->process_refcnt, 1, __ATOMIC_RELAXED); hcdev_count++; HCDEV_LOG(DEBUG, "new device %s (id %d) of total %d", @@ -194,6 +224,51 @@ rte_hcdev_allocate(const char *name) return dev; } +struct rte_hcdev * +rte_hcdev_attach(const char *name) +{ + int16_t dev_id; + struct rte_hcdev *dev; + struct rte_hcdev_mpshared *shared_dev; + + if (rte_eal_process_type() != RTE_PROC_SECONDARY) { + HCDEV_LOG(ERR, "only secondary process can attach device"); + rte_errno = EPERM; + return NULL; + } + if (name == NULL) { + HCDEV_LOG(ERR, "attach 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; + + for (dev_id = 0; dev_id < hcdev_max; dev_id++) { + shared_dev = &hcdev_shared_mem->hcdevs[dev_id]; + if (strncmp(name, shared_dev->name, RTE_DEV_NAME_MAX_LEN) == 0) + break; + } + if (dev_id >= hcdev_max) { + HCDEV_LOG(ERR, "device with name %s not found", name); + rte_errno = ENOENT; + return NULL; + } + dev = &hcdevs[dev_id]; + memset(dev, 0, sizeof(*dev)); + + TAILQ_INIT(&dev->callbacks); + dev->mpshared = shared_dev; + __atomic_fetch_add(&dev->mpshared->process_refcnt, 1, __ATOMIC_RELAXED); + + hcdev_count++; + HCDEV_LOG(DEBUG, "attached device %s (id %d) of total %d", + name, dev_id, hcdev_count); + return dev; +} + int16_t rte_hcdev_add_child(const char *name, int16_t parent, uint64_t child_context) { @@ -209,11 +284,11 @@ rte_hcdev_add_child(const char *name, int16_t parent, uint64_t child_context) if (dev == NULL) return -rte_errno; - dev->info.parent = parent; - dev->info.context = child_context; + dev->mpshared->info.parent = parent; + dev->mpshared->info.context = child_context; rte_hcdev_complete_new(dev); - return dev->info.dev_id; + return dev->mpshared->info.dev_id; } void @@ -222,7 +297,7 @@ rte_hcdev_complete_new(struct rte_hcdev *dev) if (dev == NULL) return; - dev->state = RTE_HCDEV_STATE_INITIALIZED; + dev->process_state = RTE_HCDEV_STATE_INITIALIZED; rte_hcdev_notify(dev, RTE_HCDEV_EVENT_NEW); } @@ -235,7 +310,7 @@ rte_hcdev_release(struct rte_hcdev *dev) rte_errno = ENODEV; return -rte_errno; } - dev_id = dev->info.dev_id; + dev_id = dev->mpshared->info.dev_id; RTE_HCDEV_FOREACH_CHILD(child, dev_id) { HCDEV_LOG(ERR, "cannot release device %d with child %d", dev_id, child); @@ -244,11 +319,12 @@ rte_hcdev_release(struct rte_hcdev *dev) } HCDEV_LOG(DEBUG, "free device %s (id %d)", - dev->info.name, dev->info.dev_id); + dev->mpshared->info.name, dev->mpshared->info.dev_id); rte_hcdev_notify(dev, RTE_HCDEV_EVENT_DEL); hcdev_free_callbacks(dev); - dev->state = RTE_HCDEV_STATE_UNUSED; + dev->process_state = RTE_HCDEV_STATE_UNUSED; + __atomic_fetch_sub(&dev->mpshared->process_refcnt, 1, __ATOMIC_RELAXED); hcdev_count--; return 0; @@ -394,7 +470,7 @@ rte_hcdev_notify(struct rte_hcdev *dev, enum rte_hcdev_event event) int16_t dev_id; struct rte_hcdev_callback *callback; - dev_id = dev->info.dev_id; + dev_id = dev->mpshared->info.dev_id; TAILQ_FOREACH(callback, &dev->callbacks, next) { if (callback->event != event || callback->function == NULL) continue; @@ -420,7 +496,7 @@ rte_hcdev_info_get(int16_t dev_id, struct rte_hcdev_info *info) } if (dev->ops.dev_info_get == NULL) { - *info = dev->info; + *info = dev->mpshared->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 index 39f6fc57ab..f33b56947b 100644 --- a/lib/hcdev/hcdev_driver.h +++ b/lib/hcdev/hcdev_driver.h @@ -35,19 +35,28 @@ struct rte_hcdev_ops { rte_hcdev_close_t *dev_close; }; -struct rte_hcdev { - /* Backing device. */ - struct rte_device *device; +struct rte_hcdev_mpshared { /* Unique identifier name. */ char name[RTE_DEV_NAME_MAX_LEN]; /* Updated by this library. */ + /* Driver-specific private data shared in multi-process. */ + void *dev_private; /* Device info structure. */ struct rte_hcdev_info info; + /* Counter of processes using the device. */ + uint16_t process_refcnt; /* Updated by this library. */ +}; + +struct rte_hcdev { + /* Backing device. */ + struct rte_device *device; + /* Data shared between processes. */ + struct rte_hcdev_mpshared *mpshared; /* Driver functions. */ struct rte_hcdev_ops ops; /* Event callback list. */ TAILQ_HEAD(rte_hcdev_callback_list, rte_hcdev_callback) callbacks; /* Current state (used or not) in the running process. */ - enum rte_hcdev_state state; /* Updated by this library. */ + enum rte_hcdev_state process_state; /* Updated by this library. */ /* Driver-specific private data for the running process. */ void *process_private; } __rte_cache_aligned; @@ -55,10 +64,14 @@ struct rte_hcdev { __rte_internal struct rte_hcdev *rte_hcdev_get_by_name(const char *name); -/* First step of initialization */ +/* First step of initialization in primary process. */ __rte_internal struct rte_hcdev *rte_hcdev_allocate(const char *name); +/* First step of initialization in secondary process. */ +__rte_internal +struct rte_hcdev *rte_hcdev_attach(const char *name); + /* Last step of initialization. */ __rte_internal void rte_hcdev_complete_new(struct rte_hcdev *dev); diff --git a/lib/hcdev/rte_hcdev.h b/lib/hcdev/rte_hcdev.h index 518020fd2f..c95f37063d 100644 --- a/lib/hcdev/rte_hcdev.h +++ b/lib/hcdev/rte_hcdev.h @@ -15,9 +15,8 @@ * @file * Generic library to interact with heterogeneous computing device. * - * The API is not thread-safe. - * Device management must be done by a single thread. * TODO device rwlock for callback list + * TODO mp shared rwlock for device array * * @warning * @b EXPERIMENTAL: this API may change without prior notice. diff --git a/lib/hcdev/version.map b/lib/hcdev/version.map index 6d1a1ab1c9..450c256527 100644 --- a/lib/hcdev/version.map +++ b/lib/hcdev/version.map @@ -17,6 +17,7 @@ INTERNAL { global: rte_hcdev_allocate; + rte_hcdev_attach; rte_hcdev_complete_new; rte_hcdev_get_by_name; rte_hcdev_notify; From patchwork Fri Jul 30 13:55:31 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Monjalon X-Patchwork-Id: 96465 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 8DDD2A0A0C; Fri, 30 Jul 2021 15:56:35 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 79949410DA; Fri, 30 Jul 2021 15:56:35 +0200 (CEST) Received: from out1-smtp.messagingengine.com (out1-smtp.messagingengine.com [66.111.4.25]) by mails.dpdk.org (Postfix) with ESMTP id 3274E4003F for ; Fri, 30 Jul 2021 15:56:34 +0200 (CEST) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailout.nyi.internal (Postfix) with ESMTP id C3C715C00BA; Fri, 30 Jul 2021 09:56:33 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute1.internal (MEProxy); Fri, 30 Jul 2021 09:56:33 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=monjalon.net; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm1; bh=29DJE9mHhUC+S jDNT3ePoHHFPF1FCmJ6HKVlmD0t7jk=; b=hCIG0TTM3B3vCpi1fIXP0aSWkZwFU 8BkktWe4T/ZXxwIs4gNJCkkTqWgiBqJKrIZ/atY9hxwFNlf22W42mSxqJERSINAK KC6WHBFNZwoBykCG4QxjwcxYBTzru2jrG1WoYw2YVtrenFtEH1/m+T0fw/A28NI+ X2O+20y0zT3w9S9GKvPHcIScXfoqsSMPv53uoyGSOs79cMPp2ulwpVelKa11d6lS Owu9nB8W52Bu06vjQaiXfZ98UqRqSk2kZo9lT1gU+w33xmKCddYDtNwjynkPowop LXy9h1GvwPoxc5G9NRQm/a6HEfKt4zcAxdlP8uijyt/6ZG5f22jbBLS4Q== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; bh=29DJE9mHhUC+SjDNT3ePoHHFPF1FCmJ6HKVlmD0t7jk=; b=gVOCrsC+ U9/91oIP9KUvFaGDuEJFcMUkuzrV0fFplU9DmVc/ho9KBn2qsKtoxszCtRdLRQHp NXjwSMtJJrcQmYbrvQ7VCur2jucUCTueNxwEiJ4RJH1IRy2RgukbjmZtMCNnBbeY VDoiMPv7GSx2iP1wwHm48HDtTF+wIDe1ZMfEONjJIyr+oUDdd1+XZIrmv/JPJ9Mw 5CPtksbSF8NGIbOuLe/xjALnbWdff4jMKYf2X3R5qdSJeZqv6PgN4Ji5RAXZdgip Z9VqJ4FzpzN5sD0xbiFU2b6WfnzVybuGS1OtLLLx065LwhkteSlrASkTxx9MYaPR XkNbJbxiKqzpzg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvtddrheehgdeiiecutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomhepvfhhohhmrghs ucfoohhnjhgrlhhonhcuoehthhhomhgrshesmhhonhhjrghlohhnrdhnvghtqeenucggtf frrghtthgvrhhnpedvhefgiedvjeegtdevheefhfetleefgfeivefgffevfeejgedtgfeu tdehtdegveenucevlhhushhtvghrufhiiigvpedunecurfgrrhgrmhepmhgrihhlfhhroh hmpehthhhomhgrshesmhhonhhjrghlohhnrdhnvght X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 30 Jul 2021 09:56:32 -0400 (EDT) From: Thomas Monjalon To: dev@dpdk.org Cc: Stephen Hemminger , David Marchand , Andrew Rybchenko , Haiyue Wang , Honnappa Nagarahalli , Jerin Jacob , Ferruh Yigit , Elena Agostini , Ray Kinsella Date: Fri, 30 Jul 2021 15:55:31 +0200 Message-Id: <20210730135533.417611-6-thomas@monjalon.net> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210730135533.417611-1-thomas@monjalon.net> References: <20210602203531.2288645-1-thomas@monjalon.net> <20210730135533.417611-1-thomas@monjalon.net> MIME-Version: 1.0 Subject: [dpdk-dev] [RFC PATCH v2 5/7] hcdev: add memory API X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Elena Agostini 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 Signed-off-by: Thomas Monjalon --- 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 #include #include +#include #include #include @@ -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 #include +#include #include /** @@ -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 { From patchwork Fri Jul 30 13:55:32 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Monjalon X-Patchwork-Id: 96466 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id BEC3BA0A0C; Fri, 30 Jul 2021 15:56:40 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id AD474410E2; Fri, 30 Jul 2021 15:56:40 +0200 (CEST) Received: from out1-smtp.messagingengine.com (out1-smtp.messagingengine.com [66.111.4.25]) by mails.dpdk.org (Postfix) with ESMTP id 1847A40040 for ; Fri, 30 Jul 2021 15:56:39 +0200 (CEST) Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.nyi.internal (Postfix) with ESMTP id C23EF5C00B8; Fri, 30 Jul 2021 09:56:38 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute4.internal (MEProxy); Fri, 30 Jul 2021 09:56:38 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=monjalon.net; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm1; bh=1CySdw3+Nmv89 hVEzhIEgJtGbnnFp7hd2UN57q2q99A=; b=XbSWvrtPtJ1/gGfGuZB/uiCUYfLUK pXDXw6pR0tNwqbWQ9obRvVHJvz5Ph99A/gEIU4Qo284e8O5zNEzF7k++6f11YRkG Hy9ggxmJbbNra79jRpetkGCt9EDdXXSyPBwgdT0E3OYFsXJdYLdt/dvb2p4zl13S +JR2+cSJ6adZYI5keI9N80F9Zou9rSqWN6cSg4MwC/LBFlOI/ig5arZ6HlDfJTRI GK6SoIap6dJ83jFKbczKGN8PsByGXv4hQpeqq8rmak1GZlNsqcSqEz2w1GcSxcjX ZnACgz47Kwp/jxkVuHzbx+zFEJ9vzq9cpQbw2bwNgfNwwrTkaeMMHmXFg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; bh=1CySdw3+Nmv89hVEzhIEgJtGbnnFp7hd2UN57q2q99A=; b=v6xnVgyz v4PPgP/NKRCL5FhKZdw+VXLJn2yevcdSKa46bUiqMA3y4nE6VWYfBBOsXqBUd1Bj m/kGgcj+2QtStOjqUoVgp2pgadbKXGMDDbbfx+tGJ47XBLfmIF84hrguchHqPxXa GCRAeK7lFwquO4bFspzxcF7L4ItsDsuf6RFBMd+fx7kZ6kD9JkGkISZJujJ/mFks QiLk2q+8E976/6ldrPWAD/PieTxVaFF3GesWUQjO40dSYrn/OV42oCzkGApD0GDf VXB4KTuChPOC83wsTq+0tKGO8nuZk/cNGBYHw/UkFmKpE1eEe3Ktcp8OSlRKtxDN FpMSKqAHyLw6/w== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvtddrheehgdeiiecutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomhepvfhhohhmrghs ucfoohhnjhgrlhhonhcuoehthhhomhgrshesmhhonhhjrghlohhnrdhnvghtqeenucggtf frrghtthgvrhhnpedvhefgiedvjeegtdevheefhfetleefgfeivefgffevfeejgedtgfeu tdehtdegveenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhroh hmpehthhhomhgrshesmhhonhhjrghlohhnrdhnvght X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 30 Jul 2021 09:56:36 -0400 (EDT) From: Thomas Monjalon To: dev@dpdk.org Cc: Stephen Hemminger , David Marchand , Andrew Rybchenko , Haiyue Wang , Honnappa Nagarahalli , Jerin Jacob , Ferruh Yigit , Elena Agostini , Ray Kinsella Date: Fri, 30 Jul 2021 15:55:32 +0200 Message-Id: <20210730135533.417611-7-thomas@monjalon.net> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210730135533.417611-1-thomas@monjalon.net> References: <20210602203531.2288645-1-thomas@monjalon.net> <20210730135533.417611-1-thomas@monjalon.net> MIME-Version: 1.0 Subject: [dpdk-dev] [RFC PATCH v2 6/7] hcdev: add communication flag X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Elena Agostini In heterogeneous computing system, processing is not only in the CPU. Some tasks can be delegated to devices working in parallel. When mixing network activity with task processing there may be the need to put in communication the CPU with the device in order to synchronize operations. The purpose of this flag is to allow the CPU and the device to exchange ACKs. A possible use-case is described below. CPU: - Trigger some task on the device - Prepare some data - Signal to the device the data is ready updating the communication flag Device: - Do some pre-processing - Wait for more data from the CPU polling on the communication flag - Consume the data prepared by the CPU Signed-off-by: Elena Agostini --- lib/hcdev/hcdev.c | 71 ++++++++++++++++++++++++++++ lib/hcdev/rte_hcdev.h | 107 ++++++++++++++++++++++++++++++++++++++++++ lib/hcdev/version.map | 4 ++ 3 files changed, 182 insertions(+) diff --git a/lib/hcdev/hcdev.c b/lib/hcdev/hcdev.c index 621e0b99bd..e391988e73 100644 --- a/lib/hcdev/hcdev.c +++ b/lib/hcdev/hcdev.c @@ -589,3 +589,74 @@ rte_hcdev_free(int16_t dev_id, void *ptr) /* TODO unregister callback */ /* TODO rte_free CPU memory */ } + +int +rte_hcdev_comm_create_flag(uint16_t dev_id, struct rte_hcdev_comm_flag *hcflag, + enum rte_hcdev_comm_flag_type mtype) +{ + size_t flag_size; + + if (hcflag == NULL) { + rte_errno = EINVAL; + return -rte_errno; + } + if (mtype != RTE_HCDEV_COMM_FLAG_CPU) { + rte_errno = EINVAL; + return -rte_errno; + } + + flag_size = sizeof(uint32_t); + + hcflag->ptr = rte_hcdev_malloc(dev_id, flag_size, + RTE_HCDEV_MALLOC_REGISTER_FROM_CPU); + if (hcflag->ptr == NULL) + return -rte_errno; + + hcflag->mtype = mtype; + return 0; +} + +int +rte_hcdev_comm_destroy_flag(uint16_t dev_id, struct rte_hcdev_comm_flag *hcflag) +{ + if (hcflag == NULL) { + rte_errno = EINVAL; + return -rte_errno; + } + + return rte_hcdev_free(dev_id, hcflag->ptr); +} + +int +rte_hcdev_comm_set_flag(struct rte_hcdev_comm_flag *hcflag, uint32_t val) +{ + if (hcflag == NULL) { + rte_errno = EINVAL; + return -rte_errno; + } + if (hcflag->mtype != RTE_HCDEV_COMM_FLAG_CPU) { + rte_errno = EINVAL; + return -rte_errno; + } + + RTE_HCDEV_VOLATILE(*hcflag->ptr) = val; + + return 0; +} + +int +rte_hcdev_comm_get_flag_value(struct rte_hcdev_comm_flag *hcflag, uint32_t *val) +{ + if (hcflag == NULL) { + rte_errno = EINVAL; + return -rte_errno; + } + if (hcflag->mtype != RTE_HCDEV_COMM_FLAG_CPU) { + rte_errno = EINVAL; + return -rte_errno; + } + + *val = RTE_HCDEV_VOLATILE(*hcflag->ptr); + + return 0; +} diff --git a/lib/hcdev/rte_hcdev.h b/lib/hcdev/rte_hcdev.h index 11895d9486..7b58041b3c 100644 --- a/lib/hcdev/rte_hcdev.h +++ b/lib/hcdev/rte_hcdev.h @@ -38,6 +38,9 @@ extern "C" { /** Catch-all callback data. */ #define RTE_HCDEV_CALLBACK_ANY_DATA ((void *)-1) +/** Access variable as volatile. */ +#define RTE_HCDEV_VOLATILE(x) (*(volatile typeof(x)*)&(x)) + /** Store device info. */ struct rte_hcdev_info { /** Unique identifier name. */ @@ -68,6 +71,18 @@ enum rte_hcdev_event { typedef void (rte_hcdev_callback_t)(int16_t dev_id, enum rte_hcdev_event event, void *user_data); +/** Memory where communication flag is allocated. */ +enum rte_hcdev_comm_flag_type { + /** Allocate flag on CPU memory visible from device. */ + RTE_HCDEV_COMM_FLAG_CPU = 0, +}; + +/** Communication flag to coordinate CPU with the device. */ +struct rte_hcdev_comm_flag { + uint32_t *ptr; + enum rte_hcdev_comm_flag_type mtype; +}; + /** * @warning * @b EXPERIMENTAL: this API may change without prior notice. @@ -346,6 +361,98 @@ __rte_alloc_size(2); __rte_experimental int rte_hcdev_free(int16_t dev_id, void *ptr); +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Create a communication flag that can be shared + * between CPU threads and device workload to exchange some status info + * (e.g. work is done, processing can start, etc..). + * + * @param dev_id + * Reference device ID. + * @param hcflag + * Pointer to the memory area of the hcflag structure. + * @param mtype + * Type of memory to allocate the communication flag. + * + * @return + * 0 on success, -rte_errno otherwise: + * - ENODEV if invalid dev_id + * - EINVAL if invalid inputs + * - ENOTSUP if operation not supported by the driver + * - ENOMEM if out of space + * - EPERM if driver error + */ +__rte_experimental +int rte_hcdev_comm_create_flag(uint16_t dev_id, + struct rte_hcdev_comm_flag *hcflag, + enum rte_hcdev_comm_flag_type mtype); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Deallocate a communication flag. + * + * @param dev_id + * Reference device ID. + * @param hcflag + * Pointer to the memory area of the hcflag structure. + * + * @return + * 0 on success, -rte_errno otherwise: + * - ENODEV if invalid dev_id + * - EINVAL if NULL hcflag + * - ENOTSUP if operation not supported by the driver + * - EPERM if driver error + */ +__rte_experimental +int rte_hcdev_comm_destroy_flag(uint16_t dev_id, + struct rte_hcdev_comm_flag *hcflag); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Set the value of a communication flag as the input value. + * Flag memory area is treated as volatile. + * The flag must have been allocated with RTE_HCDEV_COMM_FLAG_CPU. + * + * @param hcflag + * Pointer to the memory area of the hcflag structure. + * @param val + * Value to set in the flag. + * + * @return + * 0 on success, -rte_errno otherwise: + * - EINVAL if invalid input params + */ +__rte_experimental +int rte_hcdev_comm_set_flag(struct rte_hcdev_comm_flag *hcflag, + uint32_t val); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Get the value of the communication flag. + * Flag memory area is treated as volatile. + * The flag must have been allocated with RTE_HCDEV_COMM_FLAG_CPU. + * + * @param hcflag + * Pointer to the memory area of the hcflag structure. + * @param val + * Flag output value. + * + * @return + * 0 on success, -rte_errno otherwise: + * - EINVAL if invalid input params + */ +__rte_experimental +int rte_hcdev_comm_get_flag_value(struct rte_hcdev_comm_flag *hcflag, + uint32_t *val); + #ifdef __cplusplus } #endif diff --git a/lib/hcdev/version.map b/lib/hcdev/version.map index 9195f4f747..da969c7f1f 100644 --- a/lib/hcdev/version.map +++ b/lib/hcdev/version.map @@ -6,6 +6,10 @@ EXPERIMENTAL { rte_hcdev_callback_register; rte_hcdev_callback_unregister; rte_hcdev_close; + rte_hcdev_comm_create_flag; + rte_hcdev_comm_destroy_flag; + rte_hcdev_comm_get_flag_value; + rte_hcdev_comm_set_flag; rte_hcdev_count_avail; rte_hcdev_find_next; rte_hcdev_free; From patchwork Fri Jul 30 13:55:33 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Monjalon X-Patchwork-Id: 96467 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id F29F5A0A0C; Fri, 30 Jul 2021 15:56:45 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id D9A9A410F6; Fri, 30 Jul 2021 15:56:44 +0200 (CEST) Received: from out1-smtp.messagingengine.com (out1-smtp.messagingengine.com [66.111.4.25]) by mails.dpdk.org (Postfix) with ESMTP id 09545410F6 for ; Fri, 30 Jul 2021 15:56:43 +0200 (CEST) Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.nyi.internal (Postfix) with ESMTP id B3E535C00C4; Fri, 30 Jul 2021 09:56:42 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute4.internal (MEProxy); Fri, 30 Jul 2021 09:56:42 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=monjalon.net; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm1; bh=IKiqbwgmKuSIp Q9974aAn+RBnCawfSH9+cCtgcvEvM0=; b=3NiDBVumJDBoR5SG+sUE0P3o0lSj+ 9rPjBmsvH88ZDYjqWQGBa821VTPnd/K2jgS33VANDcDDznziXMClB5ATDUcCYMZE SudhvZZvrfx8oSJXb06p55YIYTTaIfnwteCOQK60zcDOkpLi/MU2XmAEF8h1Y3Po vO1/zzAvZ+1JVDFXBmPYFtTq310Y7oJ+hYV/0xMeervrLOE38gPrVOVhjQS6iFUM BkUIszCvcB+g/Fmy143pA+0JEH4OCAGIiTV4IY2UL0oAaEtS7piau1f3jhvRcALK x3Q3fyu8pyhQ/tMGSDuE0m+5h356JMpJv3dVWClbnLmlYCNaB4T9xDyHQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; bh=IKiqbwgmKuSIpQ9974aAn+RBnCawfSH9+cCtgcvEvM0=; b=bYfdTUe1 0x8t/i0aGUlg90IFvl3eoe4H3F66pOj8WbtwagjcHLrn8uuExOlKwyxb20mtI1Wr qHF7Pf+xC4MBD+YxXKYxJ8arnWa2feHmToRIAtjoQ4eSwgv50FFRdbaBTaqYrFMM CvInRTus5QYZbM3C6K1PZrC32dphEbx/QDESfVzID/EG5xI7awRlNAIQ7FOPxSKt kRmPBTbIqCNg7uWRWAbLZYaxn3osyB3RPylImI+hN3b7yw6QRid/kENOLMqypLSm K9PKrSGF2vFPJ5xEnHEf/F8fz1hSZY+E5MO8NsLFdVXPYaD+8wARUdlqU405KOoA k4b4nLD8cmDo5A== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvtddrheehgdeiiecutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomhepvfhhohhmrghs ucfoohhnjhgrlhhonhcuoehthhhomhgrshesmhhonhhjrghlohhnrdhnvghtqeenucggtf frrghtthgvrhhnpedvhefgiedvjeegtdevheefhfetleefgfeivefgffevfeejgedtgfeu tdehtdegveenucevlhhushhtvghrufhiiigvpedunecurfgrrhgrmhepmhgrihhlfhhroh hmpehthhhomhgrshesmhhonhhjrghlohhnrdhnvght X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 30 Jul 2021 09:56:41 -0400 (EDT) From: Thomas Monjalon To: dev@dpdk.org Cc: Stephen Hemminger , David Marchand , Andrew Rybchenko , Haiyue Wang , Honnappa Nagarahalli , Jerin Jacob , Ferruh Yigit , Elena Agostini , Ray Kinsella Date: Fri, 30 Jul 2021 15:55:33 +0200 Message-Id: <20210730135533.417611-8-thomas@monjalon.net> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210730135533.417611-1-thomas@monjalon.net> References: <20210602203531.2288645-1-thomas@monjalon.net> <20210730135533.417611-1-thomas@monjalon.net> MIME-Version: 1.0 Subject: [dpdk-dev] [RFC PATCH v2 7/7] hcdev: add communication list X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Elena Agostini In heterogeneous computing system, processing is not only in the CPU. Some tasks can be delegated to devices working in parallel. When mixing network activity with task processing there may be the need to put in communication the CPU with the device in order to synchronize operations. An example could be a receive-and-process application where CPU is responsible for receiving packets in multiple mbufs and the device is responsible for processing the content of those packets. The purpose of this list is to provide a buffer in CPU memory visible from the device that can be treated as a circular buffer to let the CPU provide fondamental info of received packets to the device. A possible use-case is described below. CPU: - Trigger some task on the device - in a loop: - receive a number of packets - provide packets info to the device Device: - Do some pre-processing - Wait to receive a new set of packet to be processed Layout of a communication list would be: ------- | 0 | => pkt_list | status | | #pkts | ------- | 1 | => pkt_list | status | | #pkts | ------- | 2 | => pkt_list | status | | #pkts | ------- | .... | => pkt_list ------- Signed-off-by: Elena Agostini --- lib/hcdev/hcdev.c | 127 ++++++++++++++++++++++++++++++++++++++++ lib/hcdev/meson.build | 2 + lib/hcdev/rte_hcdev.h | 132 ++++++++++++++++++++++++++++++++++++++++++ lib/hcdev/version.map | 4 ++ 4 files changed, 265 insertions(+) diff --git a/lib/hcdev/hcdev.c b/lib/hcdev/hcdev.c index e391988e73..572f1713fc 100644 --- a/lib/hcdev/hcdev.c +++ b/lib/hcdev/hcdev.c @@ -660,3 +660,130 @@ rte_hcdev_comm_get_flag_value(struct rte_hcdev_comm_flag *hcflag, uint32_t *val) return 0; } + +struct rte_hcdev_comm_list * +rte_hcdev_comm_create_list(uint16_t dev_id, + uint32_t num_comm_items) +{ + struct rte_hcdev_comm_list *comm_list; + uint32_t idx_l; + + if (num_comm_items == 0) { + rte_errno = EINVAL; + return NULL; + } + + comm_list = rte_hcdev_malloc(dev_id, + sizeof(struct rte_hcdev_comm_list) * num_comm_items, + RTE_HCDEV_MALLOC_REGISTER_FROM_CPU); + if (comm_list == NULL) { + rte_errno = ENOMEM; + return NULL; + } + + for (idx_l = 0; idx_l < num_comm_items; idx_l++) { + comm_list[idx_l].pkt_list = + rte_hcdev_malloc(dev_id, + sizeof(struct rte_hcdev_comm_pkt) * + RTE_HCDEV_COMM_LIST_PKTS_MAX, + RTE_HCDEV_MALLOC_REGISTER_FROM_CPU); + if (comm_list[idx_l].pkt_list == NULL) { + rte_errno = ENOMEM; + return NULL; + } + + RTE_HCDEV_VOLATILE(comm_list[idx_l].status) = + RTE_HCDEV_COMM_LIST_FREE; + comm_list[idx_l].num_pkts = 0; + } + + return comm_list; +} + +int +rte_hcdev_comm_destroy_list(uint16_t dev_id, + struct rte_hcdev_comm_list *comm_list, + uint32_t num_comm_items) +{ + uint32_t idx_l; + + if (comm_list == NULL) { + rte_errno = EINVAL; + return -rte_errno; + } + + for (idx_l = 0; idx_l < num_comm_items; idx_l++) + rte_hcdev_free(dev_id, comm_list[idx_l].pkt_list); + rte_hcdev_free(dev_id, comm_list); + + return 0; +} + +int +rte_hcdev_comm_populate_list_pkts(struct rte_hcdev_comm_list *comm_list_item, + struct rte_mbuf **mbufs, uint32_t num_mbufs) +{ + uint32_t idx; + + if (comm_list_item == NULL || comm_list_item->pkt_list == NULL || + mbufs == NULL || num_mbufs > RTE_HCDEV_COMM_LIST_PKTS_MAX) { + rte_errno = EINVAL; + return -rte_errno; + } + + for (idx = 0; idx < num_mbufs; idx++) { + /* support only unchained mbufs */ + if (unlikely((mbufs[idx]->nb_segs > 1) || + (mbufs[idx]->next != NULL) || + (mbufs[idx]->data_len != mbufs[idx]->pkt_len))) { + rte_errno = ENOTSUP; + return -rte_errno; + } + comm_list_item->pkt_list[idx].addr = + rte_pktmbuf_mtod_offset(mbufs[idx], uintptr_t, 0); + comm_list_item->pkt_list[idx].size = mbufs[idx]->pkt_len; + comm_list_item->pkt_list[idx].opaque = mbufs[idx]; + } + + RTE_HCDEV_VOLATILE(comm_list_item->num_pkts) = num_mbufs; + rte_mb(); + RTE_HCDEV_VOLATILE(comm_list_item->status) = RTE_HCDEV_COMM_LIST_READY; + + return 0; +} + +int +rte_hcdev_comm_cleanup_list(struct rte_hcdev_comm_list *comm_list_item) +{ + struct rte_mbuf *mbufs[RTE_HCDEV_COMM_LIST_PKTS_MAX]; + uint32_t idx = 0; + + if (comm_list_item == NULL) { + rte_errno = EINVAL; + return -rte_errno; + } + + if (RTE_HCDEV_VOLATILE(comm_list_item->status) == + RTE_HCDEV_COMM_LIST_READY) { + HCDEV_LOG(ERR, "packet list is still in progress"); + rte_errno = EINVAL; + return -rte_errno; + } + + for (idx = 0; idx < RTE_HCDEV_COMM_LIST_PKTS_MAX; idx++) { + if (comm_list_item->pkt_list[idx].addr == 0) + break; + + comm_list_item->pkt_list[idx].addr = 0; + comm_list_item->pkt_list[idx].size = 0; + mbufs[idx] = (struct rte_mbuf *) comm_list_item->pkt_list[idx].opaque; + } + + rte_pktmbuf_free_bulk(mbufs, idx); + + RTE_HCDEV_VOLATILE(comm_list_item->status) = RTE_HCDEV_COMM_LIST_FREE; + RTE_HCDEV_VOLATILE(comm_list_item->num_pkts) = 0; + rte_mb(); + + return 0; +} diff --git a/lib/hcdev/meson.build b/lib/hcdev/meson.build index 565c3cb623..249849e0cb 100644 --- a/lib/hcdev/meson.build +++ b/lib/hcdev/meson.build @@ -8,3 +8,5 @@ headers = files( sources = files( 'hcdev.c', ) + +deps += ['mbuf'] diff --git a/lib/hcdev/rte_hcdev.h b/lib/hcdev/rte_hcdev.h index 7b58041b3c..78f0e92957 100644 --- a/lib/hcdev/rte_hcdev.h +++ b/lib/hcdev/rte_hcdev.h @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -41,6 +42,9 @@ extern "C" { /** Access variable as volatile. */ #define RTE_HCDEV_VOLATILE(x) (*(volatile typeof(x)*)&(x)) +/** Max number of packets per communication list. */ +#define RTE_HCDEV_COMM_LIST_PKTS_MAX 1024 + /** Store device info. */ struct rte_hcdev_info { /** Unique identifier name. */ @@ -79,10 +83,47 @@ enum rte_hcdev_comm_flag_type { /** Communication flag to coordinate CPU with the device. */ struct rte_hcdev_comm_flag { + /** Pointer to flag memory area. */ uint32_t *ptr; + /** Type of memory used to allocate the flag. */ enum rte_hcdev_comm_flag_type mtype; }; +/** List of packets shared among CPU and device. */ +struct rte_hcdev_comm_pkt { + /** Address of the packet in memory (e.g. mbuf->buf_addr). */ + uintptr_t addr; + /** Size in byte of the packet. */ + size_t size; + /** Mbuf reference to release it in the rte_hcdev_comm_cleanup_list(). */ + void *opaque; +}; + +/** Possible status for the list of packets shared among CPU and device. */ +enum rte_hcdev_comm_list_status { + /** Packet list can be filled with new mbufs, no one is using it. */ + RTE_HCDEV_COMM_LIST_FREE = 0, + /** Packet list has been filled with new mbufs and it's ready to be used .*/ + RTE_HCDEV_COMM_LIST_READY, + /** Packet list has been processed, it's ready to be freed. */ + RTE_HCDEV_COMM_LIST_DONE, + /** Some error occurred during packet list processing. */ + RTE_HCDEV_COMM_LIST_ERROR, +}; + +/** + * Communication list holding a number of lists of packets + * each having a status flag. + */ +struct rte_hcdev_comm_list { + /** List of packets populated by the CPU with a set of mbufs info. */ + struct rte_hcdev_comm_pkt *pkt_list; + /** Number of packets in the list. */ + uint32_t num_pkts; + /** Status of the list. */ + enum rte_hcdev_comm_list_status status; +}; + /** * @warning * @b EXPERIMENTAL: this API may change without prior notice. @@ -453,6 +494,97 @@ __rte_experimental int rte_hcdev_comm_get_flag_value(struct rte_hcdev_comm_flag *hcflag, uint32_t *val); +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Create a communication list that can be used to share packets + * between CPU and device. + * Each element of the list contains: + * - a packet list of RTE_HCDEV_COMM_LIST_PKTS_MAX elements + * - number of packets in the list + * - a status flag to communicate if the packet list is FREE, + * READY to be processed, DONE with processing. + * + * The list is allocated in CPU-visible memory. + * At creation time, every list is in FREE state. + * + * @param dev_id + * Reference device ID. + * @param num_comm_items + * Number of items in the communication list. + * + * @return + * A pointer to the allocated list, otherwise NULL and rte_errno is set: + * - EINVAL if invalid input params + */ +__rte_experimental +struct rte_hcdev_comm_list *rte_hcdev_comm_create_list(uint16_t dev_id, + uint32_t num_comm_items); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Destroy a communication list. + * + * @param dev_id + * Reference device ID. + * @param comm_list + * Communication list to be destroyed. + * @param num_comm_items + * Number of items in the communication list. + * + * @return + * 0 on success, -rte_errno otherwise: + * - EINVAL if invalid input params + */ +__rte_experimental +int rte_hcdev_comm_destroy_list(uint16_t dev_id, + struct rte_hcdev_comm_list *comm_list, + uint32_t num_comm_items); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Populate the packets list of the communication item + * with info from a list of mbufs. + * Status flag of that packet list is set to READY. + * + * @param comm_list_item + * Communication list item to fill. + * @param mbufs + * List of mbufs. + * @param num_mbufs + * Number of mbufs. + * + * @return + * 0 on success, -rte_errno otherwise: + * - EINVAL if invalid input params + * - ENOTSUP if mbufs are chained (multiple segments) + */ +__rte_experimental +int rte_hcdev_comm_populate_list_pkts(struct rte_hcdev_comm_list *comm_list_item, + struct rte_mbuf **mbufs, uint32_t num_mbufs); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Reset a communication list item to the original state. + * The status flag set to FREE and mbufs are returned to the pool. + * + * @param comm_list_item + * Communication list item to reset. + * + * @return + * 0 on success, -rte_errno otherwise: + * - EINVAL if invalid input params + */ +__rte_experimental +int rte_hcdev_comm_cleanup_list(struct rte_hcdev_comm_list *comm_list_item); + #ifdef __cplusplus } #endif diff --git a/lib/hcdev/version.map b/lib/hcdev/version.map index da969c7f1f..caa00af647 100644 --- a/lib/hcdev/version.map +++ b/lib/hcdev/version.map @@ -6,9 +6,13 @@ EXPERIMENTAL { rte_hcdev_callback_register; rte_hcdev_callback_unregister; rte_hcdev_close; + rte_hcdev_comm_cleanup_list; rte_hcdev_comm_create_flag; + rte_hcdev_comm_create_list; rte_hcdev_comm_destroy_flag; + rte_hcdev_comm_destroy_list; rte_hcdev_comm_get_flag_value; + rte_hcdev_comm_populate_list_pkts; rte_hcdev_comm_set_flag; rte_hcdev_count_avail; rte_hcdev_find_next;