Commit 33f82bda authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull irq fixes from Ingo Molnar:
 "A sparse irq race/locking fix, and a MSI irq domains population fix"

* 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  genirq: Make sparse_irq_lock protect what it should protect
  genirq/msi: Fix populating multiple interrupts
parents 8fac2f96 12ac1d0f
...@@ -421,10 +421,8 @@ static void free_desc(unsigned int irq) ...@@ -421,10 +421,8 @@ static void free_desc(unsigned int irq)
* The sysfs entry must be serialized against a concurrent * The sysfs entry must be serialized against a concurrent
* irq_sysfs_init() as well. * irq_sysfs_init() as well.
*/ */
mutex_lock(&sparse_irq_lock);
kobject_del(&desc->kobj); kobject_del(&desc->kobj);
delete_irq_desc(irq); delete_irq_desc(irq);
mutex_unlock(&sparse_irq_lock);
/* /*
* We free the descriptor, masks and stat fields via RCU. That * We free the descriptor, masks and stat fields via RCU. That
...@@ -462,20 +460,15 @@ static int alloc_descs(unsigned int start, unsigned int cnt, int node, ...@@ -462,20 +460,15 @@ static int alloc_descs(unsigned int start, unsigned int cnt, int node,
desc = alloc_desc(start + i, node, flags, mask, owner); desc = alloc_desc(start + i, node, flags, mask, owner);
if (!desc) if (!desc)
goto err; goto err;
mutex_lock(&sparse_irq_lock);
irq_insert_desc(start + i, desc); irq_insert_desc(start + i, desc);
irq_sysfs_add(start + i, desc); irq_sysfs_add(start + i, desc);
mutex_unlock(&sparse_irq_lock);
} }
bitmap_set(allocated_irqs, start, cnt);
return start; return start;
err: err:
for (i--; i >= 0; i--) for (i--; i >= 0; i--)
free_desc(start + i); free_desc(start + i);
mutex_lock(&sparse_irq_lock);
bitmap_clear(allocated_irqs, start, cnt);
mutex_unlock(&sparse_irq_lock);
return -ENOMEM; return -ENOMEM;
} }
...@@ -575,6 +568,7 @@ static inline int alloc_descs(unsigned int start, unsigned int cnt, int node, ...@@ -575,6 +568,7 @@ static inline int alloc_descs(unsigned int start, unsigned int cnt, int node,
desc->owner = owner; desc->owner = owner;
} }
bitmap_set(allocated_irqs, start, cnt);
return start; return start;
} }
...@@ -670,10 +664,10 @@ void irq_free_descs(unsigned int from, unsigned int cnt) ...@@ -670,10 +664,10 @@ void irq_free_descs(unsigned int from, unsigned int cnt)
if (from >= nr_irqs || (from + cnt) > nr_irqs) if (from >= nr_irqs || (from + cnt) > nr_irqs)
return; return;
mutex_lock(&sparse_irq_lock);
for (i = 0; i < cnt; i++) for (i = 0; i < cnt; i++)
free_desc(from + i); free_desc(from + i);
mutex_lock(&sparse_irq_lock);
bitmap_clear(allocated_irqs, from, cnt); bitmap_clear(allocated_irqs, from, cnt);
mutex_unlock(&sparse_irq_lock); mutex_unlock(&sparse_irq_lock);
} }
...@@ -720,19 +714,15 @@ __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node, ...@@ -720,19 +714,15 @@ __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
from, cnt, 0); from, cnt, 0);
ret = -EEXIST; ret = -EEXIST;
if (irq >=0 && start != irq) if (irq >=0 && start != irq)
goto err; goto unlock;
if (start + cnt > nr_irqs) { if (start + cnt > nr_irqs) {
ret = irq_expand_nr_irqs(start + cnt); ret = irq_expand_nr_irqs(start + cnt);
if (ret) if (ret)
goto err; goto unlock;
} }
ret = alloc_descs(start, cnt, node, affinity, owner);
bitmap_set(allocated_irqs, start, cnt); unlock:
mutex_unlock(&sparse_irq_lock);
return alloc_descs(start, cnt, node, affinity, owner);
err:
mutex_unlock(&sparse_irq_lock); mutex_unlock(&sparse_irq_lock);
return ret; return ret;
} }
......
...@@ -315,11 +315,12 @@ int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev, ...@@ -315,11 +315,12 @@ int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev,
ops->set_desc(arg, desc); ops->set_desc(arg, desc);
/* Assumes the domain mutex is held! */ /* Assumes the domain mutex is held! */
ret = irq_domain_alloc_irqs_hierarchy(domain, virq, 1, arg); ret = irq_domain_alloc_irqs_hierarchy(domain, desc->irq, 1,
arg);
if (ret) if (ret)
break; break;
irq_set_msi_desc_off(virq, 0, desc); irq_set_msi_desc_off(desc->irq, 0, desc);
} }
if (ret) { if (ret) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment