Skip to content

Commit 46c3e31

Browse files
committed
Merge tag 'irq-domain-24-08-09' into irq/core
Merge the irqdomain changes which are required for regmap to apply depending patches and therefore tagged.
2 parents 6002916 + 1e7c052 commit 46c3e31

File tree

2 files changed

+121
-85
lines changed

2 files changed

+121
-85
lines changed

include/linux/irqdomain.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,12 @@ struct irq_domain_chip_generic_info;
291291
* @hwirq_max: Maximum number of interrupts supported by controller
292292
* @direct_max: Maximum value of direct maps;
293293
* Use ~0 for no limit; 0 for no direct mapping
294+
* @hwirq_base: The first hardware interrupt number (legacy domains only)
295+
* @virq_base: The first Linux interrupt number for legacy domains to
296+
* immediately associate the interrupts after domain creation
294297
* @bus_token: Domain bus token
298+
* @name_suffix: Optional name suffix to avoid collisions when multiple
299+
* domains are added using same fwnode
295300
* @ops: Domain operation callbacks
296301
* @host_data: Controller private data pointer
297302
* @dgc_info: Geneneric chip information structure pointer used to
@@ -307,7 +312,10 @@ struct irq_domain_info {
307312
unsigned int size;
308313
irq_hw_number_t hwirq_max;
309314
int direct_max;
315+
unsigned int hwirq_base;
316+
unsigned int virq_base;
310317
enum irq_domain_bus_token bus_token;
318+
const char *name_suffix;
311319
const struct irq_domain_ops *ops;
312320
void *host_data;
313321
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY

kernel/irq/irqdomain.c

Lines changed: 113 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -128,72 +128,92 @@ void irq_domain_free_fwnode(struct fwnode_handle *fwnode)
128128
}
129129
EXPORT_SYMBOL_GPL(irq_domain_free_fwnode);
130130

131-
static int irq_domain_set_name(struct irq_domain *domain,
132-
const struct fwnode_handle *fwnode,
133-
enum irq_domain_bus_token bus_token)
131+
static int alloc_name(struct irq_domain *domain, char *base, enum irq_domain_bus_token bus_token)
132+
{
133+
domain->name = bus_token ? kasprintf(GFP_KERNEL, "%s-%d", base, bus_token) :
134+
kasprintf(GFP_KERNEL, "%s", base);
135+
if (!domain->name)
136+
return -ENOMEM;
137+
138+
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
139+
return 0;
140+
}
141+
142+
static int alloc_fwnode_name(struct irq_domain *domain, const struct fwnode_handle *fwnode,
143+
enum irq_domain_bus_token bus_token, const char *suffix)
144+
{
145+
const char *sep = suffix ? "-" : "";
146+
const char *suf = suffix ? : "";
147+
char *name;
148+
149+
name = bus_token ? kasprintf(GFP_KERNEL, "%pfw-%s%s%d", fwnode, suf, sep, bus_token) :
150+
kasprintf(GFP_KERNEL, "%pfw-%s", fwnode, suf);
151+
if (!name)
152+
return -ENOMEM;
153+
154+
/*
155+
* fwnode paths contain '/', which debugfs is legitimately unhappy
156+
* about. Replace them with ':', which does the trick and is not as
157+
* offensive as '\'...
158+
*/
159+
domain->name = strreplace(name, '/', ':');
160+
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
161+
return 0;
162+
}
163+
164+
static int alloc_unknown_name(struct irq_domain *domain, enum irq_domain_bus_token bus_token)
134165
{
135166
static atomic_t unknown_domains;
136-
struct irqchip_fwid *fwid;
167+
int id = atomic_inc_return(&unknown_domains);
168+
169+
domain->name = bus_token ? kasprintf(GFP_KERNEL, "unknown-%d-%d", id, bus_token) :
170+
kasprintf(GFP_KERNEL, "unknown-%d", id);
171+
172+
if (!domain->name)
173+
return -ENOMEM;
174+
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
175+
return 0;
176+
}
177+
178+
static int irq_domain_set_name(struct irq_domain *domain, const struct irq_domain_info *info)
179+
{
180+
enum irq_domain_bus_token bus_token = info->bus_token;
181+
const struct fwnode_handle *fwnode = info->fwnode;
137182

138183
if (is_fwnode_irqchip(fwnode)) {
139-
fwid = container_of(fwnode, struct irqchip_fwid, fwnode);
184+
struct irqchip_fwid *fwid = container_of(fwnode, struct irqchip_fwid, fwnode);
185+
186+
/*
187+
* The name_suffix is only intended to be used to avoid a name
188+
* collision when multiple domains are created for a single
189+
* device and the name is picked using a real device node.
190+
* (Typical use-case is regmap-IRQ controllers for devices
191+
* providing more than one physical IRQ.) There should be no
192+
* need to use name_suffix with irqchip-fwnode.
193+
*/
194+
if (info->name_suffix)
195+
return -EINVAL;
140196

141197
switch (fwid->type) {
142198
case IRQCHIP_FWNODE_NAMED:
143199
case IRQCHIP_FWNODE_NAMED_ID:
144-
domain->name = bus_token ?
145-
kasprintf(GFP_KERNEL, "%s-%d",
146-
fwid->name, bus_token) :
147-
kstrdup(fwid->name, GFP_KERNEL);
148-
if (!domain->name)
149-
return -ENOMEM;
150-
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
151-
break;
200+
return alloc_name(domain, fwid->name, bus_token);
152201
default:
153202
domain->name = fwid->name;
154-
if (bus_token) {
155-
domain->name = kasprintf(GFP_KERNEL, "%s-%d",
156-
fwid->name, bus_token);
157-
if (!domain->name)
158-
return -ENOMEM;
159-
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
160-
}
161-
break;
203+
if (bus_token)
204+
return alloc_name(domain, fwid->name, bus_token);
162205
}
163-
} else if (is_of_node(fwnode) || is_acpi_device_node(fwnode) ||
164-
is_software_node(fwnode)) {
165-
char *name;
166-
167-
/*
168-
* fwnode paths contain '/', which debugfs is legitimately
169-
* unhappy about. Replace them with ':', which does
170-
* the trick and is not as offensive as '\'...
171-
*/
172-
name = bus_token ?
173-
kasprintf(GFP_KERNEL, "%pfw-%d", fwnode, bus_token) :
174-
kasprintf(GFP_KERNEL, "%pfw", fwnode);
175-
if (!name)
176-
return -ENOMEM;
177206

178-
domain->name = strreplace(name, '/', ':');
179-
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
207+
} else if (is_of_node(fwnode) || is_acpi_device_node(fwnode) || is_software_node(fwnode)) {
208+
return alloc_fwnode_name(domain, fwnode, bus_token, info->name_suffix);
180209
}
181210

182-
if (!domain->name) {
183-
if (fwnode)
184-
pr_err("Invalid fwnode type for irqdomain\n");
185-
domain->name = bus_token ?
186-
kasprintf(GFP_KERNEL, "unknown-%d-%d",
187-
atomic_inc_return(&unknown_domains),
188-
bus_token) :
189-
kasprintf(GFP_KERNEL, "unknown-%d",
190-
atomic_inc_return(&unknown_domains));
191-
if (!domain->name)
192-
return -ENOMEM;
193-
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
194-
}
211+
if (domain->name)
212+
return 0;
195213

196-
return 0;
214+
if (fwnode)
215+
pr_err("Invalid fwnode type for irqdomain\n");
216+
return alloc_unknown_name(domain, bus_token);
197217
}
198218

199219
static struct irq_domain *__irq_domain_create(const struct irq_domain_info *info)
@@ -211,7 +231,7 @@ static struct irq_domain *__irq_domain_create(const struct irq_domain_info *info
211231
if (!domain)
212232
return ERR_PTR(-ENOMEM);
213233

214-
err = irq_domain_set_name(domain, info->fwnode, info->bus_token);
234+
err = irq_domain_set_name(domain, info);
215235
if (err) {
216236
kfree(domain);
217237
return ERR_PTR(err);
@@ -267,13 +287,20 @@ static void irq_domain_free(struct irq_domain *domain)
267287
kfree(domain);
268288
}
269289

270-
/**
271-
* irq_domain_instantiate() - Instantiate a new irq domain data structure
272-
* @info: Domain information pointer pointing to the information for this domain
273-
*
274-
* Return: A pointer to the instantiated irq domain or an ERR_PTR value.
275-
*/
276-
struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info)
290+
static void irq_domain_instantiate_descs(const struct irq_domain_info *info)
291+
{
292+
if (!IS_ENABLED(CONFIG_SPARSE_IRQ))
293+
return;
294+
295+
if (irq_alloc_descs(info->virq_base, info->virq_base, info->size,
296+
of_node_to_nid(to_of_node(info->fwnode))) < 0) {
297+
pr_info("Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
298+
info->virq_base);
299+
}
300+
}
301+
302+
static struct irq_domain *__irq_domain_instantiate(const struct irq_domain_info *info,
303+
bool cond_alloc_descs)
277304
{
278305
struct irq_domain *domain;
279306
int err;
@@ -306,6 +333,15 @@ struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info)
306333

307334
__irq_domain_publish(domain);
308335

336+
if (cond_alloc_descs && info->virq_base > 0)
337+
irq_domain_instantiate_descs(info);
338+
339+
/* Legacy interrupt domains have a fixed Linux interrupt number */
340+
if (info->virq_base > 0) {
341+
irq_domain_associate_many(domain, info->virq_base, info->hwirq_base,
342+
info->size - info->hwirq_base);
343+
}
344+
309345
return domain;
310346

311347
err_domain_gc_remove:
@@ -315,6 +351,17 @@ struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info)
315351
irq_domain_free(domain);
316352
return ERR_PTR(err);
317353
}
354+
355+
/**
356+
* irq_domain_instantiate() - Instantiate a new irq domain data structure
357+
* @info: Domain information pointer pointing to the information for this domain
358+
*
359+
* Return: A pointer to the instantiated irq domain or an ERR_PTR value.
360+
*/
361+
struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info)
362+
{
363+
return __irq_domain_instantiate(info, false);
364+
}
318365
EXPORT_SYMBOL_GPL(irq_domain_instantiate);
319366

320367
/**
@@ -413,28 +460,13 @@ struct irq_domain *irq_domain_create_simple(struct fwnode_handle *fwnode,
413460
.fwnode = fwnode,
414461
.size = size,
415462
.hwirq_max = size,
463+
.virq_base = first_irq,
416464
.ops = ops,
417465
.host_data = host_data,
418466
};
419-
struct irq_domain *domain;
420-
421-
domain = irq_domain_instantiate(&info);
422-
if (IS_ERR(domain))
423-
return NULL;
467+
struct irq_domain *domain = __irq_domain_instantiate(&info, true);
424468

425-
if (first_irq > 0) {
426-
if (IS_ENABLED(CONFIG_SPARSE_IRQ)) {
427-
/* attempt to allocated irq_descs */
428-
int rc = irq_alloc_descs(first_irq, first_irq, size,
429-
of_node_to_nid(to_of_node(fwnode)));
430-
if (rc < 0)
431-
pr_info("Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
432-
first_irq);
433-
}
434-
irq_domain_associate_many(domain, first_irq, 0, size);
435-
}
436-
437-
return domain;
469+
return IS_ERR(domain) ? NULL : domain;
438470
}
439471
EXPORT_SYMBOL_GPL(irq_domain_create_simple);
440472

@@ -476,18 +508,14 @@ struct irq_domain *irq_domain_create_legacy(struct fwnode_handle *fwnode,
476508
.fwnode = fwnode,
477509
.size = first_hwirq + size,
478510
.hwirq_max = first_hwirq + size,
511+
.hwirq_base = first_hwirq,
512+
.virq_base = first_irq,
479513
.ops = ops,
480514
.host_data = host_data,
481515
};
482-
struct irq_domain *domain;
516+
struct irq_domain *domain = irq_domain_instantiate(&info);
483517

484-
domain = irq_domain_instantiate(&info);
485-
if (IS_ERR(domain))
486-
return NULL;
487-
488-
irq_domain_associate_many(domain, first_irq, first_hwirq, size);
489-
490-
return domain;
518+
return IS_ERR(domain) ? NULL : domain;
491519
}
492520
EXPORT_SYMBOL_GPL(irq_domain_create_legacy);
493521

0 commit comments

Comments
 (0)