From patchwork Fri Sep 24 10:53:55 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Chengwen Feng X-Patchwork-Id: 99583 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 90BF2A0548; Fri, 24 Sep 2021 12:58:21 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 62E3641308; Fri, 24 Sep 2021 12:58:17 +0200 (CEST) Received: from szxga01-in.huawei.com (szxga01-in.huawei.com [45.249.212.187]) by mails.dpdk.org (Postfix) with ESMTP id 51CFE41302 for ; Fri, 24 Sep 2021 12:58:14 +0200 (CEST) Received: from dggemv711-chm.china.huawei.com (unknown [172.30.72.57]) by szxga01-in.huawei.com (SkyGuard) with ESMTP id 4HG89l2jv5zWRYC; Fri, 24 Sep 2021 18:56:59 +0800 (CST) Received: from dggpeml500024.china.huawei.com (7.185.36.10) by dggemv711-chm.china.huawei.com (10.1.198.66) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2308.8; Fri, 24 Sep 2021 18:58:12 +0800 Received: from localhost.localdomain (10.67.165.24) by dggpeml500024.china.huawei.com (7.185.36.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2308.8; Fri, 24 Sep 2021 18:58:11 +0800 From: Chengwen Feng To: , , , , , CC: , , , , , , , , , , , Date: Fri, 24 Sep 2021 18:53:55 +0800 Message-ID: <20210924105357.15386-5-fengchengwen@huawei.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20210924105357.15386-1-fengchengwen@huawei.com> References: <1625231891-2963-1-git-send-email-fengchengwen@huawei.com> <20210924105357.15386-1-fengchengwen@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.67.165.24] X-ClientProxiedBy: dggems703-chm.china.huawei.com (10.3.19.180) To dggpeml500024.china.huawei.com (7.185.36.10) X-CFilter-Loop: Reflected Subject: [dpdk-dev] [PATCH v23 4/6] dmadev: add multi-process support 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" This patch add multi-process support for dmadev. Signed-off-by: Chengwen Feng Acked-by: Bruce Richardson Acked-by: Morten Brørup Reviewed-by: Kevin Laatz Reviewed-by: Conor Walsh --- doc/guides/rel_notes/release_21_11.rst | 1 + lib/dmadev/rte_dmadev.c | 168 ++++++++++++++++++++----- lib/dmadev/rte_dmadev.h | 24 ++-- lib/dmadev/rte_dmadev_core.h | 45 +++++-- 4 files changed, 185 insertions(+), 53 deletions(-) diff --git a/doc/guides/rel_notes/release_21_11.rst b/doc/guides/rel_notes/release_21_11.rst index 21b3c48257..67d2bf5101 100644 --- a/doc/guides/rel_notes/release_21_11.rst +++ b/doc/guides/rel_notes/release_21_11.rst @@ -111,6 +111,7 @@ New Features * Device allocation APIs. * Control plane APIs. * Data plane APIs. + * Multi-process support. Removed Items diff --git a/lib/dmadev/rte_dmadev.c b/lib/dmadev/rte_dmadev.c index e0134b9eec..1338b29937 100644 --- a/lib/dmadev/rte_dmadev.c +++ b/lib/dmadev/rte_dmadev.c @@ -17,6 +17,13 @@ struct rte_dma_dev *rte_dma_devices; static int16_t dma_devices_max; +static struct { + /* Hold the dev_max information of the primary process. This field is + * set by the primary process and is read by the secondary process. + */ + int16_t dev_max; + struct rte_dma_dev_data data[0]; +} *dma_devices_shared_data; RTE_LOG_REGISTER_DEFAULT(rte_dma_logtype, INFO); #define RTE_DMA_LOG(level, fmt, args...) \ @@ -76,11 +83,11 @@ dma_find_free_dev(void) { int16_t i; - if (rte_dma_devices == NULL) + if (rte_dma_devices == NULL || dma_devices_shared_data == NULL) return -1; for (i = 0; i < dma_devices_max; i++) { - if (rte_dma_devices[i].dev_name[0] == '\0') + if (dma_devices_shared_data->data[i].dev_name[0] == '\0') return i; } @@ -97,7 +104,7 @@ dma_find(const char *name) for (i = 0; i < dma_devices_max; i++) { if ((rte_dma_devices[i].state != RTE_DMA_DEV_UNUSED) && - (!strcmp(name, rte_dma_devices[i].dev_name))) + (!strcmp(name, rte_dma_devices[i].data->dev_name))) return &rte_dma_devices[i]; } @@ -130,16 +137,65 @@ dma_process_data_prepare(void) return 0; } +static int +dma_shared_data_prepare(void) +{ + const char *mz_name = "rte_dma_dev_data"; + const struct rte_memzone *mz; + size_t size; + + if (dma_devices_shared_data != NULL) + return 0; + + size = sizeof(*dma_devices_shared_data) + + sizeof(struct rte_dma_dev_data) * dma_devices_max; + + if (rte_eal_process_type() == RTE_PROC_PRIMARY) + mz = rte_memzone_reserve(mz_name, size, rte_socket_id(), 0); + else + mz = rte_memzone_lookup(mz_name); + if (mz == NULL) + return -ENOMEM; + + dma_devices_shared_data = mz->addr; + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + memset(dma_devices_shared_data, 0, size); + dma_devices_shared_data->dev_max = dma_devices_max; + } else { + dma_devices_max = dma_devices_shared_data->dev_max; + } + + return 0; +} + static int dma_data_prepare(void) { - if (dma_devices_max == 0) - dma_devices_max = RTE_DMADEV_DEFAULT_MAX_DEVS; - return dma_process_data_prepare(); + int ret; + + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + if (dma_devices_max == 0) + dma_devices_max = RTE_DMADEV_DEFAULT_MAX_DEVS; + ret = dma_process_data_prepare(); + if (ret) + return ret; + ret = dma_shared_data_prepare(); + if (ret) + return ret; + } else { + ret = dma_shared_data_prepare(); + if (ret) + return ret; + ret = dma_process_data_prepare(); + if (ret) + return ret; + } + + return 0; } static struct rte_dma_dev * -dma_allocate(const char *name, int numa_node, size_t private_data_size) +dma_allocate_primary(const char *name, int numa_node, size_t private_data_size) { struct rte_dma_dev *dev; void *dev_private; @@ -174,10 +230,55 @@ dma_allocate(const char *name, int numa_node, size_t private_data_size) dev = &rte_dma_devices[dev_id]; dev->dev_private = dev_private; - rte_strscpy(dev->dev_name, name, sizeof(dev->dev_name)); - dev->dev_id = dev_id; - dev->numa_node = numa_node; - dev->dev_private = dev_private; + dev->data = &dma_devices_shared_data->data[dev_id]; + rte_strscpy(dev->data->dev_name, name, sizeof(dev->data->dev_name)); + dev->data->dev_id = dev_id; + dev->data->numa_node = numa_node; + dev->data->dev_private = dev_private; + + return dev; +} + +static struct rte_dma_dev * +dma_attach_secondary(const char *name) +{ + struct rte_dma_dev *dev; + int16_t i; + int ret; + + ret = dma_data_prepare(); + if (ret < 0) { + RTE_DMA_LOG(ERR, "Cannot initialize dmadevs data"); + return NULL; + } + + for (i = 0; i < dma_devices_max; i++) { + if (!strcmp(dma_devices_shared_data->data[i].dev_name, name)) + break; + } + if (i == dma_devices_max) { + RTE_DMA_LOG(ERR, + "Device %s is not driven by the primary process", + name); + return NULL; + } + + dev = &rte_dma_devices[i]; + dev->data = &dma_devices_shared_data->data[i]; + dev->dev_private = dev->data->dev_private; + + return dev; +} + +static struct rte_dma_dev * +dma_allocate(const char *name, int numa_node, size_t private_data_size) +{ + struct rte_dma_dev *dev; + + if (rte_eal_process_type() == RTE_PROC_PRIMARY) + dev = dma_allocate_primary(name, numa_node, private_data_size); + else + dev = dma_attach_secondary(name); return dev; } @@ -185,7 +286,11 @@ dma_allocate(const char *name, int numa_node, size_t private_data_size) static void dma_release(struct rte_dma_dev *dev) { - rte_free(dev->dev_private); + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + memset(dev->data, 0, sizeof(struct rte_dma_dev_data)); + rte_free(dev->dev_private); + } + memset(dev, 0, sizeof(struct rte_dma_dev)); } @@ -219,7 +324,7 @@ rte_dma_pmd_release(const char *name) return -EINVAL; if (dev->state == RTE_DMA_DEV_READY) - return rte_dma_close(dev->dev_id); + return rte_dma_close(dev->data->dev_id); dma_release(dev); return 0; @@ -237,7 +342,7 @@ rte_dma_get_dev_id(const char *name) if (dev == NULL) return -EINVAL; - return dev->dev_id; + return dev->data->dev_id; } bool @@ -283,7 +388,7 @@ rte_dma_info_get(int16_t dev_id, struct rte_dma_info *dev_info) return ret; dev_info->numa_node = dev->device->numa_node; - dev_info->nb_vchans = dev->dev_conf.nb_vchans; + dev_info->nb_vchans = dev->data->dev_conf.nb_vchans; return 0; } @@ -299,7 +404,7 @@ rte_dma_configure(int16_t dev_id, const struct rte_dma_conf *dev_conf) if (dev_conf == NULL) return -EINVAL; - if (dev->dev_started != 0) { + if (dev->data->dev_started != 0) { RTE_DMA_LOG(ERR, "Device %d must be stopped to allow configuration", dev_id); @@ -331,7 +436,8 @@ rte_dma_configure(int16_t dev_id, const struct rte_dma_conf *dev_conf) ret = (*dev->dev_ops->dev_configure)(dev, dev_conf, sizeof(struct rte_dma_conf)); if (ret == 0) - memcpy(&dev->dev_conf, dev_conf, sizeof(struct rte_dma_conf)); + memcpy(&dev->data->dev_conf, dev_conf, + sizeof(struct rte_dma_conf)); return ret; } @@ -344,12 +450,12 @@ rte_dma_start(int16_t dev_id) RTE_DMA_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL); - if (dev->dev_conf.nb_vchans == 0) { + if (dev->data->dev_conf.nb_vchans == 0) { RTE_DMA_LOG(ERR, "Device %d must be configured first", dev_id); return -EINVAL; } - if (dev->dev_started != 0) { + if (dev->data->dev_started != 0) { RTE_DMA_LOG(WARNING, "Device %d already started", dev_id); return 0; } @@ -362,7 +468,7 @@ rte_dma_start(int16_t dev_id) return ret; mark_started: - dev->dev_started = 1; + dev->data->dev_started = 1; return 0; } @@ -374,7 +480,7 @@ rte_dma_stop(int16_t dev_id) RTE_DMA_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL); - if (dev->dev_started == 0) { + if (dev->data->dev_started == 0) { RTE_DMA_LOG(WARNING, "Device %d already stopped", dev_id); return 0; } @@ -387,7 +493,7 @@ rte_dma_stop(int16_t dev_id) return ret; mark_stopped: - dev->dev_started = 0; + dev->data->dev_started = 0; return 0; } @@ -400,7 +506,7 @@ rte_dma_close(int16_t dev_id) RTE_DMA_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL); /* Device must be stopped before it can be closed */ - if (dev->dev_started == 1) { + if (dev->data->dev_started == 1) { RTE_DMA_LOG(ERR, "Device %d must be stopped before closing", dev_id); return -EBUSY; @@ -427,7 +533,7 @@ rte_dma_vchan_setup(int16_t dev_id, uint16_t vchan, if (conf == NULL) return -EINVAL; - if (dev->dev_started != 0) { + if (dev->data->dev_started != 0) { RTE_DMA_LOG(ERR, "Device %d must be stopped to allow configuration", dev_id); @@ -439,7 +545,7 @@ rte_dma_vchan_setup(int16_t dev_id, uint16_t vchan, RTE_DMA_LOG(ERR, "Device %d get device info fail", dev_id); return -EINVAL; } - if (dev->dev_conf.nb_vchans == 0) { + if (dev->data->dev_conf.nb_vchans == 0) { RTE_DMA_LOG(ERR, "Device %d must be configured first", dev_id); return -EINVAL; } @@ -513,7 +619,7 @@ rte_dma_stats_get(int16_t dev_id, uint16_t vchan, struct rte_dma_stats *stats) RTE_DMA_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL); if (stats == NULL) return -EINVAL; - if (vchan >= dev->dev_conf.nb_vchans && + if (vchan >= dev->data->dev_conf.nb_vchans && vchan != RTE_DMA_ALL_VCHAN) { RTE_DMA_LOG(ERR, "Device %d vchan %u out of range", dev_id, vchan); @@ -532,7 +638,7 @@ rte_dma_stats_reset(int16_t dev_id, uint16_t vchan) struct rte_dma_dev *dev = &rte_dma_devices[dev_id]; RTE_DMA_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL); - if (vchan >= dev->dev_conf.nb_vchans && + if (vchan >= dev->data->dev_conf.nb_vchans && vchan != RTE_DMA_ALL_VCHAN) { RTE_DMA_LOG(ERR, "Device %d vchan %u out of range", dev_id, vchan); @@ -606,14 +712,14 @@ rte_dma_dump(int16_t dev_id, FILE *f) } (void)fprintf(f, "DMA Dev %d, '%s' [%s]\n", - dev->dev_id, - dev->dev_name, - dev->dev_started ? "started" : "stopped"); + dev->data->dev_id, + dev->data->dev_name, + dev->data->dev_started ? "started" : "stopped"); dma_dump_capability(f, dev_info.dev_capa); (void)fprintf(f, " max_vchans_supported: %u\n", dev_info.max_vchans); (void)fprintf(f, " nb_vchans_configured: %u\n", dev_info.nb_vchans); (void)fprintf(f, " silent_mode: %s\n", - dev->dev_conf.enable_silent ? "on" : "off"); + dev->data->dev_conf.enable_silent ? "on" : "off"); if (dev->dev_ops->dev_dump != NULL) return (*dev->dev_ops->dev_dump)(dev, f); diff --git a/lib/dmadev/rte_dmadev.h b/lib/dmadev/rte_dmadev.h index 84e30f7e61..561a1b1154 100644 --- a/lib/dmadev/rte_dmadev.h +++ b/lib/dmadev/rte_dmadev.h @@ -821,8 +821,8 @@ rte_dma_copy(int16_t dev_id, uint16_t vchan, rte_iova_t src, rte_iova_t dst, struct rte_dma_dev *dev = &rte_dma_devices[dev_id]; #ifdef RTE_DMADEV_DEBUG - if (!rte_dma_is_valid(dev_id) || !dev->dev_started || - vchan >= dev->dev_conf.nb_vchans || length == 0) + if (!rte_dma_is_valid(dev_id) || !dev->data->dev_started || + vchan >= dev->data->dev_conf.nb_vchans || length == 0) return -EINVAL; RTE_FUNC_PTR_OR_ERR_RET(*dev->copy, -ENOTSUP); #endif @@ -872,8 +872,8 @@ rte_dma_copy_sg(int16_t dev_id, uint16_t vchan, struct rte_dma_sge *src, struct rte_dma_dev *dev = &rte_dma_devices[dev_id]; #ifdef RTE_DMADEV_DEBUG - if (!rte_dma_is_valid(dev_id) || !dev->dev_started || - vchan >= dev->dev_conf.nb_vchans || + if (!rte_dma_is_valid(dev_id) || !dev->data->dev_started || + vchan >= dev->data->dev_conf.nb_vchans || src == NULL || dst == NULL || nb_src == 0 || nb_dst == 0) return -EINVAL; RTE_FUNC_PTR_OR_ERR_RET(*dev->copy_sg, -ENOTSUP); @@ -919,8 +919,8 @@ rte_dma_fill(int16_t dev_id, uint16_t vchan, uint64_t pattern, struct rte_dma_dev *dev = &rte_dma_devices[dev_id]; #ifdef RTE_DMADEV_DEBUG - if (!rte_dma_is_valid(dev_id) || !dev->dev_started || - vchan >= dev->dev_conf.nb_vchans || length == 0) + if (!rte_dma_is_valid(dev_id) || !dev->data->dev_started || + vchan >= dev->data->dev_conf.nb_vchans || length == 0) return -EINVAL; RTE_FUNC_PTR_OR_ERR_RET(*dev->fill, -ENOTSUP); #endif @@ -952,8 +952,8 @@ rte_dma_submit(int16_t dev_id, uint16_t vchan) struct rte_dma_dev *dev = &rte_dma_devices[dev_id]; #ifdef RTE_DMADEV_DEBUG - if (!rte_dma_is_valid(dev_id) || !dev->dev_started || - vchan >= dev->dev_conf.nb_vchans) + if (!rte_dma_is_valid(dev_id) || !dev->data->dev_started || + vchan >= dev->data->dev_conf.nb_vchans) return -EINVAL; RTE_FUNC_PTR_OR_ERR_RET(*dev->submit, -ENOTSUP); #endif @@ -994,8 +994,8 @@ rte_dma_completed(int16_t dev_id, uint16_t vchan, const uint16_t nb_cpls, bool err; #ifdef RTE_DMADEV_DEBUG - if (!rte_dma_is_valid(dev_id) || !dev->dev_started || - vchan >= dev->dev_conf.nb_vchans || nb_cpls == 0) + if (!rte_dma_is_valid(dev_id) || !dev->data->dev_started || + vchan >= dev->data->dev_conf.nb_vchans || nb_cpls == 0) return 0; RTE_FUNC_PTR_OR_ERR_RET(*dev->completed, 0); #endif @@ -1054,8 +1054,8 @@ rte_dma_completed_status(int16_t dev_id, uint16_t vchan, uint16_t idx; #ifdef RTE_DMADEV_DEBUG - if (!rte_dma_is_valid(dev_id) || !dev->dev_started || - vchan >= dev->dev_conf.nb_vchans || + if (!rte_dma_is_valid(dev_id) || !dev->data->dev_started || + vchan >= dev->data->dev_conf.nb_vchans || nb_cpls == 0 || status == NULL) return 0; RTE_FUNC_PTR_OR_ERR_RET(*dev->completed_status, 0); diff --git a/lib/dmadev/rte_dmadev_core.h b/lib/dmadev/rte_dmadev_core.h index 5c202e35ce..019ac7af9c 100644 --- a/lib/dmadev/rte_dmadev_core.h +++ b/lib/dmadev/rte_dmadev_core.h @@ -118,10 +118,39 @@ struct rte_dma_dev_ops { rte_dma_dump_t dev_dump; }; -/** @internal +/** + * @internal + * The data part, with no function pointers, associated with each DMA device. + * + * This structure is safe to place in shared memory to be common among different + * processes in a multi-process configuration. + * + * @see struct rte_dmadev::data + */ +struct rte_dma_dev_data { + char dev_name[RTE_DEV_NAME_MAX_LEN]; /**< Unique identifier name */ + int16_t dev_id; /**< Device [external] identifier. */ + int16_t numa_node; /**< Local NUMA memory ID. -1 if unknown. */ + /** PMD-specific private data. + * This is a copy of the 'dev_private' field in the 'struct rte_dmadev' + * from primary process, it is used by the secondary process to get + * dev_private information. + */ + void *dev_private; + struct rte_dma_conf dev_conf; /**< DMA device configuration. */ + uint8_t dev_started : 1; /**< Device state: STARTED(1)/STOPPED(0). */ + uint64_t reserved[2]; /**< Reserved for future fields */ +} __rte_cache_aligned; + +/** + * @internal * The generic data structure associated with each DMA device. * - * The dataplane APIs are located at the beginning of the structure. + * The dataplane APIs are located at the beginning of the structure, along + * with the pointer to where all the data elements for the particular device + * are stored in shared memory. This split scheme allows the function pointer + * and driver data to be per-process, while the actual configuration data for + * the device is shared. * And the 'dev_private' field was placed in the first cache line to optimize * performance because the PMD driver mainly depends on this field. */ @@ -134,20 +163,16 @@ struct rte_dma_dev { rte_dma_completed_t completed; rte_dma_completed_status_t completed_status; void *reserved_cl0; - /** Reserve space for future IO functions, while keeping dev_ops - * pointer on the second cacheline. + /** Reserve space for future IO functions, while keeping data and + * dev_ops pointers on the second cacheline. */ - void *reserved_cl1[7]; + void *reserved_cl1[6]; + struct rte_dma_dev_data *data; /**< Pointer to device data. */ /** Functions exported by PMD. */ const struct rte_dma_dev_ops *dev_ops; - char dev_name[RTE_DEV_NAME_MAX_LEN]; /**< Unique identifier name */ - int16_t dev_id; /**< Device [external] identifier. */ - int16_t numa_node; /**< Local NUMA memory ID. -1 if unknown. */ - struct rte_dma_conf dev_conf; /**< DMA device configuration. */ /** Device info which supplied during device initialization. */ struct rte_device *device; enum rte_dma_dev_state state; /**< Flag indicating the device state. */ - uint8_t dev_started : 1; /**< Device state: STARTED(1)/STOPPED(0). */ uint64_t reserved[2]; /**< Reserved for future fields. */ } __rte_cache_aligned;