Message ID | 20210907073224.3070-2-pshete@nvidia.com |
---|---|
State | New |
Headers | show |
Series | [v3,1/2] gpio: tegra: add multiple interrupt support | expand |
On Tue, Sep 07, 2021 at 01:02:23PM +0530, Prathamesh Shete wrote: > From: pshete <pshete@nvidia.com> > > T19x GPIO controller's support multiple interrupts. The GPIO > controller is capable to route 8 interrupts per controller in > case of NON-AON GPIO's and 4 interrupts per controller in AON GPIO. > This is new feature starting Tegra194 > The interrupt route map determines which interrupt line is to be used. > > Signed-off-by: Prathamesh Shete <pshete@nvidia.com> > --- > drivers/gpio/gpio-tegra186.c | 27 ++++++++++++++++++++++----- > 1 file changed, 22 insertions(+), 5 deletions(-) > > diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c > index d38980b9923a..c1172da9aebf 100644 > --- a/drivers/gpio/gpio-tegra186.c > +++ b/drivers/gpio/gpio-tegra186.c > @@ -1,6 +1,6 @@ > // SPDX-License-Identifier: GPL-2.0-only > /* > - * Copyright (c) 2016-2017 NVIDIA Corporation > + * Copyright (c) 2016-2021 NVIDIA Corporation > * > * Author: Thierry Reding <treding@nvidia.com> > */ > @@ -68,6 +68,7 @@ struct tegra_gpio_soc { > unsigned int num_ports; > const char *name; > unsigned int instance; > + bool multi_ints; > > const struct tegra186_pin_range *pin_ranges; > unsigned int num_pin_ranges; > @@ -450,7 +451,8 @@ static void tegra186_gpio_irq(struct irq_desc *desc) > struct irq_domain *domain = gpio->gpio.irq.domain; > struct irq_chip *chip = irq_desc_get_chip(desc); > unsigned int parent = irq_desc_get_irq(desc); > - unsigned int i, offset = 0; > + unsigned int i, j, offset = 0; > + int intr_cntr; > > chained_irq_enter(chip, desc); > > @@ -462,9 +464,20 @@ static void tegra186_gpio_irq(struct irq_desc *desc) > > base = gpio->base + port->bank * 0x1000 + port->port * 0x200; > > - /* skip ports that are not associated with this bank */ > - if (parent != gpio->irq[port->bank]) > - goto skip; > + if (!gpio->soc->multi_ints) { > + /* skip ports that are not associated with this bank */ > + if (parent != gpio->irq[port->bank]) > + goto skip; > + > + } else { > + intr_cntr = 0; > + for (j = 0; j < 8; j++) { > + if (parent != gpio->irq[(port->bank * 8) + j]) Again, I don't see how this would work. Currently the DT for Tegra194 (where you set multi_ints = true) lists 6 interrupts. So as soon as j goes beyond 5, this will end up accessing data beyond the bounds of the gpio->irq array. I've revised the patches that I created to support this a while ago and which I had sent earlier as a counter-proposal that keeps compatibility with earlier device trees. I've now tested it and found a few issues I had not run into earlier, but it should now work correctly with older and updated device trees. Thierry
diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index d38980b9923a..c1172da9aebf 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2017 NVIDIA Corporation + * Copyright (c) 2016-2021 NVIDIA Corporation * * Author: Thierry Reding <treding@nvidia.com> */ @@ -68,6 +68,7 @@ struct tegra_gpio_soc { unsigned int num_ports; const char *name; unsigned int instance; + bool multi_ints; const struct tegra186_pin_range *pin_ranges; unsigned int num_pin_ranges; @@ -450,7 +451,8 @@ static void tegra186_gpio_irq(struct irq_desc *desc) struct irq_domain *domain = gpio->gpio.irq.domain; struct irq_chip *chip = irq_desc_get_chip(desc); unsigned int parent = irq_desc_get_irq(desc); - unsigned int i, offset = 0; + unsigned int i, j, offset = 0; + int intr_cntr; chained_irq_enter(chip, desc); @@ -462,9 +464,20 @@ static void tegra186_gpio_irq(struct irq_desc *desc) base = gpio->base + port->bank * 0x1000 + port->port * 0x200; - /* skip ports that are not associated with this bank */ - if (parent != gpio->irq[port->bank]) - goto skip; + if (!gpio->soc->multi_ints) { + /* skip ports that are not associated with this bank */ + if (parent != gpio->irq[port->bank]) + goto skip; + + } else { + intr_cntr = 0; + for (j = 0; j < 8; j++) { + if (parent != gpio->irq[(port->bank * 8) + j]) + intr_cntr++; + } + if (!(intr_cntr & 0xF)) + goto skip; + } value = readl(base + TEGRA186_GPIO_INTERRUPT_STATUS(1)); @@ -772,6 +785,7 @@ static const struct tegra_gpio_soc tegra186_main_soc = { .ports = tegra186_main_ports, .name = "tegra186-gpio", .instance = 0, + .multi_ints = false, }; #define TEGRA186_AON_GPIO_PORT(_name, _bank, _port, _pins) \ @@ -798,6 +812,7 @@ static const struct tegra_gpio_soc tegra186_aon_soc = { .ports = tegra186_aon_ports, .name = "tegra186-gpio-aon", .instance = 1, + .multi_ints = false, }; #define TEGRA194_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ @@ -852,6 +867,7 @@ static const struct tegra_gpio_soc tegra194_main_soc = { .num_pin_ranges = ARRAY_SIZE(tegra194_main_pin_ranges), .pin_ranges = tegra194_main_pin_ranges, .pinmux = "nvidia,tegra194-pinmux", + .multi_ints = true, }; #define TEGRA194_AON_GPIO_PORT(_name, _bank, _port, _pins) \ @@ -875,6 +891,7 @@ static const struct tegra_gpio_soc tegra194_aon_soc = { .ports = tegra194_aon_ports, .name = "tegra194-gpio-aon", .instance = 1, + .multi_ints = true, }; static const struct of_device_id tegra186_gpio_of_match[] = {