diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-12 14:25:56 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-12 14:25:56 -0400 |
commit | 33f82bda010224e908e23e59150b4d36904affe9 (patch) | |
tree | 8cb579ae6a11a916bfce8bb7eee7d3a6fc6b8029 | |
parent | 8fac2f96ab86b0e14ec4e42851e21e9b518bdc55 (diff) | |
parent | 12ac1d0f6c3e95732d144ffa65c8b20fbd9aa462 (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.c | 24 | ||||
-rw-r--r-- | kernel/irq/msi.c | 5 |
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 | ||
472 | err: | 469 | err: |
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); | 725 | unlock: |
732 | mutex_unlock(&sparse_irq_lock); | ||
733 | return alloc_descs(start, cnt, node, affinity, owner); | ||
734 | |||
735 | err: | ||
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) { |