[PATCH 3.16 198/306] gpio/mvebu: Use irq_domain_add_linear

Ben Hutchings
2017-02-15T23:09:47Z

From: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>

commit 812d47889a8e418d7bea9bec383581a34c19183e upstream.

This fixes the irq allocation in this driver to not print:
irq: Cannot allocate irq_descs @ IRQ34, assuming pre-allocated
irq: Cannot allocate irq_descs @ IRQ66, assuming pre-allocated

Which happens because the driver already called irq_alloc_descs()
and so the change to use irq_domain_add_simple resulted in calling
irq_alloc_descs() twice.

Modernize the irq allocation in this driver to use the
irq_domain_add_linear flow directly and eliminate the use of
irq_domain_add_simple/legacy

Fixes: ce931f571b6d ("gpio/mvebu: convert to use irq_domain_add_simple()")
Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
[bwh: Backported to 3.16:
- Keep using irq_set_handler_data(), irq_set_chained_handler()
- Adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -294,10 +294,10 @@ static void mvebu_gpio_irq_ack(struct ir
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct mvebu_gpio_chip *mvchip = gc->private;
- u32 mask = ~(1 << (d->irq - gc->irq_base));
+ u32 mask = d->mask;

irq_gc_lock(gc);
- writel_relaxed(mask, mvebu_gpioreg_edge_cause(mvchip));
+ writel_relaxed(~mask, mvebu_gpioreg_edge_cause(mvchip));
irq_gc_unlock(gc);
}

@@ -306,7 +306,7 @@ static void mvebu_gpio_edge_irq_mask(str
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct mvebu_gpio_chip *mvchip = gc->private;
struct irq_chip_type *ct = irq_data_get_chip_type(d);
- u32 mask = 1 << (d->irq - gc->irq_base);
+ u32 mask = d->mask;

irq_gc_lock(gc);
ct->mask_cache_priv &= ~mask;
@@ -320,8 +320,7 @@ static void mvebu_gpio_edge_irq_unmask(s
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct mvebu_gpio_chip *mvchip = gc->private;
struct irq_chip_type *ct = irq_data_get_chip_type(d);
-
- u32 mask = 1 << (d->irq - gc->irq_base);
+ u32 mask = d->mask;

irq_gc_lock(gc);
ct->mask_cache_priv |= mask;
@@ -334,8 +333,7 @@ static void mvebu_gpio_level_irq_mask(st
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct mvebu_gpio_chip *mvchip = gc->private;
struct irq_chip_type *ct = irq_data_get_chip_type(d);
-
- u32 mask = 1 << (d->irq - gc->irq_base);
+ u32 mask = d->mask;

irq_gc_lock(gc);
ct->mask_cache_priv &= ~mask;
@@ -348,8 +346,7 @@ static void mvebu_gpio_level_irq_unmask(
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct mvebu_gpio_chip *mvchip = gc->private;
struct irq_chip_type *ct = irq_data_get_chip_type(d);
-
- u32 mask = 1 << (d->irq - gc->irq_base);
+ u32 mask = d->mask;

irq_gc_lock(gc);
ct->mask_cache_priv |= mask;
@@ -464,7 +461,7 @@ static void mvebu_gpio_irq_handler(unsig
for (i = 0; i < mvchip->chip.ngpio; i++) {
int irq;

- irq = mvchip->irqbase + i;
+ irq = irq_find_mapping(mvchip->domain, i);

if (!(cause & (1 << i)))
continue;
@@ -572,8 +569,10 @@ static int mvebu_gpio_probe(struct platf
struct irq_chip_type *ct;
struct clk *clk;
unsigned int ngpios;
+ bool have_irqs;
int soc_variant;
int i, cpu, id;
+ int err;

match = of_match_device(mvebu_gpio_of_match, &pdev->dev);
if (match)
@@ -581,6 +580,9 @@ static int mvebu_gpio_probe(struct platf
else
soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION;

+ /* Some gpio controllers do not provide irq support */
+ have_irqs = of_irq_count(np) != 0;
+
mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip), GFP_KERNEL);
if (!mvchip)
return -ENOMEM;
@@ -610,7 +612,8 @@ static int mvebu_gpio_probe(struct platf
mvchip->chip.get = mvebu_gpio_get;
mvchip->chip.direction_output = mvebu_gpio_direction_output;
mvchip->chip.set = mvebu_gpio_set;
- mvchip->chip.to_irq = mvebu_gpio_to_irq;
+ if (have_irqs)
+ mvchip->chip.to_irq = mvebu_gpio_to_irq;
mvchip->chip.base = id * MVEBU_MAX_GPIO_PER_BANK;
mvchip->chip.ngpio = ngpios;
mvchip->chip.can_sleep = false;
@@ -671,34 +674,30 @@ static int mvebu_gpio_probe(struct platf
gpiochip_add(&mvchip->chip);

/* Some gpio controllers do not provide irq support */
- if (!of_irq_count(np))
+ if (!have_irqs)
return 0;

- /* Setup the interrupt handlers. Each chip can have up to 4
- * interrupt handlers, with each handler dealing with 8 GPIO
- * pins. */
- for (i = 0; i < 4; i++) {
- int irq;
- irq = platform_get_irq(pdev, i);
- if (irq < 0)
- continue;
- irq_set_handler_data(irq, mvchip);
- irq_set_chained_handler(irq, mvebu_gpio_irq_handler);
- }
-
- mvchip->irqbase = irq_alloc_descs(-1, 0, ngpios, -1);
- if (mvchip->irqbase < 0) {
- dev_err(&pdev->dev, "no irqs\n");
- return mvchip->irqbase;
+ mvchip->domain =
+ irq_domain_add_linear(np, ngpios, &irq_generic_chip_ops, NULL);
+ if (!mvchip->domain) {
+ dev_err(&pdev->dev, "couldn't allocate irq domain %s (DT).\n",
+ mvchip->chip.label);
+ return -ENODEV;
}

- gc = irq_alloc_generic_chip("mvebu_gpio_irq", 2, mvchip->irqbase,
- mvchip->membase, handle_level_irq);
- if (!gc) {
- dev_err(&pdev->dev, "Cannot allocate generic irq_chip\n");
- return -ENOMEM;
+ err = irq_alloc_domain_generic_chips(
+ mvchip->domain, ngpios, 2, np->name, handle_level_irq,
+ IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_LEVEL, 0, 0);
+ if (err) {
+ dev_err(&pdev->dev, "couldn't allocate irq chips %s (DT).\n",
+ mvchip->chip.label);
+ goto err_domain;
}

+ /* NOTE: The common accessors cannot be used because of the percpu
+ * access to the mask registers
+ */
+ gc = irq_get_domain_generic_chip(mvchip->domain, 0);
gc->private = mvchip;
ct = &gc->chip_types[0];
ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
@@ -716,24 +715,25 @@ static int mvebu_gpio_probe(struct platf
ct->handler = handle_edge_irq;
ct->chip.name = mvchip->chip.label;

- irq_setup_generic_chip(gc, IRQ_MSK(ngpios), 0,
- IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE);
+ /* Setup the interrupt handlers. Each chip can have up to 4
+ * interrupt handlers, with each handler dealing with 8 GPIO
+ * pins.
+ */
+ for (i = 0; i < 4; i++) {
+ int irq = platform_get_irq(pdev, i);

- /* Setup irq domain on top of the generic chip. */
- mvchip->domain = irq_domain_add_simple(np, mvchip->chip.ngpio,
- mvchip->irqbase,
- &irq_domain_simple_ops,
- mvchip);
- if (!mvchip->domain) {
- dev_err(&pdev->dev, "couldn't allocate irq domain %s (DT).\n",
- mvchip->chip.label);
- irq_remove_generic_chip(gc, IRQ_MSK(ngpios), IRQ_NOREQUEST,
- IRQ_LEVEL | IRQ_NOPROBE);
- kfree(gc);
- return -ENODEV;
+ if (irq < 0)
+ continue;
+ irq_set_handler_data(irq, mvchip);
+ irq_set_chained_handler(irq, mvebu_gpio_irq_handler);
}

return 0;
+
+err_domain:
+ irq_domain_remove(mvchip->domain);
+
+ return err;
}

static struct platform_driver mvebu_gpio_driver = {