Thread (20 messages) 20 messages, 5 authors, 2020-03-17

Re: [PATCH v5 3/5] gpio: Add GPIO Aggregator

From: Linus Walleij <hidden>
Date: 2020-03-12 14:57:41
Also in: linux-gpio, linux-renesas-soc, lkml, qemu-devel

Hi Geert,

thanks for your patience and again sorry for procrastination on my part :(

Overall I start to like this driver a lot. It has come a long way.

Some comments below are nitpicky, bear with me if they seem stupid.

On Tue, Feb 18, 2020 at 4:18 PM Geert Uytterhoeven
[off-list ref] wrote:
+#define DRV_NAME       "gpio-aggregator"
+#define pr_fmt(fmt)    DRV_NAME ": " fmt
I would just use dev_[info|err] for all messages to get rid of this.
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/ctype.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <linux/gpio/machine.h>
+#include <linux/idr.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/overflow.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+
+#include "gpiolib.h"
When this file is includes I prefer if there is a comment next to
this include saying why we have to touch internals and which
ones.
+struct gpio_aggregator {
+       struct gpiod_lookup_table *lookups;
+       struct platform_device *pdev;
What about just storing struct device *dev?

Then callbacks can just

dev_err(aggregator->dev, "myerror\n");
+static char *get_arg(char **args)
+{
+       char *start = *args, *end;
+
+       start = skip_spaces(start);
+       if (!*start)
+               return NULL;
+
+       if (*start == '"') {
+               /* Quoted arg */
+               end = strchr(++start, '"');
+               if (!end)
+                       return ERR_PTR(-EINVAL);
+       } else {
+               /* Unquoted arg */
+               for (end = start; *end && !isspace(*end); end++) ;
+       }
+
+       if (*end)
+               *end++ = '\0';
+
+       *args = end;
+       return start;
+}
Isn't this function reimplementing strsep()?
while ((s = strsep(&p, " \""))) {
or something.

I'm not the best with strings, just asking so I know you tried it
already.
+static int aggr_parse(struct gpio_aggregator *aggr)
+{
+       unsigned int first_index, last_index, i, n = 0;
+       char *name, *offsets, *first, *last, *next;
+       char *args = aggr->args;
+       int error;
+
+       for (name = get_arg(&args), offsets = get_arg(&args); name;
+            offsets = get_arg(&args)) {
+               if (IS_ERR(name)) {
+                       pr_err("Cannot get GPIO specifier: %pe\n", name);
If gpio_aggregrator contained struct device *dev this would be
dev_err(aggr->dev, "...\n");
+static void gpio_aggregator_free(struct gpio_aggregator *aggr)
+{
+       platform_device_unregister(aggr->pdev);
Aha maybe store both the pdev and the dev in the struct then?

Or print using &aggr->pdev.dev.
+       /*
+        * If any of the GPIO lines are sleeping, then the entire forwarder
+        * will be sleeping.
+        * If any of the chips support .set_config(), then the forwarder will
+        * support setting configs.
+        */
+       for (i = 0; i < ngpios; i++) {
+               dev_dbg(dev, "gpio %u => gpio-%d (%s)\n", i,
+                       desc_to_gpio(descs[i]), descs[i]->label ? : "?");
If this desc->label business is why you need to include
"gpiolib.h" then I'd prefer if you just add a

const char *gpiod_get_producer_name(struct gpio_desc *desc);

to gpiolib (add in <linux/gpio/consumer.h> so that gpiolib can
try to give you something reasonable to print for the label here.
I ran into that problem before (wanting to print something like this)
and usually just printed the offset.

But if it is a serious debug issue, let's fix a helper for this.

gpiod_get_producer_name() could return the thing in
desc->label if that is set or else something along
"chipname-offset" or "unknown", I'm not very picky
with that.
error = aggr_add_gpio(aggr, name, U16_MAX, &n);
Is the reason why you use e.g. "gpiochip0" as name here that this
is a simple ABI for userspace?

Such like obtained from /sys/bus/gpio/devices/<chipname>?

I would actually prefer to just add a sysfs attribute
such as "name" and set it to the value of gpiochip->label.

These labels are compulsory and supposed to be unique.

Then whatever creates an aggregator can just use
cat /sys/bus/gpio/devices/gpiochipN/name to send in
through the sysfs interface to this kernel driver.

This will protect you in the following way:

When a system is booted and populated the N in
gpiochipN is not stable and this aggregator will be used
by scripts that assume it is. We already had this dilemma
with things like network interfaces like eth0/1.

This can be because of things like probe order which
can be random, or because someone compiled a
kernel with a new driver for a gpiochip that wasn't
detected before. This recently happened to Raspberry Pi,
that added gpio driver for "firmware GPIOs" (IIRC).

The label on the chip is going to be more stable
I think, so it is better to use that.

This should also rid the need to include "gpiolib.h"
which makes me nervous.

Yours,
Linus Walleij
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help