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 department provides:
- Support for MSI to wire bridges and a first user of it
- More ACPI support for ARM/GIC
- A new TS-4800 interrupt controller driver
- RCU based free of interrupt descriptors to support the upcoming
Intel VMD technology without introducing a locking nightmare
- The usual pile of fixes and updates to drivers and core code"
* 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (41 commits)
irqchip/omap-intc: Add support for spurious irq handling
irqchip/zevio: Use irq_data_get_chip_type() helper
irqchip/omap-intc: Remove duplicate setup for IRQ chip type handler
irqchip/ts4800: Add TS-4800 interrupt controller
irqchip/ts4800: Add documentation for TS-4800 interrupt controller
irq/platform-MSI: Increase the maximum MSIs the MSI framework can support
irqchip/gicv2m: Miscellaneous fixes for v2m resources and SPI ranges
irqchip/bcm2836: Make code more readable
irqchip/bcm2836: Tolerate IRQs while no flag is set in ISR
irqchip/bcm2836: Add SMP support for the 2836
irqchip/bcm2836: Fix initialization of the LOCAL_IRQ_CNT timers
irqchip/gic-v2m: acpi: Introducing GICv2m ACPI support
irqchip/gic-v2m: Refactor to prepare for ACPI support
irqdomain: Introduce is_fwnode_irqchip helper
acpi: pci: Setup MSI domain for ACPI based pci devices
genirq/msi: Export functions to allow MSI domains in modules
irqchip/mbigen: Implement the mbigen irq chip operation functions
irqchip/mbigen: Create irq domain for each mbigen device
irqchip/mgigen: Add platform device driver for mbigen device
dt-bindings: Documents the mbigen bindings
...
This commit is contained in:
+5
-4
@@ -338,7 +338,6 @@ void handle_nested_irq(unsigned int irq)
|
||||
raw_spin_lock_irq(&desc->lock);
|
||||
|
||||
desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
|
||||
kstat_incr_irqs_this_cpu(desc);
|
||||
|
||||
action = desc->action;
|
||||
if (unlikely(!action || irqd_irq_disabled(&desc->irq_data))) {
|
||||
@@ -346,6 +345,7 @@ void handle_nested_irq(unsigned int irq)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
kstat_incr_irqs_this_cpu(desc);
|
||||
irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS);
|
||||
raw_spin_unlock_irq(&desc->lock);
|
||||
|
||||
@@ -412,13 +412,13 @@ void handle_simple_irq(struct irq_desc *desc)
|
||||
goto out_unlock;
|
||||
|
||||
desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
|
||||
kstat_incr_irqs_this_cpu(desc);
|
||||
|
||||
if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {
|
||||
desc->istate |= IRQS_PENDING;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
kstat_incr_irqs_this_cpu(desc);
|
||||
handle_irq_event(desc);
|
||||
|
||||
out_unlock:
|
||||
@@ -462,7 +462,6 @@ void handle_level_irq(struct irq_desc *desc)
|
||||
goto out_unlock;
|
||||
|
||||
desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
|
||||
kstat_incr_irqs_this_cpu(desc);
|
||||
|
||||
/*
|
||||
* If its disabled or no action available
|
||||
@@ -473,6 +472,7 @@ void handle_level_irq(struct irq_desc *desc)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
kstat_incr_irqs_this_cpu(desc);
|
||||
handle_irq_event(desc);
|
||||
|
||||
cond_unmask_irq(desc);
|
||||
@@ -532,7 +532,6 @@ void handle_fasteoi_irq(struct irq_desc *desc)
|
||||
goto out;
|
||||
|
||||
desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
|
||||
kstat_incr_irqs_this_cpu(desc);
|
||||
|
||||
/*
|
||||
* If its disabled or no action available
|
||||
@@ -544,6 +543,7 @@ void handle_fasteoi_irq(struct irq_desc *desc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
kstat_incr_irqs_this_cpu(desc);
|
||||
if (desc->istate & IRQS_ONESHOT)
|
||||
mask_irq(desc);
|
||||
|
||||
@@ -950,6 +950,7 @@ void irq_chip_ack_parent(struct irq_data *data)
|
||||
data = data->parent_data;
|
||||
data->chip->irq_ack(data);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_chip_ack_parent);
|
||||
|
||||
/**
|
||||
* irq_chip_mask_parent - Mask the parent interrupt
|
||||
|
||||
+16
-3
@@ -159,6 +159,7 @@ static struct irq_desc *alloc_desc(int irq, int node, struct module *owner)
|
||||
|
||||
raw_spin_lock_init(&desc->lock);
|
||||
lockdep_set_class(&desc->lock, &irq_desc_lock_class);
|
||||
init_rcu_head(&desc->rcu);
|
||||
|
||||
desc_set_defaults(irq, desc, node, owner);
|
||||
|
||||
@@ -171,6 +172,15 @@ err_desc:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void delayed_free_desc(struct rcu_head *rhp)
|
||||
{
|
||||
struct irq_desc *desc = container_of(rhp, struct irq_desc, rcu);
|
||||
|
||||
free_masks(desc);
|
||||
free_percpu(desc->kstat_irqs);
|
||||
kfree(desc);
|
||||
}
|
||||
|
||||
static void free_desc(unsigned int irq)
|
||||
{
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
@@ -187,9 +197,12 @@ static void free_desc(unsigned int irq)
|
||||
delete_irq_desc(irq);
|
||||
mutex_unlock(&sparse_irq_lock);
|
||||
|
||||
free_masks(desc);
|
||||
free_percpu(desc->kstat_irqs);
|
||||
kfree(desc);
|
||||
/*
|
||||
* We free the descriptor, masks and stat fields via RCU. That
|
||||
* allows demultiplex interrupts to do rcu based management of
|
||||
* the child interrupts.
|
||||
*/
|
||||
call_rcu(&desc->rcu, delayed_free_desc);
|
||||
}
|
||||
|
||||
static int alloc_descs(unsigned int start, unsigned int cnt, int node,
|
||||
|
||||
@@ -60,6 +60,7 @@ struct fwnode_handle *irq_domain_alloc_fwnode(void *data)
|
||||
fwid->fwnode.type = FWNODE_IRQCHIP;
|
||||
return &fwid->fwnode;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_domain_alloc_fwnode);
|
||||
|
||||
/**
|
||||
* irq_domain_free_fwnode - Free a non-OF-backed fwnode_handle
|
||||
@@ -70,13 +71,14 @@ void irq_domain_free_fwnode(struct fwnode_handle *fwnode)
|
||||
{
|
||||
struct irqchip_fwid *fwid;
|
||||
|
||||
if (WARN_ON(fwnode->type != FWNODE_IRQCHIP))
|
||||
if (WARN_ON(!is_fwnode_irqchip(fwnode)))
|
||||
return;
|
||||
|
||||
fwid = container_of(fwnode, struct irqchip_fwid, fwnode);
|
||||
kfree(fwid->name);
|
||||
kfree(fwid);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_domain_free_fwnode);
|
||||
|
||||
/**
|
||||
* __irq_domain_add() - Allocate a new irq_domain data structure
|
||||
@@ -1013,6 +1015,7 @@ struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain,
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_domain_get_irq_data);
|
||||
|
||||
/**
|
||||
* irq_domain_set_hwirq_and_chip - Set hwirq and irqchip of @virq at @domain
|
||||
@@ -1125,9 +1128,9 @@ static void irq_domain_free_irqs_recursive(struct irq_domain *domain,
|
||||
}
|
||||
}
|
||||
|
||||
static int irq_domain_alloc_irqs_recursive(struct irq_domain *domain,
|
||||
unsigned int irq_base,
|
||||
unsigned int nr_irqs, void *arg)
|
||||
int irq_domain_alloc_irqs_recursive(struct irq_domain *domain,
|
||||
unsigned int irq_base,
|
||||
unsigned int nr_irqs, void *arg)
|
||||
{
|
||||
int ret = 0;
|
||||
struct irq_domain *parent = domain->parent;
|
||||
@@ -1343,6 +1346,7 @@ struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain,
|
||||
|
||||
return (irq_data && irq_data->domain == domain) ? irq_data : NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_domain_get_irq_data);
|
||||
|
||||
/**
|
||||
* irq_domain_set_info - Set the complete data for a @virq in @domain
|
||||
|
||||
@@ -1743,6 +1743,31 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(enable_percpu_irq);
|
||||
|
||||
/**
|
||||
* irq_percpu_is_enabled - Check whether the per cpu irq is enabled
|
||||
* @irq: Linux irq number to check for
|
||||
*
|
||||
* Must be called from a non migratable context. Returns the enable
|
||||
* state of a per cpu interrupt on the current cpu.
|
||||
*/
|
||||
bool irq_percpu_is_enabled(unsigned int irq)
|
||||
{
|
||||
unsigned int cpu = smp_processor_id();
|
||||
struct irq_desc *desc;
|
||||
unsigned long flags;
|
||||
bool is_enabled;
|
||||
|
||||
desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_PERCPU);
|
||||
if (!desc)
|
||||
return false;
|
||||
|
||||
is_enabled = cpumask_test_cpu(cpu, desc->percpu_enabled);
|
||||
irq_put_desc_unlock(desc, flags);
|
||||
|
||||
return is_enabled;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_percpu_is_enabled);
|
||||
|
||||
void disable_percpu_irq(unsigned int irq)
|
||||
{
|
||||
unsigned int cpu = smp_processor_id();
|
||||
|
||||
+55
-3
@@ -252,6 +252,60 @@ struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode,
|
||||
&msi_domain_ops, info);
|
||||
}
|
||||
|
||||
int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev,
|
||||
int nvec, msi_alloc_info_t *arg)
|
||||
{
|
||||
struct msi_domain_info *info = domain->host_data;
|
||||
struct msi_domain_ops *ops = info->ops;
|
||||
int ret;
|
||||
|
||||
ret = ops->msi_check(domain, info, dev);
|
||||
if (ret == 0)
|
||||
ret = ops->msi_prepare(domain, dev, nvec, arg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev,
|
||||
int virq, int nvec, msi_alloc_info_t *arg)
|
||||
{
|
||||
struct msi_domain_info *info = domain->host_data;
|
||||
struct msi_domain_ops *ops = info->ops;
|
||||
struct msi_desc *desc;
|
||||
int ret = 0;
|
||||
|
||||
for_each_msi_entry(desc, dev) {
|
||||
/* Don't even try the multi-MSI brain damage. */
|
||||
if (WARN_ON(!desc->irq || desc->nvec_used != 1)) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(desc->irq >= virq && desc->irq < (virq + nvec)))
|
||||
continue;
|
||||
|
||||
ops->set_desc(arg, desc);
|
||||
/* Assumes the domain mutex is held! */
|
||||
ret = irq_domain_alloc_irqs_recursive(domain, virq, 1, arg);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
irq_set_msi_desc_off(virq, 0, desc);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
/* Mop up the damage */
|
||||
for_each_msi_entry(desc, dev) {
|
||||
if (!(desc->irq >= virq && desc->irq < (virq + nvec)))
|
||||
continue;
|
||||
|
||||
irq_domain_free_irqs_common(domain, desc->irq, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* msi_domain_alloc_irqs - Allocate interrupts from a MSI interrupt domain
|
||||
* @domain: The domain to allocate from
|
||||
@@ -270,9 +324,7 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
|
||||
struct msi_desc *desc;
|
||||
int i, ret, virq = -1;
|
||||
|
||||
ret = ops->msi_check(domain, info, dev);
|
||||
if (ret == 0)
|
||||
ret = ops->msi_prepare(domain, dev, nvec, &arg);
|
||||
ret = msi_domain_prepare_irqs(domain, dev, nvec, &arg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user