From c2b1063e8feb2115537addce10f36c0c82d11d9b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 2 Apr 2021 08:23:25 +0200 Subject: genirq: Add a IRQF_NO_DEBUG flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The whole call to note_interrupt() can be avoided or return early when interrupts would be marked accordingly. For IPI handlers which always return HANDLED the whole procedure is pretty pointless to begin with. Add a IRQF_NO_DEBUG flag and mark the interrupt accordingly if supplied when the interrupt is requested. When noirqdebug is set on the kernel commandline, then the interrupt is marked unconditionally so that there is only one condition in the hotpath to evaluate. [ clg: Add changelog ] Signed-off-by: Thomas Gleixner Signed-off-by: Cédric Le Goater Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/r/7a8ad02f-63a8-c1aa-fdd1-39d973593d02@kaod.org --- kernel/irq/chip.c | 2 +- kernel/irq/handle.c | 2 +- kernel/irq/manage.c | 5 +++++ kernel/irq/settings.h | 12 ++++++++++++ 4 files changed, 19 insertions(+), 2 deletions(-) (limited to 'kernel') diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 8cc8e5713287..7f04c7d8296e 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -481,7 +481,7 @@ void handle_nested_irq(unsigned int irq) for_each_action_of_desc(desc, action) action_ret |= action->thread_fn(action->irq, action->dev_id); - if (!noirqdebug) + if (!irq_settings_no_debug(desc)) note_interrupt(desc, action_ret); raw_spin_lock_irq(&desc->lock); diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 762a928e18f9..221d80c31e94 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -197,7 +197,7 @@ irqreturn_t handle_irq_event_percpu(struct irq_desc *desc) add_interrupt_randomness(desc->irq_data.irq, flags); - if (!noirqdebug) + if (!irq_settings_no_debug(desc)) note_interrupt(desc, retval); return retval; } diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 4c14356543d9..7bdd09e7d5f0 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1686,8 +1686,13 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) if (new->flags & IRQF_PERCPU) { irqd_set(&desc->irq_data, IRQD_PER_CPU); irq_settings_set_per_cpu(desc); + if (new->flags & IRQF_NO_DEBUG) + irq_settings_set_no_debug(desc); } + if (noirqdebug) + irq_settings_set_no_debug(desc); + if (new->flags & IRQF_ONESHOT) desc->istate |= IRQS_ONESHOT; diff --git a/kernel/irq/settings.h b/kernel/irq/settings.h index 403378b9947b..7b7efb1a114b 100644 --- a/kernel/irq/settings.h +++ b/kernel/irq/settings.h @@ -18,6 +18,7 @@ enum { _IRQ_IS_POLLED = IRQ_IS_POLLED, _IRQ_DISABLE_UNLAZY = IRQ_DISABLE_UNLAZY, _IRQ_HIDDEN = IRQ_HIDDEN, + _IRQ_NO_DEBUG = IRQ_NO_DEBUG, _IRQF_MODIFY_MASK = IRQF_MODIFY_MASK, }; @@ -33,6 +34,7 @@ enum { #define IRQ_IS_POLLED GOT_YOU_MORON #define IRQ_DISABLE_UNLAZY GOT_YOU_MORON #define IRQ_HIDDEN GOT_YOU_MORON +#define IRQ_NO_DEBUG GOT_YOU_MORON #undef IRQF_MODIFY_MASK #define IRQF_MODIFY_MASK GOT_YOU_MORON @@ -174,3 +176,13 @@ static inline bool irq_settings_is_hidden(struct irq_desc *desc) { return desc->status_use_accessors & _IRQ_HIDDEN; } + +static inline void irq_settings_set_no_debug(struct irq_desc *desc) +{ + desc->status_use_accessors |= _IRQ_NO_DEBUG; +} + +static inline bool irq_settings_no_debug(struct irq_desc *desc) +{ + return desc->status_use_accessors & _IRQ_NO_DEBUG; +} -- cgit v1.2.3-58-ga151 From 1da027362a7db422243601e895e6f8288389f435 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 2 Apr 2021 12:50:14 +0100 Subject: irqdomain: Reimplement irq_linear_revmap() with irq_find_mapping() irq_linear_revmap() is supposed to be a fast path for domain lookups, but it only exposes low-level details of the irqdomain implementation, details which are better kept private. The *overhead* between the two is only a function call and a couple of tests, so it is likely that noone can show any meaningful difference compared to the cost of taking an interrupt. Reimplement irq_linear_revmap() with irq_find_mapping() in order to preserve source code compatibility, and rename the internal field for a measure. Signed-off-by: Marc Zyngier --- include/linux/irqdomain.h | 22 +++++++++------------- kernel/irq/irqdomain.c | 6 +++--- 2 files changed, 12 insertions(+), 16 deletions(-) (limited to 'kernel') diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 9f884c948739..42b3f7d03a32 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -151,9 +151,9 @@ struct irq_domain_chip_generic; * Revmap data, used internally by irq_domain * @revmap_direct_max_irq: The largest hwirq that can be set for controllers that * support direct mapping - * @revmap_size: Size of the linear map table @linear_revmap[] + * @revmap_size: Size of the linear map table @revmap[] * @revmap_tree: Radix map tree for hwirqs that don't fit in the linear map - * @linear_revmap: Linear table of hwirq->virq reverse mappings + * @revmap: Linear table of hwirq->virq reverse mappings */ struct irq_domain { struct list_head link; @@ -177,7 +177,7 @@ struct irq_domain { unsigned int revmap_size; struct radix_tree_root revmap_tree; struct mutex revmap_tree_mutex; - unsigned int linear_revmap[]; + unsigned int revmap[]; }; /* Irq domain flags */ @@ -394,24 +394,20 @@ static inline unsigned int irq_create_mapping(struct irq_domain *host, return irq_create_mapping_affinity(host, hwirq, NULL); } - /** - * irq_linear_revmap() - Find a linux irq from a hw irq number. + * irq_find_mapping() - Find a linux irq from a hw irq number. * @domain: domain owning this hardware interrupt * @hwirq: hardware irq number in that domain space - * - * This is a fast path alternative to irq_find_mapping() that can be - * called directly by irq controller code to save a handful of - * instructions. It is always safe to call, but won't find irqs mapped - * using the radix tree. */ +extern unsigned int irq_find_mapping(struct irq_domain *host, + irq_hw_number_t hwirq); + static inline unsigned int irq_linear_revmap(struct irq_domain *domain, irq_hw_number_t hwirq) { - return hwirq < domain->revmap_size ? domain->linear_revmap[hwirq] : 0; + return irq_find_mapping(domain, hwirq); } -extern unsigned int irq_find_mapping(struct irq_domain *host, - irq_hw_number_t hwirq); + extern unsigned int irq_create_direct_mapping(struct irq_domain *host); extern const struct irq_domain_ops irq_domain_simple_ops; diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 6284443b87ec..8bd012253989 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -486,7 +486,7 @@ static void irq_domain_clear_mapping(struct irq_domain *domain, irq_hw_number_t hwirq) { if (hwirq < domain->revmap_size) { - domain->linear_revmap[hwirq] = 0; + domain->revmap[hwirq] = 0; } else { mutex_lock(&domain->revmap_tree_mutex); radix_tree_delete(&domain->revmap_tree, hwirq); @@ -499,7 +499,7 @@ static void irq_domain_set_mapping(struct irq_domain *domain, struct irq_data *irq_data) { if (hwirq < domain->revmap_size) { - domain->linear_revmap[hwirq] = irq_data->irq; + domain->revmap[hwirq] = irq_data->irq; } else { mutex_lock(&domain->revmap_tree_mutex); radix_tree_insert(&domain->revmap_tree, hwirq, irq_data); @@ -885,7 +885,7 @@ unsigned int irq_find_mapping(struct irq_domain *domain, /* Check if the hwirq is in the linear revmap. */ if (hwirq < domain->revmap_size) - return domain->linear_revmap[hwirq]; + return domain->revmap[hwirq]; rcu_read_lock(); data = radix_tree_lookup(&domain->revmap_tree, hwirq); -- cgit v1.2.3-58-ga151 From e37af8011a9631996e6cd32dd81a152708eee7d4 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 4 Apr 2021 13:06:39 +0100 Subject: powerpc: Move the use of irq_domain_add_nomap() behind a config option Only a handful of old PPC systems are still using the old 'nomap' variant of the irqdomain library. Move the associated definitions behind a configuration option, which will allow us to make some more radical changes. Signed-off-by: Marc Zyngier --- arch/powerpc/platforms/cell/Kconfig | 1 + arch/powerpc/platforms/powermac/Kconfig | 1 + arch/powerpc/platforms/ps3/Kconfig | 1 + arch/powerpc/sysdev/xive/Kconfig | 1 + include/linux/irqdomain.h | 8 ++++++-- kernel/irq/Kconfig | 5 +++++ kernel/irq/irqdomain.c | 2 ++ 7 files changed, 17 insertions(+), 2 deletions(-) (limited to 'kernel') diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig index e7c976bcadff..cb70c5f25bc6 100644 --- a/arch/powerpc/platforms/cell/Kconfig +++ b/arch/powerpc/platforms/cell/Kconfig @@ -35,6 +35,7 @@ config PPC_IBM_CELL_BLADE config AXON_MSI bool depends on PPC_IBM_CELL_BLADE && PCI_MSI + select IRQ_DOMAIN_NOMAP default y menu "Cell Broadband Engine options" diff --git a/arch/powerpc/platforms/powermac/Kconfig b/arch/powerpc/platforms/powermac/Kconfig index c02d8c503b29..b97bf12801eb 100644 --- a/arch/powerpc/platforms/powermac/Kconfig +++ b/arch/powerpc/platforms/powermac/Kconfig @@ -24,6 +24,7 @@ config PPC_PMAC32_PSURGE bool "Support for powersurge upgrade cards" if EXPERT depends on SMP && PPC32 && PPC_PMAC select PPC_SMP_MUXED_IPI + select IRQ_DOMAIN_NOMAP default y help The powersurge cpu boards can be used in the generation diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig index e32406e918d0..4d0535cc7946 100644 --- a/arch/powerpc/platforms/ps3/Kconfig +++ b/arch/powerpc/platforms/ps3/Kconfig @@ -7,6 +7,7 @@ config PPC_PS3 select USB_OHCI_BIG_ENDIAN_MMIO select USB_EHCI_BIG_ENDIAN_MMIO select HAVE_PCI + select IRQ_DOMAIN_NOMAP help This option enables support for the Sony PS3 game console and other platforms using the PS3 hypervisor. Enabling this diff --git a/arch/powerpc/sysdev/xive/Kconfig b/arch/powerpc/sysdev/xive/Kconfig index 785c292d104b..97796c6b63f0 100644 --- a/arch/powerpc/sysdev/xive/Kconfig +++ b/arch/powerpc/sysdev/xive/Kconfig @@ -3,6 +3,7 @@ config PPC_XIVE bool select PPC_SMP_MUXED_IPI select HARDIRQS_SW_RESEND + select IRQ_DOMAIN_NOMAP config PPC_XIVE_NATIVE bool diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 42b3f7d03a32..723495ec5a2f 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -345,6 +345,8 @@ static inline struct irq_domain *irq_domain_add_linear(struct device_node *of_no { return __irq_domain_add(of_node_to_fwnode(of_node), size, size, 0, ops, host_data); } + +#ifdef CONFIG_IRQ_DOMAIN_NOMAP static inline struct irq_domain *irq_domain_add_nomap(struct device_node *of_node, unsigned int max_irq, const struct irq_domain_ops *ops, @@ -352,6 +354,10 @@ static inline struct irq_domain *irq_domain_add_nomap(struct device_node *of_nod { return __irq_domain_add(of_node_to_fwnode(of_node), 0, max_irq, max_irq, ops, host_data); } + +extern unsigned int irq_create_direct_mapping(struct irq_domain *host); +#endif + static inline struct irq_domain *irq_domain_add_tree(struct device_node *of_node, const struct irq_domain_ops *ops, void *host_data) @@ -408,8 +414,6 @@ static inline unsigned int irq_linear_revmap(struct irq_domain *domain, return irq_find_mapping(domain, hwirq); } -extern unsigned int irq_create_direct_mapping(struct irq_domain *host); - extern const struct irq_domain_ops irq_domain_simple_ops; /* stock xlate functions */ diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig index d79ef2493a28..fbc54c2a7f23 100644 --- a/kernel/irq/Kconfig +++ b/kernel/irq/Kconfig @@ -70,6 +70,11 @@ config IRQ_DOMAIN_HIERARCHY bool select IRQ_DOMAIN +# Support for obsolete non-mapping irq domains +config IRQ_DOMAIN_NOMAP + bool + select IRQ_DOMAIN + # Support for hierarchical fasteoi+edge and fasteoi+level handlers config IRQ_FASTEOI_HIERARCHY_HANDLERS bool diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 8bd012253989..e0143e640683 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -604,6 +604,7 @@ void irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base, } EXPORT_SYMBOL_GPL(irq_domain_associate_many); +#ifdef CONFIG_IRQ_DOMAIN_NOMAP /** * irq_create_direct_mapping() - Allocate an irq for direct mapping * @domain: domain to allocate the irq for or NULL for default domain @@ -644,6 +645,7 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain) return virq; } EXPORT_SYMBOL_GPL(irq_create_direct_mapping); +#endif /** * irq_create_mapping_affinity() - Map a hardware interrupt into linux irq space -- cgit v1.2.3-58-ga151 From 4f86a06e2d6ece5316e4c42fbf946ee22acb30f3 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 10 Sep 2018 18:33:46 +0100 Subject: irqdomain: Make normal and nomap irqdomains exclusive Direct mappings are completely exclusive of normal mappings, meaning that we can refactor the code slightly so that we can get rid of the revmap_direct_max_irq field and use the revmap_size field instead, reducing the size of the irqdomain structure. Signed-off-by: Marc Zyngier --- include/linux/irqdomain.h | 6 +++--- kernel/irq/irqdomain.c | 45 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 38 insertions(+), 13 deletions(-) (limited to 'kernel') diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 723495ec5a2f..0916cf9c6e20 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -149,8 +149,6 @@ struct irq_domain_chip_generic; * @parent: Pointer to parent irq_domain to support hierarchy irq_domains * * Revmap data, used internally by irq_domain - * @revmap_direct_max_irq: The largest hwirq that can be set for controllers that - * support direct mapping * @revmap_size: Size of the linear map table @revmap[] * @revmap_tree: Radix map tree for hwirqs that don't fit in the linear map * @revmap: Linear table of hwirq->virq reverse mappings @@ -173,7 +171,6 @@ struct irq_domain { /* reverse map data. The linear map gets appended to the irq_domain */ irq_hw_number_t hwirq_max; - unsigned int revmap_direct_max_irq; unsigned int revmap_size; struct radix_tree_root revmap_tree; struct mutex revmap_tree_mutex; @@ -207,6 +204,9 @@ enum { */ IRQ_DOMAIN_MSI_NOMASK_QUIRK = (1 << 6), + /* Irq domain doesn't translate anything */ + IRQ_DOMAIN_FLAG_NO_MAP = (1 << 7), + /* * Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved * for implementation specific purposes and ignored by the diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index e0143e640683..fa94c86e47d4 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -146,6 +146,10 @@ struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size, static atomic_t unknown_domains; + if (WARN_ON((size && direct_max) || + (!IS_ENABLED(CONFIG_IRQ_DOMAIN_NOMAP) && direct_max))) + return NULL; + domain = kzalloc_node(sizeof(*domain) + (sizeof(unsigned int) * size), GFP_KERNEL, of_node_to_nid(to_of_node(fwnode))); if (!domain) @@ -213,8 +217,14 @@ struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size, domain->ops = ops; domain->host_data = host_data; domain->hwirq_max = hwirq_max; + + if (direct_max) { + size = direct_max; + domain->flags |= IRQ_DOMAIN_FLAG_NO_MAP; + } + domain->revmap_size = size; - domain->revmap_direct_max_irq = direct_max; + irq_domain_check_hierarchy(domain); mutex_lock(&irq_domain_mutex); @@ -482,9 +492,18 @@ struct irq_domain *irq_get_default_host(void) return irq_default_domain; } +static bool irq_domain_is_nomap(struct irq_domain *domain) +{ + return IS_ENABLED(CONFIG_IRQ_DOMAIN_NOMAP) && + (domain->flags & IRQ_DOMAIN_FLAG_NO_MAP); +} + static void irq_domain_clear_mapping(struct irq_domain *domain, irq_hw_number_t hwirq) { + if (irq_domain_is_nomap(domain)) + return; + if (hwirq < domain->revmap_size) { domain->revmap[hwirq] = 0; } else { @@ -498,6 +517,9 @@ static void irq_domain_set_mapping(struct irq_domain *domain, irq_hw_number_t hwirq, struct irq_data *irq_data) { + if (irq_domain_is_nomap(domain)) + return; + if (hwirq < domain->revmap_size) { domain->revmap[hwirq] = irq_data->irq; } else { @@ -629,9 +651,9 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain) pr_debug("create_direct virq allocation failed\n"); return 0; } - if (virq >= domain->revmap_direct_max_irq) { + if (virq >= domain->revmap_size) { pr_err("ERROR: no free irqs available below %i maximum\n", - domain->revmap_direct_max_irq); + domain->revmap_size); irq_free_desc(virq); return 0; } @@ -879,10 +901,14 @@ unsigned int irq_find_mapping(struct irq_domain *domain, if (domain == NULL) return 0; - if (hwirq < domain->revmap_direct_max_irq) { - data = irq_domain_get_irq_data(domain, hwirq); - if (data && data->hwirq == hwirq) - return hwirq; + if (irq_domain_is_nomap(domain)) { + if (hwirq < domain->revmap_size) { + data = irq_domain_get_irq_data(domain, hwirq); + if (data && data->hwirq == hwirq) + return hwirq; + } + + return 0; } /* Check if the hwirq is in the linear revmap. */ @@ -1470,7 +1496,7 @@ static void irq_domain_fix_revmap(struct irq_data *d) { void __rcu **slot; - if (d->hwirq < d->domain->revmap_size) + if (irq_domain_is_nomap(d->domain) || d->hwirq < d->domain->revmap_size) return; /* Not using radix tree. */ /* Fix up the revmap. */ @@ -1830,8 +1856,7 @@ static void irq_domain_debug_show_one(struct seq_file *m, struct irq_domain *d, int ind) { seq_printf(m, "%*sname: %s\n", ind, "", d->name); - seq_printf(m, "%*ssize: %u\n", ind + 1, "", - d->revmap_size + d->revmap_direct_max_irq); + seq_printf(m, "%*ssize: %u\n", ind + 1, "", d->revmap_size); seq_printf(m, "%*smapped: %u\n", ind + 1, "", d->mapcount); seq_printf(m, "%*sflags: 0x%08x\n", ind +1 , "", d->flags); if (d->ops && d->ops->debug_show) -- cgit v1.2.3-58-ga151 From 426fa316148bccabf48f9c91a13c387ee911eadc Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 5 Apr 2021 11:30:51 +0100 Subject: irqdomain: Use struct_size() helper when allocating irqdomain Instead of open-coding the size computation of struct irqdomain, use the struct_size() helper instead. This is going to be handy as we change the type of the revmap array. Signed-off-by: Marc Zyngier --- kernel/irq/irqdomain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index fa94c86e47d4..cdcb1989cd20 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -150,7 +150,7 @@ struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size, (!IS_ENABLED(CONFIG_IRQ_DOMAIN_NOMAP) && direct_max))) return NULL; - domain = kzalloc_node(sizeof(*domain) + (sizeof(unsigned int) * size), + domain = kzalloc_node(struct_size(domain, revmap, size), GFP_KERNEL, of_node_to_nid(to_of_node(fwnode))); if (!domain) return NULL; -- cgit v1.2.3-58-ga151 From 48b15a7921d60680babe59f64e127816585a585c Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 5 Apr 2021 11:46:53 +0100 Subject: irqdomain: Cache irq_data instead of a virq number in the revmap Caching a virq number in the revmap is pretty inefficient, as it means we will need to convert it back to either an irq_data or irq_desc to do anything with it. It is also a bit odd, as the radix tree does cache irq_data pointers. Change the revmap type to be an irq_data pointer instead of an unsigned int, and preserve the current API for now. Signed-off-by: Marc Zyngier --- include/linux/irqdomain.h | 4 ++-- kernel/irq/irqdomain.c | 16 +++++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'kernel') diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 0916cf9c6e20..340cc04611dd 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -151,7 +151,7 @@ struct irq_domain_chip_generic; * Revmap data, used internally by irq_domain * @revmap_size: Size of the linear map table @revmap[] * @revmap_tree: Radix map tree for hwirqs that don't fit in the linear map - * @revmap: Linear table of hwirq->virq reverse mappings + * @revmap: Linear table of irq_data pointers */ struct irq_domain { struct list_head link; @@ -174,7 +174,7 @@ struct irq_domain { unsigned int revmap_size; struct radix_tree_root revmap_tree; struct mutex revmap_tree_mutex; - unsigned int revmap[]; + struct irq_data *revmap[]; }; /* Irq domain flags */ diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index cdcb1989cd20..7a4e38804487 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -505,7 +505,7 @@ static void irq_domain_clear_mapping(struct irq_domain *domain, return; if (hwirq < domain->revmap_size) { - domain->revmap[hwirq] = 0; + domain->revmap[hwirq] = NULL; } else { mutex_lock(&domain->revmap_tree_mutex); radix_tree_delete(&domain->revmap_tree, hwirq); @@ -521,7 +521,7 @@ static void irq_domain_set_mapping(struct irq_domain *domain, return; if (hwirq < domain->revmap_size) { - domain->revmap[hwirq] = irq_data->irq; + domain->revmap[hwirq] = irq_data; } else { mutex_lock(&domain->revmap_tree_mutex); radix_tree_insert(&domain->revmap_tree, hwirq, irq_data); @@ -913,7 +913,7 @@ unsigned int irq_find_mapping(struct irq_domain *domain, /* Check if the hwirq is in the linear revmap. */ if (hwirq < domain->revmap_size) - return domain->revmap[hwirq]; + return domain->revmap[hwirq]->irq; rcu_read_lock(); data = radix_tree_lookup(&domain->revmap_tree, hwirq); @@ -1496,8 +1496,14 @@ static void irq_domain_fix_revmap(struct irq_data *d) { void __rcu **slot; - if (irq_domain_is_nomap(d->domain) || d->hwirq < d->domain->revmap_size) - return; /* Not using radix tree. */ + if (irq_domain_is_nomap(d->domain)) + return; + + if (d->hwirq < d->domain->revmap_size) { + /* Not using radix tree */ + d->domain->revmap[d->hwirq] = d; + return; + } /* Fix up the revmap. */ mutex_lock(&d->domain->revmap_tree_mutex); -- cgit v1.2.3-58-ga151 From d4a45c68dc81f9117ceaff9f058d5fae674181b9 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 5 Apr 2021 12:57:27 +0100 Subject: irqdomain: Protect the linear revmap with RCU It is pretty odd that the radix tree uses RCU while the linear portion doesn't, leading to potential surprises for the users, depending on how the irqdomain has been created. Fix this by moving the update of the linear revmap under the mutex, and the lookup under the RCU read-side lock. The mutex name is updated to reflect that it doesn't only cover the radix-tree anymore. Signed-off-by: Marc Zyngier --- include/linux/irqdomain.h | 5 +++-- kernel/irq/irqdomain.c | 49 ++++++++++++++++++++++------------------------- 2 files changed, 26 insertions(+), 28 deletions(-) (limited to 'kernel') diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 340cc04611dd..2b696c9bcaaf 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -151,6 +151,7 @@ struct irq_domain_chip_generic; * Revmap data, used internally by irq_domain * @revmap_size: Size of the linear map table @revmap[] * @revmap_tree: Radix map tree for hwirqs that don't fit in the linear map + * @revmap_mutex: Lock for the revmap * @revmap: Linear table of irq_data pointers */ struct irq_domain { @@ -173,8 +174,8 @@ struct irq_domain { irq_hw_number_t hwirq_max; unsigned int revmap_size; struct radix_tree_root revmap_tree; - struct mutex revmap_tree_mutex; - struct irq_data *revmap[]; + struct mutex revmap_mutex; + struct irq_data __rcu *revmap[]; }; /* Irq domain flags */ diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 7a4e38804487..8fbadeefc814 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -213,7 +213,7 @@ struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size, /* Fill structure */ INIT_RADIX_TREE(&domain->revmap_tree, GFP_KERNEL); - mutex_init(&domain->revmap_tree_mutex); + mutex_init(&domain->revmap_mutex); domain->ops = ops; domain->host_data = host_data; domain->hwirq_max = hwirq_max; @@ -504,13 +504,12 @@ static void irq_domain_clear_mapping(struct irq_domain *domain, if (irq_domain_is_nomap(domain)) return; - if (hwirq < domain->revmap_size) { - domain->revmap[hwirq] = NULL; - } else { - mutex_lock(&domain->revmap_tree_mutex); + mutex_lock(&domain->revmap_mutex); + if (hwirq < domain->revmap_size) + rcu_assign_pointer(domain->revmap[hwirq], NULL); + else radix_tree_delete(&domain->revmap_tree, hwirq); - mutex_unlock(&domain->revmap_tree_mutex); - } + mutex_unlock(&domain->revmap_mutex); } static void irq_domain_set_mapping(struct irq_domain *domain, @@ -520,13 +519,12 @@ static void irq_domain_set_mapping(struct irq_domain *domain, if (irq_domain_is_nomap(domain)) return; - if (hwirq < domain->revmap_size) { - domain->revmap[hwirq] = irq_data; - } else { - mutex_lock(&domain->revmap_tree_mutex); + mutex_lock(&domain->revmap_mutex); + if (hwirq < domain->revmap_size) + rcu_assign_pointer(domain->revmap[hwirq], irq_data); + else radix_tree_insert(&domain->revmap_tree, hwirq, irq_data); - mutex_unlock(&domain->revmap_tree_mutex); - } + mutex_unlock(&domain->revmap_mutex); } static void irq_domain_disassociate(struct irq_domain *domain, unsigned int irq) @@ -911,12 +909,12 @@ unsigned int irq_find_mapping(struct irq_domain *domain, return 0; } + rcu_read_lock(); /* Check if the hwirq is in the linear revmap. */ if (hwirq < domain->revmap_size) - return domain->revmap[hwirq]->irq; - - rcu_read_lock(); - data = radix_tree_lookup(&domain->revmap_tree, hwirq); + data = rcu_dereference(domain->revmap[hwirq]); + else + data = radix_tree_lookup(&domain->revmap_tree, hwirq); rcu_read_unlock(); return data ? data->irq : 0; } @@ -1499,18 +1497,17 @@ static void irq_domain_fix_revmap(struct irq_data *d) if (irq_domain_is_nomap(d->domain)) return; + /* Fix up the revmap. */ + mutex_lock(&d->domain->revmap_mutex); if (d->hwirq < d->domain->revmap_size) { /* Not using radix tree */ - d->domain->revmap[d->hwirq] = d; - return; + rcu_assign_pointer(d->domain->revmap[d->hwirq], d); + } else { + slot = radix_tree_lookup_slot(&d->domain->revmap_tree, d->hwirq); + if (slot) + radix_tree_replace_slot(&d->domain->revmap_tree, slot, d); } - - /* Fix up the revmap. */ - mutex_lock(&d->domain->revmap_tree_mutex); - slot = radix_tree_lookup_slot(&d->domain->revmap_tree, d->hwirq); - if (slot) - radix_tree_replace_slot(&d->domain->revmap_tree, slot, d); - mutex_unlock(&d->domain->revmap_tree_mutex); + mutex_unlock(&d->domain->revmap_mutex); } /** -- cgit v1.2.3-58-ga151 From d22558dd0a6c888b1829f9d3a0a627e330e27585 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 4 May 2021 14:00:13 +0100 Subject: irqdomain: Introduce irq_resolve_mapping() Rework irq_find_mapping() to return an both an irq_desc pointer, optionally the virtual irq number, and rename the result to __irq_resolve_mapping(). a new helper called irq_resolve_mapping() is provided for code that doesn't need the virtual irq number. irq_find_mapping() is also rewritten in terms of __irq_resolve_mapping(). Signed-off-by: Marc Zyngier --- include/linux/irqdomain.h | 23 +++++++++++++++++++++-- kernel/irq/irqdomain.c | 28 ++++++++++++++++++++-------- 2 files changed, 41 insertions(+), 10 deletions(-) (limited to 'kernel') diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 2b696c9bcaaf..23e4ee523576 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -41,6 +41,7 @@ struct fwnode_handle; struct irq_domain; struct irq_chip; struct irq_data; +struct irq_desc; struct cpumask; struct seq_file; struct irq_affinity_desc; @@ -401,13 +402,31 @@ static inline unsigned int irq_create_mapping(struct irq_domain *host, return irq_create_mapping_affinity(host, hwirq, NULL); } +extern struct irq_desc *__irq_resolve_mapping(struct irq_domain *domain, + irq_hw_number_t hwirq, + unsigned int *irq); + +static inline struct irq_desc *irq_resolve_mapping(struct irq_domain *domain, + irq_hw_number_t hwirq) +{ + return __irq_resolve_mapping(domain, hwirq, NULL); +} + /** * irq_find_mapping() - Find a linux irq from a hw irq number. * @domain: domain owning this hardware interrupt * @hwirq: hardware irq number in that domain space */ -extern unsigned int irq_find_mapping(struct irq_domain *host, - irq_hw_number_t hwirq); +static inline unsigned int irq_find_mapping(struct irq_domain *domain, + irq_hw_number_t hwirq) +{ + unsigned int irq; + + if (__irq_resolve_mapping(domain, hwirq, &irq)) + return irq; + + return 0; +} static inline unsigned int irq_linear_revmap(struct irq_domain *domain, irq_hw_number_t hwirq) diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 8fbadeefc814..51c483ce2447 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -884,29 +884,34 @@ void irq_dispose_mapping(unsigned int virq) EXPORT_SYMBOL_GPL(irq_dispose_mapping); /** - * irq_find_mapping() - Find a linux irq from a hw irq number. + * __irq_resolve_mapping() - Find a linux irq from a hw irq number. * @domain: domain owning this hardware interrupt * @hwirq: hardware irq number in that domain space + * @irq: optional pointer to return the Linux irq if required + * + * Returns the interrupt descriptor. */ -unsigned int irq_find_mapping(struct irq_domain *domain, - irq_hw_number_t hwirq) +struct irq_desc *__irq_resolve_mapping(struct irq_domain *domain, + irq_hw_number_t hwirq, + unsigned int *irq) { + struct irq_desc *desc = NULL; struct irq_data *data; /* Look for default domain if necessary */ if (domain == NULL) domain = irq_default_domain; if (domain == NULL) - return 0; + return desc; if (irq_domain_is_nomap(domain)) { if (hwirq < domain->revmap_size) { data = irq_domain_get_irq_data(domain, hwirq); if (data && data->hwirq == hwirq) - return hwirq; + desc = irq_data_to_desc(data); } - return 0; + return desc; } rcu_read_lock(); @@ -915,10 +920,17 @@ unsigned int irq_find_mapping(struct irq_domain *domain, data = rcu_dereference(domain->revmap[hwirq]); else data = radix_tree_lookup(&domain->revmap_tree, hwirq); + + if (likely(data)) { + desc = irq_data_to_desc(data); + if (irq) + *irq = data->irq; + } + rcu_read_unlock(); - return data ? data->irq : 0; + return desc; } -EXPORT_SYMBOL_GPL(irq_find_mapping); +EXPORT_SYMBOL_GPL(__irq_resolve_mapping); /** * irq_domain_xlate_onecell() - Generic xlate for direct one cell bindings -- cgit v1.2.3-58-ga151 From a3016b26ee6ee13d5647d701404a7912d4eaea9e Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 4 May 2021 14:24:37 +0100 Subject: genirq: Use irq_resolve_mapping() to implement __handle_domain_irq() and co In order to start reaping the benefits of irq_resolve_mapping(), start using it in __handle_domain_irq() and handle_domain_nmi(). This involves splitting generic_handle_irq() to be able to directly provide the irq_desc. Signed-off-by: Marc Zyngier --- include/linux/irqdesc.h | 1 + kernel/irq/irqdesc.c | 60 ++++++++++++++++++++++++++++--------------------- 2 files changed, 36 insertions(+), 25 deletions(-) (limited to 'kernel') diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index df4651250785..cdd1cf8207f6 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -158,6 +158,7 @@ static inline void generic_handle_irq_desc(struct irq_desc *desc) desc->handle_irq(desc); } +int handle_irq_desc(struct irq_desc *desc); int generic_handle_irq(unsigned int irq); #ifdef CONFIG_HANDLE_DOMAIN_IRQ diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index 4a617d7312a4..684c5b7b7832 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -632,14 +632,8 @@ void irq_init_desc(unsigned int irq) #endif /* !CONFIG_SPARSE_IRQ */ -/** - * generic_handle_irq - Invoke the handler for a particular irq - * @irq: The irq number to handle - * - */ -int generic_handle_irq(unsigned int irq) +int handle_irq_desc(struct irq_desc *desc) { - struct irq_desc *desc = irq_to_desc(irq); struct irq_data *data; if (!desc) @@ -652,6 +646,17 @@ int generic_handle_irq(unsigned int irq) generic_handle_irq_desc(desc); return 0; } +EXPORT_SYMBOL_GPL(handle_irq_desc); + +/** + * generic_handle_irq - Invoke the handler for a particular irq + * @irq: The irq number to handle + * + */ +int generic_handle_irq(unsigned int irq) +{ + return handle_irq_desc(irq_to_desc(irq)); +} EXPORT_SYMBOL_GPL(generic_handle_irq); #ifdef CONFIG_HANDLE_DOMAIN_IRQ @@ -668,27 +673,32 @@ int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq, bool lookup, struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); - unsigned int irq = hwirq; + struct irq_desc *desc; int ret = 0; irq_enter(); -#ifdef CONFIG_IRQ_DOMAIN - if (lookup) - irq = irq_find_mapping(domain, hwirq); -#endif - - /* - * Some hardware gives randomly wrong interrupts. Rather - * than crashing, do something sensible. - */ - if (unlikely(!irq || irq >= nr_irqs)) { - ack_bad_irq(irq); - ret = -EINVAL; + if (likely(IS_ENABLED(CONFIG_IRQ_DOMAIN) && lookup)) { + /* The irqdomain code provides boundary checks */ + desc = irq_resolve_mapping(domain, hwirq); } else { - generic_handle_irq(irq); + /* + * Some hardware gives randomly wrong interrupts. Rather + * than crashing, do something sensible. + */ + if (unlikely(!hwirq || hwirq >= nr_irqs)) { + ack_bad_irq(hwirq); + desc = NULL; + } else { + desc = irq_to_desc(hwirq); + } } + if (likely(desc)) + handle_irq_desc(desc); + else + ret = -EINVAL; + irq_exit(); set_irq_regs(old_regs); return ret; @@ -709,7 +719,7 @@ int handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq, struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); - unsigned int irq; + struct irq_desc *desc; int ret = 0; /* @@ -717,14 +727,14 @@ int handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq, */ WARN_ON(!in_nmi()); - irq = irq_find_mapping(domain, hwirq); + desc = irq_resolve_mapping(domain, hwirq); /* * ack_bad_irq is not NMI-safe, just report * an invalid interrupt. */ - if (likely(irq)) - generic_handle_irq(irq); + if (likely(desc)) + handle_irq_desc(desc); else ret = -EINVAL; -- cgit v1.2.3-58-ga151 From 8240ef50d4864325b346e40bb9d30cda9f22102d Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 12 May 2021 13:45:52 +0100 Subject: genirq: Add generic_handle_domain_irq() helper Provide generic_handle_domain_irq() as a pendent to handle_domain_irq() for non-root interrupt controllers Signed-off-by: Marc Zyngier --- include/linux/irqdesc.h | 2 ++ kernel/irq/irqdesc.c | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'kernel') diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index 2971eb7e65f1..0f226c6b0c70 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -170,6 +170,8 @@ int generic_handle_irq(unsigned int irq); int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq, bool lookup, struct pt_regs *regs); +int generic_handle_domain_irq(struct irq_domain *domain, unsigned int hwirq); + static inline int handle_domain_irq(struct irq_domain *domain, unsigned int hwirq, struct pt_regs *regs) { diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index 684c5b7b7832..6179d5bde88e 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -661,7 +661,24 @@ EXPORT_SYMBOL_GPL(generic_handle_irq); #ifdef CONFIG_HANDLE_DOMAIN_IRQ /** - * __handle_domain_irq - Invoke the handler for a HW irq belonging to a domain + * generic_handle_domain_irq - Invoke the handler for a HW irq belonging + * to a domain, usually for a non-root interrupt + * controller + * @domain: The domain where to perform the lookup + * @hwirq: The HW irq number to convert to a logical one + * + * Returns: 0 on success, or -EINVAL if conversion has failed + * + */ +int generic_handle_domain_irq(struct irq_domain *domain, unsigned int hwirq) +{ + return handle_irq_desc(irq_resolve_mapping(domain, hwirq)); +} +EXPORT_SYMBOL_GPL(generic_handle_domain_irq); + +/** + * __handle_domain_irq - Invoke the handler for a HW irq belonging to a domain, + * usually for a root interrupt controller * @domain: The domain where to perform the lookup * @hwirq: The HW irq number to convert to a logical one * @lookup: Whether to perform the domain lookup or not -- cgit v1.2.3-58-ga151 From e1c054918c6c7a30a35d2c183ed86600a071cdab Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 12 May 2021 16:18:15 +0100 Subject: genirq: Move non-irqdomain handle_domain_irq() handling into ARM's handle_IRQ() Despite the name, handle_domain_irq() deals with non-irqdomain handling for the sake of a handful of legacy ARM platforms. Move such handling into ARM's handle_IRQ(), allowing for better code generation for everyone else. This allows us get rid of some complexity, and to rearrange the guards on the various helpers in a more logical way. Signed-off-by: Marc Zyngier --- arch/arm/kernel/irq.c | 22 +++++++++++++++++++++- include/linux/irqdesc.h | 14 ++++---------- kernel/irq/irqdesc.c | 30 ++++++++---------------------- 3 files changed, 33 insertions(+), 33 deletions(-) (limited to 'kernel') diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 698b6f636156..20ab1e607522 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -63,7 +63,27 @@ int arch_show_interrupts(struct seq_file *p, int prec) */ void handle_IRQ(unsigned int irq, struct pt_regs *regs) { - __handle_domain_irq(NULL, irq, false, regs); + struct pt_regs *old_regs = set_irq_regs(regs); + struct irq_desc *desc; + + irq_enter(); + + /* + * Some hardware gives randomly wrong interrupts. Rather + * than crashing, do something sensible. + */ + if (unlikely(!irq || irq >= nr_irqs)) + desc = NULL; + else + desc = irq_to_desc(irq); + + if (likely(desc)) + handle_irq_desc(desc); + else + ack_bad_irq(irq); + + irq_exit(); + set_irq_regs(old_regs); } /* diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index 0f226c6b0c70..59aea39785bf 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -161,24 +161,18 @@ static inline void generic_handle_irq_desc(struct irq_desc *desc) int handle_irq_desc(struct irq_desc *desc); int generic_handle_irq(unsigned int irq); -#ifdef CONFIG_HANDLE_DOMAIN_IRQ +#ifdef CONFIG_IRQ_DOMAIN /* * Convert a HW interrupt number to a logical one using a IRQ domain, * and handle the result interrupt number. Return -EINVAL if * conversion failed. */ -int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq, - bool lookup, struct pt_regs *regs); - int generic_handle_domain_irq(struct irq_domain *domain, unsigned int hwirq); -static inline int handle_domain_irq(struct irq_domain *domain, - unsigned int hwirq, struct pt_regs *regs) -{ - return __handle_domain_irq(domain, hwirq, true, regs); -} +#ifdef CONFIG_HANDLE_DOMAIN_IRQ +int handle_domain_irq(struct irq_domain *domain, + unsigned int hwirq, struct pt_regs *regs); -#ifdef CONFIG_IRQ_DOMAIN int handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq, struct pt_regs *regs); #endif diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index 6179d5bde88e..f4dd5186858a 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -659,7 +659,7 @@ int generic_handle_irq(unsigned int irq) } EXPORT_SYMBOL_GPL(generic_handle_irq); -#ifdef CONFIG_HANDLE_DOMAIN_IRQ +#ifdef CONFIG_IRQ_DOMAIN /** * generic_handle_domain_irq - Invoke the handler for a HW irq belonging * to a domain, usually for a non-root interrupt @@ -676,9 +676,10 @@ int generic_handle_domain_irq(struct irq_domain *domain, unsigned int hwirq) } EXPORT_SYMBOL_GPL(generic_handle_domain_irq); +#ifdef CONFIG_HANDLE_DOMAIN_IRQ /** - * __handle_domain_irq - Invoke the handler for a HW irq belonging to a domain, - * usually for a root interrupt controller + * handle_domain_irq - Invoke the handler for a HW irq belonging to a domain, + * usually for a root interrupt controller * @domain: The domain where to perform the lookup * @hwirq: The HW irq number to convert to a logical one * @lookup: Whether to perform the domain lookup or not @@ -686,8 +687,8 @@ EXPORT_SYMBOL_GPL(generic_handle_domain_irq); * * Returns: 0 on success, or -EINVAL if conversion has failed */ -int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq, - bool lookup, struct pt_regs *regs) +int handle_domain_irq(struct irq_domain *domain, + unsigned int hwirq, struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); struct irq_desc *desc; @@ -695,22 +696,8 @@ int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq, irq_enter(); - if (likely(IS_ENABLED(CONFIG_IRQ_DOMAIN) && lookup)) { - /* The irqdomain code provides boundary checks */ - desc = irq_resolve_mapping(domain, hwirq); - } else { - /* - * Some hardware gives randomly wrong interrupts. Rather - * than crashing, do something sensible. - */ - if (unlikely(!hwirq || hwirq >= nr_irqs)) { - ack_bad_irq(hwirq); - desc = NULL; - } else { - desc = irq_to_desc(hwirq); - } - } - + /* The irqdomain code provides boundary checks */ + desc = irq_resolve_mapping(domain, hwirq); if (likely(desc)) handle_irq_desc(desc); else @@ -721,7 +708,6 @@ int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq, return ret; } -#ifdef CONFIG_IRQ_DOMAIN /** * handle_domain_nmi - Invoke the handler for a HW irq belonging to a domain * @domain: The domain where to perform the lookup -- cgit v1.2.3-58-ga151