Skip to content

Commit

Permalink
genirq: Provide irq_request/release_resources chip callbacks
Browse files Browse the repository at this point in the history
For certain irq types, e.g. gpios, it's necessary to request resources
before starting up the irq.

This might fail so we cannot use the irq_startup() callback because we
might call the irq_set_type() callback before that which does not make
sense when the resource is not available. Calling irq_startup() before
irq_set_type() can lead to spurious interrupts which is not desired
either.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
Cc: Grant Likely <grant.likely@linaro.org>
Cc: linux-arm-kernel@lists.infradead.org 
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Link: http://lkml.kernel.org/r/alpine.DEB.2.02.1403080857160.18573@ionos.tec.linutronix.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
  • Loading branch information
Thomas Gleixner committed Mar 12, 2014
1 parent fa389e2 commit c1bacba
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 1 deletion.
6 changes: 6 additions & 0 deletions include/linux/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,10 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
* @irq_pm_shutdown: function called from core code on shutdown once per chip
* @irq_calc_mask: Optional function to set irq_data.mask for special cases
* @irq_print_chip: optional to print special chip info in show_interrupts
* @irq_request_resources: optional to request resources before calling
* any other callback related to this irq
* @irq_release_resources: optional to release resources acquired with
* irq_request_resources
* @flags: chip specific flags
*/
struct irq_chip {
Expand Down Expand Up @@ -336,6 +340,8 @@ struct irq_chip {
void (*irq_calc_mask)(struct irq_data *data);

void (*irq_print_chip)(struct irq_data *data, struct seq_file *p);
int (*irq_request_resources)(struct irq_data *data);
void (*irq_release_resources)(struct irq_data *data);

unsigned long flags;
};
Expand Down
28 changes: 27 additions & 1 deletion kernel/irq/manage.c
Original file line number Diff line number Diff line change
Expand Up @@ -896,6 +896,23 @@ static void irq_setup_forced_threading(struct irqaction *new)
}
}

static int irq_request_resources(struct irq_desc *desc)
{
struct irq_data *d = &desc->irq_data;
struct irq_chip *c = d->chip;

return c->irq_request_resources ? c->irq_request_resources(d) : 0;
}

static void irq_release_resources(struct irq_desc *desc)
{
struct irq_data *d = &desc->irq_data;
struct irq_chip *c = d->chip;

if (c->irq_release_resources)
c->irq_release_resources(d);
}

/*
* Internal function to register an irqaction - typically used to
* allocate special interrupts that are part of the architecture.
Expand Down Expand Up @@ -1091,6 +1108,13 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
}

if (!shared) {
ret = irq_request_resources(desc);
if (ret) {
pr_err("Failed to request resources for %s (irq %d) on irqchip %s\n",
new->name, irq, desc->irq_data.chip->name);
goto out_mask;
}

init_waitqueue_head(&desc->wait_for_threads);

/* Setup the type (level, edge polarity) if configured: */
Expand Down Expand Up @@ -1261,8 +1285,10 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
*action_ptr = action->next;

/* If this was the last handler, shut down the IRQ line: */
if (!desc->action)
if (!desc->action) {
irq_shutdown(desc);
irq_release_resources(desc);
}

#ifdef CONFIG_SMP
/* make sure affinity_hint is cleaned up */
Expand Down

0 comments on commit c1bacba

Please sign in to comment.