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;