linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] gpio: better lookup method for platform GPIOs
@ 2013-11-28  8:46 Alexandre Courbot
  2013-11-28 14:45 ` Linus Walleij
                   ` (3 more replies)
  0 siblings, 4 replies; 19+ messages in thread
From: Alexandre Courbot @ 2013-11-28  8:46 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Rhyland Klein, Mika Westerberg, Heikki Krogerus, linux-gpio,
	linux-kernel, Alexandre Courbot

Change the format of the platform GPIO lookup tables to make them less
confusing and improve lookup efficiency.

The previous format was a single linked-list that required to compare
the device name and function ID of every single GPIO defined for each
lookup. Switch that to a list of per-device tables, so that the lookup
can be done in two steps, omitting the GPIOs that are not relevant for a
particular device.

The matching rules are now defined as follows:
- The device name must match *exactly*, and can be NULL for GPIOs not
  assigned to a particular device,
- If the function ID in the lookup table is NULL, the con_id argument of
  gpiod_get() will not be used for lookup. However, if it is defined, it
  must match exactly.
- The index must always match.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
Let's change this bad design before more users start using it. ;)

 Documentation/gpio/board.txt | 25 ++++++-----
 drivers/gpio/gpiolib.c       | 99 ++++++++++++++++++++++----------------------
 include/linux/gpio/driver.h  | 22 +++++-----
 3 files changed, 76 insertions(+), 70 deletions(-)

diff --git a/Documentation/gpio/board.txt b/Documentation/gpio/board.txt
index 0d03506f2cc5..630d37b21934 100644
--- a/Documentation/gpio/board.txt
+++ b/Documentation/gpio/board.txt
@@ -72,10 +72,11 @@ where
 
   - chip_label is the label of the gpiod_chip instance providing the GPIO
   - chip_hwnum is the hardware number of the GPIO within the chip
-  - dev_id is the identifier of the device that will make use of this GPIO. If
-	NULL, the GPIO will be available to all devices.
+  - dev_id is the identifier of the device that will make use of this GPIO. It
+	can be NULL, in which case it will be matched for calls to gpiod_get()
+	with a NULL device.
   - con_id is the name of the GPIO function from the device point of view. It
-	can be NULL.
+	can be NULL, in which case it will match any function.
   - idx is the index of the GPIO within the function.
   - flags is defined to specify the following properties:
 	* GPIOF_ACTIVE_LOW	- to configure the GPIO as active-low
@@ -88,16 +89,20 @@ Note that GPIO_LOOKUP() is just a shortcut to GPIO_LOOKUP_IDX() where idx = 0.
 
 A lookup table can then be defined as follows:
 
-	struct gpiod_lookup gpios_table[] = {
-	GPIO_LOOKUP_IDX("gpio.0", 15, "foo.0", "led", 0, GPIO_ACTIVE_HIGH),
-	GPIO_LOOKUP_IDX("gpio.0", 16, "foo.0", "led", 1, GPIO_ACTIVE_HIGH),
-	GPIO_LOOKUP_IDX("gpio.0", 17, "foo.0", "led", 2, GPIO_ACTIVE_HIGH),
-	GPIO_LOOKUP("gpio.0", 1, "foo.0", "power", GPIO_ACTIVE_LOW),
-	};
+struct gpiod_lookup_table gpios_table = {
+	.dev_id = "foo.0",
+	.size = 4,
+	.table = {
+	GPIO_LOOKUP_IDX("gpio.0", 15, "led", 0, GPIO_ACTIVE_HIGH),
+	GPIO_LOOKUP_IDX("gpio.0", 16, "led", 1, GPIO_ACTIVE_HIGH),
+	GPIO_LOOKUP_IDX("gpio.0", 17, "led", 2, GPIO_ACTIVE_HIGH),
+	GPIO_LOOKUP("gpio.0", 1, "power", GPIO_ACTIVE_LOW),
+	},
+};
 
 And the table can be added by the board code as follows:
 
-	gpiod_add_table(gpios_table, ARRAY_SIZE(gpios_table));
+	gpiod_add_lookup_table(&gpios_table);
 
 The driver controlling "foo.0" will then be able to obtain its GPIOs as follows:
 
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index f72618ba716a..568db6ab7d04 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -2259,18 +2259,14 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
 EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
 
 /**
- * gpiod_add_table() - register GPIO device consumers
- * @table: array of consumers to register
- * @num: number of consumers in table
+ * gpiod_add_lookup_table() - register GPIO device consumers
+ * @table: table of consumers to register
  */
-void gpiod_add_table(struct gpiod_lookup *table, size_t size)
+void gpiod_add_lookup_table(struct gpiod_lookup_table *table)
 {
 	mutex_lock(&gpio_lookup_lock);
 
-	while (size--) {
-		list_add_tail(&table->list, &gpio_lookup_list);
-		table++;
-	}
+	list_add_tail(&table->list, &gpio_lookup_list);
 
 	mutex_unlock(&gpio_lookup_lock);
 }
@@ -2326,72 +2322,77 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
 	return desc;
 }
 
-static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
-				    unsigned int idx,
-				    enum gpio_lookup_flags *flags)
+static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev)
 {
 	const char *dev_id = dev ? dev_name(dev) : NULL;
-	struct gpio_desc *desc = ERR_PTR(-ENODEV);
-	unsigned int match, best = 0;
-	struct gpiod_lookup *p;
+	struct gpiod_lookup_table *table;
 
 	mutex_lock(&gpio_lookup_lock);
 
-	list_for_each_entry(p, &gpio_lookup_list, list) {
-		match = 0;
+	list_for_each_entry(table, &gpio_lookup_list, list) {
+		if (table->dev_id && dev_id && strcmp(table->dev_id, dev_id))
+			continue;
 
-		if (p->dev_id) {
-			if (!dev_id || strcmp(p->dev_id, dev_id))
-				continue;
+		if (dev_id != table->dev_id)
+			continue;
 
-			match += 2;
-		}
+		return table;
+	}
 
-		if (p->con_id) {
-			if (!con_id || strcmp(p->con_id, con_id))
-				continue;
+	mutex_unlock(&gpio_lookup_lock);
 
-			match += 1;
-		}
+	return NULL;
+}
 
-		if (p->idx != idx)
-			continue;
+static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
+				    unsigned int idx,
+				    enum gpio_lookup_flags *flags)
+{
+	struct gpio_desc *desc = ERR_PTR(-ENODEV);
+	struct gpiod_lookup_table *table;
+	int i;
 
-		if (match > best) {
-			struct gpio_chip *chip;
 
-			chip = find_chip_by_name(p->chip_label);
+	table = gpiod_find_lookup_table(dev);
+	if (!table)
+		return desc;
 
-			if (!chip) {
-				dev_warn(dev, "cannot find GPIO chip %s\n",
-					 p->chip_label);
-				continue;
-			}
+	for (i = 0; i < table->size; i++) {
+		struct gpio_chip *chip;
+		struct gpiod_lookup *p = &table->table[i];
 
-			if (chip->ngpio <= p->chip_hwnum) {
-				dev_warn(dev, "GPIO chip %s has %d GPIOs\n",
-					 chip->label, chip->ngpio);
+		if (p->idx != idx)
+			continue;
+
+		if (p->con_id) {
+			if (!con_id || strcmp(p->con_id, con_id))
 				continue;
-			}
+		}
 
-			desc = gpio_to_desc(chip->base + p->chip_hwnum);
-			*flags = p->flags;
+		chip = find_chip_by_name(p->chip_label);
 
-			if (match != 3)
-				best = match;
-			else
-				break;
+		if (!chip) {
+			dev_warn(dev, "cannot find GPIO chip %s\n",
+				 p->chip_label);
+			continue;
 		}
-	}
 
-	mutex_unlock(&gpio_lookup_lock);
+		if (chip->ngpio <= p->chip_hwnum) {
+			dev_warn(dev, "GPIO chip %s has %d GPIOs\n",
+				 chip->label, chip->ngpio);
+			continue;
+		}
+
+		desc = gpiochip_offset_to_desc(chip, p->chip_hwnum);
+		*flags = p->flags;
+	}
 
 	return desc;
 }
 
 /**
  * gpio_get - obtain a GPIO for a given GPIO function
- * @dev:	GPIO consumer
+ * @dev:	GPIO consumer, can be NULL for system-global GPIOs
  * @con_id:	function within the GPIO consumer
  *
  * Return the GPIO descriptor corresponding to the function con_id of device
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 3ea2cf6b0e6c..44893ef40817 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -140,7 +140,6 @@ enum gpio_lookup_flags {
  * platform data.
  */
 struct gpiod_lookup {
-	struct list_head list;
 	/*
 	 * name of the chip the GPIO belongs to
 	 */
@@ -150,10 +149,6 @@ struct gpiod_lookup {
 	 */
 	u16 chip_hwnum;
 	/*
-	 * name of device that can claim this GPIO
-	 */
-	const char *dev_id;
-	/*
 	 * name of the GPIO from the device's point of view
 	 */
 	const char *con_id;
@@ -167,28 +162,33 @@ struct gpiod_lookup {
 	enum gpio_lookup_flags flags;
 };
 
+struct gpiod_lookup_table {
+	struct list_head list;
+	const char *dev_id;
+	unsigned int size;
+	struct gpiod_lookup table[];
+};
+
 /*
  * Simple definition of a single GPIO under a con_id
  */
-#define GPIO_LOOKUP(_chip_label, _chip_hwnum, _dev_id, _con_id, _flags) \
-	GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _dev_id, _con_id, 0, _flags)
+#define GPIO_LOOKUP(_chip_label, _chip_hwnum, _con_id, _flags) \
+	GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _con_id, 0, _flags)
 
 /*
  * Use this macro if you need to have several GPIOs under the same con_id.
  * Each GPIO needs to use a different index and can be accessed using
  * gpiod_get_index()
  */
-#define GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _dev_id, _con_id, _idx, \
-			_flags)                                           \
+#define GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _con_id, _idx, _flags)  \
 {                                                                         \
 	.chip_label = _chip_label,                                        \
 	.chip_hwnum = _chip_hwnum,                                        \
-	.dev_id = _dev_id,                                                \
 	.con_id = _con_id,                                                \
 	.idx = _idx,                                                      \
 	.flags = _flags,                                                  \
 }
 
-void gpiod_add_table(struct gpiod_lookup *table, size_t size);
+void gpiod_add_lookup_table(struct gpiod_lookup_table *table);
 
 #endif
-- 
1.8.4.2


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

* Re: [PATCH] gpio: better lookup method for platform GPIOs
  2013-11-28  8:46 [PATCH] gpio: better lookup method for platform GPIOs Alexandre Courbot
@ 2013-11-28 14:45 ` Linus Walleij
  2013-11-28 15:42   ` Andy Shevchenko
  2013-11-28 16:59   ` Mika Westerberg
  2013-11-28 15:54 ` Andy Shevchenko
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 19+ messages in thread
From: Linus Walleij @ 2013-11-28 14:45 UTC (permalink / raw)
  To: Alexandre Courbot, Mika Westerberg
  Cc: Rhyland Klein, Heikki Krogerus, linux-gpio, linux-kernel

On Thu, Nov 28, 2013 at 9:46 AM, Alexandre Courbot <acourbot@nvidia.com> wrote:

> Change the format of the platform GPIO lookup tables to make them less
> confusing and improve lookup efficiency.
>
> The previous format was a single linked-list that required to compare
> the device name and function ID of every single GPIO defined for each
> lookup. Switch that to a list of per-device tables, so that the lookup
> can be done in two steps, omitting the GPIOs that are not relevant for a
> particular device.
>
> The matching rules are now defined as follows:
> - The device name must match *exactly*, and can be NULL for GPIOs not
>   assigned to a particular device,
> - If the function ID in the lookup table is NULL, the con_id argument of
>   gpiod_get() will not be used for lookup. However, if it is defined, it
>   must match exactly.
> - The index must always match.
>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> ---
> Let's change this bad design before more users start using it. ;)

OK given that Mika has based his patches on this I'll request
that he ACK this and then I'll merge this so that he can put
this patch at the bottom of his patch stack.

Mika: requesting ACK.

Yours,
Linus Walleij

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

* Re: [PATCH] gpio: better lookup method for platform GPIOs
  2013-11-28 14:45 ` Linus Walleij
@ 2013-11-28 15:42   ` Andy Shevchenko
  2013-11-28 16:59   ` Mika Westerberg
  1 sibling, 0 replies; 19+ messages in thread
From: Andy Shevchenko @ 2013-11-28 15:42 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Alexandre Courbot, Mika Westerberg, Rhyland Klein,
	Heikki Krogerus, linux-gpio, linux-kernel

On Thu, Nov 28, 2013 at 4:45 PM, Linus Walleij <linus.walleij@linaro.org> wrote:
> On Thu, Nov 28, 2013 at 9:46 AM, Alexandre Courbot <acourbot@nvidia.com> wrote:

[]

>> Let's change this bad design before more users start using it. ;)
>
> OK given that Mika has based his patches on this

Not only him, since I\have started to look for SFI GPIO solution :-)

P.S. Whenever Mika ACKs I will agree with that.

-- 
With Best Regards,
Andy Shevchenko

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

* Re: [PATCH] gpio: better lookup method for platform GPIOs
  2013-11-28  8:46 [PATCH] gpio: better lookup method for platform GPIOs Alexandre Courbot
  2013-11-28 14:45 ` Linus Walleij
@ 2013-11-28 15:54 ` Andy Shevchenko
  2013-11-29  6:17   ` Andy Shevchenko
  2013-12-02 10:50   ` Alex Courbot
  2013-11-29 11:57 ` Heikki Krogerus
  2013-12-02 11:01 ` [PATCH v2] " Alexandre Courbot
  3 siblings, 2 replies; 19+ messages in thread
From: Andy Shevchenko @ 2013-11-28 15:54 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Linus Walleij, Rhyland Klein, Mika Westerberg, Heikki Krogerus,
	linux-gpio, linux-kernel

On Thu, Nov 28, 2013 at 10:46 AM, Alexandre Courbot <acourbot@nvidia.com> wrote:
> Change the format of the platform GPIO lookup tables to make them less
> confusing and improve lookup efficiency.
>
> The previous format was a single linked-list that required to compare
> the device name and function ID of every single GPIO defined for each
> lookup. Switch that to a list of per-device tables, so that the lookup
> can be done in two steps, omitting the GPIOs that are not relevant for a
> particular device.
>
> The matching rules are now defined as follows:
> - The device name must match *exactly*, and can be NULL for GPIOs not
>   assigned to a particular device,
> - If the function ID in the lookup table is NULL, the con_id argument of
>   gpiod_get() will not be used for lookup. However, if it is defined, it
>   must match exactly.
> - The index must always match.

Thanks for that, since I'm also was a bit confused of those dev_id/con_id stuff.
Few comments below (mostly about style).


> --- a/Documentation/gpio/board.txt
> +++ b/Documentation/gpio/board.txt

> @@ -88,16 +89,20 @@ Note that GPIO_LOOKUP() is just a shortcut to GPIO_LOOKUP_IDX() where idx = 0.
>
>  A lookup table can then be defined as follows:
>
> -       struct gpiod_lookup gpios_table[] = {
> -       GPIO_LOOKUP_IDX("gpio.0", 15, "foo.0", "led", 0, GPIO_ACTIVE_HIGH),
> -       GPIO_LOOKUP_IDX("gpio.0", 16, "foo.0", "led", 1, GPIO_ACTIVE_HIGH),
> -       GPIO_LOOKUP_IDX("gpio.0", 17, "foo.0", "led", 2, GPIO_ACTIVE_HIGH),
> -       GPIO_LOOKUP("gpio.0", 1, "foo.0", "power", GPIO_ACTIVE_LOW),
> -       };
> +struct gpiod_lookup_table gpios_table = {
> +       .dev_id = "foo.0",
> +       .size = 4,
> +       .table = {
> +       GPIO_LOOKUP_IDX("gpio.0", 15, "led", 0, GPIO_ACTIVE_HIGH),
> +       GPIO_LOOKUP_IDX("gpio.0", 16, "led", 1, GPIO_ACTIVE_HIGH),
> +       GPIO_LOOKUP_IDX("gpio.0", 17, "led", 2, GPIO_ACTIVE_HIGH),
> +       GPIO_LOOKUP("gpio.0", 1, "power", GPIO_ACTIVE_LOW),

Can you use deeper indentation for GPIO_* lines here?


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

> @@ -2326,72 +2322,77 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
>         return desc;
>  }
>
> -static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
> -                                   unsigned int idx,
> -                                   enum gpio_lookup_flags *flags)
> +static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev)
>  {
>         const char *dev_id = dev ? dev_name(dev) : NULL;
> -       struct gpio_desc *desc = ERR_PTR(-ENODEV);
> -       unsigned int match, best = 0;
> -       struct gpiod_lookup *p;
> +       struct gpiod_lookup_table *table;
>
>         mutex_lock(&gpio_lookup_lock);
>
> -       list_for_each_entry(p, &gpio_lookup_list, list) {
> -               match = 0;
> +       list_for_each_entry(table, &gpio_lookup_list, list) {
> +               if (table->dev_id && dev_id && strcmp(table->dev_id, dev_id))

Maybe check !dev_id outside of loop?

> +                       continue;
>
> -               if (p->dev_id) {
> -                       if (!dev_id || strcmp(p->dev_id, dev_id))
> -                               continue;
> +               if (dev_id != table->dev_id)
> +                       continue;
>
> -                       match += 2;
> -               }
> +               return table;

What  about

if (dev_id == table->dev_id)
 return table;

?

> +       }
>
> -               if (p->con_id) {
> -                       if (!con_id || strcmp(p->con_id, con_id))
> -                               continue;
> +       mutex_unlock(&gpio_lookup_lock);
>
> -                       match += 1;
> -               }
> +       return NULL;
> +}
>
> -               if (p->idx != idx)
> -                       continue;
> +static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
> +                                   unsigned int idx,
> +                                   enum gpio_lookup_flags *flags)
> +{
> +       struct gpio_desc *desc = ERR_PTR(-ENODEV);
> +       struct gpiod_lookup_table *table;
> +       int i;
>
> -               if (match > best) {
> -                       struct gpio_chip *chip;
>

Looks like redundant empty line.

> -                       chip = find_chip_by_name(p->chip_label);
> +       table = gpiod_find_lookup_table(dev);
> +       if (!table)
> +               return desc;
>
> -                       if (!chip) {
> -                               dev_warn(dev, "cannot find GPIO chip %s\n",
> -                                        p->chip_label);
> -                               continue;
> -                       }
> +       for (i = 0; i < table->size; i++) {
> +               struct gpio_chip *chip;
> +               struct gpiod_lookup *p = &table->table[i];
>
> -                       if (chip->ngpio <= p->chip_hwnum) {
> -                               dev_warn(dev, "GPIO chip %s has %d GPIOs\n",
> -                                        chip->label, chip->ngpio);
> +               if (p->idx != idx)
> +                       continue;
> +
> +               if (p->con_id) {
> +                       if (!con_id || strcmp(p->con_id, con_id))

Could be one 'if' and moreover !con_id check might be outside a loop.

>                                 continue;
> -                       }
> +               }
>
> -                       desc = gpio_to_desc(chip->base + p->chip_hwnum);
> -                       *flags = p->flags;
> +               chip = find_chip_by_name(p->chip_label);
>
> -                       if (match != 3)
> -                               best = match;
> -                       else
> -                               break;
> +               if (!chip) {
> +                       dev_warn(dev, "cannot find GPIO chip %s\n",
> +                                p->chip_label);
> +                       continue;
>                 }
> -       }
>
> -       mutex_unlock(&gpio_lookup_lock);
> +               if (chip->ngpio <= p->chip_hwnum) {
> +                       dev_warn(dev, "GPIO chip %s has %d GPIOs\n",
> +                                chip->label, chip->ngpio);
> +                       continue;
> +               }
> +
> +               desc = gpiochip_offset_to_desc(chip, p->chip_hwnum);
> +               *flags = p->flags;
> +       }
>
>         return desc;
>  }

-- 
With Best Regards,
Andy Shevchenko

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

* Re: [PATCH] gpio: better lookup method for platform GPIOs
  2013-11-28 14:45 ` Linus Walleij
  2013-11-28 15:42   ` Andy Shevchenko
@ 2013-11-28 16:59   ` Mika Westerberg
  1 sibling, 0 replies; 19+ messages in thread
From: Mika Westerberg @ 2013-11-28 16:59 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Alexandre Courbot, Rhyland Klein, Heikki Krogerus, linux-gpio,
	linux-kernel

On Thu, Nov 28, 2013 at 03:45:37PM +0100, Linus Walleij wrote:
> On Thu, Nov 28, 2013 at 9:46 AM, Alexandre Courbot <acourbot@nvidia.com> wrote:
> 
> > Change the format of the platform GPIO lookup tables to make them less
> > confusing and improve lookup efficiency.
> >
> > The previous format was a single linked-list that required to compare
> > the device name and function ID of every single GPIO defined for each
> > lookup. Switch that to a list of per-device tables, so that the lookup
> > can be done in two steps, omitting the GPIOs that are not relevant for a
> > particular device.
> >
> > The matching rules are now defined as follows:
> > - The device name must match *exactly*, and can be NULL for GPIOs not
> >   assigned to a particular device,
> > - If the function ID in the lookup table is NULL, the con_id argument of
> >   gpiod_get() will not be used for lookup. However, if it is defined, it
> >   must match exactly.
> > - The index must always match.
> >
> > Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> > ---
> > Let's change this bad design before more users start using it. ;)
> 
> OK given that Mika has based his patches on this I'll request
> that he ACK this and then I'll merge this so that he can put
> this patch at the bottom of his patch stack.
> 
> Mika: requesting ACK.

Alexandre, please check Andy's comments.

Apart from that this looks good to me.

Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>

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

* Re: [PATCH] gpio: better lookup method for platform GPIOs
  2013-11-28 15:54 ` Andy Shevchenko
@ 2013-11-29  6:17   ` Andy Shevchenko
  2013-12-02 10:50   ` Alex Courbot
  1 sibling, 0 replies; 19+ messages in thread
From: Andy Shevchenko @ 2013-11-29  6:17 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Linus Walleij, Rhyland Klein, Mika Westerberg, Heikki Krogerus,
	linux-gpio, linux-kernel

> On Thu, Nov 28, 2013 at 10:46 AM, Alexandre Courbot <acourbot@nvidia.com> wrote:

One missed, but not least, thing.

>> +static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev)
>>  {
>>         const char *dev_id = dev ? dev_name(dev) : NULL;
>> -       struct gpio_desc *desc = ERR_PTR(-ENODEV);
>> -       unsigned int match, best = 0;
>> -       struct gpiod_lookup *p;
>> +       struct gpiod_lookup_table *table;
>>
>>         mutex_lock(&gpio_lookup_lock);
>>
>> -       list_for_each_entry(p, &gpio_lookup_list, list) {
>> -               match = 0;
>> +       list_for_each_entry(table, &gpio_lookup_list, list) {

[]

>> +               if (dev_id != table->dev_id)
>> +                       continue;
>>
>> -                       match += 2;
>> -               }
>> +               return table;
>
> What  about
>
> if (dev_id == table->dev_id)
>  return table;
>
> ?

And unlock mutex, of course! It seems you missed this in the first place.

>
>> +       }
>>
>> -               if (p->con_id) {
>> -                       if (!con_id || strcmp(p->con_id, con_id))
>> -                               continue;
>> +       mutex_unlock(&gpio_lookup_lock);
>>
>> -                       match += 1;
>> -               }
>> +       return NULL;
>> +}

-- 
With Best Regards,
Andy Shevchenko

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

* Re: [PATCH] gpio: better lookup method for platform GPIOs
  2013-11-28  8:46 [PATCH] gpio: better lookup method for platform GPIOs Alexandre Courbot
  2013-11-28 14:45 ` Linus Walleij
  2013-11-28 15:54 ` Andy Shevchenko
@ 2013-11-29 11:57 ` Heikki Krogerus
  2013-11-29 11:59   ` Heikki Krogerus
  2013-12-02 10:33   ` Alex Courbot
  2013-12-02 11:01 ` [PATCH v2] " Alexandre Courbot
  3 siblings, 2 replies; 19+ messages in thread
From: Heikki Krogerus @ 2013-11-29 11:57 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Linus Walleij, Rhyland Klein, Mika Westerberg, linux-gpio, linux-kernel

Hi,

On Thu, Nov 28, 2013 at 05:46:28PM +0900, Alexandre Courbot wrote:
> @@ -88,16 +89,20 @@ Note that GPIO_LOOKUP() is just a shortcut to GPIO_LOOKUP_IDX() where idx = 0.
>  
>  A lookup table can then be defined as follows:
>  
> -	struct gpiod_lookup gpios_table[] = {
> -	GPIO_LOOKUP_IDX("gpio.0", 15, "foo.0", "led", 0, GPIO_ACTIVE_HIGH),
> -	GPIO_LOOKUP_IDX("gpio.0", 16, "foo.0", "led", 1, GPIO_ACTIVE_HIGH),
> -	GPIO_LOOKUP_IDX("gpio.0", 17, "foo.0", "led", 2, GPIO_ACTIVE_HIGH),
> -	GPIO_LOOKUP("gpio.0", 1, "foo.0", "power", GPIO_ACTIVE_LOW),
> -	};
> +struct gpiod_lookup_table gpios_table = {
> +	.dev_id = "foo.0",
> +	.size = 4,
> +	.table = {
> +	GPIO_LOOKUP_IDX("gpio.0", 15, "led", 0, GPIO_ACTIVE_HIGH),
> +	GPIO_LOOKUP_IDX("gpio.0", 16, "led", 1, GPIO_ACTIVE_HIGH),
> +	GPIO_LOOKUP_IDX("gpio.0", 17, "led", 2, GPIO_ACTIVE_HIGH),
> +	GPIO_LOOKUP("gpio.0", 1, "power", GPIO_ACTIVE_LOW),
> +	},
> +};

Instead of using the size variable, wouldn't it be more clear to
expect the array to be null terminated?

>  And the table can be added by the board code as follows:
>  
> -	gpiod_add_table(gpios_table, ARRAY_SIZE(gpios_table));
> +	gpiod_add_lookup_table(&gpios_table);

Remove "&" from the above.

Thanks,

-- 
heikki

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

* Re: [PATCH] gpio: better lookup method for platform GPIOs
  2013-11-29 11:57 ` Heikki Krogerus
@ 2013-11-29 11:59   ` Heikki Krogerus
  2013-12-02 10:33   ` Alex Courbot
  1 sibling, 0 replies; 19+ messages in thread
From: Heikki Krogerus @ 2013-11-29 11:59 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Linus Walleij, Rhyland Klein, Mika Westerberg, linux-gpio, linux-kernel

On Fri, Nov 29, 2013 at 01:57:48PM +0200, Heikki Krogerus wrote:
> > -	gpiod_add_table(gpios_table, ARRAY_SIZE(gpios_table));
> > +	gpiod_add_lookup_table(&gpios_table);
> 
> Remove "&" from the above.

Sorry, ignore that :).

-- 
heikki

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

* Re: [PATCH] gpio: better lookup method for platform GPIOs
  2013-11-29 11:57 ` Heikki Krogerus
  2013-11-29 11:59   ` Heikki Krogerus
@ 2013-12-02 10:33   ` Alex Courbot
  2013-12-02 11:11     ` Heikki Krogerus
  1 sibling, 1 reply; 19+ messages in thread
From: Alex Courbot @ 2013-12-02 10:33 UTC (permalink / raw)
  To: Heikki Krogerus
  Cc: Linus Walleij, Rhyland Klein, Mika Westerberg, linux-gpio, linux-kernel

On 11/29/2013 08:57 PM, Heikki Krogerus wrote:
> Hi,
>
> On Thu, Nov 28, 2013 at 05:46:28PM +0900, Alexandre Courbot wrote:
>> @@ -88,16 +89,20 @@ Note that GPIO_LOOKUP() is just a shortcut to GPIO_LOOKUP_IDX() where idx = 0.
>>
>>   A lookup table can then be defined as follows:
>>
>> -	struct gpiod_lookup gpios_table[] = {
>> -	GPIO_LOOKUP_IDX("gpio.0", 15, "foo.0", "led", 0, GPIO_ACTIVE_HIGH),
>> -	GPIO_LOOKUP_IDX("gpio.0", 16, "foo.0", "led", 1, GPIO_ACTIVE_HIGH),
>> -	GPIO_LOOKUP_IDX("gpio.0", 17, "foo.0", "led", 2, GPIO_ACTIVE_HIGH),
>> -	GPIO_LOOKUP("gpio.0", 1, "foo.0", "power", GPIO_ACTIVE_LOW),
>> -	};
>> +struct gpiod_lookup_table gpios_table = {
>> +	.dev_id = "foo.0",
>> +	.size = 4,
>> +	.table = {
>> +	GPIO_LOOKUP_IDX("gpio.0", 15, "led", 0, GPIO_ACTIVE_HIGH),
>> +	GPIO_LOOKUP_IDX("gpio.0", 16, "led", 1, GPIO_ACTIVE_HIGH),
>> +	GPIO_LOOKUP_IDX("gpio.0", 17, "led", 2, GPIO_ACTIVE_HIGH),
>> +	GPIO_LOOKUP("gpio.0", 1, "power", GPIO_ACTIVE_LOW),
>> +	},
>> +};
>
> Instead of using the size variable, wouldn't it be more clear to
> expect the array to be null terminated?

This is a zero-length array, its entries are not pointers but flattened 
lookup entries. Thus you cannot simply null-terminate it. It would be 
possible to use { NULL } as a terminator, but this would expand into a 
whole gpiod_lookup and is not very pleasant esthetically-speaking. So I 
think the size member is maybe better suited here.

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

* Re: [PATCH] gpio: better lookup method for platform GPIOs
  2013-11-28 15:54 ` Andy Shevchenko
  2013-11-29  6:17   ` Andy Shevchenko
@ 2013-12-02 10:50   ` Alex Courbot
  1 sibling, 0 replies; 19+ messages in thread
From: Alex Courbot @ 2013-12-02 10:50 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Linus Walleij, Rhyland Klein, Mika Westerberg, Heikki Krogerus,
	linux-gpio, linux-kernel

On 11/29/2013 12:54 AM, Andy Shevchenko wrote:
> On Thu, Nov 28, 2013 at 10:46 AM, Alexandre Courbot <acourbot@nvidia.com> wrote:
>> Change the format of the platform GPIO lookup tables to make them less
>> confusing and improve lookup efficiency.
>>
>> The previous format was a single linked-list that required to compare
>> the device name and function ID of every single GPIO defined for each
>> lookup. Switch that to a list of per-device tables, so that the lookup
>> can be done in two steps, omitting the GPIOs that are not relevant for a
>> particular device.
>>
>> The matching rules are now defined as follows:
>> - The device name must match *exactly*, and can be NULL for GPIOs not
>>    assigned to a particular device,
>> - If the function ID in the lookup table is NULL, the con_id argument of
>>    gpiod_get() will not be used for lookup. However, if it is defined, it
>>    must match exactly.
>> - The index must always match.
>
> Thanks for that, since I'm also was a bit confused of those dev_id/con_id stuff.
> Few comments below (mostly about style).
>
>
>> --- a/Documentation/gpio/board.txt
>> +++ b/Documentation/gpio/board.txt
>
>> @@ -88,16 +89,20 @@ Note that GPIO_LOOKUP() is just a shortcut to GPIO_LOOKUP_IDX() where idx = 0.
>>
>>   A lookup table can then be defined as follows:
>>
>> -       struct gpiod_lookup gpios_table[] = {
>> -       GPIO_LOOKUP_IDX("gpio.0", 15, "foo.0", "led", 0, GPIO_ACTIVE_HIGH),
>> -       GPIO_LOOKUP_IDX("gpio.0", 16, "foo.0", "led", 1, GPIO_ACTIVE_HIGH),
>> -       GPIO_LOOKUP_IDX("gpio.0", 17, "foo.0", "led", 2, GPIO_ACTIVE_HIGH),
>> -       GPIO_LOOKUP("gpio.0", 1, "foo.0", "power", GPIO_ACTIVE_LOW),
>> -       };
>> +struct gpiod_lookup_table gpios_table = {
>> +       .dev_id = "foo.0",
>> +       .size = 4,
>> +       .table = {
>> +       GPIO_LOOKUP_IDX("gpio.0", 15, "led", 0, GPIO_ACTIVE_HIGH),
>> +       GPIO_LOOKUP_IDX("gpio.0", 16, "led", 1, GPIO_ACTIVE_HIGH),
>> +       GPIO_LOOKUP_IDX("gpio.0", 17, "led", 2, GPIO_ACTIVE_HIGH),
>> +       GPIO_LOOKUP("gpio.0", 1, "power", GPIO_ACTIVE_LOW),
>
> Can you use deeper indentation for GPIO_* lines here?

Fixed.

>> --- a/drivers/gpio/gpiolib.c
>> +++ b/drivers/gpio/gpiolib.c
>
>> @@ -2326,72 +2322,77 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
>>          return desc;
>>   }
>>
>> -static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
>> -                                   unsigned int idx,
>> -                                   enum gpio_lookup_flags *flags)
>> +static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev)
>>   {
>>          const char *dev_id = dev ? dev_name(dev) : NULL;
>> -       struct gpio_desc *desc = ERR_PTR(-ENODEV);
>> -       unsigned int match, best = 0;
>> -       struct gpiod_lookup *p;
>> +       struct gpiod_lookup_table *table;
>>
>>          mutex_lock(&gpio_lookup_lock);
>>
>> -       list_for_each_entry(p, &gpio_lookup_list, list) {
>> -               match = 0;
>> +       list_for_each_entry(table, &gpio_lookup_list, list) {
>> +               if (table->dev_id && dev_id && strcmp(table->dev_id, dev_id))
>
> Maybe check !dev_id outside of loop?

And create two loops, one for each case? Might complicate the code for 
little benefit IMHO, but please elaborate if I missed your point.

>
>> +                       continue;
>>
>> -               if (p->dev_id) {
>> -                       if (!dev_id || strcmp(p->dev_id, dev_id))
>> -                               continue;
>> +               if (dev_id != table->dev_id)
>> +                       continue;
>>
>> -                       match += 2;
>> -               }
>> +               return table;
>
> What  about
>
> if (dev_id == table->dev_id)
>   return table;
>
> ?

Actually my algorithm is broken to start with - and dangerous, as the 
missed mutex_unlock() you spotted later testifies. I will rewrite it in 
a (hopefully) sounder way.

>> +static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
>> +                                   unsigned int idx,
>> +                                   enum gpio_lookup_flags *flags)
>> +{
>> +       struct gpio_desc *desc = ERR_PTR(-ENODEV);
>> +       struct gpiod_lookup_table *table;
>> +       int i;
>>
>> -               if (match > best) {
>> -                       struct gpio_chip *chip;
>>
>
> Looks like redundant empty line.

Fixed.

>
>> -                       chip = find_chip_by_name(p->chip_label);
>> +       table = gpiod_find_lookup_table(dev);
>> +       if (!table)
>> +               return desc;
>>
>> -                       if (!chip) {
>> -                               dev_warn(dev, "cannot find GPIO chip %s\n",
>> -                                        p->chip_label);
>> -                               continue;
>> -                       }
>> +       for (i = 0; i < table->size; i++) {
>> +               struct gpio_chip *chip;
>> +               struct gpiod_lookup *p = &table->table[i];
>>
>> -                       if (chip->ngpio <= p->chip_hwnum) {
>> -                               dev_warn(dev, "GPIO chip %s has %d GPIOs\n",
>> -                                        chip->label, chip->ngpio);
>> +               if (p->idx != idx)
>> +                       continue;
>> +
>> +               if (p->con_id) {
>> +                       if (!con_id || strcmp(p->con_id, con_id))
>
> Could be one 'if' and moreover !con_id check might be outside a loop.

Again, wouldn't that require two separate loops?



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

* [PATCH v2] gpio: better lookup method for platform GPIOs
  2013-11-28  8:46 [PATCH] gpio: better lookup method for platform GPIOs Alexandre Courbot
                   ` (2 preceding siblings ...)
  2013-11-29 11:57 ` Heikki Krogerus
@ 2013-12-02 11:01 ` Alexandre Courbot
  2013-12-02 11:49   ` Andy Shevchenko
  3 siblings, 1 reply; 19+ messages in thread
From: Alexandre Courbot @ 2013-12-02 11:01 UTC (permalink / raw)
  To: Linus Walleij, Mika Westerberg, Andy Shevchenko, Rhyland Klein,
	Heikki Krogerus
  Cc: linux-gpio, linux-kernel, Alexandre Courbot

Change the format of the platform GPIO lookup tables to make them less
confusing and improve lookup efficiency.

The previous format was a single linked-list that required to compare
the device name and function ID of every single GPIO defined for each
lookup. Switch that to a list of per-device tables, so that the lookup
can be done in two steps, omitting the GPIOs that are not relevant for a
particular device.

The matching rules are now defined as follows:
- The device name must match *exactly*, and can be NULL for GPIOs not
  assigned to a particular device,
- If the function ID in the lookup table is NULL, the con_id argument of
  gpiod_get() will not be used for lookup. However, if it is defined, it
  must match exactly.
- The index must always match.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
Changes since v1:
- Applied most fixes suggested by Andy
- Hopefully safer and less confusing table lookup algorithm
- Added Mika's ack

 Documentation/gpio/board.txt |  25 ++++++----
 drivers/gpio/gpiolib.c       | 109 +++++++++++++++++++++++--------------------
 include/linux/gpio/driver.h  |  22 ++++-----
 3 files changed, 85 insertions(+), 71 deletions(-)

diff --git a/Documentation/gpio/board.txt b/Documentation/gpio/board.txt
index 0d03506f2cc5..a4fdd96cef93 100644
--- a/Documentation/gpio/board.txt
+++ b/Documentation/gpio/board.txt
@@ -72,10 +72,11 @@ where
 
   - chip_label is the label of the gpiod_chip instance providing the GPIO
   - chip_hwnum is the hardware number of the GPIO within the chip
-  - dev_id is the identifier of the device that will make use of this GPIO. If
-	NULL, the GPIO will be available to all devices.
+  - dev_id is the identifier of the device that will make use of this GPIO. It
+	can be NULL, in which case it will be matched for calls to gpiod_get()
+	with a NULL device.
   - con_id is the name of the GPIO function from the device point of view. It
-	can be NULL.
+	can be NULL, in which case it will match any function.
   - idx is the index of the GPIO within the function.
   - flags is defined to specify the following properties:
 	* GPIOF_ACTIVE_LOW	- to configure the GPIO as active-low
@@ -88,16 +89,20 @@ Note that GPIO_LOOKUP() is just a shortcut to GPIO_LOOKUP_IDX() where idx = 0.
 
 A lookup table can then be defined as follows:
 
-	struct gpiod_lookup gpios_table[] = {
-	GPIO_LOOKUP_IDX("gpio.0", 15, "foo.0", "led", 0, GPIO_ACTIVE_HIGH),
-	GPIO_LOOKUP_IDX("gpio.0", 16, "foo.0", "led", 1, GPIO_ACTIVE_HIGH),
-	GPIO_LOOKUP_IDX("gpio.0", 17, "foo.0", "led", 2, GPIO_ACTIVE_HIGH),
-	GPIO_LOOKUP("gpio.0", 1, "foo.0", "power", GPIO_ACTIVE_LOW),
-	};
+struct gpiod_lookup_table gpios_table = {
+	.dev_id = "foo.0",
+	.size = 4,
+	.table = {
+		GPIO_LOOKUP_IDX("gpio.0", 15, "led", 0, GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP_IDX("gpio.0", 16, "led", 1, GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP_IDX("gpio.0", 17, "led", 2, GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("gpio.0", 1, "power", GPIO_ACTIVE_LOW),
+	},
+};
 
 And the table can be added by the board code as follows:
 
-	gpiod_add_table(gpios_table, ARRAY_SIZE(gpios_table));
+	gpiod_add_lookup_table(&gpios_table);
 
 The driver controlling "foo.0" will then be able to obtain its GPIOs as follows:
 
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index f72618ba716a..d17d6eabed6a 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -2259,18 +2259,14 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
 EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
 
 /**
- * gpiod_add_table() - register GPIO device consumers
- * @table: array of consumers to register
- * @num: number of consumers in table
+ * gpiod_add_lookup_table() - register GPIO device consumers
+ * @table: table of consumers to register
  */
-void gpiod_add_table(struct gpiod_lookup *table, size_t size)
+void gpiod_add_lookup_table(struct gpiod_lookup_table *table)
 {
 	mutex_lock(&gpio_lookup_lock);
 
-	while (size--) {
-		list_add_tail(&table->list, &gpio_lookup_list);
-		table++;
-	}
+	list_add_tail(&table->list, &gpio_lookup_list);
 
 	mutex_unlock(&gpio_lookup_lock);
 }
@@ -2326,72 +2322,85 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
 	return desc;
 }
 
-static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
-				    unsigned int idx,
-				    enum gpio_lookup_flags *flags)
+static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev)
 {
 	const char *dev_id = dev ? dev_name(dev) : NULL;
-	struct gpio_desc *desc = ERR_PTR(-ENODEV);
-	unsigned int match, best = 0;
-	struct gpiod_lookup *p;
+	struct gpiod_lookup_table *table;
 
 	mutex_lock(&gpio_lookup_lock);
 
-	list_for_each_entry(p, &gpio_lookup_list, list) {
-		match = 0;
+	list_for_each_entry(table, &gpio_lookup_list, list) {
+		if (table->dev_id && dev_id) {
+			/*
+			 * Valid strings on both ends, must be identical to have
+			 * a match
+			 */
+			if (!strcmp(table->dev_id, dev_id))
+				goto end;
+		} else {
+			/*
+			 * One of the pointers is NULL, so both must be to have
+			 * a match
+			 */
+			if (dev_id == table->dev_id)
+				goto end;
+		}
+	}
+	table = NULL;
 
-		if (p->dev_id) {
-			if (!dev_id || strcmp(p->dev_id, dev_id))
-				continue;
+end:
+	mutex_unlock(&gpio_lookup_lock);
+	return table;
+}
 
-			match += 2;
-		}
+static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
+				    unsigned int idx,
+				    enum gpio_lookup_flags *flags)
+{
+	struct gpio_desc *desc = ERR_PTR(-ENODEV);
+	struct gpiod_lookup_table *table;
+	int i;
 
-		if (p->con_id) {
-			if (!con_id || strcmp(p->con_id, con_id))
-				continue;
+	table = gpiod_find_lookup_table(dev);
+	if (!table)
+		return desc;
 
-			match += 1;
-		}
+	for (i = 0; i < table->size; i++) {
+		struct gpio_chip *chip;
+		struct gpiod_lookup *p = &table->table[i];
 
+		/* idx must always match exactly */
 		if (p->idx != idx)
 			continue;
 
-		if (match > best) {
-			struct gpio_chip *chip;
-
-			chip = find_chip_by_name(p->chip_label);
-
-			if (!chip) {
-				dev_warn(dev, "cannot find GPIO chip %s\n",
-					 p->chip_label);
-				continue;
-			}
+		/* If the lookup entry has a con_id, require exact match */
+		if (p->con_id && (!con_id || strcmp(p->con_id, con_id)))
+			continue;
 
-			if (chip->ngpio <= p->chip_hwnum) {
-				dev_warn(dev, "GPIO chip %s has %d GPIOs\n",
-					 chip->label, chip->ngpio);
-				continue;
-			}
+		chip = find_chip_by_name(p->chip_label);
 
-			desc = gpio_to_desc(chip->base + p->chip_hwnum);
-			*flags = p->flags;
+		if (!chip) {
+			dev_warn(dev, "cannot find GPIO chip %s\n",
+				 p->chip_label);
+			continue;
+		}
 
-			if (match != 3)
-				best = match;
-			else
-				break;
+		if (chip->ngpio <= p->chip_hwnum) {
+			dev_warn(dev, "GPIO chip %s has %d GPIOs\n",
+				 chip->label, chip->ngpio);
+			continue;
 		}
-	}
 
-	mutex_unlock(&gpio_lookup_lock);
+		desc = gpiochip_offset_to_desc(chip, p->chip_hwnum);
+		*flags = p->flags;
+	}
 
 	return desc;
 }
 
 /**
  * gpio_get - obtain a GPIO for a given GPIO function
- * @dev:	GPIO consumer
+ * @dev:	GPIO consumer, can be NULL for system-global GPIOs
  * @con_id:	function within the GPIO consumer
  *
  * Return the GPIO descriptor corresponding to the function con_id of device
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 3ea2cf6b0e6c..44893ef40817 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -140,7 +140,6 @@ enum gpio_lookup_flags {
  * platform data.
  */
 struct gpiod_lookup {
-	struct list_head list;
 	/*
 	 * name of the chip the GPIO belongs to
 	 */
@@ -150,10 +149,6 @@ struct gpiod_lookup {
 	 */
 	u16 chip_hwnum;
 	/*
-	 * name of device that can claim this GPIO
-	 */
-	const char *dev_id;
-	/*
 	 * name of the GPIO from the device's point of view
 	 */
 	const char *con_id;
@@ -167,28 +162,33 @@ struct gpiod_lookup {
 	enum gpio_lookup_flags flags;
 };
 
+struct gpiod_lookup_table {
+	struct list_head list;
+	const char *dev_id;
+	unsigned int size;
+	struct gpiod_lookup table[];
+};
+
 /*
  * Simple definition of a single GPIO under a con_id
  */
-#define GPIO_LOOKUP(_chip_label, _chip_hwnum, _dev_id, _con_id, _flags) \
-	GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _dev_id, _con_id, 0, _flags)
+#define GPIO_LOOKUP(_chip_label, _chip_hwnum, _con_id, _flags) \
+	GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _con_id, 0, _flags)
 
 /*
  * Use this macro if you need to have several GPIOs under the same con_id.
  * Each GPIO needs to use a different index and can be accessed using
  * gpiod_get_index()
  */
-#define GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _dev_id, _con_id, _idx, \
-			_flags)                                           \
+#define GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _con_id, _idx, _flags)  \
 {                                                                         \
 	.chip_label = _chip_label,                                        \
 	.chip_hwnum = _chip_hwnum,                                        \
-	.dev_id = _dev_id,                                                \
 	.con_id = _con_id,                                                \
 	.idx = _idx,                                                      \
 	.flags = _flags,                                                  \
 }
 
-void gpiod_add_table(struct gpiod_lookup *table, size_t size);
+void gpiod_add_lookup_table(struct gpiod_lookup_table *table);
 
 #endif
-- 
1.8.4.2


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

* Re: [PATCH] gpio: better lookup method for platform GPIOs
  2013-12-02 10:33   ` Alex Courbot
@ 2013-12-02 11:11     ` Heikki Krogerus
  2013-12-02 12:30       ` Alexandre Courbot
  0 siblings, 1 reply; 19+ messages in thread
From: Heikki Krogerus @ 2013-12-02 11:11 UTC (permalink / raw)
  To: Alex Courbot
  Cc: Linus Walleij, Rhyland Klein, Mika Westerberg, linux-gpio, linux-kernel

Hi,

On Mon, Dec 02, 2013 at 07:33:35PM +0900, Alex Courbot wrote:
> On 11/29/2013 08:57 PM, Heikki Krogerus wrote:
> >Hi,
> >
> >On Thu, Nov 28, 2013 at 05:46:28PM +0900, Alexandre Courbot wrote:
> >>@@ -88,16 +89,20 @@ Note that GPIO_LOOKUP() is just a shortcut to GPIO_LOOKUP_IDX() where idx = 0.
> >>
> >>  A lookup table can then be defined as follows:
> >>
> >>-	struct gpiod_lookup gpios_table[] = {
> >>-	GPIO_LOOKUP_IDX("gpio.0", 15, "foo.0", "led", 0, GPIO_ACTIVE_HIGH),
> >>-	GPIO_LOOKUP_IDX("gpio.0", 16, "foo.0", "led", 1, GPIO_ACTIVE_HIGH),
> >>-	GPIO_LOOKUP_IDX("gpio.0", 17, "foo.0", "led", 2, GPIO_ACTIVE_HIGH),
> >>-	GPIO_LOOKUP("gpio.0", 1, "foo.0", "power", GPIO_ACTIVE_LOW),
> >>-	};
> >>+struct gpiod_lookup_table gpios_table = {
> >>+	.dev_id = "foo.0",
> >>+	.size = 4,
> >>+	.table = {
> >>+	GPIO_LOOKUP_IDX("gpio.0", 15, "led", 0, GPIO_ACTIVE_HIGH),
> >>+	GPIO_LOOKUP_IDX("gpio.0", 16, "led", 1, GPIO_ACTIVE_HIGH),
> >>+	GPIO_LOOKUP_IDX("gpio.0", 17, "led", 2, GPIO_ACTIVE_HIGH),
> >>+	GPIO_LOOKUP("gpio.0", 1, "power", GPIO_ACTIVE_LOW),
> >>+	},
> >>+};
> >
> >Instead of using the size variable, wouldn't it be more clear to
> >expect the array to be null terminated?
> 
> This is a zero-length array, its entries are not pointers but
> flattened lookup entries. Thus you cannot simply null-terminate it.
> It would be possible to use { NULL } as a terminator, but this would
> expand into a whole gpiod_lookup and is not very pleasant
> esthetically-speaking. So I think the size member is maybe better
> suited here.

The gpio_loopup_table would look like this, which IMO is more nicer
looking compared to the extra size variable:

struct gpiod_lookup_table gpios_table = {
	.dev_id = "foo.0",
	.table = {
        	GPIO_LOOKUP_IDX("gpio.0", 15, "led", 0, GPIO_ACTIVE_HIGH),
	        GPIO_LOOKUP_IDX("gpio.0", 16, "led", 1, GPIO_ACTIVE_HIGH),
        	GPIO_LOOKUP_IDX("gpio.0", 17, "led", 2, GPIO_ACTIVE_HIGH),
	        GPIO_LOOKUP("gpio.0", 1, "power", GPIO_ACTIVE_LOW),
                { },
	},
};

That would also make it more straight forward to handle in gbiolib.c:

struct gpiod_lookup *p;
...
for (p = table->table; p->chip_label; p++) {
...

Thanks,

-- 
heikki

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

* Re: [PATCH v2] gpio: better lookup method for platform GPIOs
  2013-12-02 11:01 ` [PATCH v2] " Alexandre Courbot
@ 2013-12-02 11:49   ` Andy Shevchenko
  2013-12-02 12:37     ` Alexandre Courbot
  0 siblings, 1 reply; 19+ messages in thread
From: Andy Shevchenko @ 2013-12-02 11:49 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Linus Walleij, Mika Westerberg, Rhyland Klein, Heikki Krogerus,
	linux-gpio, linux-kernel

On Mon, Dec 2, 2013 at 1:01 PM, Alexandre Courbot <acourbot@nvidia.com> wrote:
> Change the format of the platform GPIO lookup tables to make them less
> confusing and improve lookup efficiency.
>
> The previous format was a single linked-list that required to compare
> the device name and function ID of every single GPIO defined for each
> lookup. Switch that to a list of per-device tables, so that the lookup
> can be done in two steps, omitting the GPIOs that are not relevant for a
> particular device.
>
> The matching rules are now defined as follows:
> - The device name must match *exactly*, and can be NULL for GPIOs not
>   assigned to a particular device,
> - If the function ID in the lookup table is NULL, the con_id argument of
>   gpiod_get() will not be used for lookup. However, if it is defined, it
>   must match exactly.
> - The index must always match.

Thanks for an updated version.
Few minor comments below.
Comments about loops are here as well.

I any case:
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
> ---
> Changes since v1:
> - Applied most fixes suggested by Andy
> - Hopefully safer and less confusing table lookup algorithm
> - Added Mika's ack
>
>  Documentation/gpio/board.txt |  25 ++++++----
>  drivers/gpio/gpiolib.c       | 109 +++++++++++++++++++++++--------------------
>  include/linux/gpio/driver.h  |  22 ++++-----
>  3 files changed, 85 insertions(+), 71 deletions(-)
>
> diff --git a/Documentation/gpio/board.txt b/Documentation/gpio/board.txt
> index 0d03506f2cc5..a4fdd96cef93 100644
> --- a/Documentation/gpio/board.txt
> +++ b/Documentation/gpio/board.txt
> @@ -72,10 +72,11 @@ where
>
>    - chip_label is the label of the gpiod_chip instance providing the GPIO
>    - chip_hwnum is the hardware number of the GPIO within the chip
> -  - dev_id is the identifier of the device that will make use of this GPIO. If
> -       NULL, the GPIO will be available to all devices.
> +  - dev_id is the identifier of the device that will make use of this GPIO. It
> +       can be NULL, in which case it will be matched for calls to gpiod_get()
> +       with a NULL device.
>    - con_id is the name of the GPIO function from the device point of view. It
> -       can be NULL.
> +       can be NULL, in which case it will match any function.
>    - idx is the index of the GPIO within the function.
>    - flags is defined to specify the following properties:
>         * GPIOF_ACTIVE_LOW      - to configure the GPIO as active-low
> @@ -88,16 +89,20 @@ Note that GPIO_LOOKUP() is just a shortcut to GPIO_LOOKUP_IDX() where idx = 0.
>
>  A lookup table can then be defined as follows:
>
> -       struct gpiod_lookup gpios_table[] = {
> -       GPIO_LOOKUP_IDX("gpio.0", 15, "foo.0", "led", 0, GPIO_ACTIVE_HIGH),
> -       GPIO_LOOKUP_IDX("gpio.0", 16, "foo.0", "led", 1, GPIO_ACTIVE_HIGH),
> -       GPIO_LOOKUP_IDX("gpio.0", 17, "foo.0", "led", 2, GPIO_ACTIVE_HIGH),
> -       GPIO_LOOKUP("gpio.0", 1, "foo.0", "power", GPIO_ACTIVE_LOW),
> -       };
> +struct gpiod_lookup_table gpios_table = {
> +       .dev_id = "foo.0",
> +       .size = 4,
> +       .table = {
> +               GPIO_LOOKUP_IDX("gpio.0", 15, "led", 0, GPIO_ACTIVE_HIGH),
> +               GPIO_LOOKUP_IDX("gpio.0", 16, "led", 1, GPIO_ACTIVE_HIGH),
> +               GPIO_LOOKUP_IDX("gpio.0", 17, "led", 2, GPIO_ACTIVE_HIGH),
> +               GPIO_LOOKUP("gpio.0", 1, "power", GPIO_ACTIVE_LOW),
> +       },
> +};
>
>  And the table can be added by the board code as follows:
>
> -       gpiod_add_table(gpios_table, ARRAY_SIZE(gpios_table));
> +       gpiod_add_lookup_table(&gpios_table);
>
>  The driver controlling "foo.0" will then be able to obtain its GPIOs as follows:
>
> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> index f72618ba716a..d17d6eabed6a 100644
> --- a/drivers/gpio/gpiolib.c
> +++ b/drivers/gpio/gpiolib.c
> @@ -2259,18 +2259,14 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
>  EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
>
>  /**
> - * gpiod_add_table() - register GPIO device consumers
> - * @table: array of consumers to register
> - * @num: number of consumers in table
> + * gpiod_add_lookup_table() - register GPIO device consumers
> + * @table: table of consumers to register
>   */
> -void gpiod_add_table(struct gpiod_lookup *table, size_t size)
> +void gpiod_add_lookup_table(struct gpiod_lookup_table *table)
>  {
>         mutex_lock(&gpio_lookup_lock);
>
> -       while (size--) {
> -               list_add_tail(&table->list, &gpio_lookup_list);
> -               table++;
> -       }
> +       list_add_tail(&table->list, &gpio_lookup_list);
>
>         mutex_unlock(&gpio_lookup_lock);
>  }
> @@ -2326,72 +2322,85 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
>         return desc;
>  }
>
> -static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
> -                                   unsigned int idx,
> -                                   enum gpio_lookup_flags *flags)
> +static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev)
>  {
>         const char *dev_id = dev ? dev_name(dev) : NULL;
> -       struct gpio_desc *desc = ERR_PTR(-ENODEV);
> -       unsigned int match, best = 0;
> -       struct gpiod_lookup *p;
> +       struct gpiod_lookup_table *table;
>
>         mutex_lock(&gpio_lookup_lock);
>
> -       list_for_each_entry(p, &gpio_lookup_list, list) {
> -               match = 0;
> +       list_for_each_entry(table, &gpio_lookup_list, list) {
> +               if (table->dev_id && dev_id) {
> +                       /*
> +                        * Valid strings on both ends, must be identical to have
> +                        * a match
> +                        */
> +                       if (!strcmp(table->dev_id, dev_id))
> +                               goto end;
> +               } else {
> +                       /*
> +                        * One of the pointers is NULL, so both must be to have
> +                        * a match
> +                        */
> +                       if (dev_id == table->dev_id)
> +                               goto end;
> +               }

Yes, in this case it looks clearer. Though, you might join last else
and if in one line.

> +       }
> +       table = NULL;

Up to you, though I think it's clearer to return NULL explicitly (and
unlock mutex before).

>
> -               if (p->dev_id) {
> -                       if (!dev_id || strcmp(p->dev_id, dev_id))
> -                               continue;
> +end:

Maybe 'found' suits better?

> +       mutex_unlock(&gpio_lookup_lock);
> +       return table;
> +}
>
> -                       match += 2;
> -               }
> +static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
> +                                   unsigned int idx,
> +                                   enum gpio_lookup_flags *flags)
> +{
> +       struct gpio_desc *desc = ERR_PTR(-ENODEV);
> +       struct gpiod_lookup_table *table;
> +       int i;
>
> -               if (p->con_id) {
> -                       if (!con_id || strcmp(p->con_id, con_id))
> -                               continue;
> +       table = gpiod_find_lookup_table(dev);
> +       if (!table)
> +               return desc;
>
> -                       match += 1;
> -               }
> +       for (i = 0; i < table->size; i++) {
> +               struct gpio_chip *chip;
> +               struct gpiod_lookup *p = &table->table[i];
>
> +               /* idx must always match exactly */
>                 if (p->idx != idx)
>                         continue;
>
> -               if (match > best) {
> -                       struct gpio_chip *chip;
> -
> -                       chip = find_chip_by_name(p->chip_label);
> -
> -                       if (!chip) {
> -                               dev_warn(dev, "cannot find GPIO chip %s\n",
> -                                        p->chip_label);
> -                               continue;
> -                       }
> +               /* If the lookup entry has a con_id, require exact match */
> +               if (p->con_id && (!con_id || strcmp(p->con_id, con_id)))
> +                       continue;
>
> -                       if (chip->ngpio <= p->chip_hwnum) {
> -                               dev_warn(dev, "GPIO chip %s has %d GPIOs\n",
> -                                        chip->label, chip->ngpio);
> -                               continue;
> -                       }
> +               chip = find_chip_by_name(p->chip_label);
>
> -                       desc = gpio_to_desc(chip->base + p->chip_hwnum);
> -                       *flags = p->flags;
> +               if (!chip) {

> +                       dev_warn(dev, "cannot find GPIO chip %s\n",
> +                                p->chip_label);

Could it be one line?

> +                       continue;
> +               }
>
> -                       if (match != 3)
> -                               best = match;
> -                       else
> -                               break;
> +               if (chip->ngpio <= p->chip_hwnum) {
> +                       dev_warn(dev, "GPIO chip %s has %d GPIOs\n",
> +                                chip->label, chip->ngpio);
> +                       continue;
>                 }
> -       }
>
> -       mutex_unlock(&gpio_lookup_lock);
> +               desc = gpiochip_offset_to_desc(chip, p->chip_hwnum);
> +               *flags = p->flags;
> +       }
>
>         return desc;
>  }
>
>  /**
>   * gpio_get - obtain a GPIO for a given GPIO function
> - * @dev:       GPIO consumer
> + * @dev:       GPIO consumer, can be NULL for system-global GPIOs
>   * @con_id:    function within the GPIO consumer
>   *
>   * Return the GPIO descriptor corresponding to the function con_id of device
> diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
> index 3ea2cf6b0e6c..44893ef40817 100644
> --- a/include/linux/gpio/driver.h
> +++ b/include/linux/gpio/driver.h
> @@ -140,7 +140,6 @@ enum gpio_lookup_flags {
>   * platform data.
>   */
>  struct gpiod_lookup {
> -       struct list_head list;
>         /*
>          * name of the chip the GPIO belongs to
>          */
> @@ -150,10 +149,6 @@ struct gpiod_lookup {
>          */
>         u16 chip_hwnum;
>         /*
> -        * name of device that can claim this GPIO
> -        */
> -       const char *dev_id;
> -       /*
>          * name of the GPIO from the device's point of view
>          */
>         const char *con_id;
> @@ -167,28 +162,33 @@ struct gpiod_lookup {
>         enum gpio_lookup_flags flags;
>  };
>
> +struct gpiod_lookup_table {
> +       struct list_head list;
> +       const char *dev_id;
> +       unsigned int size;
> +       struct gpiod_lookup table[];
> +};
> +
>  /*
>   * Simple definition of a single GPIO under a con_id
>   */
> -#define GPIO_LOOKUP(_chip_label, _chip_hwnum, _dev_id, _con_id, _flags) \
> -       GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _dev_id, _con_id, 0, _flags)
> +#define GPIO_LOOKUP(_chip_label, _chip_hwnum, _con_id, _flags) \
> +       GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _con_id, 0, _flags)
>
>  /*
>   * Use this macro if you need to have several GPIOs under the same con_id.
>   * Each GPIO needs to use a different index and can be accessed using
>   * gpiod_get_index()
>   */
> -#define GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _dev_id, _con_id, _idx, \
> -                       _flags)                                           \
> +#define GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _con_id, _idx, _flags)  \
>  {                                                                         \
>         .chip_label = _chip_label,                                        \
>         .chip_hwnum = _chip_hwnum,                                        \
> -       .dev_id = _dev_id,                                                \
>         .con_id = _con_id,                                                \
>         .idx = _idx,                                                      \
>         .flags = _flags,                                                  \
>  }
>
> -void gpiod_add_table(struct gpiod_lookup *table, size_t size);
> +void gpiod_add_lookup_table(struct gpiod_lookup_table *table);
>
>  #endif
> --
> 1.8.4.2
>



-- 
With Best Regards,
Andy Shevchenko

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

* Re: [PATCH] gpio: better lookup method for platform GPIOs
  2013-12-02 11:11     ` Heikki Krogerus
@ 2013-12-02 12:30       ` Alexandre Courbot
  2013-12-03  3:20         ` [PATCH v3] " Alexandre Courbot
  0 siblings, 1 reply; 19+ messages in thread
From: Alexandre Courbot @ 2013-12-02 12:30 UTC (permalink / raw)
  To: Heikki Krogerus
  Cc: Alex Courbot, Linus Walleij, Rhyland Klein, Mika Westerberg,
	linux-gpio, linux-kernel

On Mon, Dec 2, 2013 at 8:11 PM, Heikki Krogerus
<heikki.krogerus@linux.intel.com> wrote:
> Hi,
>
> On Mon, Dec 02, 2013 at 07:33:35PM +0900, Alex Courbot wrote:
>> On 11/29/2013 08:57 PM, Heikki Krogerus wrote:
>> >Hi,
>> >
>> >On Thu, Nov 28, 2013 at 05:46:28PM +0900, Alexandre Courbot wrote:
>> >>@@ -88,16 +89,20 @@ Note that GPIO_LOOKUP() is just a shortcut to GPIO_LOOKUP_IDX() where idx = 0.
>> >>
>> >>  A lookup table can then be defined as follows:
>> >>
>> >>-   struct gpiod_lookup gpios_table[] = {
>> >>-   GPIO_LOOKUP_IDX("gpio.0", 15, "foo.0", "led", 0, GPIO_ACTIVE_HIGH),
>> >>-   GPIO_LOOKUP_IDX("gpio.0", 16, "foo.0", "led", 1, GPIO_ACTIVE_HIGH),
>> >>-   GPIO_LOOKUP_IDX("gpio.0", 17, "foo.0", "led", 2, GPIO_ACTIVE_HIGH),
>> >>-   GPIO_LOOKUP("gpio.0", 1, "foo.0", "power", GPIO_ACTIVE_LOW),
>> >>-   };
>> >>+struct gpiod_lookup_table gpios_table = {
>> >>+   .dev_id = "foo.0",
>> >>+   .size = 4,
>> >>+   .table = {
>> >>+   GPIO_LOOKUP_IDX("gpio.0", 15, "led", 0, GPIO_ACTIVE_HIGH),
>> >>+   GPIO_LOOKUP_IDX("gpio.0", 16, "led", 1, GPIO_ACTIVE_HIGH),
>> >>+   GPIO_LOOKUP_IDX("gpio.0", 17, "led", 2, GPIO_ACTIVE_HIGH),
>> >>+   GPIO_LOOKUP("gpio.0", 1, "power", GPIO_ACTIVE_LOW),
>> >>+   },
>> >>+};
>> >
>> >Instead of using the size variable, wouldn't it be more clear to
>> >expect the array to be null terminated?
>>
>> This is a zero-length array, its entries are not pointers but
>> flattened lookup entries. Thus you cannot simply null-terminate it.
>> It would be possible to use { NULL } as a terminator, but this would
>> expand into a whole gpiod_lookup and is not very pleasant
>> esthetically-speaking. So I think the size member is maybe better
>> suited here.
>
> The gpio_loopup_table would look like this, which IMO is more nicer
> looking compared to the extra size variable:
>
> struct gpiod_lookup_table gpios_table = {
>         .dev_id = "foo.0",
>         .table = {
>                 GPIO_LOOKUP_IDX("gpio.0", 15, "led", 0, GPIO_ACTIVE_HIGH),
>                 GPIO_LOOKUP_IDX("gpio.0", 16, "led", 1, GPIO_ACTIVE_HIGH),
>                 GPIO_LOOKUP_IDX("gpio.0", 17, "led", 2, GPIO_ACTIVE_HIGH),
>                 GPIO_LOOKUP("gpio.0", 1, "power", GPIO_ACTIVE_LOW),
>                 { },
>         },
> };
>
> That would also make it more straight forward to handle in gbiolib.c:
>
> struct gpiod_lookup *p;
> ...
> for (p = table->table; p->chip_label; p++) {
> ...

Ok, you're obviously right here. Will send a v3 tomorrow morning JST.

Thanks for the review!

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

* Re: [PATCH v2] gpio: better lookup method for platform GPIOs
  2013-12-02 11:49   ` Andy Shevchenko
@ 2013-12-02 12:37     ` Alexandre Courbot
  0 siblings, 0 replies; 19+ messages in thread
From: Alexandre Courbot @ 2013-12-02 12:37 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Alexandre Courbot, Linus Walleij, Mika Westerberg, Rhyland Klein,
	Heikki Krogerus, linux-gpio, linux-kernel

On Mon, Dec 2, 2013 at 8:49 PM, Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
> On Mon, Dec 2, 2013 at 1:01 PM, Alexandre Courbot <acourbot@nvidia.com> wrote:
>> Change the format of the platform GPIO lookup tables to make them less
>> confusing and improve lookup efficiency.
>>
>> The previous format was a single linked-list that required to compare
>> the device name and function ID of every single GPIO defined for each
>> lookup. Switch that to a list of per-device tables, so that the lookup
>> can be done in two steps, omitting the GPIOs that are not relevant for a
>> particular device.
>>
>> The matching rules are now defined as follows:
>> - The device name must match *exactly*, and can be NULL for GPIOs not
>>   assigned to a particular device,
>> - If the function ID in the lookup table is NULL, the con_id argument of
>>   gpiod_get() will not be used for lookup. However, if it is defined, it
>>   must match exactly.
>> - The index must always match.
>
> Thanks for an updated version.
> Few minor comments below.
> Comments about loops are here as well.
>
> I any case:
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

Thanks!

>
>>
>> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
>> Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
>> ---
>> Changes since v1:
>> - Applied most fixes suggested by Andy
>> - Hopefully safer and less confusing table lookup algorithm
>> - Added Mika's ack
>>
>>  Documentation/gpio/board.txt |  25 ++++++----
>>  drivers/gpio/gpiolib.c       | 109 +++++++++++++++++++++++--------------------
>>  include/linux/gpio/driver.h  |  22 ++++-----
>>  3 files changed, 85 insertions(+), 71 deletions(-)
>>
>> diff --git a/Documentation/gpio/board.txt b/Documentation/gpio/board.txt
>> index 0d03506f2cc5..a4fdd96cef93 100644
>> --- a/Documentation/gpio/board.txt
>> +++ b/Documentation/gpio/board.txt
>> @@ -72,10 +72,11 @@ where
>>
>>    - chip_label is the label of the gpiod_chip instance providing the GPIO
>>    - chip_hwnum is the hardware number of the GPIO within the chip
>> -  - dev_id is the identifier of the device that will make use of this GPIO. If
>> -       NULL, the GPIO will be available to all devices.
>> +  - dev_id is the identifier of the device that will make use of this GPIO. It
>> +       can be NULL, in which case it will be matched for calls to gpiod_get()
>> +       with a NULL device.
>>    - con_id is the name of the GPIO function from the device point of view. It
>> -       can be NULL.
>> +       can be NULL, in which case it will match any function.
>>    - idx is the index of the GPIO within the function.
>>    - flags is defined to specify the following properties:
>>         * GPIOF_ACTIVE_LOW      - to configure the GPIO as active-low
>> @@ -88,16 +89,20 @@ Note that GPIO_LOOKUP() is just a shortcut to GPIO_LOOKUP_IDX() where idx = 0.
>>
>>  A lookup table can then be defined as follows:
>>
>> -       struct gpiod_lookup gpios_table[] = {
>> -       GPIO_LOOKUP_IDX("gpio.0", 15, "foo.0", "led", 0, GPIO_ACTIVE_HIGH),
>> -       GPIO_LOOKUP_IDX("gpio.0", 16, "foo.0", "led", 1, GPIO_ACTIVE_HIGH),
>> -       GPIO_LOOKUP_IDX("gpio.0", 17, "foo.0", "led", 2, GPIO_ACTIVE_HIGH),
>> -       GPIO_LOOKUP("gpio.0", 1, "foo.0", "power", GPIO_ACTIVE_LOW),
>> -       };
>> +struct gpiod_lookup_table gpios_table = {
>> +       .dev_id = "foo.0",
>> +       .size = 4,
>> +       .table = {
>> +               GPIO_LOOKUP_IDX("gpio.0", 15, "led", 0, GPIO_ACTIVE_HIGH),
>> +               GPIO_LOOKUP_IDX("gpio.0", 16, "led", 1, GPIO_ACTIVE_HIGH),
>> +               GPIO_LOOKUP_IDX("gpio.0", 17, "led", 2, GPIO_ACTIVE_HIGH),
>> +               GPIO_LOOKUP("gpio.0", 1, "power", GPIO_ACTIVE_LOW),
>> +       },
>> +};
>>
>>  And the table can be added by the board code as follows:
>>
>> -       gpiod_add_table(gpios_table, ARRAY_SIZE(gpios_table));
>> +       gpiod_add_lookup_table(&gpios_table);
>>
>>  The driver controlling "foo.0" will then be able to obtain its GPIOs as follows:
>>
>> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
>> index f72618ba716a..d17d6eabed6a 100644
>> --- a/drivers/gpio/gpiolib.c
>> +++ b/drivers/gpio/gpiolib.c
>> @@ -2259,18 +2259,14 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
>>  EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
>>
>>  /**
>> - * gpiod_add_table() - register GPIO device consumers
>> - * @table: array of consumers to register
>> - * @num: number of consumers in table
>> + * gpiod_add_lookup_table() - register GPIO device consumers
>> + * @table: table of consumers to register
>>   */
>> -void gpiod_add_table(struct gpiod_lookup *table, size_t size)
>> +void gpiod_add_lookup_table(struct gpiod_lookup_table *table)
>>  {
>>         mutex_lock(&gpio_lookup_lock);
>>
>> -       while (size--) {
>> -               list_add_tail(&table->list, &gpio_lookup_list);
>> -               table++;
>> -       }
>> +       list_add_tail(&table->list, &gpio_lookup_list);
>>
>>         mutex_unlock(&gpio_lookup_lock);
>>  }
>> @@ -2326,72 +2322,85 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
>>         return desc;
>>  }
>>
>> -static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
>> -                                   unsigned int idx,
>> -                                   enum gpio_lookup_flags *flags)
>> +static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev)
>>  {
>>         const char *dev_id = dev ? dev_name(dev) : NULL;
>> -       struct gpio_desc *desc = ERR_PTR(-ENODEV);
>> -       unsigned int match, best = 0;
>> -       struct gpiod_lookup *p;
>> +       struct gpiod_lookup_table *table;
>>
>>         mutex_lock(&gpio_lookup_lock);
>>
>> -       list_for_each_entry(p, &gpio_lookup_list, list) {
>> -               match = 0;
>> +       list_for_each_entry(table, &gpio_lookup_list, list) {
>> +               if (table->dev_id && dev_id) {
>> +                       /*
>> +                        * Valid strings on both ends, must be identical to have
>> +                        * a match
>> +                        */
>> +                       if (!strcmp(table->dev_id, dev_id))
>> +                               goto end;
>> +               } else {
>> +                       /*
>> +                        * One of the pointers is NULL, so both must be to have
>> +                        * a match
>> +                        */
>> +                       if (dev_id == table->dev_id)
>> +                               goto end;
>> +               }
>
> Yes, in this case it looks clearer. Though, you might join last else
> and if in one line.

I don't think that would conform to the coding conventions. Will try
and see if checkpatch complains, but I'm rather confident it will...

>
>> +       }
>> +       table = NULL;
>
> Up to you, though I think it's clearer to return NULL explicitly (and
> unlock mutex before).

As v1 of this patch can attest, the less return statements in a
lock-holding function, the better. :)

>
>>
>> -               if (p->dev_id) {
>> -                       if (!dev_id || strcmp(p->dev_id, dev_id))
>> -                               continue;
>> +end:
>
> Maybe 'found' suits better?

But we end up here even if we haven't "found" anything...

>
>> +       mutex_unlock(&gpio_lookup_lock);
>> +       return table;
>> +}
>>
>> -                       match += 2;
>> -               }
>> +static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
>> +                                   unsigned int idx,
>> +                                   enum gpio_lookup_flags *flags)
>> +{
>> +       struct gpio_desc *desc = ERR_PTR(-ENODEV);
>> +       struct gpiod_lookup_table *table;
>> +       int i;
>>
>> -               if (p->con_id) {
>> -                       if (!con_id || strcmp(p->con_id, con_id))
>> -                               continue;
>> +       table = gpiod_find_lookup_table(dev);
>> +       if (!table)
>> +               return desc;
>>
>> -                       match += 1;
>> -               }
>> +       for (i = 0; i < table->size; i++) {
>> +               struct gpio_chip *chip;
>> +               struct gpiod_lookup *p = &table->table[i];
>>
>> +               /* idx must always match exactly */
>>                 if (p->idx != idx)
>>                         continue;
>>
>> -               if (match > best) {
>> -                       struct gpio_chip *chip;
>> -
>> -                       chip = find_chip_by_name(p->chip_label);
>> -
>> -                       if (!chip) {
>> -                               dev_warn(dev, "cannot find GPIO chip %s\n",
>> -                                        p->chip_label);
>> -                               continue;
>> -                       }
>> +               /* If the lookup entry has a con_id, require exact match */
>> +               if (p->con_id && (!con_id || strcmp(p->con_id, con_id)))
>> +                       continue;
>>
>> -                       if (chip->ngpio <= p->chip_hwnum) {
>> -                               dev_warn(dev, "GPIO chip %s has %d GPIOs\n",
>> -                                        chip->label, chip->ngpio);
>> -                               continue;
>> -                       }
>> +               chip = find_chip_by_name(p->chip_label);
>>
>> -                       desc = gpio_to_desc(chip->base + p->chip_hwnum);
>> -                       *flags = p->flags;
>> +               if (!chip) {
>
>> +                       dev_warn(dev, "cannot find GPIO chip %s\n",
>> +                                p->chip_label);
>
> Could it be one line?

The line would be 84 characters if we do that, unfortunately.

Thanks for the review!
Alex.

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

* [PATCH v3] gpio: better lookup method for platform GPIOs
  2013-12-02 12:30       ` Alexandre Courbot
@ 2013-12-03  3:20         ` Alexandre Courbot
  2013-12-03 11:04           ` Heikki Krogerus
                             ` (2 more replies)
  0 siblings, 3 replies; 19+ messages in thread
From: Alexandre Courbot @ 2013-12-03  3:20 UTC (permalink / raw)
  To: Linus Walleij, Mika Westerberg, Andy Shevchenko, Rhyland Klein,
	Heikki Krogerus
  Cc: linux-gpio, linux-kernel, Alexandre Courbot

Change the format of the platform GPIO lookup tables to make them less
confusing and improve lookup efficiency.

The previous format was a single linked-list that required to compare
the device name and function ID of every single GPIO defined for each
lookup. Switch that to a list of per-device tables, so that the lookup
can be done in two steps, omitting the GPIOs that are not relevant for a
particular device.

The matching rules are now defined as follows:
- The device name must match *exactly*, and can be NULL for GPIOs not
  assigned to a particular device,
- If the function ID in the lookup table is NULL, the con_id argument of
  gpiod_get() will not be used for lookup. However, if it is defined, it
  must match exactly.
- The index must always match.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
Changes since v2:
- Removed size member of the gpiod_lookup_table struct (thanks Heikki!)
- Added Andy's reviewed-by

 Documentation/gpio/board.txt |  28 ++++++-----
 drivers/gpio/gpiolib.c       | 108 +++++++++++++++++++++++--------------------
 include/linux/gpio/driver.h  |  21 ++++-----
 3 files changed, 85 insertions(+), 72 deletions(-)

diff --git a/Documentation/gpio/board.txt b/Documentation/gpio/board.txt
index 0d03506f2cc5..ba169faad5c6 100644
--- a/Documentation/gpio/board.txt
+++ b/Documentation/gpio/board.txt
@@ -72,10 +72,11 @@ where
 
   - chip_label is the label of the gpiod_chip instance providing the GPIO
   - chip_hwnum is the hardware number of the GPIO within the chip
-  - dev_id is the identifier of the device that will make use of this GPIO. If
-	NULL, the GPIO will be available to all devices.
+  - dev_id is the identifier of the device that will make use of this GPIO. It
+	can be NULL, in which case it will be matched for calls to gpiod_get()
+	with a NULL device.
   - con_id is the name of the GPIO function from the device point of view. It
-	can be NULL.
+	can be NULL, in which case it will match any function.
   - idx is the index of the GPIO within the function.
   - flags is defined to specify the following properties:
 	* GPIOF_ACTIVE_LOW	- to configure the GPIO as active-low
@@ -86,18 +87,23 @@ In the future, these flags might be extended to support more properties.
 
 Note that GPIO_LOOKUP() is just a shortcut to GPIO_LOOKUP_IDX() where idx = 0.
 
-A lookup table can then be defined as follows:
+A lookup table can then be defined as follows, with an empty entry defining its
+end:
 
-	struct gpiod_lookup gpios_table[] = {
-	GPIO_LOOKUP_IDX("gpio.0", 15, "foo.0", "led", 0, GPIO_ACTIVE_HIGH),
-	GPIO_LOOKUP_IDX("gpio.0", 16, "foo.0", "led", 1, GPIO_ACTIVE_HIGH),
-	GPIO_LOOKUP_IDX("gpio.0", 17, "foo.0", "led", 2, GPIO_ACTIVE_HIGH),
-	GPIO_LOOKUP("gpio.0", 1, "foo.0", "power", GPIO_ACTIVE_LOW),
-	};
+struct gpiod_lookup_table gpios_table = {
+	.dev_id = "foo.0",
+	.table = {
+		GPIO_LOOKUP_IDX("gpio.0", 15, "led", 0, GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP_IDX("gpio.0", 16, "led", 1, GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP_IDX("gpio.0", 17, "led", 2, GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("gpio.0", 1, "power", GPIO_ACTIVE_LOW),
+		{ },
+	},
+};
 
 And the table can be added by the board code as follows:
 
-	gpiod_add_table(gpios_table, ARRAY_SIZE(gpios_table));
+	gpiod_add_lookup_table(&gpios_table);
 
 The driver controlling "foo.0" will then be able to obtain its GPIOs as follows:
 
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index f72618ba716a..ea95b42c6154 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -2259,18 +2259,14 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
 EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
 
 /**
- * gpiod_add_table() - register GPIO device consumers
- * @table: array of consumers to register
- * @num: number of consumers in table
+ * gpiod_add_lookup_table() - register GPIO device consumers
+ * @table: table of consumers to register
  */
-void gpiod_add_table(struct gpiod_lookup *table, size_t size)
+void gpiod_add_lookup_table(struct gpiod_lookup_table *table)
 {
 	mutex_lock(&gpio_lookup_lock);
 
-	while (size--) {
-		list_add_tail(&table->list, &gpio_lookup_list);
-		table++;
-	}
+	list_add_tail(&table->list, &gpio_lookup_list);
 
 	mutex_unlock(&gpio_lookup_lock);
 }
@@ -2326,72 +2322,84 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
 	return desc;
 }
 
-static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
-				    unsigned int idx,
-				    enum gpio_lookup_flags *flags)
+static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev)
 {
 	const char *dev_id = dev ? dev_name(dev) : NULL;
-	struct gpio_desc *desc = ERR_PTR(-ENODEV);
-	unsigned int match, best = 0;
-	struct gpiod_lookup *p;
+	struct gpiod_lookup_table *table;
 
 	mutex_lock(&gpio_lookup_lock);
 
-	list_for_each_entry(p, &gpio_lookup_list, list) {
-		match = 0;
+	list_for_each_entry(table, &gpio_lookup_list, list) {
+		if (table->dev_id && dev_id) {
+			/*
+			 * Valid strings on both ends, must be identical to have
+			 * a match
+			 */
+			if (!strcmp(table->dev_id, dev_id))
+				goto found;
+		} else {
+			/*
+			 * One of the pointers is NULL, so both must be to have
+			 * a match
+			 */
+			if (dev_id == table->dev_id)
+				goto found;
+		}
+	}
+	table = NULL;
 
-		if (p->dev_id) {
-			if (!dev_id || strcmp(p->dev_id, dev_id))
-				continue;
+found:
+	mutex_unlock(&gpio_lookup_lock);
+	return table;
+}
 
-			match += 2;
-		}
+static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
+				    unsigned int idx,
+				    enum gpio_lookup_flags *flags)
+{
+	struct gpio_desc *desc = ERR_PTR(-ENODEV);
+	struct gpiod_lookup_table *table;
+	struct gpiod_lookup *p;
 
-		if (p->con_id) {
-			if (!con_id || strcmp(p->con_id, con_id))
-				continue;
+	table = gpiod_find_lookup_table(dev);
+	if (!table)
+		return desc;
 
-			match += 1;
-		}
+	for (p = &table->table[0]; p->chip_label; p++) {
+		struct gpio_chip *chip;
 
+		/* idx must always match exactly */
 		if (p->idx != idx)
 			continue;
 
-		if (match > best) {
-			struct gpio_chip *chip;
-
-			chip = find_chip_by_name(p->chip_label);
-
-			if (!chip) {
-				dev_warn(dev, "cannot find GPIO chip %s\n",
-					 p->chip_label);
-				continue;
-			}
+		/* If the lookup entry has a con_id, require exact match */
+		if (p->con_id && (!con_id || strcmp(p->con_id, con_id)))
+			continue;
 
-			if (chip->ngpio <= p->chip_hwnum) {
-				dev_warn(dev, "GPIO chip %s has %d GPIOs\n",
-					 chip->label, chip->ngpio);
-				continue;
-			}
+		chip = find_chip_by_name(p->chip_label);
 
-			desc = gpio_to_desc(chip->base + p->chip_hwnum);
-			*flags = p->flags;
+		if (!chip) {
+			dev_warn(dev, "cannot find GPIO chip %s\n",
+				 p->chip_label);
+			continue;
+		}
 
-			if (match != 3)
-				best = match;
-			else
-				break;
+		if (chip->ngpio <= p->chip_hwnum) {
+			dev_warn(dev, "GPIO chip %s has %d GPIOs\n",
+				 chip->label, chip->ngpio);
+			continue;
 		}
-	}
 
-	mutex_unlock(&gpio_lookup_lock);
+		desc = gpiochip_offset_to_desc(chip, p->chip_hwnum);
+		*flags = p->flags;
+	}
 
 	return desc;
 }
 
 /**
  * gpio_get - obtain a GPIO for a given GPIO function
- * @dev:	GPIO consumer
+ * @dev:	GPIO consumer, can be NULL for system-global GPIOs
  * @con_id:	function within the GPIO consumer
  *
  * Return the GPIO descriptor corresponding to the function con_id of device
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 3ea2cf6b0e6c..7193f43d0764 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -140,7 +140,6 @@ enum gpio_lookup_flags {
  * platform data.
  */
 struct gpiod_lookup {
-	struct list_head list;
 	/*
 	 * name of the chip the GPIO belongs to
 	 */
@@ -150,10 +149,6 @@ struct gpiod_lookup {
 	 */
 	u16 chip_hwnum;
 	/*
-	 * name of device that can claim this GPIO
-	 */
-	const char *dev_id;
-	/*
 	 * name of the GPIO from the device's point of view
 	 */
 	const char *con_id;
@@ -167,28 +162,32 @@ struct gpiod_lookup {
 	enum gpio_lookup_flags flags;
 };
 
+struct gpiod_lookup_table {
+	struct list_head list;
+	const char *dev_id;
+	struct gpiod_lookup table[];
+};
+
 /*
  * Simple definition of a single GPIO under a con_id
  */
-#define GPIO_LOOKUP(_chip_label, _chip_hwnum, _dev_id, _con_id, _flags) \
-	GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _dev_id, _con_id, 0, _flags)
+#define GPIO_LOOKUP(_chip_label, _chip_hwnum, _con_id, _flags) \
+	GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _con_id, 0, _flags)
 
 /*
  * Use this macro if you need to have several GPIOs under the same con_id.
  * Each GPIO needs to use a different index and can be accessed using
  * gpiod_get_index()
  */
-#define GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _dev_id, _con_id, _idx, \
-			_flags)                                           \
+#define GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _con_id, _idx, _flags)  \
 {                                                                         \
 	.chip_label = _chip_label,                                        \
 	.chip_hwnum = _chip_hwnum,                                        \
-	.dev_id = _dev_id,                                                \
 	.con_id = _con_id,                                                \
 	.idx = _idx,                                                      \
 	.flags = _flags,                                                  \
 }
 
-void gpiod_add_table(struct gpiod_lookup *table, size_t size);
+void gpiod_add_lookup_table(struct gpiod_lookup_table *table);
 
 #endif
-- 
1.8.4.2


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

* Re: [PATCH v3] gpio: better lookup method for platform GPIOs
  2013-12-03  3:20         ` [PATCH v3] " Alexandre Courbot
@ 2013-12-03 11:04           ` Heikki Krogerus
  2013-12-03 12:12           ` Linus Walleij
  2013-12-09 13:07           ` Linus Walleij
  2 siblings, 0 replies; 19+ messages in thread
From: Heikki Krogerus @ 2013-12-03 11:04 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Linus Walleij, Mika Westerberg, Andy Shevchenko, Rhyland Klein,
	linux-gpio, linux-kernel

Hi,

On Tue, Dec 03, 2013 at 12:20:11PM +0900, Alexandre Courbot wrote:
> Change the format of the platform GPIO lookup tables to make them less
> confusing and improve lookup efficiency.
> 
> The previous format was a single linked-list that required to compare
> the device name and function ID of every single GPIO defined for each
> lookup. Switch that to a list of per-device tables, so that the lookup
> can be done in two steps, omitting the GPIOs that are not relevant for a
> particular device.
> 
> The matching rules are now defined as follows:
> - The device name must match *exactly*, and can be NULL for GPIOs not
>   assigned to a particular device,
> - If the function ID in the lookup table is NULL, the con_id argument of
>   gpiod_get() will not be used for lookup. However, if it is defined, it
>   must match exactly.
> - The index must always match.
> 
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
> Changes since v2:
> - Removed size member of the gpiod_lookup_table struct (thanks Heikki!)
> - Added Andy's reviewed-by
> 
>  Documentation/gpio/board.txt |  28 ++++++-----
>  drivers/gpio/gpiolib.c       | 108 +++++++++++++++++++++++--------------------
>  include/linux/gpio/driver.h  |  21 ++++-----
>  3 files changed, 85 insertions(+), 72 deletions(-)

Looks good. Thanks Alexandre!


-- 
heikki

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

* Re: [PATCH v3] gpio: better lookup method for platform GPIOs
  2013-12-03  3:20         ` [PATCH v3] " Alexandre Courbot
  2013-12-03 11:04           ` Heikki Krogerus
@ 2013-12-03 12:12           ` Linus Walleij
  2013-12-09 13:07           ` Linus Walleij
  2 siblings, 0 replies; 19+ messages in thread
From: Linus Walleij @ 2013-12-03 12:12 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Mika Westerberg, Andy Shevchenko, Rhyland Klein, Heikki Krogerus,
	linux-gpio, linux-kernel

On Tue, Dec 3, 2013 at 4:20 AM, Alexandre Courbot <acourbot@nvidia.com> wrote:

> Change the format of the platform GPIO lookup tables to make them less
> confusing and improve lookup efficiency.
>
> The previous format was a single linked-list that required to compare
> the device name and function ID of every single GPIO defined for each
> lookup. Switch that to a list of per-device tables, so that the lookup
> can be done in two steps, omitting the GPIOs that are not relevant for a
> particular device.
>
> The matching rules are now defined as follows:
> - The device name must match *exactly*, and can be NULL for GPIOs not
>   assigned to a particular device,
> - If the function ID in the lookup table is NULL, the con_id argument of
>   gpiod_get() will not be used for lookup. However, if it is defined, it
>   must match exactly.
> - The index must always match.
>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
> Changes since v2:
> - Removed size member of the gpiod_lookup_table struct (thanks Heikki!)
> - Added Andy's reviewed-by

OK looks good, however I must get my fixes stack to Torvalds
and pull -rc3 back in before I can apply this, it seems, as
it builds upon pending fixes.

Yours,
Linus Walleij

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

* Re: [PATCH v3] gpio: better lookup method for platform GPIOs
  2013-12-03  3:20         ` [PATCH v3] " Alexandre Courbot
  2013-12-03 11:04           ` Heikki Krogerus
  2013-12-03 12:12           ` Linus Walleij
@ 2013-12-09 13:07           ` Linus Walleij
  2 siblings, 0 replies; 19+ messages in thread
From: Linus Walleij @ 2013-12-09 13:07 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Mika Westerberg, Andy Shevchenko, Rhyland Klein, Heikki Krogerus,
	linux-gpio, linux-kernel

On Tue, Dec 3, 2013 at 4:20 AM, Alexandre Courbot <acourbot@nvidia.com> wrote:

> Change the format of the platform GPIO lookup tables to make them less
> confusing and improve lookup efficiency.
>
> The previous format was a single linked-list that required to compare
> the device name and function ID of every single GPIO defined for each
> lookup. Switch that to a list of per-device tables, so that the lookup
> can be done in two steps, omitting the GPIOs that are not relevant for a
> particular device.
>
> The matching rules are now defined as follows:
> - The device name must match *exactly*, and can be NULL for GPIOs not
>   assigned to a particular device,
> - If the function ID in the lookup table is NULL, the con_id argument of
>   gpiod_get() will not be used for lookup. However, if it is defined, it
>   must match exactly.
> - The index must always match.
>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
> Changes since v2:
> - Removed size member of the gpiod_lookup_table struct (thanks Heikki!)
> - Added Andy's reviewed-by

Merged in v3.13-rc3 into my devel branch and applied this on top
today.

Thanks!
Linus Walleij

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

end of thread, other threads:[~2013-12-09 13:07 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-11-28  8:46 [PATCH] gpio: better lookup method for platform GPIOs Alexandre Courbot
2013-11-28 14:45 ` Linus Walleij
2013-11-28 15:42   ` Andy Shevchenko
2013-11-28 16:59   ` Mika Westerberg
2013-11-28 15:54 ` Andy Shevchenko
2013-11-29  6:17   ` Andy Shevchenko
2013-12-02 10:50   ` Alex Courbot
2013-11-29 11:57 ` Heikki Krogerus
2013-11-29 11:59   ` Heikki Krogerus
2013-12-02 10:33   ` Alex Courbot
2013-12-02 11:11     ` Heikki Krogerus
2013-12-02 12:30       ` Alexandre Courbot
2013-12-03  3:20         ` [PATCH v3] " Alexandre Courbot
2013-12-03 11:04           ` Heikki Krogerus
2013-12-03 12:12           ` Linus Walleij
2013-12-09 13:07           ` Linus Walleij
2013-12-02 11:01 ` [PATCH v2] " Alexandre Courbot
2013-12-02 11:49   ` Andy Shevchenko
2013-12-02 12:37     ` Alexandre Courbot

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