linux-gpio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3] gpio: sim: don't fiddle with GPIOLIB private members
@ 2023-09-05  8:24 Bartosz Golaszewski
  2023-09-05 12:05 ` Andy Shevchenko
  0 siblings, 1 reply; 6+ messages in thread
From: Bartosz Golaszewski @ 2023-09-05  8:24 UTC (permalink / raw)
  To: Linus Walleij, Andy Shevchenko, Kent Gibson
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

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

We access internals of struct gpio_device and struct gpio_desc because
it's easier but it can actually be avoided and we're working towards a
better encapsulation of GPIO data structures across the kernel so let's
start at home.

Instead of checking gpio_desc flags, let's just track the requests of
GPIOs in the driver. We also already store the information about
direction of simulated lines.

For kobjects needed by sysfs callbacks: we can iterate over the children
devices of the top-level platform device and compare their fwnodes
against the one passed to the init function from probe.

While at it: fix one line break and remove the untrue part about
configfs callbacks using dev_get_drvdata() from a comment.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
v1 -> v2:
- use get_dev_from_fwnode() instead of dereferencing fwnode directly

v2 -> v3:
- don't use fwnode internal fields, instead: iterate over the platform
  device's children and locate the GPIO device

 drivers/gpio/gpio-sim.c | 66 ++++++++++++++++++++++++++++++-----------
 1 file changed, 48 insertions(+), 18 deletions(-)

diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c
index 271db3639a78..16a865e79559 100644
--- a/drivers/gpio/gpio-sim.c
+++ b/drivers/gpio/gpio-sim.c
@@ -12,6 +12,7 @@
 #include <linux/completion.h>
 #include <linux/configfs.h>
 #include <linux/device.h>
+#include <linux/gpio/consumer.h>
 #include <linux/gpio/driver.h>
 #include <linux/gpio/machine.h>
 #include <linux/idr.h>
@@ -30,8 +31,6 @@
 #include <linux/string_helpers.h>
 #include <linux/sysfs.h>
 
-#include "gpiolib.h"
-
 #define GPIO_SIM_NGPIO_MAX	1024
 #define GPIO_SIM_PROP_MAX	4 /* Max 3 properties + sentinel. */
 #define GPIO_SIM_NUM_ATTRS	3 /* value, pull and sentinel */
@@ -40,6 +39,9 @@ static DEFINE_IDA(gpio_sim_ida);
 
 struct gpio_sim_chip {
 	struct gpio_chip gc;
+	struct fwnode_handle *swnode;
+	struct device *dev;
+	unsigned long *request_map;
 	unsigned long *direction_map;
 	unsigned long *value_map;
 	unsigned long *pull_map;
@@ -63,16 +65,11 @@ static int gpio_sim_apply_pull(struct gpio_sim_chip *chip,
 			       unsigned int offset, int value)
 {
 	int irq, irq_type, ret;
-	struct gpio_desc *desc;
-	struct gpio_chip *gc;
-
-	gc = &chip->gc;
-	desc = &gc->gpiodev->descs[offset];
 
 	guard(mutex)(&chip->lock);
 
-	if (test_bit(FLAG_REQUESTED, &desc->flags) &&
-	    !test_bit(FLAG_IS_OUT, &desc->flags)) {
+	if (test_bit(offset, chip->request_map) &&
+	    test_bit(offset, chip->direction_map)) {
 		if (value == !!test_bit(offset, chip->value_map))
 			goto set_pull;
 
@@ -99,8 +96,8 @@ static int gpio_sim_apply_pull(struct gpio_sim_chip *chip,
 
 set_value:
 	/* Change the value unless we're actively driving the line. */
-	if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
-	    !test_bit(FLAG_IS_OUT, &desc->flags))
+	if (!test_bit(offset, chip->request_map) ||
+	    test_bit(offset, chip->direction_map))
 		__assign_bit(offset, chip->value_map, value);
 
 set_pull:
@@ -181,7 +178,7 @@ static int gpio_sim_get_direction(struct gpio_chip *gc, unsigned int offset)
 }
 
 static int gpio_sim_set_config(struct gpio_chip *gc,
-				  unsigned int offset, unsigned long config)
+			       unsigned int offset, unsigned long config)
 {
 	struct gpio_sim_chip *chip = gpiochip_get_data(gc);
 
@@ -204,13 +201,25 @@ static int gpio_sim_to_irq(struct gpio_chip *gc, unsigned int offset)
 	return irq_create_mapping(chip->irq_sim, offset);
 }
 
+static int gpio_sim_request(struct gpio_chip *gc, unsigned int offset)
+{
+	struct gpio_sim_chip *chip = gpiochip_get_data(gc);
+
+	scoped_guard(mutex, &chip->lock)
+		__set_bit(offset, chip->request_map);
+
+	return 0;
+}
+
 static void gpio_sim_free(struct gpio_chip *gc, unsigned int offset)
 {
 	struct gpio_sim_chip *chip = gpiochip_get_data(gc);
 
-	scoped_guard(mutex, &chip->lock)
+	scoped_guard(mutex, &chip->lock) {
 		__assign_bit(offset, chip->value_map,
 			     !!test_bit(offset, chip->pull_map));
+		__clear_bit(offset, chip->request_map);
+	}
 }
 
 static ssize_t gpio_sim_sysfs_val_show(struct device *dev,
@@ -295,7 +304,7 @@ static void gpio_sim_sysfs_remove(void *data)
 {
 	struct gpio_sim_chip *chip = data;
 
-	sysfs_remove_groups(&chip->gc.gpiodev->dev.kobj, chip->attr_groups);
+	sysfs_remove_groups(&chip->dev->kobj, chip->attr_groups);
 }
 
 static int gpio_sim_setup_sysfs(struct gpio_sim_chip *chip)
@@ -352,14 +361,25 @@ static int gpio_sim_setup_sysfs(struct gpio_sim_chip *chip)
 		chip->attr_groups[i] = attr_group;
 	}
 
-	ret = sysfs_create_groups(&chip->gc.gpiodev->dev.kobj,
-				  chip->attr_groups);
+	ret = sysfs_create_groups(&chip->dev->kobj, chip->attr_groups);
 	if (ret)
 		return ret;
 
 	return devm_add_action_or_reset(dev, gpio_sim_sysfs_remove, chip);
 }
 
+static int gpio_sim_chip_set_device(struct device *dev, void *data)
+{
+	struct gpio_sim_chip *chip = data;
+
+	if (chip->swnode == dev->fwnode) {
+		chip->dev = dev;
+		return 1;
+	}
+
+	return 0;
+}
+
 static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev)
 {
 	struct gpio_sim_chip *chip;
@@ -387,6 +407,10 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev)
 	if (!chip)
 		return -ENOMEM;
 
+	chip->request_map = devm_bitmap_zalloc(dev, num_lines, GFP_KERNEL);
+	if (!chip->request_map)
+		return -ENOMEM;
+
 	chip->direction_map = devm_bitmap_alloc(dev, num_lines, GFP_KERNEL);
 	if (!chip->direction_map)
 		return -ENOMEM;
@@ -432,6 +456,7 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev)
 	gc->get_direction = gpio_sim_get_direction;
 	gc->set_config = gpio_sim_set_config;
 	gc->to_irq = gpio_sim_to_irq;
+	gc->request = gpio_sim_request;
 	gc->free = gpio_sim_free;
 	gc->can_sleep = true;
 
@@ -439,8 +464,13 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev)
 	if (ret)
 		return ret;
 
-	/* Used by sysfs and configfs callbacks. */
-	dev_set_drvdata(&gc->gpiodev->dev, chip);
+	chip->swnode = swnode;
+	ret = device_for_each_child(dev, chip, gpio_sim_chip_set_device);
+	if (!ret)
+		return -ENODEV;
+
+	/* Used by sysfs callbacks. */
+	dev_set_drvdata(chip->dev, chip);
 
 	return gpio_sim_setup_sysfs(chip);
 }
-- 
2.39.2


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

* Re: [PATCH v3] gpio: sim: don't fiddle with GPIOLIB private members
  2023-09-05  8:24 [PATCH v3] gpio: sim: don't fiddle with GPIOLIB private members Bartosz Golaszewski
@ 2023-09-05 12:05 ` Andy Shevchenko
  2023-09-05 12:08   ` Andy Shevchenko
  2023-09-05 12:09   ` Bartosz Golaszewski
  0 siblings, 2 replies; 6+ messages in thread
From: Andy Shevchenko @ 2023-09-05 12:05 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Linus Walleij, Kent Gibson, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Sep 05, 2023 at 10:24:13AM +0200, Bartosz Golaszewski wrote:
> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> 
> We access internals of struct gpio_device and struct gpio_desc because
> it's easier but it can actually be avoided and we're working towards a
> better encapsulation of GPIO data structures across the kernel so let's
> start at home.
> 
> Instead of checking gpio_desc flags, let's just track the requests of
> GPIOs in the driver. We also already store the information about
> direction of simulated lines.
> 
> For kobjects needed by sysfs callbacks: we can iterate over the children
> devices of the top-level platform device and compare their fwnodes
> against the one passed to the init function from probe.
> 
> While at it: fix one line break and remove the untrue part about
> configfs callbacks using dev_get_drvdata() from a comment.

...

> v2 -> v3:
> - don't use fwnode internal fields, instead: iterate over the platform
>   device's children and locate the GPIO device

Thank you!

...

> @@ -181,7 +178,7 @@ static int gpio_sim_get_direction(struct gpio_chip *gc, unsigned int offset)

>  static int gpio_sim_set_config(struct gpio_chip *gc,
> -				  unsigned int offset, unsigned long config)
> +			       unsigned int offset, unsigned long config)

Looking at other prototypes, it can be

static int gpio_sim_set_config(struct gpio_chip *gc, unsigned int offset,
			       unsigned long config)

...

> +static int gpio_sim_chip_set_device(struct device *dev, void *data)
> +{
> +	struct gpio_sim_chip *chip = data;

> +	if (chip->swnode == dev->fwnode) {

Please do not dereference fwnode from the struct device, we have an API!
device_match_fwnode()

> +		chip->dev = dev;
> +		return 1;
> +	}
> +
> +	return 0;
> +}

...

> +	chip->swnode = swnode;
> +	ret = device_for_each_child(dev, chip, gpio_sim_chip_set_device);
> +	if (!ret)
> +		return -ENODEV;

Can bus_find_device_by_fwnode() be used here?

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v3] gpio: sim: don't fiddle with GPIOLIB private members
  2023-09-05 12:05 ` Andy Shevchenko
@ 2023-09-05 12:08   ` Andy Shevchenko
  2023-09-05 12:10     ` Bartosz Golaszewski
  2023-09-05 12:09   ` Bartosz Golaszewski
  1 sibling, 1 reply; 6+ messages in thread
From: Andy Shevchenko @ 2023-09-05 12:08 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Linus Walleij, Kent Gibson, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Sep 05, 2023 at 03:05:17PM +0300, Andy Shevchenko wrote:
> On Tue, Sep 05, 2023 at 10:24:13AM +0200, Bartosz Golaszewski wrote:

...

> > +	chip->swnode = swnode;
> > +	ret = device_for_each_child(dev, chip, gpio_sim_chip_set_device);
> > +	if (!ret)
> > +		return -ENODEV;
> 
> Can bus_find_device_by_fwnode() be used here?

Answering to myself: you already mentioned that this should cover any bus,
so the answer is "no".

But also we have device_find_child() if I understood the purpose of the above
it should suit better, no?

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v3] gpio: sim: don't fiddle with GPIOLIB private members
  2023-09-05 12:05 ` Andy Shevchenko
  2023-09-05 12:08   ` Andy Shevchenko
@ 2023-09-05 12:09   ` Bartosz Golaszewski
  1 sibling, 0 replies; 6+ messages in thread
From: Bartosz Golaszewski @ 2023-09-05 12:09 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Linus Walleij, Kent Gibson, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Sep 5, 2023 at 2:05 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Tue, Sep 05, 2023 at 10:24:13AM +0200, Bartosz Golaszewski wrote:
> > From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> >
> > We access internals of struct gpio_device and struct gpio_desc because
> > it's easier but it can actually be avoided and we're working towards a
> > better encapsulation of GPIO data structures across the kernel so let's
> > start at home.
> >
> > Instead of checking gpio_desc flags, let's just track the requests of
> > GPIOs in the driver. We also already store the information about
> > direction of simulated lines.
> >
> > For kobjects needed by sysfs callbacks: we can iterate over the children
> > devices of the top-level platform device and compare their fwnodes
> > against the one passed to the init function from probe.
> >
> > While at it: fix one line break and remove the untrue part about
> > configfs callbacks using dev_get_drvdata() from a comment.
>
> ...
>
> > v2 -> v3:
> > - don't use fwnode internal fields, instead: iterate over the platform
> >   device's children and locate the GPIO device
>
> Thank you!
>
> ...
>
> > @@ -181,7 +178,7 @@ static int gpio_sim_get_direction(struct gpio_chip *gc, unsigned int offset)
>
> >  static int gpio_sim_set_config(struct gpio_chip *gc,
> > -                               unsigned int offset, unsigned long config)
> > +                            unsigned int offset, unsigned long config)
>
> Looking at other prototypes, it can be
>
> static int gpio_sim_set_config(struct gpio_chip *gc, unsigned int offset,
>                                unsigned long config)
>
> ...
>
> > +static int gpio_sim_chip_set_device(struct device *dev, void *data)
> > +{
> > +     struct gpio_sim_chip *chip = data;
>
> > +     if (chip->swnode == dev->fwnode) {
>
> Please do not dereference fwnode from the struct device, we have an API!
> device_match_fwnode()
>
> > +             chip->dev = dev;
> > +             return 1;
> > +     }
> > +
> > +     return 0;
> > +}
>
> ...
>
> > +     chip->swnode = swnode;
> > +     ret = device_for_each_child(dev, chip, gpio_sim_chip_set_device);
> > +     if (!ret)
> > +             return -ENODEV;
>
> Can bus_find_device_by_fwnode() be used here?
>

I can but then we're iterating over all platform devices and not just
children of this GPIO simulator. If you think it's better for even
less fwnode juggling then I can go with it.

Bart

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

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

* Re: [PATCH v3] gpio: sim: don't fiddle with GPIOLIB private members
  2023-09-05 12:08   ` Andy Shevchenko
@ 2023-09-05 12:10     ` Bartosz Golaszewski
  2023-09-05 12:35       ` Andy Shevchenko
  0 siblings, 1 reply; 6+ messages in thread
From: Bartosz Golaszewski @ 2023-09-05 12:10 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Linus Walleij, Kent Gibson, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Sep 5, 2023 at 2:09 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Tue, Sep 05, 2023 at 03:05:17PM +0300, Andy Shevchenko wrote:
> > On Tue, Sep 05, 2023 at 10:24:13AM +0200, Bartosz Golaszewski wrote:
>
> ...
>
> > > +   chip->swnode = swnode;
> > > +   ret = device_for_each_child(dev, chip, gpio_sim_chip_set_device);
> > > +   if (!ret)
> > > +           return -ENODEV;
> >
> > Can bus_find_device_by_fwnode() be used here?
>
> Answering to myself: you already mentioned that this should cover any bus,
> so the answer is "no".
>

I think I mentioned it under the gpio-consumer where it's true. Here
we are sure it's on the platform bus.

> But also we have device_find_child() if I understood the purpose of the above
> it should suit better, no?
>

Right, it's a better match.

Bart

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

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

* Re: [PATCH v3] gpio: sim: don't fiddle with GPIOLIB private members
  2023-09-05 12:10     ` Bartosz Golaszewski
@ 2023-09-05 12:35       ` Andy Shevchenko
  0 siblings, 0 replies; 6+ messages in thread
From: Andy Shevchenko @ 2023-09-05 12:35 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Linus Walleij, Kent Gibson, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Sep 05, 2023 at 02:10:38PM +0200, Bartosz Golaszewski wrote:
> On Tue, Sep 5, 2023 at 2:09 PM Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
> > On Tue, Sep 05, 2023 at 03:05:17PM +0300, Andy Shevchenko wrote:
> > > On Tue, Sep 05, 2023 at 10:24:13AM +0200, Bartosz Golaszewski wrote:

...

> > > > +   chip->swnode = swnode;
> > > > +   ret = device_for_each_child(dev, chip, gpio_sim_chip_set_device);
> > > > +   if (!ret)
> > > > +           return -ENODEV;
> > >
> > > Can bus_find_device_by_fwnode() be used here?
> >
> > Answering to myself: you already mentioned that this should cover any bus,
> > so the answer is "no".
> 
> I think I mentioned it under the gpio-consumer where it's true. Here
> we are sure it's on the platform bus.

Then bus_find_device_by_fwnode() can be used here, no?

> > But also we have device_find_child() if I understood the purpose of the above
> > it should suit better, no?
> 
> Right, it's a better match.

In either case be careful about reference counting on the returned dev.

-- 
With Best Regards,
Andy Shevchenko



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

end of thread, other threads:[~2023-09-05 16:20 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-09-05  8:24 [PATCH v3] gpio: sim: don't fiddle with GPIOLIB private members Bartosz Golaszewski
2023-09-05 12:05 ` Andy Shevchenko
2023-09-05 12:08   ` Andy Shevchenko
2023-09-05 12:10     ` Bartosz Golaszewski
2023-09-05 12:35       ` Andy Shevchenko
2023-09-05 12:09   ` 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).