Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull irq updates from Thomas Gleixner: "The irq departement delivers: - plug a potential race related to chained interrupt handlers - core updates which address the needs of the x86 irqdomain conversion - new irqchip callback to support affinity settings for VCPUs - the usual pile of updates to interrupt chip drivers - a few helper functions to allow further cleanups and simplifications I have a largish pile of coccinelle scripted/verified cleanups and simplifications pending on top of that, but I prefer to send that towards the end of the merge window when the arch/driver changes have hit your tree to avoid API change wreckage as far as possible" * 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (34 commits) genirq: Remove bogus restriction in irq_move_mask_irq() irqchip: atmel-aic5: Add sama5d2 support irq: spear-shirq: Fix race in installing chained IRQ handler irq: irq-keystone: Fix race in installing chained IRQ handler gpio: gpio-tegra: Fix race in installing chained IRQ handler gpio: gpio-mxs: Fix race in installing chained IRQ handler gpio: gpio-mxc: Fix race in installing chained IRQ handler ARM: gemini: Fix race in installing GPIO chained IRQ handler GPU: ipu: Fix race in installing IPU chained IRQ handler ARM: sa1100: convert SA11x0 related code to use new chained handler helper irq: Add irq_set_chained_handler_and_data() irqchip: exynos-combiner: Save IRQ enable set on suspend genirq: Introduce helper function irq_data_get_affinity_mask() genirq: Introduce helper function irq_data_get_node() genirq: Introduce struct irq_common_data to host shared irq data genirq: Prevent crash in irq_move_irq() genirq: Enhance irq_data_to_desc() to support hierarchy irqdomain irqchip: gic: Simplify gic_configure_irq by using IRQCHIP_SET_TYPE_MASKED irqchip: renesas: intc-irqpin: Improve binding documentation genirq: Set IRQCHIP_SKIP_SET_WAKE for no_irq_chip ...
This commit is contained in:
@@ -719,15 +719,9 @@ void handle_percpu_devid_irq(unsigned int irq, struct irq_desc *desc)
|
||||
}
|
||||
|
||||
void
|
||||
__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
|
||||
const char *name)
|
||||
__irq_do_set_handler(struct irq_desc *desc, irq_flow_handler_t handle,
|
||||
int is_chained, const char *name)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0);
|
||||
|
||||
if (!desc)
|
||||
return;
|
||||
|
||||
if (!handle) {
|
||||
handle = handle_bad_irq;
|
||||
} else {
|
||||
@@ -749,13 +743,13 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
|
||||
* right away.
|
||||
*/
|
||||
if (WARN_ON(is_chained))
|
||||
goto out;
|
||||
return;
|
||||
/* Try the parent */
|
||||
irq_data = irq_data->parent_data;
|
||||
}
|
||||
#endif
|
||||
if (WARN_ON(!irq_data || irq_data->chip == &no_irq_chip))
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Uninstall? */
|
||||
@@ -774,11 +768,40 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
|
||||
irq_settings_set_nothread(desc);
|
||||
irq_startup(desc, true);
|
||||
}
|
||||
out:
|
||||
}
|
||||
|
||||
void
|
||||
__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
|
||||
const char *name)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0);
|
||||
|
||||
if (!desc)
|
||||
return;
|
||||
|
||||
__irq_do_set_handler(desc, handle, is_chained, name);
|
||||
irq_put_desc_busunlock(desc, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__irq_set_handler);
|
||||
|
||||
void
|
||||
irq_set_chained_handler_and_data(unsigned int irq, irq_flow_handler_t handle,
|
||||
void *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0);
|
||||
|
||||
if (!desc)
|
||||
return;
|
||||
|
||||
__irq_do_set_handler(desc, handle, 1, NULL);
|
||||
desc->irq_data.handler_data = data;
|
||||
|
||||
irq_put_desc_busunlock(desc, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_set_chained_handler_and_data);
|
||||
|
||||
void
|
||||
irq_set_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
|
||||
irq_flow_handler_t handle, const char *name)
|
||||
@@ -875,6 +898,34 @@ void irq_cpu_offline(void)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
|
||||
/**
|
||||
* irq_chip_enable_parent - Enable the parent interrupt (defaults to unmask if
|
||||
* NULL)
|
||||
* @data: Pointer to interrupt specific data
|
||||
*/
|
||||
void irq_chip_enable_parent(struct irq_data *data)
|
||||
{
|
||||
data = data->parent_data;
|
||||
if (data->chip->irq_enable)
|
||||
data->chip->irq_enable(data);
|
||||
else
|
||||
data->chip->irq_unmask(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* irq_chip_disable_parent - Disable the parent interrupt (defaults to mask if
|
||||
* NULL)
|
||||
* @data: Pointer to interrupt specific data
|
||||
*/
|
||||
void irq_chip_disable_parent(struct irq_data *data)
|
||||
{
|
||||
data = data->parent_data;
|
||||
if (data->chip->irq_disable)
|
||||
data->chip->irq_disable(data);
|
||||
else
|
||||
data->chip->irq_mask(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* irq_chip_ack_parent - Acknowledge the parent interrupt
|
||||
* @data: Pointer to interrupt specific data
|
||||
|
@@ -104,7 +104,7 @@ int devm_request_any_context_irq(struct device *dev, unsigned int irq,
|
||||
return -ENOMEM;
|
||||
|
||||
rc = request_any_context_irq(irq, handler, irqflags, devname, dev_id);
|
||||
if (rc) {
|
||||
if (rc < 0) {
|
||||
devres_free(dr);
|
||||
return rc;
|
||||
}
|
||||
@@ -113,7 +113,7 @@ int devm_request_any_context_irq(struct device *dev, unsigned int irq,
|
||||
dr->dev_id = dev_id;
|
||||
devres_add(dev, dr);
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_request_any_context_irq);
|
||||
|
||||
|
@@ -42,6 +42,7 @@ struct irq_chip no_irq_chip = {
|
||||
.irq_enable = noop,
|
||||
.irq_disable = noop,
|
||||
.irq_ack = ack_bad,
|
||||
.flags = IRQCHIP_SKIP_SET_WAKE,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@@ -360,7 +360,7 @@ static struct lock_class_key irq_nested_lock_class;
|
||||
int irq_map_generic_chip(struct irq_domain *d, unsigned int virq,
|
||||
irq_hw_number_t hw_irq)
|
||||
{
|
||||
struct irq_data *data = irq_get_irq_data(virq);
|
||||
struct irq_data *data = irq_domain_get_irq_data(d, virq);
|
||||
struct irq_domain_chip_generic *dgc = d->gc;
|
||||
struct irq_chip_generic *gc;
|
||||
struct irq_chip_type *ct;
|
||||
@@ -405,8 +405,7 @@ int irq_map_generic_chip(struct irq_domain *d, unsigned int virq,
|
||||
else
|
||||
data->mask = 1 << idx;
|
||||
|
||||
irq_set_chip_and_handler(virq, chip, ct->handler);
|
||||
irq_set_chip_data(virq, gc);
|
||||
irq_domain_set_info(d, virq, hw_irq, chip, gc, ct->handler, NULL, NULL);
|
||||
irq_modify_status(virq, dgc->irq_flags_to_clear, dgc->irq_flags_to_set);
|
||||
return 0;
|
||||
}
|
||||
|
@@ -168,27 +168,27 @@ irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags)
|
||||
*/
|
||||
static inline void irqd_set_move_pending(struct irq_data *d)
|
||||
{
|
||||
d->state_use_accessors |= IRQD_SETAFFINITY_PENDING;
|
||||
__irqd_to_state(d) |= IRQD_SETAFFINITY_PENDING;
|
||||
}
|
||||
|
||||
static inline void irqd_clr_move_pending(struct irq_data *d)
|
||||
{
|
||||
d->state_use_accessors &= ~IRQD_SETAFFINITY_PENDING;
|
||||
__irqd_to_state(d) &= ~IRQD_SETAFFINITY_PENDING;
|
||||
}
|
||||
|
||||
static inline void irqd_clear(struct irq_data *d, unsigned int mask)
|
||||
{
|
||||
d->state_use_accessors &= ~mask;
|
||||
__irqd_to_state(d) &= ~mask;
|
||||
}
|
||||
|
||||
static inline void irqd_set(struct irq_data *d, unsigned int mask)
|
||||
{
|
||||
d->state_use_accessors |= mask;
|
||||
__irqd_to_state(d) |= mask;
|
||||
}
|
||||
|
||||
static inline bool irqd_has_set(struct irq_data *d, unsigned int mask)
|
||||
{
|
||||
return d->state_use_accessors & mask;
|
||||
return __irqd_to_state(d) & mask;
|
||||
}
|
||||
|
||||
static inline void kstat_incr_irqs_this_cpu(unsigned int irq, struct irq_desc *desc)
|
||||
@@ -197,6 +197,11 @@ static inline void kstat_incr_irqs_this_cpu(unsigned int irq, struct irq_desc *d
|
||||
__this_cpu_inc(kstat.irqs_sum);
|
||||
}
|
||||
|
||||
static inline int irq_desc_get_node(struct irq_desc *desc)
|
||||
{
|
||||
return irq_data_get_node(&desc->irq_data);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
bool irq_pm_check_wakeup(struct irq_desc *desc);
|
||||
void irq_pm_install_action(struct irq_desc *desc, struct irqaction *action);
|
||||
|
@@ -59,16 +59,10 @@ static void desc_smp_init(struct irq_desc *desc, int node)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int desc_node(struct irq_desc *desc)
|
||||
{
|
||||
return desc->irq_data.node;
|
||||
}
|
||||
|
||||
#else
|
||||
static inline int
|
||||
alloc_masks(struct irq_desc *desc, gfp_t gfp, int node) { return 0; }
|
||||
static inline void desc_smp_init(struct irq_desc *desc, int node) { }
|
||||
static inline int desc_node(struct irq_desc *desc) { return 0; }
|
||||
#endif
|
||||
|
||||
static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node,
|
||||
@@ -76,6 +70,7 @@ static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node,
|
||||
{
|
||||
int cpu;
|
||||
|
||||
desc->irq_data.common = &desc->irq_common_data;
|
||||
desc->irq_data.irq = irq;
|
||||
desc->irq_data.chip = &no_irq_chip;
|
||||
desc->irq_data.chip_data = NULL;
|
||||
@@ -299,7 +294,7 @@ static void free_desc(unsigned int irq)
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&desc->lock, flags);
|
||||
desc_set_defaults(irq, desc, desc_node(desc), NULL);
|
||||
desc_set_defaults(irq, desc, irq_desc_get_node(desc), NULL);
|
||||
raw_spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
|
||||
@@ -619,7 +614,7 @@ unsigned int kstat_irqs(unsigned int irq)
|
||||
{
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
int cpu;
|
||||
int sum = 0;
|
||||
unsigned int sum = 0;
|
||||
|
||||
if (!desc || !desc->kstat_irqs)
|
||||
return 0;
|
||||
@@ -639,7 +634,7 @@ unsigned int kstat_irqs(unsigned int irq)
|
||||
*/
|
||||
unsigned int kstat_irqs_usr(unsigned int irq)
|
||||
{
|
||||
int sum;
|
||||
unsigned int sum;
|
||||
|
||||
irq_lock_sparse();
|
||||
sum = kstat_irqs(irq);
|
||||
|
@@ -830,10 +830,12 @@ static struct irq_data *irq_domain_insert_irq_data(struct irq_domain *domain,
|
||||
{
|
||||
struct irq_data *irq_data;
|
||||
|
||||
irq_data = kzalloc_node(sizeof(*irq_data), GFP_KERNEL, child->node);
|
||||
irq_data = kzalloc_node(sizeof(*irq_data), GFP_KERNEL,
|
||||
irq_data_get_node(child));
|
||||
if (irq_data) {
|
||||
child->parent_data = irq_data;
|
||||
irq_data->irq = child->irq;
|
||||
irq_data->common = child->common;
|
||||
irq_data->node = child->node;
|
||||
irq_data->domain = domain;
|
||||
}
|
||||
@@ -1232,6 +1234,27 @@ struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain,
|
||||
return (irq_data && irq_data->domain == domain) ? irq_data : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* irq_domain_set_info - Set the complete data for a @virq in @domain
|
||||
* @domain: Interrupt domain to match
|
||||
* @virq: IRQ number
|
||||
* @hwirq: The hardware interrupt number
|
||||
* @chip: The associated interrupt chip
|
||||
* @chip_data: The associated interrupt chip data
|
||||
* @handler: The interrupt flow handler
|
||||
* @handler_data: The interrupt flow handler data
|
||||
* @handler_name: The interrupt handler name
|
||||
*/
|
||||
void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
|
||||
irq_hw_number_t hwirq, struct irq_chip *chip,
|
||||
void *chip_data, irq_flow_handler_t handler,
|
||||
void *handler_data, const char *handler_name)
|
||||
{
|
||||
irq_set_chip_and_handler_name(virq, chip, handler, handler_name);
|
||||
irq_set_chip_data(virq, chip_data);
|
||||
irq_set_handler_data(virq, handler_data);
|
||||
}
|
||||
|
||||
static void irq_domain_check_hierarchy(struct irq_domain *domain)
|
||||
{
|
||||
}
|
||||
|
@@ -363,7 +363,7 @@ static int
|
||||
setup_affinity(unsigned int irq, struct irq_desc *desc, struct cpumask *mask)
|
||||
{
|
||||
struct cpumask *set = irq_default_affinity;
|
||||
int node = desc->irq_data.node;
|
||||
int node = irq_desc_get_node(desc);
|
||||
|
||||
/* Excludes PER_CPU and NO_BALANCE interrupts */
|
||||
if (!irq_can_set_affinity(irq))
|
||||
|
@@ -12,16 +12,16 @@ void irq_move_masked_irq(struct irq_data *idata)
|
||||
if (likely(!irqd_is_setaffinity_pending(&desc->irq_data)))
|
||||
return;
|
||||
|
||||
irqd_clr_move_pending(&desc->irq_data);
|
||||
|
||||
/*
|
||||
* Paranoia: cpu-local interrupts shouldn't be calling in here anyway.
|
||||
*/
|
||||
if (!irqd_can_balance(&desc->irq_data)) {
|
||||
if (irqd_is_per_cpu(&desc->irq_data)) {
|
||||
WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
|
||||
irqd_clr_move_pending(&desc->irq_data);
|
||||
|
||||
if (unlikely(cpumask_empty(desc->pending_mask)))
|
||||
return;
|
||||
|
||||
|
@@ -124,7 +124,7 @@ static void msi_domain_free(struct irq_domain *domain, unsigned int virq,
|
||||
irq_domain_free_irqs_top(domain, virq, nr_irqs);
|
||||
}
|
||||
|
||||
static struct irq_domain_ops msi_domain_ops = {
|
||||
static const struct irq_domain_ops msi_domain_ops = {
|
||||
.alloc = msi_domain_alloc,
|
||||
.free = msi_domain_free,
|
||||
.activate = msi_domain_activate,
|
||||
|
@@ -123,6 +123,8 @@ void suspend_device_irqs(void)
|
||||
unsigned long flags;
|
||||
bool sync;
|
||||
|
||||
if (irq_settings_is_nested_thread(desc))
|
||||
continue;
|
||||
raw_spin_lock_irqsave(&desc->lock, flags);
|
||||
sync = suspend_device_irq(desc, irq);
|
||||
raw_spin_unlock_irqrestore(&desc->lock, flags);
|
||||
@@ -163,6 +165,8 @@ static void resume_irqs(bool want_early)
|
||||
|
||||
if (!is_early && want_early)
|
||||
continue;
|
||||
if (irq_settings_is_nested_thread(desc))
|
||||
continue;
|
||||
|
||||
raw_spin_lock_irqsave(&desc->lock, flags);
|
||||
resume_irq(desc, irq);
|
||||
|
@@ -241,7 +241,7 @@ static int irq_node_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct irq_desc *desc = irq_to_desc((long) m->private);
|
||||
|
||||
seq_printf(m, "%d\n", desc->irq_data.node);
|
||||
seq_printf(m, "%d\n", irq_desc_get_node(desc));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user