From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <dev-bounces@dpdk.org>
Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124])
	by inbox.dpdk.org (Postfix) with ESMTP id 3B3EEA0548;
	Sun, 28 Nov 2021 16:46:14 +0100 (CET)
Received: from [217.70.189.124] (localhost [127.0.0.1])
	by mails.dpdk.org (Postfix) with ESMTP id DA71D4274C;
	Sun, 28 Nov 2021 16:46:11 +0100 (CET)
Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com
 [67.231.156.173])
 by mails.dpdk.org (Postfix) with ESMTP id 5A3A04111B
 for <dev@dpdk.org>; Sun, 28 Nov 2021 16:46:08 +0100 (CET)
Received: from pps.filterd (m0045851.ppops.net [127.0.0.1])
 by mx0b-0016f401.pphosted.com (8.16.1.2/8.16.1.2) with ESMTP id 1ASB5ITq013483;
 Sun, 28 Nov 2021 07:46:07 -0800
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=CuOWkM5lf8/+Gmt/D6Vchvy706z77gLS2dFSGW6BAjA=;
 b=FCnBdQNOYqKQdD6iEpq05vqsg9thcRRPryD+vVLjJ/DrZ23J/7xgnZtDwK6xGLUpZYRd
 h9fK9mFFTsBayfe4VpuHumDUyjx4LsFnxJCdjEbC78aqPgSnBA7qYGfjRP90mbh969/0
 zXOVxogqbPY6xa11CtLpdLYR34w9wUp7XP8YRhV8I568wK5y86hphosQ6ogYGcGhbMYh
 L5nl03TRUvb4R0lguzBHGOyRBPYPfL4+TTVvxzM7900uyacc7OB1N9I56tgZw2IvNmfm
 xoUHRvnKeB8+E7f8Mrab+q0K3/vi9Z3U07N/SKbUgyAZWuPSum9uwEc1epbz74w2N8xi cw== 
Received: from dc5-exch02.marvell.com ([199.233.59.182])
 by mx0b-0016f401.pphosted.com (PPS) with ESMTPS id 3ckn2satkp-1
 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT);
 Sun, 28 Nov 2021 07:46:07 -0800
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.18;
 Sun, 28 Nov 2021 07:46:05 -0800
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.2 via Frontend
 Transport; Sun, 28 Nov 2021 07:46:05 -0800
Received: from localhost.localdomain (unknown [10.28.34.39])
 by maili.marvell.com (Postfix) with ESMTP id 1A5493F70B9;
 Sun, 28 Nov 2021 07:46:03 -0800 (PST)
From: Tomasz Duszynski <tduszynski@marvell.com>
To: <dev@dpdk.org>
CC: <jerinj@marvell.com>, <stephen@networkplumber.org>, Tomasz Duszynski
 <tduszynski@marvell.com>
Subject: [PATCH v2 01/10] raw/cnxk_gpio: add GPIO driver skeleton
Date: Sun, 28 Nov 2021 16:44:33 +0100
Message-ID: <20211128154442.4029049-2-tduszynski@marvell.com>
X-Mailer: git-send-email 2.25.1
In-Reply-To: <20211128154442.4029049-1-tduszynski@marvell.com>
References: <20211117002155.293267-1-tduszynski@marvell.com>
 <20211128154442.4029049-1-tduszynski@marvell.com>
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
Content-Type: text/plain
X-Proofpoint-GUID: Xu2Z5k34s9nQweeFiqeVUSo1K1ZrxjR8
X-Proofpoint-ORIG-GUID: Xu2Z5k34s9nQweeFiqeVUSo1K1ZrxjR8
X-Proofpoint-Virus-Version: vendor=baseguard
 engine=ICAP:2.0.205,Aquarius:18.0.790,Hydra:6.0.425,FMLib:17.0.607.475
 definitions=2021-11-28_06,2021-11-28_01,2020-04-07_01
X-BeenThere: dev@dpdk.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: DPDK patches and discussions <dev.dpdk.org>
List-Unsubscribe: <https://mails.dpdk.org/options/dev>,
 <mailto:dev-request@dpdk.org?subject=unsubscribe>
List-Archive: <http://mails.dpdk.org/archives/dev/>
List-Post: <mailto:dev@dpdk.org>
List-Help: <mailto:dev-request@dpdk.org?subject=help>
List-Subscribe: <https://mails.dpdk.org/listinfo/dev>,
 <mailto:dev-request@dpdk.org?subject=subscribe>
Errors-To: dev-bounces@dpdk.org

Add initial support for PMD that allows to control particular pins form
userspace. Moreover PMD allows to attach custom interrupt handlers to
controllable GPIOs.

Main users of this PMD are dataplain applications requiring fast and low
latency access to pin state.

Signed-off-by: Tomasz Duszynski <tduszynski@marvell.com>
---
 doc/guides/rawdevs/cnxk_gpio.rst  |  65 +++++++++
 doc/guides/rawdevs/index.rst      |   1 +
 drivers/raw/cnxk_gpio/cnxk_gpio.c | 235 ++++++++++++++++++++++++++++++
 drivers/raw/cnxk_gpio/cnxk_gpio.h |  22 +++
 drivers/raw/cnxk_gpio/meson.build |   8 +
 drivers/raw/cnxk_gpio/version.map |   3 +
 drivers/raw/meson.build           |   1 +
 7 files changed, 335 insertions(+)
 create mode 100644 doc/guides/rawdevs/cnxk_gpio.rst
 create mode 100644 drivers/raw/cnxk_gpio/cnxk_gpio.c
 create mode 100644 drivers/raw/cnxk_gpio/cnxk_gpio.h
 create mode 100644 drivers/raw/cnxk_gpio/meson.build
 create mode 100644 drivers/raw/cnxk_gpio/version.map

diff --git a/doc/guides/rawdevs/cnxk_gpio.rst b/doc/guides/rawdevs/cnxk_gpio.rst
new file mode 100644
index 0000000000..868302d07f
--- /dev/null
+++ b/doc/guides/rawdevs/cnxk_gpio.rst
@@ -0,0 +1,65 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright(c) 2021 Marvell.
+
+Marvell CNXK GPIO Driver
+========================
+
+CNXK GPIO PMD configures and manages GPIOs available on the system using
+standard enqueue/dequeue mechanism offered by raw device abstraction. PMD relies
+both on standard sysfs GPIO interface provided by the Linux kernel and GPIO
+kernel driver custom interface allowing one to install userspace interrupt
+handlers.
+
+Features
+--------
+
+Following features are available:
+
+- export/unexport a GPIO
+- read/write specific value from/to exported GPIO
+- set GPIO direction
+- set GPIO edge that triggers interrupt
+- set GPIO active low
+- register interrupt handler for specific GPIO
+
+Requirements
+------------
+
+PMD relies on modified kernel GPIO driver which exposes ``ioctl()`` interface
+for installing interrupt handlers for low latency signal processing.
+
+Driver is shipped with Marvell SDK.
+
+Device Setup
+------------
+
+CNXK GPIO PMD binds to virtual device which gets created by passing
+`--vdev=cnxk_gpio,gpiochip=<number>` command line to EAL. `gpiochip` parameter
+tells PMD which GPIO controller should be used. Available controllers are
+available under `/sys/class/gpio`. For further details on how Linux represents
+GPIOs in userspace please refer to
+`sysfs.txt <https://www.kernel.org/doc/Documentation/gpio/sysfs.txt>`_.
+
+If `gpiochip=<number>` was omitted then first gpiochip from the alphabetically
+sort list of available gpiochips is used.
+
+.. code-block:: console
+
+   $ ls /sys/class/gpio
+   export gpiochip448 unexport
+
+In above scenario only one GPIO controller is present hence
+`--vdev=cnxk_gpio,gpiochip=448` should be passed to EAL.
+
+Before performing actual data transfer one needs to call
+``rte_rawdev_queue_count()`` followed by ``rte_rawdev_queue_conf_get()``. The
+former returns number GPIOs available in the system irrespective of GPIOs
+being controllable or not. Thus it is user responsibility to pick the proper
+ones. The latter call simply returns queue capacity.
+
+Respective queue needs to be configured with ``rte_rawdev_queue_setup()``. This
+call barely exports GPIO to userspace.
+
+To perform actual data transfer use standard ``rte_rawdev_enqueue_buffers()``
+and ``rte_rawdev_dequeue_buffers()`` APIs. Not all messages produce sensible
+responses hence dequeueing is not always necessary.
diff --git a/doc/guides/rawdevs/index.rst b/doc/guides/rawdevs/index.rst
index b6cf917443..0c02da6e90 100644
--- a/doc/guides/rawdevs/index.rst
+++ b/doc/guides/rawdevs/index.rst
@@ -12,6 +12,7 @@ application through rawdev API.
     :numbered:
 
     cnxk_bphy
+    cnxk_gpio
     dpaa2_cmdif
     dpaa2_qdma
     ifpga
diff --git a/drivers/raw/cnxk_gpio/cnxk_gpio.c b/drivers/raw/cnxk_gpio/cnxk_gpio.c
new file mode 100644
index 0000000000..bcce4b8fb7
--- /dev/null
+++ b/drivers/raw/cnxk_gpio/cnxk_gpio.c
@@ -0,0 +1,235 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2021 Marvell.
+ */
+
+#include <dirent.h>
+#include <string.h>
+
+#include <rte_bus_vdev.h>
+#include <rte_eal.h>
+#include <rte_kvargs.h>
+#include <rte_lcore.h>
+#include <rte_rawdev_pmd.h>
+
+#include <roc_api.h>
+
+#include "cnxk_gpio.h"
+
+#define CNXK_GPIO_BUFSZ 128
+#define CNXK_GPIO_CLASS_PATH "/sys/class/gpio"
+
+static const char *const cnxk_gpio_args[] = {
+#define CNXK_GPIO_ARG_GPIOCHIP "gpiochip"
+	CNXK_GPIO_ARG_GPIOCHIP,
+	NULL
+};
+
+static void
+cnxk_gpio_format_name(char *name, size_t len)
+{
+	snprintf(name, len, "cnxk_gpio");
+}
+
+static int
+cnxk_gpio_filter_gpiochip(const struct dirent *dirent)
+{
+	const char *pattern = "gpiochip";
+
+	return !strncmp(dirent->d_name, pattern, strlen(pattern));
+}
+
+static void
+cnxk_gpio_set_defaults(struct cnxk_gpiochip *gpiochip)
+{
+	struct dirent **namelist;
+	int n;
+
+	n = scandir(CNXK_GPIO_CLASS_PATH, &namelist, cnxk_gpio_filter_gpiochip,
+		    alphasort);
+	if (n < 0 || n == 0)
+		return;
+
+	sscanf(namelist[0]->d_name, "gpiochip%d", &gpiochip->num);
+	while (n--)
+		free(namelist[n]);
+	free(namelist);
+}
+
+static int
+cnxk_gpio_parse_arg_gpiochip(const char *key __rte_unused, const char *value,
+			     void *extra_args)
+{
+	long val;
+
+	errno = 0;
+	val = strtol(value, NULL, 10);
+	if (errno)
+		return -errno;
+
+	*(int *)extra_args = (int)val;
+
+	return 0;
+}
+
+static int
+cnxk_gpio_parse_args(struct cnxk_gpiochip *gpiochip,
+		     struct rte_devargs *devargs)
+{
+	struct rte_kvargs *kvlist;
+	int ret;
+
+	kvlist = rte_kvargs_parse(devargs->args, cnxk_gpio_args);
+	if (!kvlist)
+		return 0;
+
+	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);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int
+cnxk_gpio_read_attr(char *attr, char *val)
+{
+	FILE *fp;
+	int ret;
+
+	fp = fopen(attr, "r");
+	if (!fp)
+		return -errno;
+
+	ret = fscanf(fp, "%s", val);
+	if (ret < 0)
+		return -errno;
+	if (ret != 1)
+		return -EIO;
+
+	ret = fclose(fp);
+	if (ret)
+		return -errno;
+
+	return 0;
+}
+
+static int
+cnxk_gpio_read_attr_int(char *attr, int *val)
+{
+	char buf[CNXK_GPIO_BUFSZ];
+	int ret;
+
+	ret = cnxk_gpio_read_attr(attr, buf);
+	if (ret)
+		return ret;
+
+	ret = sscanf(buf, "%d", val);
+	if (ret < 0)
+		return -errno;
+
+	return 0;
+}
+
+static const struct rte_rawdev_ops cnxk_gpio_rawdev_ops = {
+};
+
+static int
+cnxk_gpio_probe(struct rte_vdev_device *dev)
+{
+	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());
+	if (!rawdev) {
+		RTE_LOG(ERR, PMD, "failed to allocate %s rawdev", name);
+		return -ENOMEM;
+	}
+
+	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, dev->device.devargs);
+	if (ret)
+		goto out;
+
+	/* read gpio base */
+	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);
+		goto out;
+	}
+
+	/* read number of available gpios */
+	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);
+		goto out;
+	}
+
+	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;
+		goto out;
+	}
+
+	return 0;
+out:
+	rte_rawdev_pmd_release(rawdev);
+
+	return ret;
+}
+
+static int
+cnxk_gpio_remove(struct rte_vdev_device *dev)
+{
+	char name[RTE_RAWDEV_NAME_MAX_LEN];
+	struct cnxk_gpiochip *gpiochip;
+	struct rte_rawdev *rawdev;
+
+	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)
+		return -ENODEV;
+
+	gpiochip = rawdev->dev_private;
+	rte_free(gpiochip->gpios);
+	rte_rawdev_pmd_release(rawdev);
+
+	return 0;
+}
+
+static struct rte_vdev_driver cnxk_gpio_drv = {
+	.probe = cnxk_gpio_probe,
+	.remove = cnxk_gpio_remove,
+};
+
+RTE_PMD_REGISTER_VDEV(cnxk_gpio, cnxk_gpio_drv);
+RTE_PMD_REGISTER_PARAM_STRING(cnxk_gpio, "gpiochip=<int>");
diff --git a/drivers/raw/cnxk_gpio/cnxk_gpio.h b/drivers/raw/cnxk_gpio/cnxk_gpio.h
new file mode 100644
index 0000000000..4dae8316ba
--- /dev/null
+++ b/drivers/raw/cnxk_gpio/cnxk_gpio.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2021 Marvell.
+ */
+
+#ifndef _CNXK_GPIO_H_
+#define _CNXK_GPIO_H_
+
+struct cnxk_gpiochip;
+
+struct cnxk_gpio {
+	struct cnxk_gpiochip *gpiochip;
+	int num;
+};
+
+struct cnxk_gpiochip {
+	int num;
+	int base;
+	int num_gpios;
+	struct cnxk_gpio **gpios;
+};
+
+#endif /* _CNXK_GPIO_H_ */
diff --git a/drivers/raw/cnxk_gpio/meson.build b/drivers/raw/cnxk_gpio/meson.build
new file mode 100644
index 0000000000..9a7e716c1e
--- /dev/null
+++ b/drivers/raw/cnxk_gpio/meson.build
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(C) 2021 Marvell.
+#
+
+deps += ['bus_vdev', 'common_cnxk', 'rawdev', 'kvargs']
+sources = files(
+        'cnxk_gpio.c',
+)
diff --git a/drivers/raw/cnxk_gpio/version.map b/drivers/raw/cnxk_gpio/version.map
new file mode 100644
index 0000000000..4a76d1d52d
--- /dev/null
+++ b/drivers/raw/cnxk_gpio/version.map
@@ -0,0 +1,3 @@
+DPDK_21 {
+	local: *;
+};
diff --git a/drivers/raw/meson.build b/drivers/raw/meson.build
index 87694a758e..4b52e93945 100644
--- a/drivers/raw/meson.build
+++ b/drivers/raw/meson.build
@@ -7,6 +7,7 @@ endif
 
 drivers = [
         'cnxk_bphy',
+	'cnxk_gpio',
         'dpaa2_cmdif',
         'dpaa2_qdma',
         'ifpga',
-- 
2.25.1