Skip to content

Commit fea922e

Browse files
hcodinaKAGA-KOKO
authored andcommitted
genirq/generic_chip: Introduce init() and exit() hooks
Most of generic chip drivers need to perform some more additional initializations on the generic chips allocated before they can be fully ready. These additional initializations need to be performed before the IRQ domain is published to avoid a race condition between IRQ consumers and suppliers. Introduce the init() hook to perform these initializations at the right place just after the generic chip creation. Also introduce the exit() hook to allow reverting operations done by the init() hook just before the generic chip is destroyed. Suggested-by: Thomas Gleixner <[email protected]> Signed-off-by: Herve Codina <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent e25f553 commit fea922e

File tree

2 files changed

+30
-2
lines changed

2 files changed

+30
-2
lines changed

include/linux/irq.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,7 @@ enum irq_gc_flags {
11061106
* @irq_flags_to_set: IRQ* flags to set on irq setup
11071107
* @irq_flags_to_clear: IRQ* flags to clear on irq setup
11081108
* @gc_flags: Generic chip specific setup flags
1109+
* @exit: Function called on each chip when they are destroyed.
11091110
* @gc: Array of pointers to generic interrupt chips
11101111
*/
11111112
struct irq_domain_chip_generic {
@@ -1114,6 +1115,7 @@ struct irq_domain_chip_generic {
11141115
unsigned int irq_flags_to_clear;
11151116
unsigned int irq_flags_to_set;
11161117
enum irq_gc_flags gc_flags;
1118+
void (*exit)(struct irq_chip_generic *gc);
11171119
struct irq_chip_generic *gc[];
11181120
};
11191121

@@ -1127,6 +1129,10 @@ struct irq_domain_chip_generic {
11271129
* @irq_flags_to_clear: IRQ_* bits to clear in the mapping function
11281130
* @irq_flags_to_set: IRQ_* bits to set in the mapping function
11291131
* @gc_flags: Generic chip specific setup flags
1132+
* @init: Function called on each chip when they are created.
1133+
* Allow to do some additional chip initialisation.
1134+
* @exit: Function called on each chip when they are destroyed.
1135+
* Allow to do some chip cleanup operation.
11301136
*/
11311137
struct irq_domain_chip_generic_info {
11321138
const char *name;
@@ -1136,6 +1142,8 @@ struct irq_domain_chip_generic_info {
11361142
unsigned int irq_flags_to_clear;
11371143
unsigned int irq_flags_to_set;
11381144
enum irq_gc_flags gc_flags;
1145+
int (*init)(struct irq_chip_generic *gc);
1146+
void (*exit)(struct irq_chip_generic *gc);
11391147
};
11401148

11411149
/* Generic chip callback functions */

kernel/irq/generic-chip.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ int irq_domain_alloc_generic_chips(struct irq_domain *d,
293293
size_t gc_sz;
294294
size_t sz;
295295
void *tmp;
296+
int ret;
296297

297298
if (d->gc)
298299
return -EBUSY;
@@ -314,6 +315,7 @@ int irq_domain_alloc_generic_chips(struct irq_domain *d,
314315
dgc->irq_flags_to_set = info->irq_flags_to_set;
315316
dgc->irq_flags_to_clear = info->irq_flags_to_clear;
316317
dgc->gc_flags = info->gc_flags;
318+
dgc->exit = info->exit;
317319
d->gc = dgc;
318320

319321
/* Calc pointer to the first generic chip */
@@ -331,13 +333,29 @@ int irq_domain_alloc_generic_chips(struct irq_domain *d,
331333
gc->reg_writel = &irq_writel_be;
332334
}
333335

336+
if (info->init) {
337+
ret = info->init(gc);
338+
if (ret)
339+
goto err;
340+
}
341+
334342
raw_spin_lock_irqsave(&gc_lock, flags);
335343
list_add_tail(&gc->list, &gc_list);
336344
raw_spin_unlock_irqrestore(&gc_lock, flags);
337345
/* Calc pointer to the next generic chip */
338346
tmp += gc_sz;
339347
}
340348
return 0;
349+
350+
err:
351+
while (i--) {
352+
if (dgc->exit)
353+
dgc->exit(dgc->gc[i]);
354+
irq_remove_generic_chip(dgc->gc[i], ~0U, 0, 0);
355+
}
356+
d->gc = NULL;
357+
kfree(dgc);
358+
return ret;
341359
}
342360
EXPORT_SYMBOL_GPL(irq_domain_alloc_generic_chips);
343361

@@ -353,9 +371,11 @@ void irq_domain_remove_generic_chips(struct irq_domain *d)
353371
if (!dgc)
354372
return;
355373

356-
for (i = 0; i < dgc->num_chips; i++)
374+
for (i = 0; i < dgc->num_chips; i++) {
375+
if (dgc->exit)
376+
dgc->exit(dgc->gc[i]);
357377
irq_remove_generic_chip(dgc->gc[i], ~0U, 0, 0);
358-
378+
}
359379
d->gc = NULL;
360380
kfree(dgc);
361381
}

0 commit comments

Comments
 (0)