@@ -128,72 +128,92 @@ void irq_domain_free_fwnode(struct fwnode_handle *fwnode)
128
128
}
129
129
EXPORT_SYMBOL_GPL (irq_domain_free_fwnode );
130
130
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 )
134
165
{
135
166
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 ;
137
182
138
183
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 ;
140
196
141
197
switch (fwid -> type ) {
142
198
case IRQCHIP_FWNODE_NAMED :
143
199
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 );
152
201
default :
153
202
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 );
162
205
}
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 ;
177
206
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 ) ;
180
209
}
181
210
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 ;
195
213
196
- return 0 ;
214
+ if (fwnode )
215
+ pr_err ("Invalid fwnode type for irqdomain\n" );
216
+ return alloc_unknown_name (domain , bus_token );
197
217
}
198
218
199
219
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
211
231
if (!domain )
212
232
return ERR_PTR (- ENOMEM );
213
233
214
- err = irq_domain_set_name (domain , info -> fwnode , info -> bus_token );
234
+ err = irq_domain_set_name (domain , info );
215
235
if (err ) {
216
236
kfree (domain );
217
237
return ERR_PTR (err );
@@ -267,13 +287,20 @@ static void irq_domain_free(struct irq_domain *domain)
267
287
kfree (domain );
268
288
}
269
289
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 )
277
304
{
278
305
struct irq_domain * domain ;
279
306
int err ;
@@ -306,6 +333,15 @@ struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info)
306
333
307
334
__irq_domain_publish (domain );
308
335
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
+
309
345
return domain ;
310
346
311
347
err_domain_gc_remove :
@@ -315,6 +351,17 @@ struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info)
315
351
irq_domain_free (domain );
316
352
return ERR_PTR (err );
317
353
}
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
+ }
318
365
EXPORT_SYMBOL_GPL (irq_domain_instantiate );
319
366
320
367
/**
@@ -413,28 +460,13 @@ struct irq_domain *irq_domain_create_simple(struct fwnode_handle *fwnode,
413
460
.fwnode = fwnode ,
414
461
.size = size ,
415
462
.hwirq_max = size ,
463
+ .virq_base = first_irq ,
416
464
.ops = ops ,
417
465
.host_data = host_data ,
418
466
};
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);
424
468
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 ;
438
470
}
439
471
EXPORT_SYMBOL_GPL (irq_domain_create_simple );
440
472
@@ -476,18 +508,14 @@ struct irq_domain *irq_domain_create_legacy(struct fwnode_handle *fwnode,
476
508
.fwnode = fwnode ,
477
509
.size = first_hwirq + size ,
478
510
.hwirq_max = first_hwirq + size ,
511
+ .hwirq_base = first_hwirq ,
512
+ .virq_base = first_irq ,
479
513
.ops = ops ,
480
514
.host_data = host_data ,
481
515
};
482
- struct irq_domain * domain ;
516
+ struct irq_domain * domain = irq_domain_instantiate ( & info ) ;
483
517
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 ;
491
519
}
492
520
EXPORT_SYMBOL_GPL (irq_domain_create_legacy );
493
521
0 commit comments