aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-09-12 14:25:56 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-09-12 14:25:56 -0400
commit33f82bda010224e908e23e59150b4d36904affe9 (patch)
tree8cb579ae6a11a916bfce8bb7eee7d3a6fc6b8029
parent8fac2f96ab86b0e14ec4e42851e21e9b518bdc55 (diff)
parent12ac1d0f6c3e95732d144ffa65c8b20fbd9aa462 (diff)
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
-rw-r--r--kernel/irq/irqdesc.c24
-rw-r--r--kernel/irq/msi.c5
2 files changed, 10 insertions, 19 deletions
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
index 73be2b3909bd..82afb7ed369f 100644
--- a/kernel/irq/irqdesc.c
+++ b/kernel/irq/irqdesc.c
@@ -421,10 +421,8 @@ static void free_desc(unsigned int irq)
421 * The sysfs entry must be serialized against a concurrent 421 * The sysfs entry must be serialized against a concurrent
422 * irq_sysfs_init() as well. 422 * irq_sysfs_init() as well.
423 */ 423 */
424 mutex_lock(&sparse_irq_lock);
425 kobject_del(&desc->kobj); 424 kobject_del(&desc->kobj);
426 delete_irq_desc(irq); 425 delete_irq_desc(irq);
427 mutex_unlock(&sparse_irq_lock);
428 426
429 /* 427 /*
430 * We free the descriptor, masks and stat fields via RCU. That 428 * 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 desc = alloc_desc(start + i, node, flags, mask, owner); 460 desc = alloc_desc(start + i, node, flags, mask, owner);
463 if (!desc) 461 if (!desc)
464 goto err; 462 goto err;
465 mutex_lock(&sparse_irq_lock);
466 irq_insert_desc(start + i, desc); 463 irq_insert_desc(start + i, desc);
467 irq_sysfs_add(start + i, desc); 464 irq_sysfs_add(start + i, desc);
468 mutex_unlock(&sparse_irq_lock);
469 } 465 }
466 bitmap_set(allocated_irqs, start, cnt);
470 return start; 467 return start;
471 468
472err: 469err:
473 for (i--; i >= 0; i--) 470 for (i--; i >= 0; i--)
474 free_desc(start + i); 471 free_desc(start + i);
475
476 mutex_lock(&sparse_irq_lock);
477 bitmap_clear(allocated_irqs, start, cnt);
478 mutex_unlock(&sparse_irq_lock);
479 return -ENOMEM; 472 return -ENOMEM;
480} 473}
481 474
@@ -575,6 +568,7 @@ static inline int alloc_descs(unsigned int start, unsigned int cnt, int node,
575 568
576 desc->owner = owner; 569 desc->owner = owner;
577 } 570 }
571 bitmap_set(allocated_irqs, start, cnt);
578 return start; 572 return start;
579} 573}
580 574
@@ -670,10 +664,10 @@ void irq_free_descs(unsigned int from, unsigned int cnt)
670 if (from >= nr_irqs || (from + cnt) > nr_irqs) 664 if (from >= nr_irqs || (from + cnt) > nr_irqs)
671 return; 665 return;
672 666
667 mutex_lock(&sparse_irq_lock);
673 for (i = 0; i < cnt; i++) 668 for (i = 0; i < cnt; i++)
674 free_desc(from + i); 669 free_desc(from + i);
675 670
676 mutex_lock(&sparse_irq_lock);
677 bitmap_clear(allocated_irqs, from, cnt); 671 bitmap_clear(allocated_irqs, from, cnt);
678 mutex_unlock(&sparse_irq_lock); 672 mutex_unlock(&sparse_irq_lock);
679} 673}
@@ -720,19 +714,15 @@ __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
720 from, cnt, 0); 714 from, cnt, 0);
721 ret = -EEXIST; 715 ret = -EEXIST;
722 if (irq >=0 && start != irq) 716 if (irq >=0 && start != irq)
723 goto err; 717 goto unlock;
724 718
725 if (start + cnt > nr_irqs) { 719 if (start + cnt > nr_irqs) {
726 ret = irq_expand_nr_irqs(start + cnt); 720 ret = irq_expand_nr_irqs(start + cnt);
727 if (ret) 721 if (ret)
728 goto err; 722 goto unlock;
729 } 723 }
730 724 ret = alloc_descs(start, cnt, node, affinity, owner);
731 bitmap_set(allocated_irqs, start, cnt); 725unlock:
732 mutex_unlock(&sparse_irq_lock);
733 return alloc_descs(start, cnt, node, affinity, owner);
734
735err:
736 mutex_unlock(&sparse_irq_lock); 726 mutex_unlock(&sparse_irq_lock);
737 return ret; 727 return ret;
738} 728}
diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
index 48eadf416c24..3fa4bd59f569 100644
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -315,11 +315,12 @@ int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev,
315 315
316 ops->set_desc(arg, desc); 316 ops->set_desc(arg, desc);
317 /* Assumes the domain mutex is held! */ 317 /* Assumes the domain mutex is held! */
318 ret = irq_domain_alloc_irqs_hierarchy(domain, virq, 1, arg); 318 ret = irq_domain_alloc_irqs_hierarchy(domain, desc->irq, 1,
319 arg);
319 if (ret) 320 if (ret)
320 break; 321 break;
321 322
322 irq_set_msi_desc_off(virq, 0, desc); 323 irq_set_msi_desc_off(desc->irq, 0, desc);
323 } 324 }
324 325
325 if (ret) { 326 if (ret) {