Re: [PATCH v2] RFC: interrupt consistency check for OF GPIO IRQs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On Thursday 15 August 2013 at 11:53:15, Tomasz Figa wrote:
> Hi Lars, Linus,
> 
> On Tuesday 13 of August 2013 11:46:35 Lars Poeschel wrote:
> > From: Linus Walleij <linus.walleij@xxxxxxxxxx>
> > 
> > Currently the kernel is ambigously treating GPIOs and interrupts
> > from a GPIO controller: GPIOs and interrupts are treated as
> > orthogonal. This unfortunately makes it unclear how to actually
> > retrieve and request a GPIO line or interrupt from a GPIO
> > controller in the device tree probe path.
> > 
> > In the non-DT probe path it is clear that the GPIO number has to
> > be passed to the consuming device, and if it is to be used as
> > an interrupt, the consumer shall performa a gpio_to_irq() mapping
> > and request the resulting IRQ number.
> > 
> > In the DT boot path consumers may have been given one or more
> > interrupts from the interrupt-controller side of the GPIO chip
> > in an abstract way, such that the driver is not aware of the
> > fact that a GPIO chip is backing this interrupt, and the GPIO
> > side of the same line is never requested with gpio_request().
> > A typical case for this is ethernet chips which just take some
> > interrupt line which may be a "hard" interrupt line (such as an
> > external interrupt line from an SoC) or a cascaded interrupt
> > connected to a GPIO line.
> > 
> > This has the following undesired effects:
> > 
> > - The GPIOlib subsystem is not aware that the line is in use
> > 
> >   and willingly lets some other consumer perform gpio_request()
> >   on it, leading to a complex resource conflict if it occurs.
> > 
> > - The GPIO debugfs file claims this GPIO line is "free".
> > 
> > - The line direction of the interrupt GPIO line is not
> > 
> >   explicitly set as input, even though it is obvious that such
> >   a line need to be set up in this way, often making the system
> >   depend on boot-on defaults for this kind of settings.
> > 
> > To solve this dilemma, perform an interrupt consistency check
> > when adding a GPIO chip: if the chip is both gpio-controller and
> > interrupt-controller, walk all children of the device tree,
> > check if these in turn reference the interrupt-controller, and
> > if they do, loop over the interrupts used by that child and
> > perform gpio_reques() and gpio_direction_input() on these,
> > making them unreachable from the GPIO side.
> 
> The idea is rather interesting, but there are some problems I commented
> on inline. (Feel free to ignore those that are nits, since this is at
> RFC stage.)

I don't want to ignore. I want to discuss and test the idea here. Thanks 
for your contribution!

> >  /**
> > 
> > + * of_gpio_scan_nodes_and_x_irq_lines - internal function to
> 
> Hmm, what is an "x irq line"?

You already found out. Comment on this is below.
 
> > +	for_each_child_of_node(node, child) {
> > +		of_gpio_scan_nodes_and_x_irq_lines(child, gcn, gc,
> 
> request);
> 
> nit: A blank line would be nice here.

Ok.

> > +		/* Check if we have an IRQ parent, else continue */
> > +		irq_parent = of_irq_find_parent(child);
> > +		if (!irq_parent)
> > +			continue;
> 
> You can probably put the irq_parent node here to not duplicate calls in
> both code paths below.

I thought about that before. Is this really allowed? Would the inequality-
check (irq_parent != gcn) after of_node_put be still valid?
 
> > +		/* Is it so that this very GPIO chip is the parent? */
> > +		if (irq_parent != gcn) {
> > +			of_node_put(irq_parent);
> > +			continue;
> > +		}
> > +		of_node_put(irq_parent);
> > +
> > +		pr_debug("gpiochip OF: node %s references GPIO interrupt
> 
> lines\n",
> 
> > +				child->name);
> > +
> > +		/* Get the interrupts property */
> > +		intspec = of_get_property(child, "interrupts", &intlen);
> > +		if (intspec == NULL)
> > +			continue;
> > +		intlen /= sizeof(*intspec);
> > +
> > +		num_irq = of_irq_count(gcn);
> > +		for (i = 0; i < num_irq; i++) {
> > +			/*
> > +			 * The first cell is always the local IRQ number,
> 
> and
> 
> > +			 * this corresponds to the GPIO line offset for a
> 
> GPIO
> 
> > +			 * chip.
> > +			 *
> > +			 * FIXME: take interrupt-cells into account here.
> 
> This is the biggest problem of this patch. It assumes that there is only
> a single and shared GPIO/interrupt specification scheme, which might
> not be true.
> 
> First of all, almost all interrupt bindings have an extra, semi-generic
> flags field as last cell in the specifier. Now there can be more than
> one cell used to index GPIOs and interrupts, for example:
> 
> 	interrupts = <1 3 8>
> 
> which could mean: bank 1, pin 3, low level triggered.
> 
> I think you may need to reuse a lot of the code that normally parses the
> interrupts property, i.e. the irq_of_parse_and_map() path, which will
> then give you the hwirq index inside your irq chip, which may (or may
> not) be the same as the GPIO offset inside your GPIO chip.

Ok, valid objection. This is what the FIXME is about. But this should be 
solvable. Am I right that there are 3 cases to handle:
interrupt-cells = 1: It is the index for the gpio.
interrupt-cells = 2: First is index for the gpio, second flags (like low 
level triggered)
interrupt-cells = 3: First bank number, middle gpio inside that bank, last 
flags.

You are right, that we should try to reuse existing code for that. I will 
see, if I find the time to put up a third patch, which honors this.

> If you're unlucky enough to spot a controller that uses completely
> different numbering schemes for GPIOs and interrupts, then you're
> probably screwed, because only the driver for this controller can know
> the mapping between them.

Do such cases exist right now? Shouldn't be the number I request for 
interrupt in the device tree the gpio number I use with this chip ? 
Everything else would be weird.

> I don't have any good ideas for doing this properly at the moment, but I
> will think about it and post another reply if something nice comes to my
> mind.

If we really have to take this into account, that would require an 
additional function pointer inside gpio_chip, something like irq_to_gpio. 
The driver has to implement this functions then.
 
> > +			 */
> > +			offset = of_read_number(intspec + i, 1);
> 
> nit: of_read_number is a little overkill for simply getting a single
> cell. You could use be32_to_cpup(intspec + i) to achieve the same.

Ok.

> > +			pr_debug("gpiochip: OF node references
> 
> offset=%d\n",
> 
> > +				 offset);
> > +
> > +			if (request) {
> > +				/*
> > +				 * This child is making a reference to
> 
> this
> 
> > +				 * chip through the interrupts property,
> 
> so
> 
> > +				 * reserve these GPIO lines and set them
> 
> as
> 
> > +				 * input.
> > +				 */
> > +				ret = gpio_request(gc->base + offset, "OF
> 
> IRQ");
> 
> > +				if (ret)
> > +					pr_err("gpiolib OF: could not
> 
> request IRQ GPIO %d (%d)\n",
> 
> > +					       gc->base + offset, offset);
> 
> Would some kind of error handling be a bad idea here? Like, for example,
> marking this IRQ as invalid or something among these lines.

If that fails, things are like before and someone would request an irq for 
a gpio he does not own. Again what misses here is a connection between gpio 
and irq subsystem. I could only record that this gpio pin failed somewhere 
in the gpio subsystem, but what has to fail later is the request for the 
irq inside the irq subsystem.
Hmm....

> > +				ret = gpio_direction_input(gc->base +
> 
> offset);
> 
> > +				if (ret)
> > +					pr_err("gpiolib OF: could not set
> 
> IRQ GPIO %d (%d) as input\n",
> 
> > +					       gc->base + offset, offset);
> 
> I'm not sure if this is the correct action if someone already requested
> the GPIO before and probably already set it up with their own set of
> parameters (not necessarily the same as enforced by calling
> gpio_direction_input()).

That should definitely not happen! This is what this patch is for. As we 
are requesting this gpio somewhere inside the gpiochip_add process, no one 
should be able to request that gpio earlier.
 
> > +			} else {
> > +				gpio_free(gc->base + offset);
> 
> What if the request failed? This would mean calling gpio_free() on a
> GPIO previously requested by someone else.

See above.

> > +			}
> > +		}
> > +	}
> > +}
> > +
> > +#define of_gpiochip_request_irq_lines(np, gc) \
> > +	of_gpiochip_x_irq_lines(np, gc, 1)
> > +
> > +#define of_gpiochip_free_irq_lines(np, gc) \
> > +	of_gpiochip_x_irq_lines(np, gc, 0)
> 
> Aha, so the x is a wildcard. Fine, although it makes the code slightly
> less reader-friendly IMHO.

I am not happy with this naming as well, but I did not want to duplicate 
the code. I could have seperate request_irq_lines and free_irq_lines 
functions having most of the code in common. Has someone a better solution 
in mind ?

Thanks,
Lars
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux