linux-gpio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/9] gpio: sysfs: add a per-chip export/unexport attribute pair
@ 2025-06-23  8:59 Bartosz Golaszewski
  2025-06-23  8:59 ` [PATCH v2 1/9] gpio: sysfs: add a parallel class device for each GPIO chip using device IDs Bartosz Golaszewski
                   ` (8 more replies)
  0 siblings, 9 replies; 31+ messages in thread
From: Bartosz Golaszewski @ 2025-06-23  8:59 UTC (permalink / raw)
  To: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, Linus Walleij, Bartosz Golaszewski
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

Following our discussion[1], here's a proposal for extending the sysfs
interface with attributes not referring to GPIO lines by their global
numbers in a backward compatible way.

Long story short: there is now a new class device for each GPIO chip.
It's called chipX where X is the ID of the device as per the driver
model and it lives next to the old gpiochipABC where ABC is the GPIO
base. Each new chip class device has a pair of export/unexport
attributes which work similarly to the global ones under /sys/class/gpio
but take hardware offsets within the chip as input, instead of the
global numbers. Finally, each exported line appears at the same time as
the global /sys/class/gpio/gpioABC as well as per-chip
/sys/class/gpio/chipX/gpioY sysfs group.

The series contains the implementation of a parallel GPIO chip entry not
containing the base GPIO number in the name and the corresponding sysfs
attribute group for each exported line that lives under the new chip
class device as well as a way to allow to compile out the legacy parts
leaving only the new elements of the sysfs ABI.

This series passes the compatibility tests I wrote while working on the
user-space compatibility layer for sysfs[2].

[1] https://lore.kernel.org/all/CAMRc=McUCeZcU6co1aN54rTudo+JfPjjForu4iKQ5npwXk6GXA@mail.gmail.com/
[2] https://github.com/brgl/gpio-sysfs-compat-tests

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
Changes in v2:
- add missing call to sysfs_remove_groups() in gpiod_unexport()
- pick up review tags
- drop patches that were already applied
- add missing documentation for the chip-local line attributes
- correct the statement about chip's label uniqueness in docs
- Link to v1: https://lore.kernel.org/r/20250610-gpio-sysfs-chip-export-v1-0-a8c7aa4478b1@linaro.org

---
Bartosz Golaszewski (9):
      gpio: sysfs: add a parallel class device for each GPIO chip using device IDs
      gpio: sysfs: only get the dirent reference for the value attr once
      gpio: sysfs: pass gpiod_data directly to internal GPIO sysfs functions
      gpio: sysfs: don't use driver data in sysfs callbacks for line attributes
      gpio: sysfs: rename the data variable in gpiod_(un)export()
      gpio: sysfs: don't look up exported lines as class devices
      gpio: sysfs: export the GPIO directory locally in the gpiochip<id> directory
      gpio: sysfs: allow disabling the legacy parts of the GPIO sysfs interface
      gpio: TODO: remove the task for the sysfs rework

 Documentation/ABI/obsolete/sysfs-gpio |  12 +-
 drivers/gpio/Kconfig                  |   8 +
 drivers/gpio/TODO                     |  13 -
 drivers/gpio/gpiolib-sysfs.c          | 502 +++++++++++++++++++++++++---------
 4 files changed, 388 insertions(+), 147 deletions(-)
---
base-commit: cb908f3699fb137e28017a8fdf506c35762b3eb6
change-id: 20250402-gpio-sysfs-chip-export-84ac424b61c5

Best regards,
-- 
Bartosz Golaszewski <bartosz.golaszewski@linaro.org>


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

* [PATCH v2 1/9] gpio: sysfs: add a parallel class device for each GPIO chip using device IDs
  2025-06-23  8:59 [PATCH v2 0/9] gpio: sysfs: add a per-chip export/unexport attribute pair Bartosz Golaszewski
@ 2025-06-23  8:59 ` Bartosz Golaszewski
  2025-06-27 15:21   ` Andy Shevchenko
  2025-06-23  8:59 ` [PATCH v2 2/9] gpio: sysfs: only get the dirent reference for the value attr once Bartosz Golaszewski
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 31+ messages in thread
From: Bartosz Golaszewski @ 2025-06-23  8:59 UTC (permalink / raw)
  To: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, Linus Walleij, Bartosz Golaszewski
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

In order to enable moving away from the global GPIO numberspace-based
exporting of lines over sysfs: add a parallel, per-chip entry under
/sys/class/gpio/ for every registered GPIO chip, denoted by device ID
in the file name and not its base GPIO number.

Compared to the existing chip group: it does not contain the "base"
attribute as the goal of this change is to not refer to GPIOs by their
global number from user-space anymore. It also contains its own,
per-chip export/unexport attribute pair which allow to export lines by
their hardware offset within the chip.

Caveat #1: the new device cannot be a link to (or be linked to by) the
existing "gpiochip<BASE>" entry as we cannot create links in
/sys/class/xyz/.

Caveat #2: the new entry cannot be named "gpiochipX" as it could
conflict with devices whose base is statically defined to a low number.
Let's go with "chipX" instead.

While at it: the chip label is unique so update the untrue statement
when extending the docs.

Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 Documentation/ABI/obsolete/sysfs-gpio |   7 +-
 drivers/gpio/gpiolib-sysfs.c          | 191 +++++++++++++++++++++++++---------
 2 files changed, 149 insertions(+), 49 deletions(-)

diff --git a/Documentation/ABI/obsolete/sysfs-gpio b/Documentation/ABI/obsolete/sysfs-gpio
index 480316fee6d80fb7a0ed61706559838591ec0932..ff694708a3bef787afa42dedf94faf209c44dbf0 100644
--- a/Documentation/ABI/obsolete/sysfs-gpio
+++ b/Documentation/ABI/obsolete/sysfs-gpio
@@ -25,8 +25,13 @@ Description:
 	    /active_low ... r/w as: 0, 1
 	/gpiochipN ... for each gpiochip; #N is its first GPIO
 	    /base ... (r/o) same as N
-	    /label ... (r/o) descriptive, not necessarily unique
+	    /label ... (r/o) descriptive chip name
 	    /ngpio ... (r/o) number of GPIOs; numbered N to N + (ngpio - 1)
+	/chipX ... for each gpiochip; #X is the gpio device ID
+	    /export ... asks the kernel to export a GPIO at HW offset X to userspace
+	    /unexport ... to return a GPIO at HW offset X to the kernel
+	    /label ... (r/o) descriptive chip name
+	    /ngpio ... (r/o) number of GPIOs exposed by the chip
 
   This ABI is obsoleted by Documentation/ABI/testing/gpio-cdev and will be
   removed after 2020.
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index c4c21e25c682b939e4a0517393308343feb6585a..fbe93cda4ca16038a1cffe766f7e5ead55ace5e6 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -46,6 +46,7 @@ struct gpiod_data {
 struct gpiodev_data {
 	struct gpio_device *gdev;
 	struct device *cdev_base; /* Class device by GPIO base */
+	struct device *cdev_id; /* Class device by GPIO device ID */
 };
 
 /*
@@ -399,6 +400,14 @@ static const struct attribute_group *gpio_groups[] = {
  *   /base ... matching gpio_chip.base (N)
  *   /label ... matching gpio_chip.label
  *   /ngpio ... matching gpio_chip.ngpio
+ *
+ * AND
+ *
+ * /sys/class/gpio/chipX/
+ *   /export ... export GPIO at given offset
+ *   /unexport ... unexport GPIO at given offset
+ *   /label ... matching gpio_chip.label
+ *   /ngpio ... matching gpio_chip.ngpio
  */
 
 static ssize_t base_show(struct device *dev, struct device_attribute *attr,
@@ -428,6 +437,111 @@ static ssize_t ngpio_show(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_RO(ngpio);
 
+static int export_gpio_desc(struct gpio_desc *desc)
+{
+	int offset, ret;
+
+	CLASS(gpio_chip_guard, guard)(desc);
+	if (!guard.gc)
+		return -ENODEV;
+
+	offset = gpio_chip_hwgpio(desc);
+	if (!gpiochip_line_is_valid(guard.gc, offset)) {
+		pr_debug_ratelimited("%s: GPIO %d masked\n", __func__,
+				     gpio_chip_hwgpio(desc));
+		return -EINVAL;
+	}
+
+	/*
+	 * No extra locking here; FLAG_SYSFS just signifies that the
+	 * request and export were done by on behalf of userspace, so
+	 * they may be undone on its behalf too.
+	 */
+
+	ret = gpiod_request_user(desc, "sysfs");
+	if (ret)
+		return ret;
+
+	ret = gpiod_set_transitory(desc, false);
+	if (ret) {
+		gpiod_free(desc);
+		return ret;
+	}
+
+	ret = gpiod_export(desc, true);
+	if (ret < 0) {
+		gpiod_free(desc);
+	} else {
+		set_bit(FLAG_SYSFS, &desc->flags);
+		gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_REQUESTED);
+	}
+
+	return ret;
+}
+
+static int unexport_gpio_desc(struct gpio_desc *desc)
+{
+	/*
+	 * No extra locking here; FLAG_SYSFS just signifies that the
+	 * request and export were done by on behalf of userspace, so
+	 * they may be undone on its behalf too.
+	 */
+	if (!test_and_clear_bit(FLAG_SYSFS, &desc->flags))
+		return -EINVAL;
+
+	gpiod_unexport(desc);
+	gpiod_free(desc);
+
+	return 0;
+}
+
+static ssize_t do_chip_export_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, ssize_t size,
+				    int (*handler)(struct gpio_desc *desc))
+{
+	struct gpiodev_data *data = dev_get_drvdata(dev);
+	struct gpio_device *gdev = data->gdev;
+	struct gpio_desc *desc;
+	unsigned int gpio;
+	int ret;
+
+	ret = kstrtouint(buf, 0, &gpio);
+	if (ret)
+		return ret;
+
+	desc = gpio_device_get_desc(gdev, gpio);
+	if (IS_ERR(desc))
+		return PTR_ERR(desc);
+
+	ret = handler(desc);
+	if (ret)
+		return ret;
+
+	return size;
+}
+
+static ssize_t chip_export_store(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t size)
+{
+	return do_chip_export_store(dev, attr, buf, size, export_gpio_desc);
+}
+
+static struct device_attribute dev_attr_export = __ATTR(export, 0200, NULL,
+							chip_export_store);
+
+static ssize_t chip_unexport_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t size)
+{
+	return do_chip_export_store(dev, attr, buf, size, unexport_gpio_desc);
+}
+
+static struct device_attribute dev_attr_unexport = __ATTR(unexport, 0200,
+							  NULL,
+							  chip_unexport_store);
+
 static struct attribute *gpiochip_attrs[] = {
 	&dev_attr_base.attr,
 	&dev_attr_label.attr,
@@ -436,6 +550,15 @@ static struct attribute *gpiochip_attrs[] = {
 };
 ATTRIBUTE_GROUPS(gpiochip);
 
+static struct attribute *gpiochip_ext_attrs[] = {
+	&dev_attr_label.attr,
+	&dev_attr_ngpio.attr,
+	&dev_attr_export.attr,
+	&dev_attr_unexport.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(gpiochip_ext);
+
 /*
  * /sys/class/gpio/export ... write-only
  *	integer N ... number of GPIO to export (full access)
@@ -447,7 +570,7 @@ static ssize_t export_store(const struct class *class,
 			    const char *buf, size_t len)
 {
 	struct gpio_desc *desc;
-	int status, offset;
+	int status;
 	long gpio;
 
 	status = kstrtol(buf, 0, &gpio);
@@ -461,40 +584,7 @@ static ssize_t export_store(const struct class *class,
 		return -EINVAL;
 	}
 
-	CLASS(gpio_chip_guard, guard)(desc);
-	if (!guard.gc)
-		return -ENODEV;
-
-	offset = gpio_chip_hwgpio(desc);
-	if (!gpiochip_line_is_valid(guard.gc, offset)) {
-		pr_debug_ratelimited("%s: GPIO %ld masked\n", __func__, gpio);
-		return -EINVAL;
-	}
-
-	/* No extra locking here; FLAG_SYSFS just signifies that the
-	 * request and export were done by on behalf of userspace, so
-	 * they may be undone on its behalf too.
-	 */
-
-	status = gpiod_request_user(desc, "sysfs");
-	if (status)
-		goto done;
-
-	status = gpiod_set_transitory(desc, false);
-	if (status) {
-		gpiod_free(desc);
-		goto done;
-	}
-
-	status = gpiod_export(desc, true);
-	if (status < 0) {
-		gpiod_free(desc);
-	} else {
-		set_bit(FLAG_SYSFS, &desc->flags);
-		gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_REQUESTED);
-	}
-
-done:
+	status = export_gpio_desc(desc);
 	if (status)
 		pr_debug("%s: status %d\n", __func__, status);
 	return status ? : len;
@@ -511,7 +601,7 @@ static ssize_t unexport_store(const struct class *class,
 
 	status = kstrtol(buf, 0, &gpio);
 	if (status < 0)
-		goto done;
+		return status;
 
 	desc = gpio_to_desc(gpio);
 	/* reject bogus commands (gpiod_unexport() ignores them) */
@@ -520,18 +610,7 @@ static ssize_t unexport_store(const struct class *class,
 		return -EINVAL;
 	}
 
-	status = -EINVAL;
-
-	/* No extra locking here; FLAG_SYSFS just signifies that the
-	 * request and export were done by on behalf of userspace, so
-	 * they may be undone on its behalf too.
-	 */
-	if (test_and_clear_bit(FLAG_SYSFS, &desc->flags)) {
-		gpiod_unexport(desc);
-		gpiod_free(desc);
-		status = 0;
-	}
-done:
+	status = unexport_gpio_desc(desc);
 	if (status)
 		pr_debug("%s: status %d\n", __func__, status);
 	return status ? : len;
@@ -561,6 +640,11 @@ static int match_gdev(struct device *dev, const void *desc)
 static struct gpiodev_data *
 gdev_get_data(struct gpio_device *gdev) __must_hold(&sysfs_lock)
 {
+	/*
+	 * Find the first device in GPIO class that matches. Whether that's
+	 * the one indexed by GPIO base or device ID doesn't matter, it has
+	 * the same address set as driver data.
+	 */
 	struct device *cdev __free(put_device) = class_find_device(&gpio_class,
 								   NULL, gdev,
 								   match_gdev);
@@ -787,6 +871,16 @@ int gpiochip_sysfs_register(struct gpio_device *gdev)
 		return err;
 	}
 
+	data->cdev_id = device_create_with_groups(&gpio_class, parent,
+						  MKDEV(0, 0), data,
+						  gpiochip_ext_groups,
+						  "chip%d", gdev->id);
+	if (IS_ERR(data->cdev_id)) {
+		device_unregister(data->cdev_base);
+		kfree(data);
+		return PTR_ERR(data->cdev_id);
+	}
+
 	return 0;
 }
 
@@ -802,6 +896,7 @@ void gpiochip_sysfs_unregister(struct gpio_device *gdev)
 			return;
 
 		device_unregister(data->cdev_base);
+		device_unregister(data->cdev_id);
 		kfree(data);
 	}
 

-- 
2.48.1


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

* [PATCH v2 2/9] gpio: sysfs: only get the dirent reference for the value attr once
  2025-06-23  8:59 [PATCH v2 0/9] gpio: sysfs: add a per-chip export/unexport attribute pair Bartosz Golaszewski
  2025-06-23  8:59 ` [PATCH v2 1/9] gpio: sysfs: add a parallel class device for each GPIO chip using device IDs Bartosz Golaszewski
@ 2025-06-23  8:59 ` Bartosz Golaszewski
  2025-06-27 15:35   ` Andy Shevchenko
  2025-06-23  8:59 ` [PATCH v2 3/9] gpio: sysfs: pass gpiod_data directly to internal GPIO sysfs functions Bartosz Golaszewski
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 31+ messages in thread
From: Bartosz Golaszewski @ 2025-06-23  8:59 UTC (permalink / raw)
  To: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, Linus Walleij, Bartosz Golaszewski
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

There's no reason to retrieve the reference to the sysfs dirent every
time we request an interrupt, we can as well only do it once when
exporting the GPIO.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib-sysfs.c | 23 +++++++++++++----------
 1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index fbe93cda4ca16038a1cffe766f7e5ead55ace5e6..c812c58e171448501f3d67e6287d32fcac00797d 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -36,7 +36,7 @@ struct gpiod_data {
 	struct gpio_desc *desc;
 
 	struct mutex mutex;
-	struct kernfs_node *value_kn;
+	struct kernfs_node *value_class_node;
 	int irq;
 	unsigned char irq_flags;
 
@@ -156,7 +156,7 @@ static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
 {
 	struct gpiod_data *data = priv;
 
-	sysfs_notify_dirent(data->value_kn);
+	sysfs_notify_dirent(data->value_class_node);
 
 	return IRQ_HANDLED;
 }
@@ -177,10 +177,6 @@ static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags)
 	if (data->irq < 0)
 		return -EIO;
 
-	data->value_kn = sysfs_get_dirent(dev->kobj.sd, "value");
-	if (!data->value_kn)
-		return -ENODEV;
-
 	irq_flags = IRQF_SHARED;
 	if (flags & GPIO_IRQF_TRIGGER_FALLING) {
 		irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
@@ -203,7 +199,7 @@ static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags)
 	 */
 	ret = gpiochip_lock_as_irq(guard.gc, gpio_chip_hwgpio(desc));
 	if (ret < 0)
-		goto err_put_kn;
+		goto err_clr_bits;
 
 	ret = request_any_context_irq(data->irq, gpio_sysfs_irq, irq_flags,
 				"gpiolib", data);
@@ -216,10 +212,9 @@ static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags)
 
 err_unlock:
 	gpiochip_unlock_as_irq(guard.gc, gpio_chip_hwgpio(desc));
-err_put_kn:
+err_clr_bits:
 	clear_bit(FLAG_EDGE_RISING, &desc->flags);
 	clear_bit(FLAG_EDGE_FALLING, &desc->flags);
-	sysfs_put(data->value_kn);
 
 	return ret;
 }
@@ -242,7 +237,6 @@ static void gpio_sysfs_free_irq(struct device *dev)
 	gpiochip_unlock_as_irq(guard.gc, gpio_chip_hwgpio(desc));
 	clear_bit(FLAG_EDGE_RISING, &desc->flags);
 	clear_bit(FLAG_EDGE_FALLING, &desc->flags);
-	sysfs_put(data->value_kn);
 }
 
 static const char *const trigger_names[] = {
@@ -726,8 +720,16 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 		goto err_free_data;
 	}
 
+	data->value_class_node = sysfs_get_dirent(dev->kobj.sd, "value");
+	if (!data->value_class_node) {
+		status = -ENODEV;
+		goto err_unregister_device;
+	}
+
 	return 0;
 
+err_unregister_device:
+	device_unregister(dev);
 err_free_data:
 	kfree(data);
 err_clear_bit:
@@ -804,6 +806,7 @@ void gpiod_unexport(struct gpio_desc *desc)
 
 		data = dev_get_drvdata(dev);
 		clear_bit(FLAG_EXPORT, &desc->flags);
+		sysfs_put(data->value_class_node);
 		device_unregister(dev);
 
 		/*

-- 
2.48.1


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

* [PATCH v2 3/9] gpio: sysfs: pass gpiod_data directly to internal GPIO sysfs functions
  2025-06-23  8:59 [PATCH v2 0/9] gpio: sysfs: add a per-chip export/unexport attribute pair Bartosz Golaszewski
  2025-06-23  8:59 ` [PATCH v2 1/9] gpio: sysfs: add a parallel class device for each GPIO chip using device IDs Bartosz Golaszewski
  2025-06-23  8:59 ` [PATCH v2 2/9] gpio: sysfs: only get the dirent reference for the value attr once Bartosz Golaszewski
@ 2025-06-23  8:59 ` Bartosz Golaszewski
  2025-06-24 19:32   ` Linus Walleij
  2025-06-27 15:37   ` Andy Shevchenko
  2025-06-23  8:59 ` [PATCH v2 4/9] gpio: sysfs: don't use driver data in sysfs callbacks for line attributes Bartosz Golaszewski
                   ` (5 subsequent siblings)
  8 siblings, 2 replies; 31+ messages in thread
From: Bartosz Golaszewski @ 2025-06-23  8:59 UTC (permalink / raw)
  To: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, Linus Walleij, Bartosz Golaszewski
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

To make the transition to not using dev_get_drvdata() across line
callbacks for sysfs attributes, pass gpiod_data directly to
gpio_sysfs_request_irq(), gpio_sysfs_free_irq() and
gpio_sysfs_set_active_low() instead of having it wrapped in struct
device.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib-sysfs.c | 21 +++++++++------------
 1 file changed, 9 insertions(+), 12 deletions(-)

diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index c812c58e171448501f3d67e6287d32fcac00797d..0e2c6b2d0940b1d4e4ad0a90aa172e7d01908969 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -162,9 +162,8 @@ static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
 }
 
 /* Caller holds gpiod-data mutex. */
-static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags)
+static int gpio_sysfs_request_irq(struct gpiod_data *data, unsigned char flags)
 {
-	struct gpiod_data *data = dev_get_drvdata(dev);
 	struct gpio_desc *desc = data->desc;
 	unsigned long irq_flags;
 	int ret;
@@ -223,9 +222,8 @@ static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags)
  * Caller holds gpiod-data mutex (unless called after class-device
  * deregistration).
  */
-static void gpio_sysfs_free_irq(struct device *dev)
+static void gpio_sysfs_free_irq(struct gpiod_data *data)
 {
-	struct gpiod_data *data = dev_get_drvdata(dev);
 	struct gpio_desc *desc = data->desc;
 
 	CLASS(gpio_chip_guard, guard)(desc);
@@ -278,12 +276,12 @@ static ssize_t edge_store(struct device *dev, struct device_attribute *attr,
 		return size;
 
 	if (data->irq_flags)
-		gpio_sysfs_free_irq(dev);
+		gpio_sysfs_free_irq(data);
 
 	if (!flags)
 		return size;
 
-	status = gpio_sysfs_request_irq(dev, flags);
+	status = gpio_sysfs_request_irq(data, flags);
 	if (status)
 		return status;
 
@@ -294,9 +292,8 @@ static ssize_t edge_store(struct device *dev, struct device_attribute *attr,
 static DEVICE_ATTR_RW(edge);
 
 /* Caller holds gpiod-data mutex. */
-static int gpio_sysfs_set_active_low(struct device *dev, int value)
+static int gpio_sysfs_set_active_low(struct gpiod_data *data, int value)
 {
-	struct gpiod_data *data = dev_get_drvdata(dev);
 	unsigned int flags = data->irq_flags;
 	struct gpio_desc *desc = data->desc;
 	int status = 0;
@@ -309,8 +306,8 @@ static int gpio_sysfs_set_active_low(struct device *dev, int value)
 	/* reconfigure poll(2) support if enabled on one edge only */
 	if (flags == GPIO_IRQF_TRIGGER_FALLING ||
 	    flags == GPIO_IRQF_TRIGGER_RISING) {
-		gpio_sysfs_free_irq(dev);
-		status = gpio_sysfs_request_irq(dev, flags);
+		gpio_sysfs_free_irq(data);
+		status = gpio_sysfs_request_irq(data, flags);
 	}
 
 	gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_CONFIG);
@@ -345,7 +342,7 @@ static ssize_t active_low_store(struct device *dev,
 
 	guard(mutex)(&data->mutex);
 
-	return gpio_sysfs_set_active_low(dev, value) ?: size;
+	return gpio_sysfs_set_active_low(data, value) ?: size;
 }
 static DEVICE_ATTR_RW(active_low);
 
@@ -814,7 +811,7 @@ void gpiod_unexport(struct gpio_desc *desc)
 		 * edge_store.
 		 */
 		if (data->irq_flags)
-			gpio_sysfs_free_irq(dev);
+			gpio_sysfs_free_irq(data);
 	}
 
 	put_device(dev);

-- 
2.48.1


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

* [PATCH v2 4/9] gpio: sysfs: don't use driver data in sysfs callbacks for line attributes
  2025-06-23  8:59 [PATCH v2 0/9] gpio: sysfs: add a per-chip export/unexport attribute pair Bartosz Golaszewski
                   ` (2 preceding siblings ...)
  2025-06-23  8:59 ` [PATCH v2 3/9] gpio: sysfs: pass gpiod_data directly to internal GPIO sysfs functions Bartosz Golaszewski
@ 2025-06-23  8:59 ` Bartosz Golaszewski
  2025-06-24 19:33   ` Linus Walleij
  2025-06-27 15:41   ` Andy Shevchenko
  2025-06-23  8:59 ` [PATCH v2 5/9] gpio: sysfs: rename the data variable in gpiod_(un)export() Bartosz Golaszewski
                   ` (4 subsequent siblings)
  8 siblings, 2 replies; 31+ messages in thread
From: Bartosz Golaszewski @ 2025-06-23  8:59 UTC (permalink / raw)
  To: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, Linus Walleij, Bartosz Golaszewski
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Currently each exported GPIO is represented in sysfs as a separate class
device. This allows us to simply use dev_get_drvdata() to retrieve the
pointer passed to device_create_with_groups() from sysfs ops callbacks.

However, we're preparing to add a parallel set of per-line sysfs
attributes that will live inside the associated gpiochip group. They are
not registered as class devices and so have the parent device passed as
argument to their callbacks (the GPIO chip class device).

Put the attribute structs inside the GPIO descriptor data and
dereference the relevant ones using container_of() in the callbacks.
This way, we'll be able to reuse the same code for both the legacy and
new GPIO attributes.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib-sysfs.c | 122 +++++++++++++++++++++++++++++--------------
 1 file changed, 82 insertions(+), 40 deletions(-)

diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index 0e2c6b2d0940b1d4e4ad0a90aa172e7d01908969..2f1df2ceb7360200c718ea95089720ebfa5a513a 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -32,6 +32,15 @@ struct kernfs_node;
 #define GPIO_IRQF_TRIGGER_BOTH		(GPIO_IRQF_TRIGGER_FALLING | \
 					 GPIO_IRQF_TRIGGER_RISING)
 
+enum {
+	GPIO_SYSFS_LINE_ATTR_DIRECTION = 0,
+	GPIO_SYSFS_LINE_ATTR_VALUE,
+	GPIO_SYSFS_LINE_ATTR_EDGE,
+	GPIO_SYSFS_LINE_ATTR_ACTIVE_LOW,
+	GPIO_SYSFS_LINE_ATTR_SENTINEL,
+	GPIO_SYSFS_LINE_ATTR_SIZE,
+};
+
 struct gpiod_data {
 	struct gpio_desc *desc;
 
@@ -41,6 +50,14 @@ struct gpiod_data {
 	unsigned char irq_flags;
 
 	bool direction_can_change;
+
+	struct device_attribute dir_attr;
+	struct device_attribute val_attr;
+	struct device_attribute edge_attr;
+	struct device_attribute active_low_attr;
+	struct attribute *attrs[GPIO_SYSFS_LINE_ATTR_SIZE];
+	struct attribute_group attr_group;
+	const struct attribute_group *attr_groups[2];
 };
 
 struct gpiodev_data {
@@ -79,7 +96,8 @@ static DEFINE_MUTEX(sysfs_lock);
 static ssize_t direction_show(struct device *dev,
 			      struct device_attribute *attr, char *buf)
 {
-	struct gpiod_data *data = dev_get_drvdata(dev);
+	struct gpiod_data *data = container_of(attr, struct gpiod_data,
+					       dir_attr);
 	struct gpio_desc *desc = data->desc;
 	int value;
 
@@ -95,7 +113,8 @@ static ssize_t direction_store(struct device *dev,
 			       struct device_attribute *attr, const char *buf,
 			       size_t size)
 {
-	struct gpiod_data *data = dev_get_drvdata(dev);
+	struct gpiod_data *data = container_of(attr, struct gpiod_data,
+					       dir_attr);
 	struct gpio_desc *desc = data->desc;
 	ssize_t status;
 
@@ -112,12 +131,12 @@ static ssize_t direction_store(struct device *dev,
 
 	return status ? : size;
 }
-static DEVICE_ATTR_RW(direction);
 
 static ssize_t value_show(struct device *dev, struct device_attribute *attr,
 			  char *buf)
 {
-	struct gpiod_data *data = dev_get_drvdata(dev);
+	struct gpiod_data *data = container_of(attr, struct gpiod_data,
+					       val_attr);
 	struct gpio_desc *desc = data->desc;
 	ssize_t status;
 
@@ -133,7 +152,8 @@ static ssize_t value_show(struct device *dev, struct device_attribute *attr,
 static ssize_t value_store(struct device *dev, struct device_attribute *attr,
 			   const char *buf, size_t size)
 {
-	struct gpiod_data *data = dev_get_drvdata(dev);
+	struct gpiod_data *data = container_of(attr, struct gpiod_data,
+					       val_attr);
 	struct gpio_desc *desc = data->desc;
 	ssize_t status;
 	long value;
@@ -150,7 +170,6 @@ static ssize_t value_store(struct device *dev, struct device_attribute *attr,
 
 	return size;
 }
-static DEVICE_ATTR_PREALLOC(value, S_IWUSR | S_IRUGO, value_show, value_store);
 
 static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
 {
@@ -247,7 +266,8 @@ static const char *const trigger_names[] = {
 static ssize_t edge_show(struct device *dev, struct device_attribute *attr,
 			 char *buf)
 {
-	struct gpiod_data *data = dev_get_drvdata(dev);
+	struct gpiod_data *data = container_of(attr, struct gpiod_data,
+					       edge_attr);
 	int flags;
 
 	scoped_guard(mutex, &data->mutex)
@@ -262,7 +282,8 @@ static ssize_t edge_show(struct device *dev, struct device_attribute *attr,
 static ssize_t edge_store(struct device *dev, struct device_attribute *attr,
 			  const char *buf, size_t size)
 {
-	struct gpiod_data *data = dev_get_drvdata(dev);
+	struct gpiod_data *data = container_of(attr, struct gpiod_data,
+					       edge_attr);
 	ssize_t status = size;
 	int flags;
 
@@ -289,7 +310,6 @@ static ssize_t edge_store(struct device *dev, struct device_attribute *attr,
 
 	return size;
 }
-static DEVICE_ATTR_RW(edge);
 
 /* Caller holds gpiod-data mutex. */
 static int gpio_sysfs_set_active_low(struct gpiod_data *data, int value)
@@ -318,7 +338,8 @@ static int gpio_sysfs_set_active_low(struct gpiod_data *data, int value)
 static ssize_t active_low_show(struct device *dev,
 			       struct device_attribute *attr, char *buf)
 {
-	struct gpiod_data *data = dev_get_drvdata(dev);
+	struct gpiod_data *data = container_of(attr, struct gpiod_data,
+					       active_low_attr);
 	struct gpio_desc *desc = data->desc;
 	int value;
 
@@ -332,7 +353,8 @@ static ssize_t active_low_store(struct device *dev,
 				struct device_attribute *attr,
 				const char *buf, size_t size)
 {
-	struct gpiod_data *data = dev_get_drvdata(dev);
+	struct gpiod_data *data = container_of(attr, struct gpiod_data,
+					       active_low_attr);
 	ssize_t status;
 	long value;
 
@@ -344,48 +366,34 @@ static ssize_t active_low_store(struct device *dev,
 
 	return gpio_sysfs_set_active_low(data, value) ?: size;
 }
-static DEVICE_ATTR_RW(active_low);
 
 static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr,
 			       int n)
 {
-	struct device *dev = kobj_to_dev(kobj);
-	struct gpiod_data *data = dev_get_drvdata(dev);
-	struct gpio_desc *desc = data->desc;
+	struct device_attribute *dev_attr = container_of(attr,
+						struct device_attribute, attr);
 	umode_t mode = attr->mode;
-	bool show_direction = data->direction_can_change;
+	struct gpiod_data *data;
 
-	if (attr == &dev_attr_direction.attr) {
-		if (!show_direction)
+	if (strcmp(attr->name, "direction") == 0) {
+		data = container_of(dev_attr, struct gpiod_data, dir_attr);
+
+		if (!data->direction_can_change)
 			mode = 0;
-	} else if (attr == &dev_attr_edge.attr) {
-		if (gpiod_to_irq(desc) < 0)
+	} else if (strcmp(attr->name, "edge") == 0) {
+		data = container_of(dev_attr, struct gpiod_data, edge_attr);
+
+		if (gpiod_to_irq(data->desc) < 0)
 			mode = 0;
-		if (!show_direction && test_bit(FLAG_IS_OUT, &desc->flags))
+
+		if (!data->direction_can_change &&
+		    test_bit(FLAG_IS_OUT, &data->desc->flags))
 			mode = 0;
 	}
 
 	return mode;
 }
 
-static struct attribute *gpio_attrs[] = {
-	&dev_attr_direction.attr,
-	&dev_attr_edge.attr,
-	&dev_attr_value.attr,
-	&dev_attr_active_low.attr,
-	NULL,
-};
-
-static const struct attribute_group gpio_group = {
-	.attrs = gpio_attrs,
-	.is_visible = gpio_is_visible,
-};
-
-static const struct attribute_group *gpio_groups[] = {
-	&gpio_group,
-	NULL
-};
-
 /*
  * /sys/class/gpio/gpiochipN/
  *   /base ... matching gpio_chip.base (N)
@@ -645,6 +653,21 @@ gdev_get_data(struct gpio_device *gdev) __must_hold(&sysfs_lock)
 	return dev_get_drvdata(cdev);
 };
 
+static void gpiod_attr_init(struct device_attribute *dev_attr, const char *name,
+			    ssize_t (*show)(struct device *dev,
+					    struct device_attribute *attr,
+					    char *buf),
+			    ssize_t (*store)(struct device *dev,
+					     struct device_attribute *attr,
+					     const char *buf, size_t count))
+{
+	sysfs_attr_init(&dev_attr->attr);
+	dev_attr->attr.name = name;
+	dev_attr->attr.mode = 0644;
+	dev_attr->show = show;
+	dev_attr->store = store;
+}
+
 /**
  * gpiod_export - export a GPIO through sysfs
  * @desc: GPIO to make available, already requested
@@ -664,6 +687,7 @@ gdev_get_data(struct gpio_device *gdev) __must_hold(&sysfs_lock)
 int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 {
 	struct gpio_device *gdev;
+	struct attribute **attrs;
 	struct gpiod_data *data;
 	struct device *dev;
 	int status;
@@ -709,8 +733,26 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 	else
 		data->direction_can_change = false;
 
+	gpiod_attr_init(&data->dir_attr, "direction",
+			direction_show, direction_store);
+	gpiod_attr_init(&data->val_attr, "value", value_show, value_store);
+	gpiod_attr_init(&data->edge_attr, "edge", edge_show, edge_store);
+	gpiod_attr_init(&data->active_low_attr, "active_low",
+			active_low_show, active_low_store);
+
+	attrs = data->attrs;
+	data->attr_group.is_visible = gpio_is_visible;
+	attrs[GPIO_SYSFS_LINE_ATTR_DIRECTION] = &data->dir_attr.attr;
+	attrs[GPIO_SYSFS_LINE_ATTR_VALUE] = &data->val_attr.attr;
+	attrs[GPIO_SYSFS_LINE_ATTR_EDGE] = &data->edge_attr.attr;
+	attrs[GPIO_SYSFS_LINE_ATTR_ACTIVE_LOW] =
+						&data->active_low_attr.attr;
+
+	data->attr_group.attrs = data->attrs;
+	data->attr_groups[0] = &data->attr_group;
+
 	dev = device_create_with_groups(&gpio_class, &gdev->dev,
-					MKDEV(0, 0), data, gpio_groups,
+					MKDEV(0, 0), data, data->attr_groups,
 					"gpio%u", desc_to_gpio(desc));
 	if (IS_ERR(dev)) {
 		status = PTR_ERR(dev);

-- 
2.48.1


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

* [PATCH v2 5/9] gpio: sysfs: rename the data variable in gpiod_(un)export()
  2025-06-23  8:59 [PATCH v2 0/9] gpio: sysfs: add a per-chip export/unexport attribute pair Bartosz Golaszewski
                   ` (3 preceding siblings ...)
  2025-06-23  8:59 ` [PATCH v2 4/9] gpio: sysfs: don't use driver data in sysfs callbacks for line attributes Bartosz Golaszewski
@ 2025-06-23  8:59 ` Bartosz Golaszewski
  2025-06-24 19:34   ` Linus Walleij
  2025-06-27 15:43   ` Andy Shevchenko
  2025-06-23  8:59 ` [PATCH v2 6/9] gpio: sysfs: don't look up exported lines as class devices Bartosz Golaszewski
                   ` (3 subsequent siblings)
  8 siblings, 2 replies; 31+ messages in thread
From: Bartosz Golaszewski @ 2025-06-23  8:59 UTC (permalink / raw)
  To: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, Linus Walleij, Bartosz Golaszewski
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

In preparation for future commits which will make use of descriptor AND
GPIO-device data in the same functions rename the former from data to
desc_data separately which will make future changes smaller and easier
to read.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib-sysfs.c | 63 ++++++++++++++++++++++----------------------
 1 file changed, 32 insertions(+), 31 deletions(-)

diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index 2f1df2ceb7360200c718ea95089720ebfa5a513a..515fd0d307cf820b036b1ea966b300715992359f 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -686,9 +686,9 @@ static void gpiod_attr_init(struct device_attribute *dev_attr, const char *name,
  */
 int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 {
+	struct gpiod_data *desc_data;
 	struct gpio_device *gdev;
 	struct attribute **attrs;
-	struct gpiod_data *data;
 	struct device *dev;
 	int status;
 
@@ -720,47 +720,48 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 		goto err_clear_bit;
 	}
 
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (!data) {
+	desc_data = kzalloc(sizeof(*desc_data), GFP_KERNEL);
+	if (!desc_data) {
 		status = -ENOMEM;
 		goto err_clear_bit;
 	}
 
-	data->desc = desc;
-	mutex_init(&data->mutex);
+	desc_data->desc = desc;
+	mutex_init(&desc_data->mutex);
 	if (guard.gc->direction_input && guard.gc->direction_output)
-		data->direction_can_change = direction_may_change;
+		desc_data->direction_can_change = direction_may_change;
 	else
-		data->direction_can_change = false;
+		desc_data->direction_can_change = false;
 
-	gpiod_attr_init(&data->dir_attr, "direction",
+	gpiod_attr_init(&desc_data->dir_attr, "direction",
 			direction_show, direction_store);
-	gpiod_attr_init(&data->val_attr, "value", value_show, value_store);
-	gpiod_attr_init(&data->edge_attr, "edge", edge_show, edge_store);
-	gpiod_attr_init(&data->active_low_attr, "active_low",
-			active_low_show, active_low_store);
+	gpiod_attr_init(&desc_data->val_attr, "value", value_show, value_store);
+	gpiod_attr_init(&desc_data->edge_attr, "edge", edge_show, edge_store);
+	gpiod_attr_init(&desc_data->active_low_attr, "active_low",
+				active_low_show, active_low_store);
 
-	attrs = data->attrs;
-	data->attr_group.is_visible = gpio_is_visible;
-	attrs[GPIO_SYSFS_LINE_ATTR_DIRECTION] = &data->dir_attr.attr;
-	attrs[GPIO_SYSFS_LINE_ATTR_VALUE] = &data->val_attr.attr;
-	attrs[GPIO_SYSFS_LINE_ATTR_EDGE] = &data->edge_attr.attr;
+	attrs = desc_data->attrs;
+	desc_data->attr_group.is_visible = gpio_is_visible;
+	attrs[GPIO_SYSFS_LINE_ATTR_DIRECTION] = &desc_data->dir_attr.attr;
+	attrs[GPIO_SYSFS_LINE_ATTR_VALUE] = &desc_data->val_attr.attr;
+	attrs[GPIO_SYSFS_LINE_ATTR_EDGE] = &desc_data->edge_attr.attr;
 	attrs[GPIO_SYSFS_LINE_ATTR_ACTIVE_LOW] =
-						&data->active_low_attr.attr;
+				&desc_data->active_low_attr.attr;
 
-	data->attr_group.attrs = data->attrs;
-	data->attr_groups[0] = &data->attr_group;
+	desc_data->attr_group.attrs = desc_data->attrs;
+	desc_data->attr_groups[0] = &desc_data->attr_group;
 
 	dev = device_create_with_groups(&gpio_class, &gdev->dev,
-					MKDEV(0, 0), data, data->attr_groups,
+					MKDEV(0, 0), desc_data,
+					desc_data->attr_groups,
 					"gpio%u", desc_to_gpio(desc));
 	if (IS_ERR(dev)) {
 		status = PTR_ERR(dev);
 		goto err_free_data;
 	}
 
-	data->value_class_node = sysfs_get_dirent(dev->kobj.sd, "value");
-	if (!data->value_class_node) {
+	desc_data->value_class_node = sysfs_get_dirent(dev->kobj.sd, "value");
+	if (!desc_data->value_class_node) {
 		status = -ENODEV;
 		goto err_unregister_device;
 	}
@@ -770,7 +771,7 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 err_unregister_device:
 	device_unregister(dev);
 err_free_data:
-	kfree(data);
+	kfree(desc_data);
 err_clear_bit:
 	clear_bit(FLAG_EXPORT, &desc->flags);
 	gpiod_dbg(desc, "%s: status %d\n", __func__, status);
@@ -827,7 +828,7 @@ EXPORT_SYMBOL_GPL(gpiod_export_link);
  */
 void gpiod_unexport(struct gpio_desc *desc)
 {
-	struct gpiod_data *data;
+	struct gpiod_data *desc_data;
 	struct device *dev;
 
 	if (!desc) {
@@ -843,22 +844,22 @@ void gpiod_unexport(struct gpio_desc *desc)
 		if (!dev)
 			return;
 
-		data = dev_get_drvdata(dev);
+		desc_data = dev_get_drvdata(dev);
 		clear_bit(FLAG_EXPORT, &desc->flags);
-		sysfs_put(data->value_class_node);
+		sysfs_put(desc_data->value_class_node);
 		device_unregister(dev);
 
 		/*
 		 * Release irq after deregistration to prevent race with
 		 * edge_store.
 		 */
-		if (data->irq_flags)
-			gpio_sysfs_free_irq(data);
+		if (desc_data->irq_flags)
+			gpio_sysfs_free_irq(desc_data);
 	}
 
 	put_device(dev);
-	mutex_destroy(&data->mutex);
-	kfree(data);
+	mutex_destroy(&desc_data->mutex);
+	kfree(desc_data);
 }
 EXPORT_SYMBOL_GPL(gpiod_unexport);
 

-- 
2.48.1


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

* [PATCH v2 6/9] gpio: sysfs: don't look up exported lines as class devices
  2025-06-23  8:59 [PATCH v2 0/9] gpio: sysfs: add a per-chip export/unexport attribute pair Bartosz Golaszewski
                   ` (4 preceding siblings ...)
  2025-06-23  8:59 ` [PATCH v2 5/9] gpio: sysfs: rename the data variable in gpiod_(un)export() Bartosz Golaszewski
@ 2025-06-23  8:59 ` Bartosz Golaszewski
  2025-06-24 19:34   ` Linus Walleij
  2025-06-27 15:47   ` Andy Shevchenko
  2025-06-23  8:59 ` [PATCH v2 7/9] gpio: sysfs: export the GPIO directory locally in the gpiochip<id> directory Bartosz Golaszewski
                   ` (2 subsequent siblings)
  8 siblings, 2 replies; 31+ messages in thread
From: Bartosz Golaszewski @ 2025-06-23  8:59 UTC (permalink / raw)
  To: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, Linus Walleij, Bartosz Golaszewski
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

In preparation for adding a parallel, per-chip attribute group for
exported GPIO lines, stop using class device APIs to refer to it in the
code. When unregistering the chip, don't call class_find_device() but
instead store exported lines in a linked list inside the GPIO chip data
object and look it up there.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib-sysfs.c | 60 ++++++++++++++++++++++++++++++++------------
 1 file changed, 44 insertions(+), 16 deletions(-)

diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index 515fd0d307cf820b036b1ea966b300715992359f..adf030f74eb163f5d8b1092d00418b84354f923f 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -43,6 +43,7 @@ enum {
 
 struct gpiod_data {
 	struct gpio_desc *desc;
+	struct device *dev;
 
 	struct mutex mutex;
 	struct kernfs_node *value_class_node;
@@ -58,12 +59,15 @@ struct gpiod_data {
 	struct attribute *attrs[GPIO_SYSFS_LINE_ATTR_SIZE];
 	struct attribute_group attr_group;
 	const struct attribute_group *attr_groups[2];
+
+	struct list_head list;
 };
 
 struct gpiodev_data {
 	struct gpio_device *gdev;
 	struct device *cdev_base; /* Class device by GPIO base */
 	struct device *cdev_id; /* Class device by GPIO device ID */
+	struct list_head exported_lines;
 };
 
 /*
@@ -686,10 +690,10 @@ static void gpiod_attr_init(struct device_attribute *dev_attr, const char *name,
  */
 int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 {
+	struct gpiodev_data *gdev_data;
 	struct gpiod_data *desc_data;
 	struct gpio_device *gdev;
 	struct attribute **attrs;
-	struct device *dev;
 	int status;
 
 	/* can't export until sysfs is available ... */
@@ -751,25 +755,40 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 	desc_data->attr_group.attrs = desc_data->attrs;
 	desc_data->attr_groups[0] = &desc_data->attr_group;
 
-	dev = device_create_with_groups(&gpio_class, &gdev->dev,
-					MKDEV(0, 0), desc_data,
-					desc_data->attr_groups,
-					"gpio%u", desc_to_gpio(desc));
-	if (IS_ERR(dev)) {
-		status = PTR_ERR(dev);
+	/*
+	 * Note: we need to continue passing desc_data here as there's still
+	 * at least one known user of gpiod_export_link() in the tree. This
+	 * function still uses class_find_device() internally.
+	 */
+	desc_data->dev = device_create_with_groups(&gpio_class, &gdev->dev,
+						   MKDEV(0, 0), desc_data,
+						   desc_data->attr_groups,
+						   "gpio%u",
+						   desc_to_gpio(desc));
+	if (IS_ERR(desc_data->dev)) {
+		status = PTR_ERR(desc_data->dev);
 		goto err_free_data;
 	}
 
-	desc_data->value_class_node = sysfs_get_dirent(dev->kobj.sd, "value");
+	desc_data->value_class_node = sysfs_get_dirent(desc_data->dev->kobj.sd,
+						       "value");
 	if (!desc_data->value_class_node) {
 		status = -ENODEV;
 		goto err_unregister_device;
 	}
 
+	gdev_data = gdev_get_data(gdev);
+	if (!gdev_data) {
+		status = -ENODEV;
+		goto err_unregister_device;
+	}
+
+	list_add(&desc_data->list, &gdev_data->exported_lines);
+
 	return 0;
 
 err_unregister_device:
-	device_unregister(dev);
+	device_unregister(desc_data->dev);
 err_free_data:
 	kfree(desc_data);
 err_clear_bit:
@@ -828,8 +847,9 @@ EXPORT_SYMBOL_GPL(gpiod_export_link);
  */
 void gpiod_unexport(struct gpio_desc *desc)
 {
-	struct gpiod_data *desc_data;
-	struct device *dev;
+	struct gpiod_data *desc_data = NULL;
+	struct gpiodev_data *gdev_data;
+	struct gpio_device *gdev;
 
 	if (!desc) {
 		pr_warn("%s: invalid GPIO\n", __func__);
@@ -840,14 +860,22 @@ void gpiod_unexport(struct gpio_desc *desc)
 		if (!test_bit(FLAG_EXPORT, &desc->flags))
 			return;
 
-		dev = class_find_device(&gpio_class, NULL, desc, match_export);
-		if (!dev)
+		gdev = gpiod_to_gpio_device(desc);
+		gdev_data = gdev_get_data(gdev);
+		if (!gdev_data)
 			return;
 
-		desc_data = dev_get_drvdata(dev);
+		list_for_each_entry(desc_data, &gdev_data->exported_lines, list)
+			if (desc == desc_data->desc)
+				break;
+
+		if (!desc_data)
+			return;
+
+		list_del(&desc_data->list);
 		clear_bit(FLAG_EXPORT, &desc->flags);
 		sysfs_put(desc_data->value_class_node);
-		device_unregister(dev);
+		device_unregister(desc_data->dev);
 
 		/*
 		 * Release irq after deregistration to prevent race with
@@ -857,7 +885,6 @@ void gpiod_unexport(struct gpio_desc *desc)
 			gpio_sysfs_free_irq(desc_data);
 	}
 
-	put_device(dev);
 	mutex_destroy(&desc_data->mutex);
 	kfree(desc_data);
 }
@@ -899,6 +926,7 @@ int gpiochip_sysfs_register(struct gpio_device *gdev)
 		return -ENOMEM;
 
 	data->gdev = gdev;
+	INIT_LIST_HEAD(&data->exported_lines);
 
 	guard(mutex)(&sysfs_lock);
 

-- 
2.48.1


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

* [PATCH v2 7/9] gpio: sysfs: export the GPIO directory locally in the gpiochip<id> directory
  2025-06-23  8:59 [PATCH v2 0/9] gpio: sysfs: add a per-chip export/unexport attribute pair Bartosz Golaszewski
                   ` (5 preceding siblings ...)
  2025-06-23  8:59 ` [PATCH v2 6/9] gpio: sysfs: don't look up exported lines as class devices Bartosz Golaszewski
@ 2025-06-23  8:59 ` Bartosz Golaszewski
  2025-06-23 22:07   ` kernel test robot
  2025-06-23  8:59 ` [PATCH v2 8/9] gpio: sysfs: allow disabling the legacy parts of the GPIO sysfs interface Bartosz Golaszewski
  2025-06-23  8:59 ` [PATCH v2 9/9] gpio: TODO: remove the task for the sysfs rework Bartosz Golaszewski
  8 siblings, 1 reply; 31+ messages in thread
From: Bartosz Golaszewski @ 2025-06-23  8:59 UTC (permalink / raw)
  To: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, Linus Walleij, Bartosz Golaszewski
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

As a way to allow the user-space to stop referring to GPIOs by their
global numbers, introduce a parallel group of line attributes for
exported GPIO that live inside the GPIO chip class device and are
referred to by their HW offset within their parent chip.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 Documentation/ABI/obsolete/sysfs-gpio |  5 +++++
 drivers/gpio/gpiolib-sysfs.c          | 40 ++++++++++++++++++++++++++++++++++-
 2 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/Documentation/ABI/obsolete/sysfs-gpio b/Documentation/ABI/obsolete/sysfs-gpio
index ff694708a3bef787afa42dedf94faf209c44dbf0..c0bb51412a912cefe032c4e84288f99754acb1b5 100644
--- a/Documentation/ABI/obsolete/sysfs-gpio
+++ b/Documentation/ABI/obsolete/sysfs-gpio
@@ -27,6 +27,11 @@ Description:
 	    /base ... (r/o) same as N
 	    /label ... (r/o) descriptive chip name
 	    /ngpio ... (r/o) number of GPIOs; numbered N to N + (ngpio - 1)
+	    /gpio<OFFSET>
+	        /value ... always readable, writes fail for input GPIOs
+	        /direction ... r/w as: in, out (default low); write: high, low
+	        /edge ... r/w as: none, falling, rising, both
+	        /active-low ... r/w as: 0, 1
 	/chipX ... for each gpiochip; #X is the gpio device ID
 	    /export ... asks the kernel to export a GPIO at HW offset X to userspace
 	    /unexport ... to return a GPIO at HW offset X to the kernel
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index adf030f74eb163f5d8b1092d00418b84354f923f..37d58009a51333f7d6a8d600dbeaeb333df27ac3 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -47,11 +47,13 @@ struct gpiod_data {
 
 	struct mutex mutex;
 	struct kernfs_node *value_class_node;
+	struct kernfs_node *value_chip_node;
 	int irq;
 	unsigned char irq_flags;
 
 	bool direction_can_change;
 
+	struct kobject *parent;
 	struct device_attribute dir_attr;
 	struct device_attribute val_attr;
 	struct device_attribute edge_attr;
@@ -180,6 +182,7 @@ static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
 	struct gpiod_data *data = priv;
 
 	sysfs_notify_dirent(data->value_class_node);
+	kernfs_notify(data->value_chip_node);
 
 	return IRQ_HANDLED;
 }
@@ -780,13 +783,46 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 	gdev_data = gdev_get_data(gdev);
 	if (!gdev_data) {
 		status = -ENODEV;
-		goto err_unregister_device;
+		goto err_put_dirent;
 	}
 
 	list_add(&desc_data->list, &gdev_data->exported_lines);
 
+	desc_data->attr_group.name = kasprintf(GFP_KERNEL, "gpio%u",
+					       gpio_chip_hwgpio(desc));
+	if (!desc_data->attr_group.name) {
+		status = -ENOMEM;
+		goto err_put_dirent;
+	}
+
+	desc_data->parent = &gdev_data->cdev_id->kobj;
+	status = sysfs_create_groups(desc_data->parent,
+				     desc_data->attr_groups);
+	if (status)
+		goto err_free_name;
+
+	char *path __free(kfree) = kasprintf(GFP_KERNEL, "gpio%u/value",
+					     gpio_chip_hwgpio(desc));
+	if (!path) {
+		status = -ENOMEM;
+		goto err_remove_groups;
+	}
+
+	desc_data->value_chip_node = kernfs_walk_and_get(desc_data->parent->sd,
+							 path);
+	if (!desc_data->value_chip_node) {
+		status = -ENODEV;
+		goto err_remove_groups;
+	}
+
 	return 0;
 
+err_remove_groups:
+	sysfs_remove_groups(desc_data->parent, desc_data->attr_groups);
+err_free_name:
+	kfree(desc_data->attr_group.name);
+err_put_dirent:
+	sysfs_put(desc_data->value_class_node);
 err_unregister_device:
 	device_unregister(desc_data->dev);
 err_free_data:
@@ -876,6 +912,8 @@ void gpiod_unexport(struct gpio_desc *desc)
 		clear_bit(FLAG_EXPORT, &desc->flags);
 		sysfs_put(desc_data->value_class_node);
 		device_unregister(desc_data->dev);
+		sysfs_remove_groups(desc_data->parent, desc_data->attr_groups);
+		kernfs_put(desc_data->value_chip_node);
 
 		/*
 		 * Release irq after deregistration to prevent race with

-- 
2.48.1


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

* [PATCH v2 8/9] gpio: sysfs: allow disabling the legacy parts of the GPIO sysfs interface
  2025-06-23  8:59 [PATCH v2 0/9] gpio: sysfs: add a per-chip export/unexport attribute pair Bartosz Golaszewski
                   ` (6 preceding siblings ...)
  2025-06-23  8:59 ` [PATCH v2 7/9] gpio: sysfs: export the GPIO directory locally in the gpiochip<id> directory Bartosz Golaszewski
@ 2025-06-23  8:59 ` Bartosz Golaszewski
  2025-06-24 11:31   ` Geert Uytterhoeven
                     ` (2 more replies)
  2025-06-23  8:59 ` [PATCH v2 9/9] gpio: TODO: remove the task for the sysfs rework Bartosz Golaszewski
  8 siblings, 3 replies; 31+ messages in thread
From: Bartosz Golaszewski @ 2025-06-23  8:59 UTC (permalink / raw)
  To: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, Linus Walleij, Bartosz Golaszewski
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Add a Kconfig switch allowing to disable the legacy parts of the GPIO
sysfs interface. This means that even though we keep the
/sys/class/gpio/ directory, it no longer contains the global
export/unexport attribute pair (instead, the user should use the
per-chip export/unpexport) nor the gpiochip$BASE entries. This option
default to y if GPIO sysfs is enabled but we'll default it to n at some
point in the future.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/Kconfig         |  8 ++++++++
 drivers/gpio/gpiolib-sysfs.c | 32 ++++++++++++++++++++++++++++++++
 2 files changed, 40 insertions(+)

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 44f922e10db2f8dcbdacf79ccd27b0fd9cd93564..d040fdd95ee4b19851057fbedbb023f277149c9c 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -69,6 +69,14 @@ config GPIO_SYSFS
 	  use the character device /dev/gpiochipN with the appropriate
 	  ioctl() operations instead.
 
+config GPIO_SYSFS_LEGACY
+	bool "Enable legacy functionalities of the sysfs interface"
+	depends on GPIO_SYSFS
+	default y if GPIO_SYSFS
+	help
+	  Say Y here if you want to enable the legacy, global GPIO
+	  numberspace-based functionalities of the sysfs interface.
+
 config GPIO_CDEV
 	bool "Character device (/dev/gpiochipN) support" if EXPERT
 	default y
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index 37d58009a51333f7d6a8d600dbeaeb333df27ac3..0e7605fee3bd9edbe4e90d8e466742df11a8d579 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -46,7 +46,9 @@ struct gpiod_data {
 	struct device *dev;
 
 	struct mutex mutex;
+#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY)
 	struct kernfs_node *value_class_node;
+#endif /* CONFIG_GPIO_SYSFS_LEGACY */
 	struct kernfs_node *value_chip_node;
 	int irq;
 	unsigned char irq_flags;
@@ -67,7 +69,9 @@ struct gpiod_data {
 
 struct gpiodev_data {
 	struct gpio_device *gdev;
+#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY)
 	struct device *cdev_base; /* Class device by GPIO base */
+#endif /* CONFIG_GPIO_SYSFS_LEGACY */
 	struct device *cdev_id; /* Class device by GPIO device ID */
 	struct list_head exported_lines;
 };
@@ -181,7 +185,9 @@ static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
 {
 	struct gpiod_data *data = priv;
 
+#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY)
 	sysfs_notify_dirent(data->value_class_node);
+#endif /* CONFIG_GPIO_SYSFS_LEGACY */
 	kernfs_notify(data->value_chip_node);
 
 	return IRQ_HANDLED;
@@ -416,6 +422,7 @@ static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr,
  *   /ngpio ... matching gpio_chip.ngpio
  */
 
+#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY)
 static ssize_t base_show(struct device *dev, struct device_attribute *attr,
 			 char *buf)
 {
@@ -424,6 +431,7 @@ static ssize_t base_show(struct device *dev, struct device_attribute *attr,
 	return sysfs_emit(buf, "%u\n", data->gdev->base);
 }
 static DEVICE_ATTR_RO(base);
+#endif /* CONFIG_GPIO_SYSFS_LEGACY */
 
 static ssize_t label_show(struct device *dev, struct device_attribute *attr,
 			  char *buf)
@@ -548,6 +556,7 @@ static struct device_attribute dev_attr_unexport = __ATTR(unexport, 0200,
 							  NULL,
 							  chip_unexport_store);
 
+#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY)
 static struct attribute *gpiochip_attrs[] = {
 	&dev_attr_base.attr,
 	&dev_attr_label.attr,
@@ -555,6 +564,7 @@ static struct attribute *gpiochip_attrs[] = {
 	NULL,
 };
 ATTRIBUTE_GROUPS(gpiochip);
+#endif /* CONFIG_GPIO_SYSFS_LEGACY */
 
 static struct attribute *gpiochip_ext_attrs[] = {
 	&dev_attr_label.attr,
@@ -565,6 +575,7 @@ static struct attribute *gpiochip_ext_attrs[] = {
 };
 ATTRIBUTE_GROUPS(gpiochip_ext);
 
+#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY)
 /*
  * /sys/class/gpio/export ... write-only
  *	integer N ... number of GPIO to export (full access)
@@ -629,10 +640,13 @@ static struct attribute *gpio_class_attrs[] = {
 	NULL,
 };
 ATTRIBUTE_GROUPS(gpio_class);
+#endif /* CONFIG_GPIO_SYSFS_LEGACY */
 
 static const struct class gpio_class = {
 	.name =		"gpio",
+#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY)
 	.class_groups =	gpio_class_groups,
+#endif /* CONFIG_GPIO_SYSFS_LEGACY */
 };
 
 static int match_gdev(struct device *dev, const void *desc)
@@ -763,6 +777,7 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 	 * at least one known user of gpiod_export_link() in the tree. This
 	 * function still uses class_find_device() internally.
 	 */
+#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY)
 	desc_data->dev = device_create_with_groups(&gpio_class, &gdev->dev,
 						   MKDEV(0, 0), desc_data,
 						   desc_data->attr_groups,
@@ -779,6 +794,7 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 		status = -ENODEV;
 		goto err_unregister_device;
 	}
+#endif /* CONFIG_GPIO_SYSFS_LEGACY */
 
 	gdev_data = gdev_get_data(gdev);
 	if (!gdev_data) {
@@ -822,10 +838,12 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 err_free_name:
 	kfree(desc_data->attr_group.name);
 err_put_dirent:
+#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY)
 	sysfs_put(desc_data->value_class_node);
 err_unregister_device:
 	device_unregister(desc_data->dev);
 err_free_data:
+#endif /* CONFIG_GPIO_SYSFS_LEGACY */
 	kfree(desc_data);
 err_clear_bit:
 	clear_bit(FLAG_EXPORT, &desc->flags);
@@ -834,12 +852,14 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 }
 EXPORT_SYMBOL_GPL(gpiod_export);
 
+#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY)
 static int match_export(struct device *dev, const void *desc)
 {
 	struct gpiod_data *data = dev_get_drvdata(dev);
 
 	return data->desc == desc;
 }
+#endif /* CONFIG_GPIO_SYSFS_LEGACY */
 
 /**
  * gpiod_export_link - create a sysfs link to an exported GPIO node
@@ -856,6 +876,7 @@ static int match_export(struct device *dev, const void *desc)
 int gpiod_export_link(struct device *dev, const char *name,
 		      struct gpio_desc *desc)
 {
+#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY)
 	struct device *cdev;
 	int ret;
 
@@ -872,6 +893,9 @@ int gpiod_export_link(struct device *dev, const char *name,
 	put_device(cdev);
 
 	return ret;
+#else
+	return -EOPNOTSUPP;
+#endif /* CONFIG_GPIO_SYSFS_LEGACY */
 }
 EXPORT_SYMBOL_GPL(gpiod_export_link);
 
@@ -910,8 +934,10 @@ void gpiod_unexport(struct gpio_desc *desc)
 
 		list_del(&desc_data->list);
 		clear_bit(FLAG_EXPORT, &desc->flags);
+#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY)
 		sysfs_put(desc_data->value_class_node);
 		device_unregister(desc_data->dev);
+#endif /* CONFIG_GPIO_SYSFS_LEGACY */
 		sysfs_remove_groups(desc_data->parent, desc_data->attr_groups);
 		kernfs_put(desc_data->value_chip_node);
 
@@ -968,6 +994,7 @@ int gpiochip_sysfs_register(struct gpio_device *gdev)
 
 	guard(mutex)(&sysfs_lock);
 
+#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY)
 	/* use chip->base for the ID; it's already known to be unique */
 	data->cdev_base = device_create_with_groups(&gpio_class, parent,
 						    MKDEV(0, 0), data,
@@ -979,13 +1006,16 @@ int gpiochip_sysfs_register(struct gpio_device *gdev)
 		kfree(data);
 		return err;
 	}
+#endif /* CONFIG_GPIO_SYSFS_LEGACY */
 
 	data->cdev_id = device_create_with_groups(&gpio_class, parent,
 						  MKDEV(0, 0), data,
 						  gpiochip_ext_groups,
 						  "chip%d", gdev->id);
 	if (IS_ERR(data->cdev_id)) {
+#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY)
 		device_unregister(data->cdev_base);
+#endif /* CONFIG_GPIO_SYSFS_LEGACY */
 		kfree(data);
 		return PTR_ERR(data->cdev_id);
 	}
@@ -1004,7 +1034,9 @@ void gpiochip_sysfs_unregister(struct gpio_device *gdev)
 		if (!data)
 			return;
 
+#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY)
 		device_unregister(data->cdev_base);
+#endif /* CONFIG_GPIO_SYSFS_LEGACY */
 		device_unregister(data->cdev_id);
 		kfree(data);
 	}

-- 
2.48.1


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

* [PATCH v2 9/9] gpio: TODO: remove the task for the sysfs rework
  2025-06-23  8:59 [PATCH v2 0/9] gpio: sysfs: add a per-chip export/unexport attribute pair Bartosz Golaszewski
                   ` (7 preceding siblings ...)
  2025-06-23  8:59 ` [PATCH v2 8/9] gpio: sysfs: allow disabling the legacy parts of the GPIO sysfs interface Bartosz Golaszewski
@ 2025-06-23  8:59 ` Bartosz Golaszewski
  8 siblings, 0 replies; 31+ messages in thread
From: Bartosz Golaszewski @ 2025-06-23  8:59 UTC (permalink / raw)
  To: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, Linus Walleij, Bartosz Golaszewski
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Remove the completed task tracking the rework of the sysfs interface.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/TODO | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/drivers/gpio/TODO b/drivers/gpio/TODO
index ef53892cb44d7c01d100f10f1b805c0aca561b46..a6380e51699cc5704aebefbda906762fa60cfef3 100644
--- a/drivers/gpio/TODO
+++ b/drivers/gpio/TODO
@@ -188,19 +188,6 @@ remove the old ones and finally rename the new ones back to the old names.
 
 -------------------------------------------------------------------------------
 
-Extend the sysfs ABI to allow exporting lines by their HW offsets
-
-The need to support the sysfs GPIO class is one of the main obstacles to
-removing the global GPIO numberspace from the kernel. In order to wean users
-off using global numbers from user-space, extend the existing interface with
-new per-gpiochip export/unexport attributes that allow to refer to GPIOs using
-their hardware offsets within the chip.
-
-Encourage users to switch to using them and eventually remove the existing
-global export/unexport attribues.
-
--------------------------------------------------------------------------------
-
 Remove GPIOD_FLAGS_BIT_NONEXCLUSIVE
 
 GPIOs in the linux kernel are meant to be an exclusive resource. This means

-- 
2.48.1


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

* Re: [PATCH v2 7/9] gpio: sysfs: export the GPIO directory locally in the gpiochip<id> directory
  2025-06-23  8:59 ` [PATCH v2 7/9] gpio: sysfs: export the GPIO directory locally in the gpiochip<id> directory Bartosz Golaszewski
@ 2025-06-23 22:07   ` kernel test robot
  0 siblings, 0 replies; 31+ messages in thread
From: kernel test robot @ 2025-06-23 22:07 UTC (permalink / raw)
  To: Bartosz Golaszewski, Ahmad Fatoum, Kent Gibson, Jan Lübbe,
	Marek Vasut, Geert Uytterhoeven, Linus Walleij
  Cc: llvm, oe-kbuild-all, linux-gpio, linux-kernel

Hi Bartosz,

kernel test robot noticed the following build errors:

[auto build test ERROR on cb908f3699fb137e28017a8fdf506c35762b3eb6]

url:    https://github.com/intel-lab-lkp/linux/commits/Bartosz-Golaszewski/gpio-sysfs-add-a-parallel-class-device-for-each-GPIO-chip-using-device-IDs/20250623-170412
base:   cb908f3699fb137e28017a8fdf506c35762b3eb6
patch link:    https://lore.kernel.org/r/20250623-gpio-sysfs-chip-export-v2-7-d592793f8964%40linaro.org
patch subject: [PATCH v2 7/9] gpio: sysfs: export the GPIO directory locally in the gpiochip<id> directory
config: s390-allmodconfig (https://download.01.org/0day-ci/archive/20250624/202506240548.l2wS2XW6-lkp@intel.com/config)
compiler: clang version 18.1.8 (https://github.com/llvm/llvm-project 3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250624/202506240548.l2wS2XW6-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202506240548.l2wS2XW6-lkp@intel.com/

All errors (new ones prefixed by >>):

>> drivers/gpio/gpiolib-sysfs.c:802:3: error: cannot jump from this goto statement to its label
     802 |                 goto err_free_name;
         |                 ^
   drivers/gpio/gpiolib-sysfs.c:804:8: note: jump bypasses initialization of variable with __attribute__((cleanup))
     804 |         char *path __free(kfree) = kasprintf(GFP_KERNEL, "gpio%u/value",
         |               ^
   drivers/gpio/gpiolib-sysfs.c:795:3: error: cannot jump from this goto statement to its label
     795 |                 goto err_put_dirent;
         |                 ^
   drivers/gpio/gpiolib-sysfs.c:804:8: note: jump bypasses initialization of variable with __attribute__((cleanup))
     804 |         char *path __free(kfree) = kasprintf(GFP_KERNEL, "gpio%u/value",
         |               ^
   drivers/gpio/gpiolib-sysfs.c:786:3: error: cannot jump from this goto statement to its label
     786 |                 goto err_put_dirent;
         |                 ^
   drivers/gpio/gpiolib-sysfs.c:804:8: note: jump bypasses initialization of variable with __attribute__((cleanup))
     804 |         char *path __free(kfree) = kasprintf(GFP_KERNEL, "gpio%u/value",
         |               ^
   drivers/gpio/gpiolib-sysfs.c:780:3: error: cannot jump from this goto statement to its label
     780 |                 goto err_unregister_device;
         |                 ^
   drivers/gpio/gpiolib-sysfs.c:804:8: note: jump bypasses initialization of variable with __attribute__((cleanup))
     804 |         char *path __free(kfree) = kasprintf(GFP_KERNEL, "gpio%u/value",
         |               ^
   drivers/gpio/gpiolib-sysfs.c:773:3: error: cannot jump from this goto statement to its label
     773 |                 goto err_free_data;
         |                 ^
   drivers/gpio/gpiolib-sysfs.c:804:8: note: jump bypasses initialization of variable with __attribute__((cleanup))
     804 |         char *path __free(kfree) = kasprintf(GFP_KERNEL, "gpio%u/value",
         |               ^
   drivers/gpio/gpiolib-sysfs.c:733:3: error: cannot jump from this goto statement to its label
     733 |                 goto err_clear_bit;
         |                 ^
   drivers/gpio/gpiolib-sysfs.c:804:8: note: jump bypasses initialization of variable with __attribute__((cleanup))
     804 |         char *path __free(kfree) = kasprintf(GFP_KERNEL, "gpio%u/value",
         |               ^
   drivers/gpio/gpiolib-sysfs.c:727:3: error: cannot jump from this goto statement to its label
     727 |                 goto err_clear_bit;
         |                 ^
   drivers/gpio/gpiolib-sysfs.c:804:8: note: jump bypasses initialization of variable with __attribute__((cleanup))
     804 |         char *path __free(kfree) = kasprintf(GFP_KERNEL, "gpio%u/value",
         |               ^
   7 errors generated.


vim +802 drivers/gpio/gpiolib-sysfs.c

   677	
   678	/**
   679	 * gpiod_export - export a GPIO through sysfs
   680	 * @desc: GPIO to make available, already requested
   681	 * @direction_may_change: true if userspace may change GPIO direction
   682	 * Context: arch_initcall or later
   683	 *
   684	 * When drivers want to make a GPIO accessible to userspace after they
   685	 * have requested it -- perhaps while debugging, or as part of their
   686	 * public interface -- they may use this routine.  If the GPIO can
   687	 * change direction (some can't) and the caller allows it, userspace
   688	 * will see "direction" sysfs attribute which may be used to change
   689	 * the gpio's direction.  A "value" attribute will always be provided.
   690	 *
   691	 * Returns:
   692	 * 0 on success, or negative errno on failure.
   693	 */
   694	int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
   695	{
   696		struct gpiodev_data *gdev_data;
   697		struct gpiod_data *desc_data;
   698		struct gpio_device *gdev;
   699		struct attribute **attrs;
   700		int status;
   701	
   702		/* can't export until sysfs is available ... */
   703		if (!class_is_registered(&gpio_class)) {
   704			pr_debug("%s: called too early!\n", __func__);
   705			return -ENOENT;
   706		}
   707	
   708		if (!desc) {
   709			pr_debug("%s: invalid gpio descriptor\n", __func__);
   710			return -EINVAL;
   711		}
   712	
   713		CLASS(gpio_chip_guard, guard)(desc);
   714		if (!guard.gc)
   715			return -ENODEV;
   716	
   717		if (test_and_set_bit(FLAG_EXPORT, &desc->flags))
   718			return -EPERM;
   719	
   720		gdev = desc->gdev;
   721	
   722		guard(mutex)(&sysfs_lock);
   723	
   724		if (!test_bit(FLAG_REQUESTED, &desc->flags)) {
   725			gpiod_dbg(desc, "%s: unavailable (not requested)\n", __func__);
   726			status = -EPERM;
   727			goto err_clear_bit;
   728		}
   729	
   730		desc_data = kzalloc(sizeof(*desc_data), GFP_KERNEL);
   731		if (!desc_data) {
   732			status = -ENOMEM;
   733			goto err_clear_bit;
   734		}
   735	
   736		desc_data->desc = desc;
   737		mutex_init(&desc_data->mutex);
   738		if (guard.gc->direction_input && guard.gc->direction_output)
   739			desc_data->direction_can_change = direction_may_change;
   740		else
   741			desc_data->direction_can_change = false;
   742	
   743		gpiod_attr_init(&desc_data->dir_attr, "direction",
   744				direction_show, direction_store);
   745		gpiod_attr_init(&desc_data->val_attr, "value", value_show, value_store);
   746		gpiod_attr_init(&desc_data->edge_attr, "edge", edge_show, edge_store);
   747		gpiod_attr_init(&desc_data->active_low_attr, "active_low",
   748					active_low_show, active_low_store);
   749	
   750		attrs = desc_data->attrs;
   751		desc_data->attr_group.is_visible = gpio_is_visible;
   752		attrs[GPIO_SYSFS_LINE_ATTR_DIRECTION] = &desc_data->dir_attr.attr;
   753		attrs[GPIO_SYSFS_LINE_ATTR_VALUE] = &desc_data->val_attr.attr;
   754		attrs[GPIO_SYSFS_LINE_ATTR_EDGE] = &desc_data->edge_attr.attr;
   755		attrs[GPIO_SYSFS_LINE_ATTR_ACTIVE_LOW] =
   756					&desc_data->active_low_attr.attr;
   757	
   758		desc_data->attr_group.attrs = desc_data->attrs;
   759		desc_data->attr_groups[0] = &desc_data->attr_group;
   760	
   761		/*
   762		 * Note: we need to continue passing desc_data here as there's still
   763		 * at least one known user of gpiod_export_link() in the tree. This
   764		 * function still uses class_find_device() internally.
   765		 */
   766		desc_data->dev = device_create_with_groups(&gpio_class, &gdev->dev,
   767							   MKDEV(0, 0), desc_data,
   768							   desc_data->attr_groups,
   769							   "gpio%u",
   770							   desc_to_gpio(desc));
   771		if (IS_ERR(desc_data->dev)) {
   772			status = PTR_ERR(desc_data->dev);
   773			goto err_free_data;
   774		}
   775	
   776		desc_data->value_class_node = sysfs_get_dirent(desc_data->dev->kobj.sd,
   777							       "value");
   778		if (!desc_data->value_class_node) {
   779			status = -ENODEV;
   780			goto err_unregister_device;
   781		}
   782	
   783		gdev_data = gdev_get_data(gdev);
   784		if (!gdev_data) {
   785			status = -ENODEV;
   786			goto err_put_dirent;
   787		}
   788	
   789		list_add(&desc_data->list, &gdev_data->exported_lines);
   790	
   791		desc_data->attr_group.name = kasprintf(GFP_KERNEL, "gpio%u",
   792						       gpio_chip_hwgpio(desc));
   793		if (!desc_data->attr_group.name) {
   794			status = -ENOMEM;
   795			goto err_put_dirent;
   796		}
   797	
   798		desc_data->parent = &gdev_data->cdev_id->kobj;
   799		status = sysfs_create_groups(desc_data->parent,
   800					     desc_data->attr_groups);
   801		if (status)
 > 802			goto err_free_name;
   803	
   804		char *path __free(kfree) = kasprintf(GFP_KERNEL, "gpio%u/value",
   805						     gpio_chip_hwgpio(desc));
   806		if (!path) {
   807			status = -ENOMEM;
   808			goto err_remove_groups;
   809		}
   810	
   811		desc_data->value_chip_node = kernfs_walk_and_get(desc_data->parent->sd,
   812								 path);
   813		if (!desc_data->value_chip_node) {
   814			status = -ENODEV;
   815			goto err_remove_groups;
   816		}
   817	
   818		return 0;
   819	
   820	err_remove_groups:
   821		sysfs_remove_groups(desc_data->parent, desc_data->attr_groups);
   822	err_free_name:
   823		kfree(desc_data->attr_group.name);
   824	err_put_dirent:
   825		sysfs_put(desc_data->value_class_node);
   826	err_unregister_device:
   827		device_unregister(desc_data->dev);
   828	err_free_data:
   829		kfree(desc_data);
   830	err_clear_bit:
   831		clear_bit(FLAG_EXPORT, &desc->flags);
   832		gpiod_dbg(desc, "%s: status %d\n", __func__, status);
   833		return status;
   834	}
   835	EXPORT_SYMBOL_GPL(gpiod_export);
   836	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

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

* Re: [PATCH v2 8/9] gpio: sysfs: allow disabling the legacy parts of the GPIO sysfs interface
  2025-06-23  8:59 ` [PATCH v2 8/9] gpio: sysfs: allow disabling the legacy parts of the GPIO sysfs interface Bartosz Golaszewski
@ 2025-06-24 11:31   ` Geert Uytterhoeven
  2025-06-24 19:40   ` Linus Walleij
  2025-06-27 11:40   ` kernel test robot
  2 siblings, 0 replies; 31+ messages in thread
From: Geert Uytterhoeven @ 2025-06-24 11:31 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Linus Walleij, linux-gpio, linux-kernel, Bartosz Golaszewski

Hi Bartosz,

On Mon, 23 Jun 2025 at 11:01, Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> Add a Kconfig switch allowing to disable the legacy parts of the GPIO
> sysfs interface. This means that even though we keep the
> /sys/class/gpio/ directory, it no longer contains the global
> export/unexport attribute pair (instead, the user should use the
> per-chip export/unpexport) nor the gpiochip$BASE entries. This option
> default to y if GPIO sysfs is enabled but we'll default it to n at some
> point in the future.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Thanks for your patch!

> --- a/drivers/gpio/gpiolib-sysfs.c
> +++ b/drivers/gpio/gpiolib-sysfs.c

> @@ -968,6 +994,7 @@ int gpiochip_sysfs_register(struct gpio_device *gdev)
>
>         guard(mutex)(&sysfs_lock);
>
> +#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY)
>         /* use chip->base for the ID; it's already known to be unique */
>         data->cdev_base = device_create_with_groups(&gpio_class, parent,
>                                                     MKDEV(0, 0), data,
> @@ -979,13 +1006,16 @@ int gpiochip_sysfs_register(struct gpio_device *gdev)
>                 kfree(data);
>                 return err;
>         }
> +#endif /* CONFIG_GPIO_SYSFS_LEGACY */

"err" is always declared, but only used in this block.
Hence if CONFIG_GPIO_SYSFS_LEGACY=n:

    drivers/gpio/gpiolib-sysfs.c: In function ‘gpiochip_sysfs_register’:
    drivers/gpio/gpiolib-sysfs.c:962:13: error: unused variable ‘err’
[-Werror=unused-variable]
      962 |         int err;
          |             ^~~

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* Re: [PATCH v2 3/9] gpio: sysfs: pass gpiod_data directly to internal GPIO sysfs functions
  2025-06-23  8:59 ` [PATCH v2 3/9] gpio: sysfs: pass gpiod_data directly to internal GPIO sysfs functions Bartosz Golaszewski
@ 2025-06-24 19:32   ` Linus Walleij
  2025-06-27 15:37   ` Andy Shevchenko
  1 sibling, 0 replies; 31+ messages in thread
From: Linus Walleij @ 2025-06-24 19:32 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, linux-gpio, linux-kernel, Bartosz Golaszewski

On Mon, Jun 23, 2025 at 11:00 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> To make the transition to not using dev_get_drvdata() across line
> callbacks for sysfs attributes, pass gpiod_data directly to
> gpio_sysfs_request_irq(), gpio_sysfs_free_irq() and
> gpio_sysfs_set_active_low() instead of having it wrapped in struct
> device.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

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

* Re: [PATCH v2 4/9] gpio: sysfs: don't use driver data in sysfs callbacks for line attributes
  2025-06-23  8:59 ` [PATCH v2 4/9] gpio: sysfs: don't use driver data in sysfs callbacks for line attributes Bartosz Golaszewski
@ 2025-06-24 19:33   ` Linus Walleij
  2025-06-27 15:41   ` Andy Shevchenko
  1 sibling, 0 replies; 31+ messages in thread
From: Linus Walleij @ 2025-06-24 19:33 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, linux-gpio, linux-kernel, Bartosz Golaszewski

On Mon, Jun 23, 2025 at 11:00 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> Currently each exported GPIO is represented in sysfs as a separate class
> device. This allows us to simply use dev_get_drvdata() to retrieve the
> pointer passed to device_create_with_groups() from sysfs ops callbacks.
>
> However, we're preparing to add a parallel set of per-line sysfs
> attributes that will live inside the associated gpiochip group. They are
> not registered as class devices and so have the parent device passed as
> argument to their callbacks (the GPIO chip class device).
>
> Put the attribute structs inside the GPIO descriptor data and
> dereference the relevant ones using container_of() in the callbacks.
> This way, we'll be able to reuse the same code for both the legacy and
> new GPIO attributes.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

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

* Re: [PATCH v2 5/9] gpio: sysfs: rename the data variable in gpiod_(un)export()
  2025-06-23  8:59 ` [PATCH v2 5/9] gpio: sysfs: rename the data variable in gpiod_(un)export() Bartosz Golaszewski
@ 2025-06-24 19:34   ` Linus Walleij
  2025-06-27 15:43   ` Andy Shevchenko
  1 sibling, 0 replies; 31+ messages in thread
From: Linus Walleij @ 2025-06-24 19:34 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, linux-gpio, linux-kernel, Bartosz Golaszewski

On Mon, Jun 23, 2025 at 11:00 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> In preparation for future commits which will make use of descriptor AND
> GPIO-device data in the same functions rename the former from data to
> desc_data separately which will make future changes smaller and easier
> to read.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

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

* Re: [PATCH v2 6/9] gpio: sysfs: don't look up exported lines as class devices
  2025-06-23  8:59 ` [PATCH v2 6/9] gpio: sysfs: don't look up exported lines as class devices Bartosz Golaszewski
@ 2025-06-24 19:34   ` Linus Walleij
  2025-06-27 15:47   ` Andy Shevchenko
  1 sibling, 0 replies; 31+ messages in thread
From: Linus Walleij @ 2025-06-24 19:34 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, linux-gpio, linux-kernel, Bartosz Golaszewski

On Mon, Jun 23, 2025 at 11:00 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> In preparation for adding a parallel, per-chip attribute group for
> exported GPIO lines, stop using class device APIs to refer to it in the
> code. When unregistering the chip, don't call class_find_device() but
> instead store exported lines in a linked list inside the GPIO chip data
> object and look it up there.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

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

* Re: [PATCH v2 8/9] gpio: sysfs: allow disabling the legacy parts of the GPIO sysfs interface
  2025-06-23  8:59 ` [PATCH v2 8/9] gpio: sysfs: allow disabling the legacy parts of the GPIO sysfs interface Bartosz Golaszewski
  2025-06-24 11:31   ` Geert Uytterhoeven
@ 2025-06-24 19:40   ` Linus Walleij
  2025-06-27 11:40   ` kernel test robot
  2 siblings, 0 replies; 31+ messages in thread
From: Linus Walleij @ 2025-06-24 19:40 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, linux-gpio, linux-kernel, Bartosz Golaszewski

On Mon, Jun 23, 2025 at 11:00 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> Add a Kconfig switch allowing to disable the legacy parts of the GPIO
> sysfs interface. This means that even though we keep the
> /sys/class/gpio/ directory, it no longer contains the global
> export/unexport attribute pair (instead, the user should use the
> per-chip export/unpexport) nor the gpiochip$BASE entries. This option
> default to y if GPIO sysfs is enabled but we'll default it to n at some
> point in the future.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

This is great.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

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

* Re: [PATCH v2 8/9] gpio: sysfs: allow disabling the legacy parts of the GPIO sysfs interface
  2025-06-23  8:59 ` [PATCH v2 8/9] gpio: sysfs: allow disabling the legacy parts of the GPIO sysfs interface Bartosz Golaszewski
  2025-06-24 11:31   ` Geert Uytterhoeven
  2025-06-24 19:40   ` Linus Walleij
@ 2025-06-27 11:40   ` kernel test robot
  2 siblings, 0 replies; 31+ messages in thread
From: kernel test robot @ 2025-06-27 11:40 UTC (permalink / raw)
  To: Bartosz Golaszewski, Ahmad Fatoum, Kent Gibson, Jan Lübbe,
	Marek Vasut, Geert Uytterhoeven, Linus Walleij
  Cc: llvm, oe-kbuild-all, linux-gpio, linux-kernel

Hi Bartosz,

kernel test robot noticed the following build warnings:

[auto build test WARNING on cb908f3699fb137e28017a8fdf506c35762b3eb6]

url:    https://github.com/intel-lab-lkp/linux/commits/Bartosz-Golaszewski/gpio-sysfs-add-a-parallel-class-device-for-each-GPIO-chip-using-device-IDs/20250623-170412
base:   cb908f3699fb137e28017a8fdf506c35762b3eb6
patch link:    https://lore.kernel.org/r/20250623-gpio-sysfs-chip-export-v2-8-d592793f8964%40linaro.org
patch subject: [PATCH v2 8/9] gpio: sysfs: allow disabling the legacy parts of the GPIO sysfs interface
config: s390-randconfig-002-20250627 (https://download.01.org/0day-ci/archive/20250627/202506271940.T2QaCrba-lkp@intel.com/config)
compiler: clang version 21.0.0git (https://github.com/llvm/llvm-project e04c938cc08a90ae60440ce22d072ebc69d67ee8)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250627/202506271940.T2QaCrba-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202506271940.T2QaCrba-lkp@intel.com/

All warnings (new ones prefixed by >>):

   drivers/gpio/gpiolib-sysfs.c:818:3: error: cannot jump from this goto statement to its label
     818 |                 goto err_free_name;
         |                 ^
   drivers/gpio/gpiolib-sysfs.c:820:8: note: jump bypasses initialization of variable with __attribute__((cleanup))
     820 |         char *path __free(kfree) = kasprintf(GFP_KERNEL, "gpio%u/value",
         |               ^
   drivers/gpio/gpiolib-sysfs.c:811:3: error: cannot jump from this goto statement to its label
     811 |                 goto err_put_dirent;
         |                 ^
   drivers/gpio/gpiolib-sysfs.c:820:8: note: jump bypasses initialization of variable with __attribute__((cleanup))
     820 |         char *path __free(kfree) = kasprintf(GFP_KERNEL, "gpio%u/value",
         |               ^
   drivers/gpio/gpiolib-sysfs.c:802:3: error: cannot jump from this goto statement to its label
     802 |                 goto err_put_dirent;
         |                 ^
   drivers/gpio/gpiolib-sysfs.c:820:8: note: jump bypasses initialization of variable with __attribute__((cleanup))
     820 |         char *path __free(kfree) = kasprintf(GFP_KERNEL, "gpio%u/value",
         |               ^
   drivers/gpio/gpiolib-sysfs.c:747:3: error: cannot jump from this goto statement to its label
     747 |                 goto err_clear_bit;
         |                 ^
   drivers/gpio/gpiolib-sysfs.c:820:8: note: jump bypasses initialization of variable with __attribute__((cleanup))
     820 |         char *path __free(kfree) = kasprintf(GFP_KERNEL, "gpio%u/value",
         |               ^
   drivers/gpio/gpiolib-sysfs.c:741:3: error: cannot jump from this goto statement to its label
     741 |                 goto err_clear_bit;
         |                 ^
   drivers/gpio/gpiolib-sysfs.c:820:8: note: jump bypasses initialization of variable with __attribute__((cleanup))
     820 |         char *path __free(kfree) = kasprintf(GFP_KERNEL, "gpio%u/value",
         |               ^
>> drivers/gpio/gpiolib-sysfs.c:962:6: warning: unused variable 'err' [-Wunused-variable]
     962 |         int err;
         |             ^~~
   1 warning and 5 errors generated.


vim +/err +962 drivers/gpio/gpiolib-sysfs.c

65fbd24108991d Bartosz Golaszewski 2025-06-23  798  
574194e59098d9 Bartosz Golaszewski 2025-06-23  799  	gdev_data = gdev_get_data(gdev);
574194e59098d9 Bartosz Golaszewski 2025-06-23  800  	if (!gdev_data) {
574194e59098d9 Bartosz Golaszewski 2025-06-23  801  		status = -ENODEV;
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  802  		goto err_put_dirent;
574194e59098d9 Bartosz Golaszewski 2025-06-23  803  	}
574194e59098d9 Bartosz Golaszewski 2025-06-23  804  
574194e59098d9 Bartosz Golaszewski 2025-06-23  805  	list_add(&desc_data->list, &gdev_data->exported_lines);
574194e59098d9 Bartosz Golaszewski 2025-06-23  806  
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  807  	desc_data->attr_group.name = kasprintf(GFP_KERNEL, "gpio%u",
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  808  					       gpio_chip_hwgpio(desc));
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  809  	if (!desc_data->attr_group.name) {
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  810  		status = -ENOMEM;
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  811  		goto err_put_dirent;
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  812  	}
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  813  
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  814  	desc_data->parent = &gdev_data->cdev_id->kobj;
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  815  	status = sysfs_create_groups(desc_data->parent,
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  816  				     desc_data->attr_groups);
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  817  	if (status)
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  818  		goto err_free_name;
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  819  
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23 @820  	char *path __free(kfree) = kasprintf(GFP_KERNEL, "gpio%u/value",
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  821  					     gpio_chip_hwgpio(desc));
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  822  	if (!path) {
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  823  		status = -ENOMEM;
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  824  		goto err_remove_groups;
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  825  	}
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  826  
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  827  	desc_data->value_chip_node = kernfs_walk_and_get(desc_data->parent->sd,
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  828  							 path);
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  829  	if (!desc_data->value_chip_node) {
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  830  		status = -ENODEV;
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  831  		goto err_remove_groups;
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  832  	}
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  833  
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  834  	return 0;
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  835  
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  836  err_remove_groups:
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  837  	sysfs_remove_groups(desc_data->parent, desc_data->attr_groups);
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  838  err_free_name:
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  839  	kfree(desc_data->attr_group.name);
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  840  err_put_dirent:
d6fe296d76af3f Bartosz Golaszewski 2025-06-23  841  #if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY)
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  842  	sysfs_put(desc_data->value_class_node);
65fbd24108991d Bartosz Golaszewski 2025-06-23  843  err_unregister_device:
574194e59098d9 Bartosz Golaszewski 2025-06-23  844  	device_unregister(desc_data->dev);
c43960fbcc514b Johan Hovold        2015-05-04  845  err_free_data:
d6fe296d76af3f Bartosz Golaszewski 2025-06-23  846  #endif /* CONFIG_GPIO_SYSFS_LEGACY */
d54627a4c4f9a8 Bartosz Golaszewski 2025-06-23  847  	kfree(desc_data);
f4af1671c28854 Bartosz Golaszewski 2024-10-31  848  err_clear_bit:
35b545332b809a Bartosz Golaszewski 2024-01-12  849  	clear_bit(FLAG_EXPORT, &desc->flags);
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  850  	gpiod_dbg(desc, "%s: status %d\n", __func__, status);
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  851  	return status;
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  852  }
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  853  EXPORT_SYMBOL_GPL(gpiod_export);
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  854  
d6fe296d76af3f Bartosz Golaszewski 2025-06-23  855  #if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY)
c43960fbcc514b Johan Hovold        2015-05-04  856  static int match_export(struct device *dev, const void *desc)
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  857  {
c43960fbcc514b Johan Hovold        2015-05-04  858  	struct gpiod_data *data = dev_get_drvdata(dev);
c43960fbcc514b Johan Hovold        2015-05-04  859  
c43960fbcc514b Johan Hovold        2015-05-04  860  	return data->desc == desc;
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  861  }
d6fe296d76af3f Bartosz Golaszewski 2025-06-23  862  #endif /* CONFIG_GPIO_SYSFS_LEGACY */
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  863  
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  864  /**
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  865   * gpiod_export_link - create a sysfs link to an exported GPIO node
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  866   * @dev: device under which to create symlink
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  867   * @name: name of the symlink
2d9d05192e7d1a Thierry Reding      2017-07-24  868   * @desc: GPIO to create symlink to, already exported
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  869   *
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  870   * Set up a symlink from /sys/.../dev/name to /sys/class/gpio/gpioN
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  871   * node. Caller is responsible for unlinking.
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  872   *
94bd9ce16063a2 Andy Shevchenko     2024-08-28  873   * Returns:
94bd9ce16063a2 Andy Shevchenko     2024-08-28  874   * 0 on success, or negative errno on failure.
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  875   */
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  876  int gpiod_export_link(struct device *dev, const char *name,
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  877  		      struct gpio_desc *desc)
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  878  {
d6fe296d76af3f Bartosz Golaszewski 2025-06-23  879  #if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY)
56d30ec14c1330 Johan Hovold        2015-05-04  880  	struct device *cdev;
56d30ec14c1330 Johan Hovold        2015-05-04  881  	int ret;
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  882  
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  883  	if (!desc) {
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  884  		pr_warn("%s: invalid GPIO\n", __func__);
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  885  		return -EINVAL;
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  886  	}
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  887  
56d30ec14c1330 Johan Hovold        2015-05-04  888  	cdev = class_find_device(&gpio_class, NULL, desc, match_export);
56d30ec14c1330 Johan Hovold        2015-05-04  889  	if (!cdev)
56d30ec14c1330 Johan Hovold        2015-05-04  890  		return -ENODEV;
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  891  
56d30ec14c1330 Johan Hovold        2015-05-04  892  	ret = sysfs_create_link(&dev->kobj, &cdev->kobj, name);
56d30ec14c1330 Johan Hovold        2015-05-04  893  	put_device(cdev);
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  894  
56d30ec14c1330 Johan Hovold        2015-05-04  895  	return ret;
d6fe296d76af3f Bartosz Golaszewski 2025-06-23  896  #else
d6fe296d76af3f Bartosz Golaszewski 2025-06-23  897  	return -EOPNOTSUPP;
d6fe296d76af3f Bartosz Golaszewski 2025-06-23  898  #endif /* CONFIG_GPIO_SYSFS_LEGACY */
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  899  }
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  900  EXPORT_SYMBOL_GPL(gpiod_export_link);
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  901  
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  902  /**
31963eb039b7d5 Amitesh Singh       2016-09-08  903   * gpiod_unexport - reverse effect of gpiod_export()
2d9d05192e7d1a Thierry Reding      2017-07-24  904   * @desc: GPIO to make unavailable
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  905   *
31963eb039b7d5 Amitesh Singh       2016-09-08  906   * This is implicit on gpiod_free().
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  907   */
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  908  void gpiod_unexport(struct gpio_desc *desc)
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  909  {
574194e59098d9 Bartosz Golaszewski 2025-06-23  910  	struct gpiod_data *desc_data = NULL;
574194e59098d9 Bartosz Golaszewski 2025-06-23  911  	struct gpiodev_data *gdev_data;
574194e59098d9 Bartosz Golaszewski 2025-06-23  912  	struct gpio_device *gdev;
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  913  
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  914  	if (!desc) {
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  915  		pr_warn("%s: invalid GPIO\n", __func__);
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  916  		return;
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  917  	}
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  918  
f4af1671c28854 Bartosz Golaszewski 2024-10-31  919  	scoped_guard(mutex, &sysfs_lock) {
72eba6f66a0017 Johan Hovold        2015-05-04  920  		if (!test_bit(FLAG_EXPORT, &desc->flags))
f4af1671c28854 Bartosz Golaszewski 2024-10-31  921  			return;
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  922  
574194e59098d9 Bartosz Golaszewski 2025-06-23  923  		gdev = gpiod_to_gpio_device(desc);
574194e59098d9 Bartosz Golaszewski 2025-06-23  924  		gdev_data = gdev_get_data(gdev);
574194e59098d9 Bartosz Golaszewski 2025-06-23  925  		if (!gdev_data)
574194e59098d9 Bartosz Golaszewski 2025-06-23  926  			return;
574194e59098d9 Bartosz Golaszewski 2025-06-23  927  
574194e59098d9 Bartosz Golaszewski 2025-06-23  928  		list_for_each_entry(desc_data, &gdev_data->exported_lines, list)
574194e59098d9 Bartosz Golaszewski 2025-06-23  929  			if (desc == desc_data->desc)
574194e59098d9 Bartosz Golaszewski 2025-06-23  930  				break;
574194e59098d9 Bartosz Golaszewski 2025-06-23  931  
574194e59098d9 Bartosz Golaszewski 2025-06-23  932  		if (!desc_data)
f4af1671c28854 Bartosz Golaszewski 2024-10-31  933  			return;
72eba6f66a0017 Johan Hovold        2015-05-04  934  
574194e59098d9 Bartosz Golaszewski 2025-06-23  935  		list_del(&desc_data->list);
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  936  		clear_bit(FLAG_EXPORT, &desc->flags);
d6fe296d76af3f Bartosz Golaszewski 2025-06-23  937  #if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY)
d54627a4c4f9a8 Bartosz Golaszewski 2025-06-23  938  		sysfs_put(desc_data->value_class_node);
574194e59098d9 Bartosz Golaszewski 2025-06-23  939  		device_unregister(desc_data->dev);
d6fe296d76af3f Bartosz Golaszewski 2025-06-23  940  #endif /* CONFIG_GPIO_SYSFS_LEGACY */
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  941  		sysfs_remove_groups(desc_data->parent, desc_data->attr_groups);
d65a6b43cccca4 Bartosz Golaszewski 2025-06-23  942  		kernfs_put(desc_data->value_chip_node);
72eba6f66a0017 Johan Hovold        2015-05-04  943  
54d9acd7540995 Johan Hovold        2015-05-04  944  		/*
f4af1671c28854 Bartosz Golaszewski 2024-10-31  945  		 * Release irq after deregistration to prevent race with
f4af1671c28854 Bartosz Golaszewski 2024-10-31  946  		 * edge_store.
54d9acd7540995 Johan Hovold        2015-05-04  947  		 */
d54627a4c4f9a8 Bartosz Golaszewski 2025-06-23  948  		if (desc_data->irq_flags)
d54627a4c4f9a8 Bartosz Golaszewski 2025-06-23  949  			gpio_sysfs_free_irq(desc_data);
f4af1671c28854 Bartosz Golaszewski 2024-10-31  950  	}
72eba6f66a0017 Johan Hovold        2015-05-04  951  
d54627a4c4f9a8 Bartosz Golaszewski 2025-06-23  952  	mutex_destroy(&desc_data->mutex);
d54627a4c4f9a8 Bartosz Golaszewski 2025-06-23  953  	kfree(desc_data);
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  954  }
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  955  EXPORT_SYMBOL_GPL(gpiod_unexport);
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  956  
afbc4f312b5e6e Linus Walleij       2016-02-09  957  int gpiochip_sysfs_register(struct gpio_device *gdev)
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  958  {
fd19792851db77 Bartosz Golaszewski 2025-06-10  959  	struct gpiodev_data *data;
d83cee3d2bb131 Bartosz Golaszewski 2024-01-23  960  	struct gpio_chip *chip;
513246a34b8dc5 Bartosz Golaszewski 2023-12-21  961  	struct device *parent;
e6bb78570f7d53 Antonio Quartulli   2025-06-23 @962  	int err;
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  963  
426577bd8846d6 Johan Hovold        2015-05-04  964  	/*
426577bd8846d6 Johan Hovold        2015-05-04  965  	 * Many systems add gpio chips for SOC support very early,
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  966  	 * before driver model support is available.  In those cases we
426577bd8846d6 Johan Hovold        2015-05-04  967  	 * register later, in gpiolib_sysfs_init() ... here we just
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  968  	 * verify that _some_ field of gpio_class got initialized.
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  969  	 */
6f14c02220c791 Greg Kroah-Hartman  2023-03-31  970  	if (!class_is_registered(&gpio_class))
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  971  		return 0;
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  972  
d83cee3d2bb131 Bartosz Golaszewski 2024-01-23  973  	guard(srcu)(&gdev->srcu);
d83cee3d2bb131 Bartosz Golaszewski 2024-01-23  974  
d82b9e0887e69d Bartosz Golaszewski 2024-02-14  975  	chip = srcu_dereference(gdev->chip, &gdev->srcu);
d83cee3d2bb131 Bartosz Golaszewski 2024-01-23  976  	if (!chip)
d83cee3d2bb131 Bartosz Golaszewski 2024-01-23  977  		return -ENODEV;
d83cee3d2bb131 Bartosz Golaszewski 2024-01-23  978  
d27c17285eb7eb Bamvor Jian Zhang   2016-02-24  979  	/*
d27c17285eb7eb Bamvor Jian Zhang   2016-02-24  980  	 * For sysfs backward compatibility we need to preserve this
d27c17285eb7eb Bamvor Jian Zhang   2016-02-24  981  	 * preferred parenting to the gpio_chip parent field, if set.
d27c17285eb7eb Bamvor Jian Zhang   2016-02-24  982  	 */
d27c17285eb7eb Bamvor Jian Zhang   2016-02-24  983  	if (chip->parent)
d27c17285eb7eb Bamvor Jian Zhang   2016-02-24  984  		parent = chip->parent;
d27c17285eb7eb Bamvor Jian Zhang   2016-02-24  985  	else
d27c17285eb7eb Bamvor Jian Zhang   2016-02-24  986  		parent = &gdev->dev;
d27c17285eb7eb Bamvor Jian Zhang   2016-02-24  987  
fd19792851db77 Bartosz Golaszewski 2025-06-10  988  	data = kmalloc(sizeof(*data), GFP_KERNEL);
fd19792851db77 Bartosz Golaszewski 2025-06-10  989  	if (!data)
fd19792851db77 Bartosz Golaszewski 2025-06-10  990  		return -ENOMEM;
fd19792851db77 Bartosz Golaszewski 2025-06-10  991  
fd19792851db77 Bartosz Golaszewski 2025-06-10  992  	data->gdev = gdev;
574194e59098d9 Bartosz Golaszewski 2025-06-23  993  	INIT_LIST_HEAD(&data->exported_lines);
3ff74be5c1a72d Johan Hovold        2015-05-04  994  
f4af1671c28854 Bartosz Golaszewski 2024-10-31  995  	guard(mutex)(&sysfs_lock);
fd19792851db77 Bartosz Golaszewski 2025-06-10  996  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

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

* Re: [PATCH v2 1/9] gpio: sysfs: add a parallel class device for each GPIO chip using device IDs
  2025-06-23  8:59 ` [PATCH v2 1/9] gpio: sysfs: add a parallel class device for each GPIO chip using device IDs Bartosz Golaszewski
@ 2025-06-27 15:21   ` Andy Shevchenko
  2025-06-30  8:34     ` Bartosz Golaszewski
  0 siblings, 1 reply; 31+ messages in thread
From: Andy Shevchenko @ 2025-06-27 15:21 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, Linus Walleij, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Mon, Jun 23, 2025 at 10:59:49AM +0200, Bartosz Golaszewski wrote:
> 
> In order to enable moving away from the global GPIO numberspace-based
> exporting of lines over sysfs: add a parallel, per-chip entry under
> /sys/class/gpio/ for every registered GPIO chip, denoted by device ID
> in the file name and not its base GPIO number.
> 
> Compared to the existing chip group: it does not contain the "base"
> attribute as the goal of this change is to not refer to GPIOs by their
> global number from user-space anymore. It also contains its own,
> per-chip export/unexport attribute pair which allow to export lines by
> their hardware offset within the chip.
> 
> Caveat #1: the new device cannot be a link to (or be linked to by) the
> existing "gpiochip<BASE>" entry as we cannot create links in
> /sys/class/xyz/.
> 
> Caveat #2: the new entry cannot be named "gpiochipX" as it could
> conflict with devices whose base is statically defined to a low number.
> Let's go with "chipX" instead.
> 
> While at it: the chip label is unique so update the untrue statement
> when extending the docs.

...

>  struct gpiodev_data {
>  	struct gpio_device *gdev;
>  	struct device *cdev_base; /* Class device by GPIO base */
> +	struct device *cdev_id; /* Class device by GPIO device ID */

I would add it in the middle in a way of the possible drop or conditional
compiling of the legacy access in the future.

>  };

...

> +static int export_gpio_desc(struct gpio_desc *desc)
> +{
> +	int offset, ret;

Why offset is signed?

> +	CLASS(gpio_chip_guard, guard)(desc);
> +	if (!guard.gc)
> +		return -ENODEV;
> +
> +	offset = gpio_chip_hwgpio(desc);
> +	if (!gpiochip_line_is_valid(guard.gc, offset)) {
> +		pr_debug_ratelimited("%s: GPIO %d masked\n", __func__,
> +				     gpio_chip_hwgpio(desc));

Can we use gdev here? (IIRC we can't due to some legacy corner cases)

> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * No extra locking here; FLAG_SYSFS just signifies that the
> +	 * request and export were done by on behalf of userspace, so
> +	 * they may be undone on its behalf too.
> +	 */
> +
> +	ret = gpiod_request_user(desc, "sysfs");
> +	if (ret)
> +		return ret;
> +
> +	ret = gpiod_set_transitory(desc, false);
> +	if (ret) {
> +		gpiod_free(desc);
> +		return ret;
> +	}
> +
> +	ret = gpiod_export(desc, true);
> +	if (ret < 0) {
> +		gpiod_free(desc);
> +	} else {
> +		set_bit(FLAG_SYSFS, &desc->flags);
> +		gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_REQUESTED);
> +	}
> +
> +	return ret;
> +}

...

> +static struct device_attribute dev_attr_export = __ATTR(export, 0200, NULL,
> +							chip_export_store);

__ATTR_WO()

...

> +static struct device_attribute dev_attr_unexport = __ATTR(unexport, 0200,
> +							  NULL,
> +							  chip_unexport_store);

Ditto.

...

> +static struct attribute *gpiochip_ext_attrs[] = {
> +	&dev_attr_label.attr,
> +	&dev_attr_ngpio.attr,
> +	&dev_attr_export.attr,
> +	&dev_attr_unexport.attr,
> +	NULL,

No comma for the terminator, please.

> +};

...

> +	data->cdev_id = device_create_with_groups(&gpio_class, parent,
> +						  MKDEV(0, 0), data,
> +						  gpiochip_ext_groups,
> +						  "chip%d", gdev->id);
> +	if (IS_ERR(data->cdev_id)) {
> +		device_unregister(data->cdev_base);
> +		kfree(data);

UAF

> +		return PTR_ERR(data->cdev_id);
> +	}

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v2 2/9] gpio: sysfs: only get the dirent reference for the value attr once
  2025-06-23  8:59 ` [PATCH v2 2/9] gpio: sysfs: only get the dirent reference for the value attr once Bartosz Golaszewski
@ 2025-06-27 15:35   ` Andy Shevchenko
  2025-06-30  8:41     ` Bartosz Golaszewski
  0 siblings, 1 reply; 31+ messages in thread
From: Andy Shevchenko @ 2025-06-27 15:35 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, Linus Walleij, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Mon, Jun 23, 2025 at 10:59:50AM +0200, Bartosz Golaszewski wrote:
> 
> There's no reason to retrieve the reference to the sysfs dirent every
> time we request an interrupt, we can as well only do it once when
> exporting the GPIO.

...

> -	struct kernfs_node *value_kn;
> +	struct kernfs_node *value_class_node;

This change is not mentioned in the commit message. Why?

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v2 3/9] gpio: sysfs: pass gpiod_data directly to internal GPIO sysfs functions
  2025-06-23  8:59 ` [PATCH v2 3/9] gpio: sysfs: pass gpiod_data directly to internal GPIO sysfs functions Bartosz Golaszewski
  2025-06-24 19:32   ` Linus Walleij
@ 2025-06-27 15:37   ` Andy Shevchenko
  1 sibling, 0 replies; 31+ messages in thread
From: Andy Shevchenko @ 2025-06-27 15:37 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, Linus Walleij, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Mon, Jun 23, 2025 at 10:59:51AM +0200, Bartosz Golaszewski wrote:
> 
> To make the transition to not using dev_get_drvdata() across line
> callbacks for sysfs attributes, pass gpiod_data directly to
> gpio_sysfs_request_irq(), gpio_sysfs_free_irq() and
> gpio_sysfs_set_active_low() instead of having it wrapped in struct
> device.

I would improve the commit message by mentioning why using data over dev is
better. Something like "since we do not use anything from dev, pass the data
object pointer ...".


-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v2 4/9] gpio: sysfs: don't use driver data in sysfs callbacks for line attributes
  2025-06-23  8:59 ` [PATCH v2 4/9] gpio: sysfs: don't use driver data in sysfs callbacks for line attributes Bartosz Golaszewski
  2025-06-24 19:33   ` Linus Walleij
@ 2025-06-27 15:41   ` Andy Shevchenko
  2025-06-30  8:57     ` Bartosz Golaszewski
  1 sibling, 1 reply; 31+ messages in thread
From: Andy Shevchenko @ 2025-06-27 15:41 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, Linus Walleij, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Mon, Jun 23, 2025 at 10:59:52AM +0200, Bartosz Golaszewski wrote:
> 
> Currently each exported GPIO is represented in sysfs as a separate class
> device. This allows us to simply use dev_get_drvdata() to retrieve the
> pointer passed to device_create_with_groups() from sysfs ops callbacks.
> 
> However, we're preparing to add a parallel set of per-line sysfs
> attributes that will live inside the associated gpiochip group. They are
> not registered as class devices and so have the parent device passed as
> argument to their callbacks (the GPIO chip class device).
> 
> Put the attribute structs inside the GPIO descriptor data and
> dereference the relevant ones using container_of() in the callbacks.
> This way, we'll be able to reuse the same code for both the legacy and
> new GPIO attributes.

...

> -	struct gpiod_data *data = dev_get_drvdata(dev);
> +	struct gpiod_data *data = container_of(attr, struct gpiod_data,
> +					       dir_attr);

Defining once something like

#define to_gpiod_data() ...

we may leave this and others as one-liners.

...

> +	attrs[GPIO_SYSFS_LINE_ATTR_ACTIVE_LOW] =
> +						&data->active_low_attr.attr;

What's the point of two lines here?

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v2 5/9] gpio: sysfs: rename the data variable in gpiod_(un)export()
  2025-06-23  8:59 ` [PATCH v2 5/9] gpio: sysfs: rename the data variable in gpiod_(un)export() Bartosz Golaszewski
  2025-06-24 19:34   ` Linus Walleij
@ 2025-06-27 15:43   ` Andy Shevchenko
  2025-06-30  8:57     ` Bartosz Golaszewski
  1 sibling, 1 reply; 31+ messages in thread
From: Andy Shevchenko @ 2025-06-27 15:43 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, Linus Walleij, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Mon, Jun 23, 2025 at 10:59:53AM +0200, Bartosz Golaszewski wrote:
> 
> In preparation for future commits which will make use of descriptor AND
> GPIO-device data in the same functions rename the former from data to
> desc_data separately which will make future changes smaller and easier
> to read.

...

> +	attrs = desc_data->attrs;
> +	desc_data->attr_group.is_visible = gpio_is_visible;
> +	attrs[GPIO_SYSFS_LINE_ATTR_DIRECTION] = &desc_data->dir_attr.attr;
> +	attrs[GPIO_SYSFS_LINE_ATTR_VALUE] = &desc_data->val_attr.attr;
> +	attrs[GPIO_SYSFS_LINE_ATTR_EDGE] = &desc_data->edge_attr.attr;
>  	attrs[GPIO_SYSFS_LINE_ATTR_ACTIVE_LOW] =
> -						&data->active_low_attr.attr;
> +				&desc_data->active_low_attr.attr;

These were added in the previous patch and immediately got rewritten?!
Sounds like a wrong patch order.

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v2 6/9] gpio: sysfs: don't look up exported lines as class devices
  2025-06-23  8:59 ` [PATCH v2 6/9] gpio: sysfs: don't look up exported lines as class devices Bartosz Golaszewski
  2025-06-24 19:34   ` Linus Walleij
@ 2025-06-27 15:47   ` Andy Shevchenko
  1 sibling, 0 replies; 31+ messages in thread
From: Andy Shevchenko @ 2025-06-27 15:47 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, Linus Walleij, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Mon, Jun 23, 2025 at 10:59:54AM +0200, Bartosz Golaszewski wrote:
> 
> In preparation for adding a parallel, per-chip attribute group for
> exported GPIO lines, stop using class device APIs to refer to it in the
> code. When unregistering the chip, don't call class_find_device() but
> instead store exported lines in a linked list inside the GPIO chip data
> object and look it up there.

...

> +	struct list_head list;
>  };

If you make this to be the first member, you may make the container_of() (from
list_entry APIs) to be no-op. Have you checked with bloat-o-meter the difference?

...

> +	struct list_head exported_lines;
>  };

Ditto.


...

> -	desc_data->value_class_node = sysfs_get_dirent(dev->kobj.sd, "value");
> +	desc_data->value_class_node = sysfs_get_dirent(desc_data->dev->kobj.sd,
> +						       "value");

In such cases I find the following style to be slightly better to read.

	desc_data->value_class_node =
			sysfs_get_dirent(desc_data->dev->kobj.sd, "value");

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v2 1/9] gpio: sysfs: add a parallel class device for each GPIO chip using device IDs
  2025-06-27 15:21   ` Andy Shevchenko
@ 2025-06-30  8:34     ` Bartosz Golaszewski
  2025-06-30  9:16       ` Andy Shevchenko
  0 siblings, 1 reply; 31+ messages in thread
From: Bartosz Golaszewski @ 2025-06-30  8:34 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, Linus Walleij, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Fri, Jun 27, 2025 at 5:21 PM Andy Shevchenko
<andriy.shevchenko@intel.com> wrote:
>
> On Mon, Jun 23, 2025 at 10:59:49AM +0200, Bartosz Golaszewski wrote:
> >
> > In order to enable moving away from the global GPIO numberspace-based
> > exporting of lines over sysfs: add a parallel, per-chip entry under
> > /sys/class/gpio/ for every registered GPIO chip, denoted by device ID
> > in the file name and not its base GPIO number.
> >
> > Compared to the existing chip group: it does not contain the "base"
> > attribute as the goal of this change is to not refer to GPIOs by their
> > global number from user-space anymore. It also contains its own,
> > per-chip export/unexport attribute pair which allow to export lines by
> > their hardware offset within the chip.
> >
> > Caveat #1: the new device cannot be a link to (or be linked to by) the
> > existing "gpiochip<BASE>" entry as we cannot create links in
> > /sys/class/xyz/.
> >
> > Caveat #2: the new entry cannot be named "gpiochipX" as it could
> > conflict with devices whose base is statically defined to a low number.
> > Let's go with "chipX" instead.
> >
> > While at it: the chip label is unique so update the untrue statement
> > when extending the docs.
>
> ...
>
> >  struct gpiodev_data {
> >       struct gpio_device *gdev;
> >       struct device *cdev_base; /* Class device by GPIO base */
> > +     struct device *cdev_id; /* Class device by GPIO device ID */
>
> I would add it in the middle in a way of the possible drop or conditional
> compiling of the legacy access in the future.
>

I'm not sure what difference it makes?

> >  };
>
> ...
>
> > +static int export_gpio_desc(struct gpio_desc *desc)
> > +{
> > +     int offset, ret;
>
> Why offset is signed?
>

Because gpio_chip_hwgpio() returns a signed int.

> > +     CLASS(gpio_chip_guard, guard)(desc);
> > +     if (!guard.gc)
> > +             return -ENODEV;
> > +
> > +     offset = gpio_chip_hwgpio(desc);
> > +     if (!gpiochip_line_is_valid(guard.gc, offset)) {
> > +             pr_debug_ratelimited("%s: GPIO %d masked\n", __func__,
> > +                                  gpio_chip_hwgpio(desc));
>
> Can we use gdev here? (IIRC we can't due to some legacy corner cases)
>

Yeah, I think there was some revert here? In any case: it's material
for a different series, I'm just moving the code here.

> > +             return -EINVAL;
> > +     }
> > +
> > +     /*
> > +      * No extra locking here; FLAG_SYSFS just signifies that the
> > +      * request and export were done by on behalf of userspace, so
> > +      * they may be undone on its behalf too.
> > +      */
> > +
> > +     ret = gpiod_request_user(desc, "sysfs");
> > +     if (ret)
> > +             return ret;
> > +
> > +     ret = gpiod_set_transitory(desc, false);
> > +     if (ret) {
> > +             gpiod_free(desc);
> > +             return ret;
> > +     }
> > +
> > +     ret = gpiod_export(desc, true);
> > +     if (ret < 0) {
> > +             gpiod_free(desc);
> > +     } else {
> > +             set_bit(FLAG_SYSFS, &desc->flags);
> > +             gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_REQUESTED);
> > +     }
> > +
> > +     return ret;
> > +}
>
> ...
>
> > +static struct device_attribute dev_attr_export = __ATTR(export, 0200, NULL,
> > +                                                     chip_export_store);
>
> __ATTR_WO()
>

No can do, the attribute would have to be called "chip_export". A
function called export_store() already exists in this file.

> ...
>
> > +static struct device_attribute dev_attr_unexport = __ATTR(unexport, 0200,
> > +                                                       NULL,
> > +                                                       chip_unexport_store);
>
> Ditto.
>
> ...
>
> > +static struct attribute *gpiochip_ext_attrs[] = {
> > +     &dev_attr_label.attr,
> > +     &dev_attr_ngpio.attr,
> > +     &dev_attr_export.attr,
> > +     &dev_attr_unexport.attr,
> > +     NULL,
>
> No comma for the terminator, please.
>

Ok.

> > +};
>
> ...
>
> > +     data->cdev_id = device_create_with_groups(&gpio_class, parent,
> > +                                               MKDEV(0, 0), data,
> > +                                               gpiochip_ext_groups,
> > +                                               "chip%d", gdev->id);
> > +     if (IS_ERR(data->cdev_id)) {
> > +             device_unregister(data->cdev_base);
> > +             kfree(data);
>
> UAF
>

Ok.

> > +             return PTR_ERR(data->cdev_id);
> > +     }
>
> --
> With Best Regards,
> Andy Shevchenko
>
>

Thanks,
Bart

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

* Re: [PATCH v2 2/9] gpio: sysfs: only get the dirent reference for the value attr once
  2025-06-27 15:35   ` Andy Shevchenko
@ 2025-06-30  8:41     ` Bartosz Golaszewski
  0 siblings, 0 replies; 31+ messages in thread
From: Bartosz Golaszewski @ 2025-06-30  8:41 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, Linus Walleij, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Fri, Jun 27, 2025 at 5:35 PM Andy Shevchenko
<andriy.shevchenko@intel.com> wrote:
>
> On Mon, Jun 23, 2025 at 10:59:50AM +0200, Bartosz Golaszewski wrote:
> >
> > There's no reason to retrieve the reference to the sysfs dirent every
> > time we request an interrupt, we can as well only do it once when
> > exporting the GPIO.
>
> ...
>
> > -     struct kernfs_node *value_kn;
> > +     struct kernfs_node *value_class_node;
>
> This change is not mentioned in the commit message. Why?
>

Yeah, I'll mention it.

Bart

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

* Re: [PATCH v2 4/9] gpio: sysfs: don't use driver data in sysfs callbacks for line attributes
  2025-06-27 15:41   ` Andy Shevchenko
@ 2025-06-30  8:57     ` Bartosz Golaszewski
  2025-06-30 10:05       ` Andy Shevchenko
  0 siblings, 1 reply; 31+ messages in thread
From: Bartosz Golaszewski @ 2025-06-30  8:57 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, Linus Walleij, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Fri, Jun 27, 2025 at 5:41 PM Andy Shevchenko
<andriy.shevchenko@intel.com> wrote:
>
> On Mon, Jun 23, 2025 at 10:59:52AM +0200, Bartosz Golaszewski wrote:
> >
> > Currently each exported GPIO is represented in sysfs as a separate class
> > device. This allows us to simply use dev_get_drvdata() to retrieve the
> > pointer passed to device_create_with_groups() from sysfs ops callbacks.
> >
> > However, we're preparing to add a parallel set of per-line sysfs
> > attributes that will live inside the associated gpiochip group. They are
> > not registered as class devices and so have the parent device passed as
> > argument to their callbacks (the GPIO chip class device).
> >
> > Put the attribute structs inside the GPIO descriptor data and
> > dereference the relevant ones using container_of() in the callbacks.
> > This way, we'll be able to reuse the same code for both the legacy and
> > new GPIO attributes.
>
> ...
>
> > -     struct gpiod_data *data = dev_get_drvdata(dev);
> > +     struct gpiod_data *data = container_of(attr, struct gpiod_data,
> > +                                            dir_attr);
>
> Defining once something like
>
> #define to_gpiod_data() ...
>
> we may leave this and others as one-liners.

We'd need one per every attribute. Look closer, we do get a different
attr address in every pair of callbacks.

>
> ...
>
> > +     attrs[GPIO_SYSFS_LINE_ATTR_ACTIVE_LOW] =
> > +                                             &data->active_low_attr.attr;
>
> What's the point of two lines here?
>

I tend to stick with the 80 chars limit even though it was lifted.

Bart

> --
> With Best Regards,
> Andy Shevchenko
>
>

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

* Re: [PATCH v2 5/9] gpio: sysfs: rename the data variable in gpiod_(un)export()
  2025-06-27 15:43   ` Andy Shevchenko
@ 2025-06-30  8:57     ` Bartosz Golaszewski
  2025-06-30  9:03       ` Bartosz Golaszewski
  0 siblings, 1 reply; 31+ messages in thread
From: Bartosz Golaszewski @ 2025-06-30  8:57 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, Linus Walleij, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Fri, Jun 27, 2025 at 5:43 PM Andy Shevchenko
<andriy.shevchenko@intel.com> wrote:
>
> On Mon, Jun 23, 2025 at 10:59:53AM +0200, Bartosz Golaszewski wrote:
> >
> > In preparation for future commits which will make use of descriptor AND
> > GPIO-device data in the same functions rename the former from data to
> > desc_data separately which will make future changes smaller and easier
> > to read.
>
> ...
>
> > +     attrs = desc_data->attrs;
> > +     desc_data->attr_group.is_visible = gpio_is_visible;
> > +     attrs[GPIO_SYSFS_LINE_ATTR_DIRECTION] = &desc_data->dir_attr.attr;
> > +     attrs[GPIO_SYSFS_LINE_ATTR_VALUE] = &desc_data->val_attr.attr;
> > +     attrs[GPIO_SYSFS_LINE_ATTR_EDGE] = &desc_data->edge_attr.attr;
> >       attrs[GPIO_SYSFS_LINE_ATTR_ACTIVE_LOW] =
> > -                                             &data->active_low_attr.attr;
> > +                             &desc_data->active_low_attr.attr;
>
> These were added in the previous patch and immediately got rewritten?!
> Sounds like a wrong patch order.
>

Yeah, bad rebase. Thanks for catching it.

Bart

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

* Re: [PATCH v2 5/9] gpio: sysfs: rename the data variable in gpiod_(un)export()
  2025-06-30  8:57     ` Bartosz Golaszewski
@ 2025-06-30  9:03       ` Bartosz Golaszewski
  0 siblings, 0 replies; 31+ messages in thread
From: Bartosz Golaszewski @ 2025-06-30  9:03 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, Linus Walleij, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Mon, Jun 30, 2025 at 10:57 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>
> On Fri, Jun 27, 2025 at 5:43 PM Andy Shevchenko
> <andriy.shevchenko@intel.com> wrote:
> >
> > On Mon, Jun 23, 2025 at 10:59:53AM +0200, Bartosz Golaszewski wrote:
> > >
> > > In preparation for future commits which will make use of descriptor AND
> > > GPIO-device data in the same functions rename the former from data to
> > > desc_data separately which will make future changes smaller and easier
> > > to read.
> >
> > ...
> >
> > > +     attrs = desc_data->attrs;
> > > +     desc_data->attr_group.is_visible = gpio_is_visible;
> > > +     attrs[GPIO_SYSFS_LINE_ATTR_DIRECTION] = &desc_data->dir_attr.attr;
> > > +     attrs[GPIO_SYSFS_LINE_ATTR_VALUE] = &desc_data->val_attr.attr;
> > > +     attrs[GPIO_SYSFS_LINE_ATTR_EDGE] = &desc_data->edge_attr.attr;
> > >       attrs[GPIO_SYSFS_LINE_ATTR_ACTIVE_LOW] =
> > > -                                             &data->active_low_attr.attr;
> > > +                             &desc_data->active_low_attr.attr;
> >
> > These were added in the previous patch and immediately got rewritten?!
> > Sounds like a wrong patch order.
> >
>
> Yeah, bad rebase. Thanks for catching it.
>
> Bart

Ah, no actually I got misled by the indentation difference. It was
supposed to be like this but maybe it is better to change places of
those two patches.

Bart

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

* Re: [PATCH v2 1/9] gpio: sysfs: add a parallel class device for each GPIO chip using device IDs
  2025-06-30  8:34     ` Bartosz Golaszewski
@ 2025-06-30  9:16       ` Andy Shevchenko
  0 siblings, 0 replies; 31+ messages in thread
From: Andy Shevchenko @ 2025-06-30  9:16 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, Linus Walleij, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Mon, Jun 30, 2025 at 10:34:52AM +0200, Bartosz Golaszewski wrote:
> On Fri, Jun 27, 2025 at 5:21 PM Andy Shevchenko
> <andriy.shevchenko@intel.com> wrote:
> > On Mon, Jun 23, 2025 at 10:59:49AM +0200, Bartosz Golaszewski wrote:

...

> > >  struct gpiodev_data {
> > >       struct gpio_device *gdev;
> > >       struct device *cdev_base; /* Class device by GPIO base */
> > > +     struct device *cdev_id; /* Class device by GPIO device ID */
> >
> > I would add it in the middle in a way of the possible drop or conditional
> > compiling of the legacy access in the future.
> 
> I'm not sure what difference it makes?

It collects optional (which you do with ifdeffery later on) at the end of the
structure. Maybe there is no effect now, but it might be in the future.

> > >  };

...

> > > +static struct device_attribute dev_attr_export = __ATTR(export, 0200, NULL,
> > > +                                                     chip_export_store);
> >
> > __ATTR_WO()
> >
> 
> No can do, the attribute would have to be called "chip_export". A
> function called export_store() already exists in this file.

I didn't get, we have two "export" nodes implemented in the same file?

...

> > > +static struct device_attribute dev_attr_unexport = __ATTR(unexport, 0200,
> > > +                                                       NULL,
> > > +                                                       chip_unexport_store);
> >
> > Ditto.

Ditto.

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v2 4/9] gpio: sysfs: don't use driver data in sysfs callbacks for line attributes
  2025-06-30  8:57     ` Bartosz Golaszewski
@ 2025-06-30 10:05       ` Andy Shevchenko
  0 siblings, 0 replies; 31+ messages in thread
From: Andy Shevchenko @ 2025-06-30 10:05 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Ahmad Fatoum, Kent Gibson, Jan Lübbe, Marek Vasut,
	Geert Uytterhoeven, Linus Walleij, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Mon, Jun 30, 2025 at 10:57:06AM +0200, Bartosz Golaszewski wrote:
> On Fri, Jun 27, 2025 at 5:41 PM Andy Shevchenko
> <andriy.shevchenko@intel.com> wrote:
> > On Mon, Jun 23, 2025 at 10:59:52AM +0200, Bartosz Golaszewski wrote:

...

> > Defining once something like
> >
> > #define to_gpiod_data() ...
> >
> > we may leave this and others as one-liners.
> 
> We'd need one per every attribute. Look closer, we do get a different
> attr address in every pair of callbacks.

I see, thanks for pointing that out.

...

> > > +     attrs[GPIO_SYSFS_LINE_ATTR_ACTIVE_LOW] =
> > > +                                             &data->active_low_attr.attr;
> >
> > What's the point of two lines here?
> >
> 
> I tend to stick with the 80 chars limit even though it was lifted.

The above looks just ugly. Saving one character on the line here doesn't
justify readability loss.


-- 
With Best Regards,
Andy Shevchenko



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

end of thread, other threads:[~2025-06-30 10:05 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-23  8:59 [PATCH v2 0/9] gpio: sysfs: add a per-chip export/unexport attribute pair Bartosz Golaszewski
2025-06-23  8:59 ` [PATCH v2 1/9] gpio: sysfs: add a parallel class device for each GPIO chip using device IDs Bartosz Golaszewski
2025-06-27 15:21   ` Andy Shevchenko
2025-06-30  8:34     ` Bartosz Golaszewski
2025-06-30  9:16       ` Andy Shevchenko
2025-06-23  8:59 ` [PATCH v2 2/9] gpio: sysfs: only get the dirent reference for the value attr once Bartosz Golaszewski
2025-06-27 15:35   ` Andy Shevchenko
2025-06-30  8:41     ` Bartosz Golaszewski
2025-06-23  8:59 ` [PATCH v2 3/9] gpio: sysfs: pass gpiod_data directly to internal GPIO sysfs functions Bartosz Golaszewski
2025-06-24 19:32   ` Linus Walleij
2025-06-27 15:37   ` Andy Shevchenko
2025-06-23  8:59 ` [PATCH v2 4/9] gpio: sysfs: don't use driver data in sysfs callbacks for line attributes Bartosz Golaszewski
2025-06-24 19:33   ` Linus Walleij
2025-06-27 15:41   ` Andy Shevchenko
2025-06-30  8:57     ` Bartosz Golaszewski
2025-06-30 10:05       ` Andy Shevchenko
2025-06-23  8:59 ` [PATCH v2 5/9] gpio: sysfs: rename the data variable in gpiod_(un)export() Bartosz Golaszewski
2025-06-24 19:34   ` Linus Walleij
2025-06-27 15:43   ` Andy Shevchenko
2025-06-30  8:57     ` Bartosz Golaszewski
2025-06-30  9:03       ` Bartosz Golaszewski
2025-06-23  8:59 ` [PATCH v2 6/9] gpio: sysfs: don't look up exported lines as class devices Bartosz Golaszewski
2025-06-24 19:34   ` Linus Walleij
2025-06-27 15:47   ` Andy Shevchenko
2025-06-23  8:59 ` [PATCH v2 7/9] gpio: sysfs: export the GPIO directory locally in the gpiochip<id> directory Bartosz Golaszewski
2025-06-23 22:07   ` kernel test robot
2025-06-23  8:59 ` [PATCH v2 8/9] gpio: sysfs: allow disabling the legacy parts of the GPIO sysfs interface Bartosz Golaszewski
2025-06-24 11:31   ` Geert Uytterhoeven
2025-06-24 19:40   ` Linus Walleij
2025-06-27 11:40   ` kernel test robot
2025-06-23  8:59 ` [PATCH v2 9/9] gpio: TODO: remove the task for the sysfs rework Bartosz Golaszewski

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).