From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 7420A4317D; Mon, 16 Oct 2023 12:06:21 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 58ED440269; Mon, 16 Oct 2023 12:06:21 +0200 (CEST) Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com [67.231.156.173]) by mails.dpdk.org (Postfix) with ESMTP id A2A7D4021D for ; Mon, 16 Oct 2023 12:06:19 +0200 (CEST) Received: from pps.filterd (m0045851.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 39FMqfg1002130; Mon, 16 Oct 2023 03:06:19 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0220; bh=55xuZ3K6QQrfX9N2vJGL+pL8PyqDlPUBeTEH5ADNO8Y=; b=TBkVjr6kZxPWZbrxcptqjYpVr9/dGpPdpFYIVen76j/PZp+HFFDNO7a+A5LUkNvrykjr CpUoOiTrug68TnVJCoZ14EqOPyqhi09iE47Elva4TJQSNJIQ1+yLLmbfXVe8JfUVtjve eAAiGR/FkN92iEoPqIpjmiINgvTfCnN4G0BNkJNdRWTZJtk2fKenYUN74pmLUSuhIgX6 74Gs0+wLAqPdCBVG0sSXeKIaFsafQMiai2yfYdonFfXTn/9lGWSVcvp9jcF7+Sc4Z6zw iy/9Z+5hdwEM4vCRfKQpBIJb5dcxczVhwCvH9/+dWvRzFdiHsAzN4/ENR76JV9+dT3cs fA== Received: from dc5-exch02.marvell.com ([199.233.59.182]) by mx0b-0016f401.pphosted.com (PPS) with ESMTPS id 3tqtgkmt1b-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Mon, 16 Oct 2023 03:06:18 -0700 Received: from DC5-EXCH01.marvell.com (10.69.176.38) by DC5-EXCH02.marvell.com (10.69.176.39) with Microsoft SMTP Server (TLS) id 15.0.1497.48; Mon, 16 Oct 2023 03:04:46 -0700 Received: from maili.marvell.com (10.69.176.80) by DC5-EXCH01.marvell.com (10.69.176.38) with Microsoft SMTP Server id 15.0.1497.48 via Frontend Transport; Mon, 16 Oct 2023 03:04:46 -0700 Received: from cavium-DT10.. (unknown [10.28.34.39]) by maili.marvell.com (Postfix) with ESMTP id 1049F3F70BC; Mon, 16 Oct 2023 03:04:43 -0700 (PDT) From: Tomasz Duszynski To: , Jakub Palider , Tomasz Duszynski , Anatoly Burakov CC: , , Subject: [PATCH v3 1/2] raw/cnxk_gpio: support multi-process mode Date: Mon, 16 Oct 2023 12:04:21 +0200 Message-ID: <20231016100422.1476232-1-tduszynski@marvell.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231005211000.1099054-1-tduszynski@marvell.com> References: <20231005211000.1099054-1-tduszynski@marvell.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain X-Proofpoint-GUID: IFqGtvgCingDJXNPZIEZ1nkjPcnWMHGm X-Proofpoint-ORIG-GUID: IFqGtvgCingDJXNPZIEZ1nkjPcnWMHGm X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.272,Aquarius:18.0.980,Hydra:6.0.619,FMLib:17.11.176.26 definitions=2023-10-16_03,2023-10-12_01,2023-05-22_02 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 GPIO PMD uses a mixture of standard sysfs attributes and custom ioctl()s to control behaviour of respective GPIOs available in the system. This means that each userspace application, either running as a primary or a secondary, should be able to control a set of distinct GPIOs. In rare cases where multiple processes need to control the same set of GPIOs userspace application is responsible for synchronizing accesses. Signed-off-by: Tomasz Duszynski --- v3: - make gpiochip number unsigned - do not hardcode length of PMD cmd line parameters buffer - fix unchecked sscanf return value warning doc/guides/rawdevs/cnxk_gpio.rst | 7 ++ drivers/raw/cnxk_gpio/cnxk_gpio.c | 188 ++++++++++++++++++++---------- 2 files changed, 134 insertions(+), 61 deletions(-) diff --git a/doc/guides/rawdevs/cnxk_gpio.rst b/doc/guides/rawdevs/cnxk_gpio.rst index adff535a77..848ad329e7 100644 --- a/doc/guides/rawdevs/cnxk_gpio.rst +++ b/doc/guides/rawdevs/cnxk_gpio.rst @@ -21,6 +21,7 @@ Following features are available: - set GPIO edge that triggers interrupt - set GPIO active low - register interrupt handler for specific GPIO +- multiprocess aware Requirements ------------ @@ -30,6 +31,12 @@ for installing interrupt handlers for low latency signal processing. Driver is shipped with Marvell SDK. +Limitations +----------- + +In multiprocess mode user-space application must ensure no GPIO sharing across +processes takes place. + Device Setup ------------ diff --git a/drivers/raw/cnxk_gpio/cnxk_gpio.c b/drivers/raw/cnxk_gpio/cnxk_gpio.c index e2907c18b5..c480711942 100644 --- a/drivers/raw/cnxk_gpio/cnxk_gpio.c +++ b/drivers/raw/cnxk_gpio/cnxk_gpio.c @@ -19,6 +19,12 @@ #define CNXK_GPIO_BUFSZ 128 #define CNXK_GPIO_CLASS_PATH "/sys/class/gpio" +#define CNXK_GPIO_PARAMS_MZ_NAME "cnxk_gpio_params_mz" + +struct cnxk_gpio_params { + unsigned int num; + char allowlist[]; +}; static const char *const cnxk_gpio_args[] = { #define CNXK_GPIO_ARG_GPIOCHIP "gpiochip" @@ -28,8 +34,6 @@ static const char *const cnxk_gpio_args[] = { NULL }; -static char *allowlist; - static void cnxk_gpio_format_name(char *name, size_t len) { @@ -44,78 +48,138 @@ cnxk_gpio_filter_gpiochip(const struct dirent *dirent) return !strncmp(dirent->d_name, pattern, strlen(pattern)); } -static void -cnxk_gpio_set_defaults(struct cnxk_gpiochip *gpiochip) +static int +cnxk_gpio_set_defaults(struct cnxk_gpio_params *params) { struct dirent **namelist; - int n; + int ret = 0, n; n = scandir(CNXK_GPIO_CLASS_PATH, &namelist, cnxk_gpio_filter_gpiochip, alphasort); if (n < 0 || n == 0) - return; + return -ENODEV; + + if (sscanf(namelist[0]->d_name, "gpiochip%d", ¶ms->num) != 1) + ret = -EINVAL; - sscanf(namelist[0]->d_name, "gpiochip%d", &gpiochip->num); while (n--) free(namelist[n]); free(namelist); + + return ret; } static int cnxk_gpio_parse_arg_gpiochip(const char *key __rte_unused, const char *value, void *extra_args) { - long val; + unsigned long val; errno = 0; - val = strtol(value, NULL, 10); + val = strtoul(value, NULL, 10); if (errno) return -errno; - *(int *)extra_args = (int)val; + *(unsigned int *)extra_args = val; return 0; } static int -cnxk_gpio_parse_arg_allowlist(const char *key __rte_unused, const char *value, - void *extra_args __rte_unused) +cnxk_gpio_parse_arg_allowlist(const char *key __rte_unused, const char *value, void *extra_args) { - allowlist = strdup(value); - if (!allowlist) - return -ENOMEM; + *(const char **)extra_args = value; + + return 0; +} + +static int +cnxk_gpio_params_restore(struct cnxk_gpio_params **params) +{ + const struct rte_memzone *mz; + + mz = rte_memzone_lookup(CNXK_GPIO_PARAMS_MZ_NAME); + if (!mz) + return -ENODEV; + + *params = mz->addr; return 0; } +static struct cnxk_gpio_params * +cnxk_gpio_params_reserve(size_t len) +{ + const struct rte_memzone *mz; + + mz = rte_memzone_reserve(CNXK_GPIO_PARAMS_MZ_NAME, len, rte_socket_id(), 0); + if (!mz) + return NULL; + + return mz->addr; +} + +static void +cnxk_gpio_params_release(void) +{ + if (rte_eal_process_type() == RTE_PROC_PRIMARY) + rte_memzone_free(rte_memzone_lookup(CNXK_GPIO_PARAMS_MZ_NAME)); +} + static int -cnxk_gpio_parse_args(struct cnxk_gpiochip *gpiochip, const char *args) +cnxk_gpio_parse_arg(struct rte_kvargs *kvlist, const char *arg, arg_handler_t handler, void *data) { + int ret; + + ret = rte_kvargs_count(kvlist, arg); + if (ret == 0) + return 0; + if (ret > 1) + return -EINVAL; + + return rte_kvargs_process(kvlist, arg, handler, data) ? -EIO : 1; +} + +static int +cnxk_gpio_parse_store_args(struct cnxk_gpio_params **params, const char *args) +{ + size_t len = sizeof(**params); + const char *allowlist = NULL; struct rte_kvargs *kvlist; int ret; kvlist = rte_kvargs_parse(args, cnxk_gpio_args); - if (!kvlist) - return 0; + if (!kvlist) { + *params = cnxk_gpio_params_reserve(len); + if (!*params) + return -ENOMEM; - ret = rte_kvargs_count(kvlist, CNXK_GPIO_ARG_GPIOCHIP); - if (ret == 1) { - ret = rte_kvargs_process(kvlist, CNXK_GPIO_ARG_GPIOCHIP, - cnxk_gpio_parse_arg_gpiochip, - &gpiochip->num); + ret = cnxk_gpio_set_defaults(*params); if (ret) goto out; - } - ret = rte_kvargs_count(kvlist, CNXK_GPIO_ARG_ALLOWLIST); - if (ret == 1) { - ret = rte_kvargs_process(kvlist, CNXK_GPIO_ARG_ALLOWLIST, - cnxk_gpio_parse_arg_allowlist, NULL); - if (ret) - goto out; + return 0; } - ret = 0; + ret = cnxk_gpio_parse_arg(kvlist, CNXK_GPIO_ARG_ALLOWLIST, cnxk_gpio_parse_arg_allowlist, + &allowlist); + if (ret < 0) + goto out; + + if (allowlist) + len += strlen(allowlist) + 1; + + *params = cnxk_gpio_params_reserve(len); + if (!(*params)) + return -ENOMEM; + + strlcpy((*params)->allowlist, allowlist, strlen(allowlist) + 1); + + ret = cnxk_gpio_parse_arg(kvlist, CNXK_GPIO_ARG_GPIOCHIP, cnxk_gpio_parse_arg_gpiochip, + &(*params)->num); + if (ret == 0) + ret = cnxk_gpio_set_defaults(*params); + out: rte_kvargs_free(kvlist); @@ -123,7 +187,7 @@ cnxk_gpio_parse_args(struct cnxk_gpiochip *gpiochip, const char *args) } static int -cnxk_gpio_parse_allowlist(struct cnxk_gpiochip *gpiochip) +cnxk_gpio_parse_allowlist(struct cnxk_gpiochip *gpiochip, char *allowlist) { int i, ret, val, queue = 0; char *token; @@ -133,6 +197,12 @@ cnxk_gpio_parse_allowlist(struct cnxk_gpiochip *gpiochip) if (!list) return -ENOMEM; + allowlist = strdup(allowlist); + if (!allowlist) { + ret = -ENOMEM; + goto out; + } + /* replace brackets with something meaningless for strtol() */ allowlist[0] = ' '; allowlist[strlen(allowlist) - 1] = ' '; @@ -166,11 +236,13 @@ cnxk_gpio_parse_allowlist(struct cnxk_gpiochip *gpiochip) list[queue++] = val; } while ((token = strtok(NULL, ","))); + free(allowlist); gpiochip->allowlist = list; gpiochip->num_queues = queue; return 0; out: + free(allowlist); rte_free(list); return ret; @@ -562,8 +634,7 @@ cnxk_gpio_process_buf(struct cnxk_gpio *gpio, struct rte_rawdev_buf *rbuf) *(int *)rsp = val; break; case CNXK_GPIO_MSG_TYPE_REGISTER_IRQ: - ret = cnxk_gpio_register_irq(gpio, - (struct cnxk_gpio_irq *)msg->data); + ret = cnxk_gpio_register_irq(gpio, (struct cnxk_gpio_irq *)msg->data); break; case CNXK_GPIO_MSG_TYPE_UNREGISTER_IRQ: ret = cnxk_gpio_unregister_irq(gpio); @@ -659,17 +730,14 @@ static int cnxk_gpio_probe(struct rte_vdev_device *dev) { char name[RTE_RAWDEV_NAME_MAX_LEN]; + struct cnxk_gpio_params *params; struct cnxk_gpiochip *gpiochip; struct rte_rawdev *rawdev; char buf[CNXK_GPIO_BUFSZ]; int ret; - if (rte_eal_process_type() != RTE_PROC_PRIMARY) - return 0; - cnxk_gpio_format_name(name, sizeof(name)); - rawdev = rte_rawdev_pmd_allocate(name, sizeof(*gpiochip), - rte_socket_id()); + rawdev = rte_rawdev_pmd_allocate(name, sizeof(*gpiochip), rte_socket_id()); if (!rawdev) { RTE_LOG(ERR, PMD, "failed to allocate %s rawdev", name); return -ENOMEM; @@ -678,22 +746,26 @@ cnxk_gpio_probe(struct rte_vdev_device *dev) rawdev->dev_ops = &cnxk_gpio_rawdev_ops; rawdev->device = &dev->device; rawdev->driver_name = dev->device.name; - gpiochip = rawdev->dev_private; - cnxk_gpio_set_defaults(gpiochip); - /* defaults may be overwritten by this call */ - ret = cnxk_gpio_parse_args(gpiochip, rte_vdev_device_args(dev)); - if (ret) - goto out; + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + ret = cnxk_gpio_parse_store_args(¶ms, rte_vdev_device_args(dev)); + if (ret < 0) + goto out; + } else { + ret = cnxk_gpio_params_restore(¶ms); + if (ret) + goto out; + } + + gpiochip->num = params->num; ret = cnxk_gpio_irq_init(gpiochip); if (ret) goto out; /* read gpio base */ - snprintf(buf, sizeof(buf), "%s/gpiochip%d/base", CNXK_GPIO_CLASS_PATH, - gpiochip->num); + snprintf(buf, sizeof(buf), "%s/gpiochip%d/base", CNXK_GPIO_CLASS_PATH, gpiochip->num); ret = cnxk_gpio_read_attr_int(buf, &gpiochip->base); if (ret) { RTE_LOG(ERR, PMD, "failed to read %s", buf); @@ -701,8 +773,7 @@ cnxk_gpio_probe(struct rte_vdev_device *dev) } /* read number of available gpios */ - snprintf(buf, sizeof(buf), "%s/gpiochip%d/ngpio", CNXK_GPIO_CLASS_PATH, - gpiochip->num); + snprintf(buf, sizeof(buf), "%s/gpiochip%d/ngpio", CNXK_GPIO_CLASS_PATH, gpiochip->num); ret = cnxk_gpio_read_attr_int(buf, &gpiochip->num_gpios); if (ret) { RTE_LOG(ERR, PMD, "failed to read %s", buf); @@ -710,16 +781,13 @@ cnxk_gpio_probe(struct rte_vdev_device *dev) } gpiochip->num_queues = gpiochip->num_gpios; - if (allowlist) { - ret = cnxk_gpio_parse_allowlist(gpiochip); - free(allowlist); - allowlist = NULL; - if (ret) - goto out; + ret = cnxk_gpio_parse_allowlist(gpiochip, params->allowlist); + if (ret) { + RTE_LOG(ERR, PMD, "failed to parse allowed gpios\n"); + goto out; } - gpiochip->gpios = rte_calloc(NULL, gpiochip->num_gpios, - sizeof(struct cnxk_gpio *), 0); + gpiochip->gpios = rte_calloc(NULL, gpiochip->num_gpios, sizeof(struct cnxk_gpio *), 0); if (!gpiochip->gpios) { RTE_LOG(ERR, PMD, "failed to allocate gpios memory"); ret = -ENOMEM; @@ -728,8 +796,8 @@ cnxk_gpio_probe(struct rte_vdev_device *dev) return 0; out: - free(allowlist); rte_free(gpiochip->allowlist); + cnxk_gpio_params_release(); rte_rawdev_pmd_release(rawdev); return ret; @@ -746,9 +814,6 @@ cnxk_gpio_remove(struct rte_vdev_device *dev) RTE_SET_USED(dev); - if (rte_eal_process_type() != RTE_PROC_PRIMARY) - return 0; - cnxk_gpio_format_name(name, sizeof(name)); rawdev = rte_rawdev_pmd_get_named_dev(name); if (!rawdev) @@ -769,6 +834,7 @@ cnxk_gpio_remove(struct rte_vdev_device *dev) rte_free(gpiochip->allowlist); rte_free(gpiochip->gpios); cnxk_gpio_irq_fini(); + cnxk_gpio_params_release(); rte_rawdev_pmd_release(rawdev); return 0; -- 2.34.1