Skip to content

Commit 8932c32

Browse files
author
Marc Zyngier
committed
irqdomain: Fix domain registration race
Hierarchical domains created using irq_domain_create_hierarchy() are currently added to the domain list before having been fully initialised. This specifically means that a racing allocation request might fail to allocate irq data for the inner domains of a hierarchy in case the parent domain pointer has not yet been set up. Note that this is not really any issue for irqchip drivers that are registered early (e.g. via IRQCHIP_DECLARE() or IRQCHIP_ACPI_DECLARE()) but could potentially cause trouble with drivers that are registered later (e.g. modular drivers using IRQCHIP_PLATFORM_DRIVER_BEGIN(), gpiochip drivers, etc.). Fixes: afb7da8 ("irqdomain: Introduce helper function irq_domain_add_hierarchy()") Cc: [email protected] # 3.19 Signed-off-by: Marc Zyngier <[email protected]> [ johan: add commit message ] Signed-off-by: Johan Hovold <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 601363c commit 8932c32

File tree

1 file changed

+43
-19
lines changed

1 file changed

+43
-19
lines changed

kernel/irq/irqdomain.c

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -126,23 +126,12 @@ void irq_domain_free_fwnode(struct fwnode_handle *fwnode)
126126
}
127127
EXPORT_SYMBOL_GPL(irq_domain_free_fwnode);
128128

129-
/**
130-
* __irq_domain_add() - Allocate a new irq_domain data structure
131-
* @fwnode: firmware node for the interrupt controller
132-
* @size: Size of linear map; 0 for radix mapping only
133-
* @hwirq_max: Maximum number of interrupts supported by controller
134-
* @direct_max: Maximum value of direct maps; Use ~0 for no limit; 0 for no
135-
* direct mapping
136-
* @ops: domain callbacks
137-
* @host_data: Controller private data pointer
138-
*
139-
* Allocates and initializes an irq_domain structure.
140-
* Returns pointer to IRQ domain, or NULL on failure.
141-
*/
142-
struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, unsigned int size,
143-
irq_hw_number_t hwirq_max, int direct_max,
144-
const struct irq_domain_ops *ops,
145-
void *host_data)
129+
static struct irq_domain *__irq_domain_create(struct fwnode_handle *fwnode,
130+
unsigned int size,
131+
irq_hw_number_t hwirq_max,
132+
int direct_max,
133+
const struct irq_domain_ops *ops,
134+
void *host_data)
146135
{
147136
struct irqchip_fwid *fwid;
148137
struct irq_domain *domain;
@@ -230,12 +219,44 @@ struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, unsigned int s
230219

231220
irq_domain_check_hierarchy(domain);
232221

222+
return domain;
223+
}
224+
225+
static void __irq_domain_publish(struct irq_domain *domain)
226+
{
233227
mutex_lock(&irq_domain_mutex);
234228
debugfs_add_domain_dir(domain);
235229
list_add(&domain->link, &irq_domain_list);
236230
mutex_unlock(&irq_domain_mutex);
237231

238232
pr_debug("Added domain %s\n", domain->name);
233+
}
234+
235+
/**
236+
* __irq_domain_add() - Allocate a new irq_domain data structure
237+
* @fwnode: firmware node for the interrupt controller
238+
* @size: Size of linear map; 0 for radix mapping only
239+
* @hwirq_max: Maximum number of interrupts supported by controller
240+
* @direct_max: Maximum value of direct maps; Use ~0 for no limit; 0 for no
241+
* direct mapping
242+
* @ops: domain callbacks
243+
* @host_data: Controller private data pointer
244+
*
245+
* Allocates and initializes an irq_domain structure.
246+
* Returns pointer to IRQ domain, or NULL on failure.
247+
*/
248+
struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, unsigned int size,
249+
irq_hw_number_t hwirq_max, int direct_max,
250+
const struct irq_domain_ops *ops,
251+
void *host_data)
252+
{
253+
struct irq_domain *domain;
254+
255+
domain = __irq_domain_create(fwnode, size, hwirq_max, direct_max,
256+
ops, host_data);
257+
if (domain)
258+
__irq_domain_publish(domain);
259+
239260
return domain;
240261
}
241262
EXPORT_SYMBOL_GPL(__irq_domain_add);
@@ -1138,12 +1159,15 @@ struct irq_domain *irq_domain_create_hierarchy(struct irq_domain *parent,
11381159
struct irq_domain *domain;
11391160

11401161
if (size)
1141-
domain = irq_domain_create_linear(fwnode, size, ops, host_data);
1162+
domain = __irq_domain_create(fwnode, size, size, 0, ops, host_data);
11421163
else
1143-
domain = irq_domain_create_tree(fwnode, ops, host_data);
1164+
domain = __irq_domain_create(fwnode, 0, ~0, 0, ops, host_data);
1165+
11441166
if (domain) {
11451167
domain->parent = parent;
11461168
domain->flags |= flags;
1169+
1170+
__irq_domain_publish(domain);
11471171
}
11481172

11491173
return domain;

0 commit comments

Comments
 (0)