Skip to content

Commit 4f86a06

Browse files
author
Marc Zyngier
committed
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 <maz@kernel.org>
1 parent e37af80 commit 4f86a06

2 files changed

Lines changed: 38 additions & 13 deletions

File tree

include/linux/irqdomain.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,6 @@ struct irq_domain_chip_generic;
149149
* @parent: Pointer to parent irq_domain to support hierarchy irq_domains
150150
*
151151
* Revmap data, used internally by irq_domain
152-
* @revmap_direct_max_irq: The largest hwirq that can be set for controllers that
153-
* support direct mapping
154152
* @revmap_size: Size of the linear map table @revmap[]
155153
* @revmap_tree: Radix map tree for hwirqs that don't fit in the linear map
156154
* @revmap: Linear table of hwirq->virq reverse mappings
@@ -173,7 +171,6 @@ struct irq_domain {
173171

174172
/* reverse map data. The linear map gets appended to the irq_domain */
175173
irq_hw_number_t hwirq_max;
176-
unsigned int revmap_direct_max_irq;
177174
unsigned int revmap_size;
178175
struct radix_tree_root revmap_tree;
179176
struct mutex revmap_tree_mutex;
@@ -207,6 +204,9 @@ enum {
207204
*/
208205
IRQ_DOMAIN_MSI_NOMASK_QUIRK = (1 << 6),
209206

207+
/* Irq domain doesn't translate anything */
208+
IRQ_DOMAIN_FLAG_NO_MAP = (1 << 7),
209+
210210
/*
211211
* Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved
212212
* for implementation specific purposes and ignored by the

kernel/irq/irqdomain.c

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@ struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size,
146146

147147
static atomic_t unknown_domains;
148148

149+
if (WARN_ON((size && direct_max) ||
150+
(!IS_ENABLED(CONFIG_IRQ_DOMAIN_NOMAP) && direct_max)))
151+
return NULL;
152+
149153
domain = kzalloc_node(sizeof(*domain) + (sizeof(unsigned int) * size),
150154
GFP_KERNEL, of_node_to_nid(to_of_node(fwnode)));
151155
if (!domain)
@@ -213,8 +217,14 @@ struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size,
213217
domain->ops = ops;
214218
domain->host_data = host_data;
215219
domain->hwirq_max = hwirq_max;
220+
221+
if (direct_max) {
222+
size = direct_max;
223+
domain->flags |= IRQ_DOMAIN_FLAG_NO_MAP;
224+
}
225+
216226
domain->revmap_size = size;
217-
domain->revmap_direct_max_irq = direct_max;
227+
218228
irq_domain_check_hierarchy(domain);
219229

220230
mutex_lock(&irq_domain_mutex);
@@ -482,9 +492,18 @@ struct irq_domain *irq_get_default_host(void)
482492
return irq_default_domain;
483493
}
484494

495+
static bool irq_domain_is_nomap(struct irq_domain *domain)
496+
{
497+
return IS_ENABLED(CONFIG_IRQ_DOMAIN_NOMAP) &&
498+
(domain->flags & IRQ_DOMAIN_FLAG_NO_MAP);
499+
}
500+
485501
static void irq_domain_clear_mapping(struct irq_domain *domain,
486502
irq_hw_number_t hwirq)
487503
{
504+
if (irq_domain_is_nomap(domain))
505+
return;
506+
488507
if (hwirq < domain->revmap_size) {
489508
domain->revmap[hwirq] = 0;
490509
} else {
@@ -498,6 +517,9 @@ static void irq_domain_set_mapping(struct irq_domain *domain,
498517
irq_hw_number_t hwirq,
499518
struct irq_data *irq_data)
500519
{
520+
if (irq_domain_is_nomap(domain))
521+
return;
522+
501523
if (hwirq < domain->revmap_size) {
502524
domain->revmap[hwirq] = irq_data->irq;
503525
} else {
@@ -629,9 +651,9 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
629651
pr_debug("create_direct virq allocation failed\n");
630652
return 0;
631653
}
632-
if (virq >= domain->revmap_direct_max_irq) {
654+
if (virq >= domain->revmap_size) {
633655
pr_err("ERROR: no free irqs available below %i maximum\n",
634-
domain->revmap_direct_max_irq);
656+
domain->revmap_size);
635657
irq_free_desc(virq);
636658
return 0;
637659
}
@@ -879,10 +901,14 @@ unsigned int irq_find_mapping(struct irq_domain *domain,
879901
if (domain == NULL)
880902
return 0;
881903

882-
if (hwirq < domain->revmap_direct_max_irq) {
883-
data = irq_domain_get_irq_data(domain, hwirq);
884-
if (data && data->hwirq == hwirq)
885-
return hwirq;
904+
if (irq_domain_is_nomap(domain)) {
905+
if (hwirq < domain->revmap_size) {
906+
data = irq_domain_get_irq_data(domain, hwirq);
907+
if (data && data->hwirq == hwirq)
908+
return hwirq;
909+
}
910+
911+
return 0;
886912
}
887913

888914
/* Check if the hwirq is in the linear revmap. */
@@ -1470,7 +1496,7 @@ static void irq_domain_fix_revmap(struct irq_data *d)
14701496
{
14711497
void __rcu **slot;
14721498

1473-
if (d->hwirq < d->domain->revmap_size)
1499+
if (irq_domain_is_nomap(d->domain) || d->hwirq < d->domain->revmap_size)
14741500
return; /* Not using radix tree. */
14751501

14761502
/* Fix up the revmap. */
@@ -1830,8 +1856,7 @@ static void
18301856
irq_domain_debug_show_one(struct seq_file *m, struct irq_domain *d, int ind)
18311857
{
18321858
seq_printf(m, "%*sname: %s\n", ind, "", d->name);
1833-
seq_printf(m, "%*ssize: %u\n", ind + 1, "",
1834-
d->revmap_size + d->revmap_direct_max_irq);
1859+
seq_printf(m, "%*ssize: %u\n", ind + 1, "", d->revmap_size);
18351860
seq_printf(m, "%*smapped: %u\n", ind + 1, "", d->mapcount);
18361861
seq_printf(m, "%*sflags: 0x%08x\n", ind +1 , "", d->flags);
18371862
if (d->ops && d->ops->debug_show)

0 commit comments

Comments
 (0)