aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2017-09-13 17:29:11 -0400
committerThomas Gleixner <tglx@linutronix.de>2017-09-25 14:38:24 -0400
commitbb9b428a5c832d7abb494fbabac37c515c01c6c4 (patch)
treed5a448d6832547bc940e137bff492c0d88b1786a
parent72491643469aab736536ae71dcd199b19dabd891 (diff)
genirq/irqdomain: Allow irq_domain_activate_irq() to fail
Allow irq_domain_activate_irq() to fail. This is required to support a reservation and late vector assignment scheme. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Juergen Gross <jgross@suse.com> Tested-by: Yu Chen <yu.c.chen@intel.com> Acked-by: Juergen Gross <jgross@suse.com> Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com> Cc: Tony Luck <tony.luck@intel.com> Cc: Marc Zyngier <marc.zyngier@arm.com> Cc: Alok Kataria <akataria@vmware.com> Cc: Joerg Roedel <joro@8bytes.org> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Christoph Hellwig <hch@lst.de> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Rui Zhang <rui.zhang@intel.com> Cc: "K. Y. Srinivasan" <kys@microsoft.com> Cc: Arjan van de Ven <arjan@linux.intel.com> Cc: Dan Williams <dan.j.williams@intel.com> Cc: Len Brown <lenb@kernel.org> Link: https://lkml.kernel.org/r/20170913213152.933882227@linutronix.de
-rw-r--r--include/linux/irqdomain.h2
-rw-r--r--kernel/irq/chip.c9
-rw-r--r--kernel/irq/internals.h3
-rw-r--r--kernel/irq/irqdomain.c40
-rw-r--r--kernel/irq/msi.c19
5 files changed, 52 insertions, 21 deletions
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 9bc07f59b090..8fb877121984 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -441,7 +441,7 @@ extern int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
441 unsigned int nr_irqs, int node, void *arg, 441 unsigned int nr_irqs, int node, void *arg,
442 bool realloc, const struct cpumask *affinity); 442 bool realloc, const struct cpumask *affinity);
443extern void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs); 443extern void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs);
444extern void irq_domain_activate_irq(struct irq_data *irq_data); 444extern int irq_domain_activate_irq(struct irq_data *irq_data);
445extern void irq_domain_deactivate_irq(struct irq_data *irq_data); 445extern void irq_domain_deactivate_irq(struct irq_data *irq_data);
446 446
447static inline int irq_domain_alloc_irqs(struct irq_domain *domain, 447static inline int irq_domain_alloc_irqs(struct irq_domain *domain,
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 37dd34d922f4..cd5b3eb38082 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -219,7 +219,12 @@ __irq_startup_managed(struct irq_desc *desc, struct cpumask *aff, bool force)
219 */ 219 */
220 return IRQ_STARTUP_ABORT; 220 return IRQ_STARTUP_ABORT;
221 } 221 }
222 irq_domain_activate_irq(d); 222 /*
223 * Managed interrupts have reserved resources, so this should not
224 * happen.
225 */
226 if (WARN_ON(irq_domain_activate_irq(d)))
227 return IRQ_STARTUP_ABORT;
223 return IRQ_STARTUP_MANAGED; 228 return IRQ_STARTUP_MANAGED;
224} 229}
225#else 230#else
@@ -285,7 +290,7 @@ int irq_activate(struct irq_desc *desc)
285 struct irq_data *d = irq_desc_get_irq_data(desc); 290 struct irq_data *d = irq_desc_get_irq_data(desc);
286 291
287 if (!irqd_affinity_is_managed(d)) 292 if (!irqd_affinity_is_managed(d))
288 irq_domain_activate_irq(d); 293 return irq_domain_activate_irq(d);
289 return 0; 294 return 0;
290} 295}
291 296
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
index 8bd131e4c944..e84d0e3899f6 100644
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -439,9 +439,10 @@ static inline bool irq_fixup_move_pending(struct irq_desc *desc, bool fclear)
439#endif /* !CONFIG_GENERIC_PENDING_IRQ */ 439#endif /* !CONFIG_GENERIC_PENDING_IRQ */
440 440
441#if !defined(CONFIG_IRQ_DOMAIN) || !defined(CONFIG_IRQ_DOMAIN_HIERARCHY) 441#if !defined(CONFIG_IRQ_DOMAIN) || !defined(CONFIG_IRQ_DOMAIN_HIERARCHY)
442static inline void irq_domain_activate_irq(struct irq_data *data) 442static inline int irq_domain_activate_irq(struct irq_data *data)
443{ 443{
444 irqd_set_activated(data); 444 irqd_set_activated(data);
445 return 0;
445} 446}
446static inline void irq_domain_deactivate_irq(struct irq_data *data) 447static inline void irq_domain_deactivate_irq(struct irq_data *data)
447{ 448{
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 1423f8a6c75d..47e8ddd9e8cf 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -1682,28 +1682,35 @@ void irq_domain_free_irqs_parent(struct irq_domain *domain,
1682} 1682}
1683EXPORT_SYMBOL_GPL(irq_domain_free_irqs_parent); 1683EXPORT_SYMBOL_GPL(irq_domain_free_irqs_parent);
1684 1684
1685static void __irq_domain_activate_irq(struct irq_data *irq_data) 1685static void __irq_domain_deactivate_irq(struct irq_data *irq_data)
1686{ 1686{
1687 if (irq_data && irq_data->domain) { 1687 if (irq_data && irq_data->domain) {
1688 struct irq_domain *domain = irq_data->domain; 1688 struct irq_domain *domain = irq_data->domain;
1689 1689
1690 if (domain->ops->deactivate)
1691 domain->ops->deactivate(domain, irq_data);
1690 if (irq_data->parent_data) 1692 if (irq_data->parent_data)
1691 __irq_domain_activate_irq(irq_data->parent_data); 1693 __irq_domain_deactivate_irq(irq_data->parent_data);
1692 if (domain->ops->activate)
1693 domain->ops->activate(domain, irq_data, false);
1694 } 1694 }
1695} 1695}
1696 1696
1697static void __irq_domain_deactivate_irq(struct irq_data *irq_data) 1697static int __irq_domain_activate_irq(struct irq_data *irqd)
1698{ 1698{
1699 if (irq_data && irq_data->domain) { 1699 int ret = 0;
1700 struct irq_domain *domain = irq_data->domain;
1701 1700
1702 if (domain->ops->deactivate) 1701 if (irqd && irqd->domain) {
1703 domain->ops->deactivate(domain, irq_data); 1702 struct irq_domain *domain = irqd->domain;
1704 if (irq_data->parent_data) 1703
1705 __irq_domain_deactivate_irq(irq_data->parent_data); 1704 if (irqd->parent_data)
1705 ret = __irq_domain_activate_irq(irqd->parent_data);
1706 if (!ret && domain->ops->activate) {
1707 ret = domain->ops->activate(domain, irqd, false);
1708 /* Rollback in case of error */
1709 if (ret && irqd->parent_data)
1710 __irq_domain_deactivate_irq(irqd->parent_data);
1711 }
1706 } 1712 }
1713 return ret;
1707} 1714}
1708 1715
1709/** 1716/**
@@ -1714,12 +1721,15 @@ static void __irq_domain_deactivate_irq(struct irq_data *irq_data)
1714 * This is the second step to call domain_ops->activate to program interrupt 1721 * This is the second step to call domain_ops->activate to program interrupt
1715 * controllers, so the interrupt could actually get delivered. 1722 * controllers, so the interrupt could actually get delivered.
1716 */ 1723 */
1717void irq_domain_activate_irq(struct irq_data *irq_data) 1724int irq_domain_activate_irq(struct irq_data *irq_data)
1718{ 1725{
1719 if (!irqd_is_activated(irq_data)) { 1726 int ret = 0;
1720 __irq_domain_activate_irq(irq_data); 1727
1728 if (!irqd_is_activated(irq_data))
1729 ret = __irq_domain_activate_irq(irq_data);
1730 if (!ret)
1721 irqd_set_activated(irq_data); 1731 irqd_set_activated(irq_data);
1722 } 1732 return ret;
1723} 1733}
1724 1734
1725/** 1735/**
diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
index 6155fff9f647..5ece369950ec 100644
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -401,11 +401,26 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
401 struct irq_data *irq_data; 401 struct irq_data *irq_data;
402 402
403 irq_data = irq_domain_get_irq_data(domain, desc->irq); 403 irq_data = irq_domain_get_irq_data(domain, desc->irq);
404 irq_domain_activate_irq(irq_data); 404 ret = irq_domain_activate_irq(irq_data);
405 if (ret)
406 goto cleanup;
405 } 407 }
406 } 408 }
407
408 return 0; 409 return 0;
410
411cleanup:
412 for_each_msi_entry(desc, dev) {
413 struct irq_data *irqd;
414
415 if (desc->irq == virq)
416 break;
417
418 irqd = irq_domain_get_irq_data(domain, desc->irq);
419 if (irqd_is_activated(irqd))
420 irq_domain_deactivate_irq(irqd);
421 }
422 msi_domain_free_irqs(domain, dev);
423 return ret;
409} 424}
410 425
411/** 426/**