Skip to content

Commit bb9b428

Browse files
committed
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
1 parent 7249164 commit bb9b428

File tree

5 files changed

+52
-21
lines changed

5 files changed

+52
-21
lines changed

include/linux/irqdomain.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ extern int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
441441
unsigned int nr_irqs, int node, void *arg,
442442
bool realloc, const struct cpumask *affinity);
443443
extern void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs);
444-
extern void irq_domain_activate_irq(struct irq_data *irq_data);
444+
extern int irq_domain_activate_irq(struct irq_data *irq_data);
445445
extern void irq_domain_deactivate_irq(struct irq_data *irq_data);
446446

447447
static inline int irq_domain_alloc_irqs(struct irq_domain *domain,

kernel/irq/chip.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,12 @@ __irq_startup_managed(struct irq_desc *desc, struct cpumask *aff, bool force)
219219
*/
220220
return IRQ_STARTUP_ABORT;
221221
}
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;
223228
return IRQ_STARTUP_MANAGED;
224229
}
225230
#else
@@ -285,7 +290,7 @@ int irq_activate(struct irq_desc *desc)
285290
struct irq_data *d = irq_desc_get_irq_data(desc);
286291

287292
if (!irqd_affinity_is_managed(d))
288-
irq_domain_activate_irq(d);
293+
return irq_domain_activate_irq(d);
289294
return 0;
290295
}
291296

kernel/irq/internals.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,9 +439,10 @@ static inline bool irq_fixup_move_pending(struct irq_desc *desc, bool fclear)
439439
#endif /* !CONFIG_GENERIC_PENDING_IRQ */
440440

441441
#if !defined(CONFIG_IRQ_DOMAIN) || !defined(CONFIG_IRQ_DOMAIN_HIERARCHY)
442-
static inline void irq_domain_activate_irq(struct irq_data *data)
442+
static inline int irq_domain_activate_irq(struct irq_data *data)
443443
{
444444
irqd_set_activated(data);
445+
return 0;
445446
}
446447
static inline void irq_domain_deactivate_irq(struct irq_data *data)
447448
{

kernel/irq/irqdomain.c

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1682,28 +1682,35 @@ void irq_domain_free_irqs_parent(struct irq_domain *domain,
16821682
}
16831683
EXPORT_SYMBOL_GPL(irq_domain_free_irqs_parent);
16841684

1685-
static void __irq_domain_activate_irq(struct irq_data *irq_data)
1685+
static void __irq_domain_deactivate_irq(struct irq_data *irq_data)
16861686
{
16871687
if (irq_data && irq_data->domain) {
16881688
struct irq_domain *domain = irq_data->domain;
16891689

1690+
if (domain->ops->deactivate)
1691+
domain->ops->deactivate(domain, irq_data);
16901692
if (irq_data->parent_data)
1691-
__irq_domain_activate_irq(irq_data->parent_data);
1692-
if (domain->ops->activate)
1693-
domain->ops->activate(domain, irq_data, false);
1693+
__irq_domain_deactivate_irq(irq_data->parent_data);
16941694
}
16951695
}
16961696

1697-
static void __irq_domain_deactivate_irq(struct irq_data *irq_data)
1697+
static int __irq_domain_activate_irq(struct irq_data *irqd)
16981698
{
1699-
if (irq_data && irq_data->domain) {
1700-
struct irq_domain *domain = irq_data->domain;
1699+
int ret = 0;
17011700

1702-
if (domain->ops->deactivate)
1703-
domain->ops->deactivate(domain, irq_data);
1704-
if (irq_data->parent_data)
1705-
__irq_domain_deactivate_irq(irq_data->parent_data);
1701+
if (irqd && irqd->domain) {
1702+
struct irq_domain *domain = irqd->domain;
1703+
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+
}
17061712
}
1713+
return ret;
17071714
}
17081715

17091716
/**
@@ -1714,12 +1721,15 @@ static void __irq_domain_deactivate_irq(struct irq_data *irq_data)
17141721
* This is the second step to call domain_ops->activate to program interrupt
17151722
* controllers, so the interrupt could actually get delivered.
17161723
*/
1717-
void irq_domain_activate_irq(struct irq_data *irq_data)
1724+
int irq_domain_activate_irq(struct irq_data *irq_data)
17181725
{
1719-
if (!irqd_is_activated(irq_data)) {
1720-
__irq_domain_activate_irq(irq_data);
1726+
int ret = 0;
1727+
1728+
if (!irqd_is_activated(irq_data))
1729+
ret = __irq_domain_activate_irq(irq_data);
1730+
if (!ret)
17211731
irqd_set_activated(irq_data);
1722-
}
1732+
return ret;
17231733
}
17241734

17251735
/**

kernel/irq/msi.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -401,11 +401,26 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
401401
struct irq_data *irq_data;
402402

403403
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;
405407
}
406408
}
407-
408409
return 0;
410+
411+
cleanup:
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;
409424
}
410425

411426
/**

0 commit comments

Comments
 (0)