DPDK patches and discussions
 help / color / mirror / Atom feed
* [PATCH 1/2] raw/cnxk_gpio: support multi-process mode
@ 2023-10-03 20:46 Tomasz Duszynski
  2023-10-03 20:46 ` [PATCH 2/2] raw/cnxk_gpio: add bunch of newlines Tomasz Duszynski
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Tomasz Duszynski @ 2023-10-03 20:46 UTC (permalink / raw)
  To: dev, Jakub Palider, Tomasz Duszynski, Anatoly Burakov; +Cc: jerinj, thomas

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 <tduszynski@marvell.com>
Reviewed-by: Jerin Jacob Kollanukkaran <jerinj@marvell.com>
---
 doc/guides/rawdevs/cnxk_gpio.rst  |   7 ++
 drivers/raw/cnxk_gpio/cnxk_gpio.c | 143 ++++++++++++++++++++----------
 2 files changed, 104 insertions(+), 46 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..dcd646397e 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 {
+	char allowlist[CNXK_GPIO_BUFSZ];
+	int num;
+};
 
 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,8 +48,8 @@ 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;
@@ -53,12 +57,14 @@ cnxk_gpio_set_defaults(struct cnxk_gpiochip *gpiochip)
 	n = scandir(CNXK_GPIO_CLASS_PATH, &namelist, cnxk_gpio_filter_gpiochip,
 		    alphasort);
 	if (n < 0 || n == 0)
-		return;
+		return -ENODEV;
 
-	sscanf(namelist[0]->d_name, "gpiochip%d", &gpiochip->num);
+	sscanf(namelist[0]->d_name, "gpiochip%d", &params->num);
 	while (n--)
 		free(namelist[n]);
 	free(namelist);
+
+	return 0;
 }
 
 static int
@@ -78,21 +84,53 @@ cnxk_gpio_parse_arg_gpiochip(const char *key __rte_unused, const char *value,
 }
 
 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)
+	char *allowlist = extra_args;
+
+	rte_strlcpy(allowlist, value, sizeof(((struct cnxk_gpio_params *)0)->allowlist));
+
+	return 0;
+}
+
+static int
+cnxk_gpio_params_store(struct cnxk_gpio_params *params)
+{
+	const struct rte_memzone *mz;
+
+	mz = rte_memzone_reserve(CNXK_GPIO_PARAMS_MZ_NAME, sizeof(*params), rte_socket_id(), 0);
+	if (!mz)
 		return -ENOMEM;
 
+	memcpy(mz->addr, params, sizeof(*params));
+
 	return 0;
 }
 
+static void
+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;
+
+	memcpy(params, mz->addr, sizeof(*params));
+}
+
+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_args(struct cnxk_gpio_params *params, const char *args)
 {
 	struct rte_kvargs *kvlist;
-	int ret;
+	int ret, num = 0;
 
 	kvlist = rte_kvargs_parse(args, cnxk_gpio_args);
 	if (!kvlist)
@@ -101,21 +139,21 @@ cnxk_gpio_parse_args(struct cnxk_gpiochip *gpiochip, const char *args)
 	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);
+					 cnxk_gpio_parse_arg_gpiochip, &params->num);
 		if (ret)
 			goto out;
 	}
+	num++;
 
 	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);
+					 cnxk_gpio_parse_arg_allowlist, params->allowlist);
 		if (ret)
 			goto out;
 	}
 
-	ret = 0;
+	ret = num++;
 out:
 	rte_kvargs_free(kvlist);
 
@@ -123,7 +161,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 +171,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 +210,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 +608,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);
@@ -658,18 +703,15 @@ static const struct rte_rawdev_ops cnxk_gpio_rawdev_ops = {
 static int
 cnxk_gpio_probe(struct rte_vdev_device *dev)
 {
+	struct cnxk_gpio_params params = { };
 	char name[RTE_RAWDEV_NAME_MAX_LEN];
 	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 +720,37 @@ 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;
+	ret = cnxk_gpio_set_defaults(&params);
+	if (ret) {
+		RTE_LOG(ERR, PMD, "failed to set defaults\n");
+		return ret;
+	}
+
+	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+		ret = cnxk_gpio_parse_args(&params, rte_vdev_device_args(dev));
+		if (ret < 0)
+			goto out;
+		if (ret > 0) {
+			ret = cnxk_gpio_params_store(&params);
+			if (ret) {
+				RTE_LOG(ERR, PMD, "failed to store params\n");
+				goto out;
+			}
+		}
+	} else {
+		cnxk_gpio_params_restore(&params);
+	}
+
+	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 +758,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 +766,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 +781,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 +799,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 +819,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


^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2023-10-18  6:52 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-10-03 20:46 [PATCH 1/2] raw/cnxk_gpio: support multi-process mode Tomasz Duszynski
2023-10-03 20:46 ` [PATCH 2/2] raw/cnxk_gpio: add bunch of newlines Tomasz Duszynski
2023-10-03 22:26   ` Stephen Hemminger
2023-10-04 20:42     ` [EXT] " Tomasz Duszynski
2023-10-05  2:54       ` Stephen Hemminger
2023-10-05  7:36         ` Tomasz Duszynski
2023-10-03 22:28 ` [PATCH 1/2] raw/cnxk_gpio: support multi-process mode Stephen Hemminger
2023-10-04 20:35   ` [EXT] " Tomasz Duszynski
2023-10-05 21:09 ` [PATCH v2 " Tomasz Duszynski
2023-10-05 21:10   ` [PATCH v2 2/2] raw/cnxk_gpio: add bunch of newlines Tomasz Duszynski
2023-10-16 10:04   ` [PATCH v3 1/2] raw/cnxk_gpio: support multi-process mode Tomasz Duszynski
2023-10-16 10:04     ` [PATCH v3 2/2] raw/cnxk_gpio: add bunch of newlines Tomasz Duszynski
2023-10-18  6:51       ` Jerin Jacob

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).