Skip to content

Commit 1e2a7d7

Browse files
jonhunterMarc Zyngier
authored andcommitted
irqdomain: Don't set type when mapping an IRQ
Some IRQ chips, such as GPIO controllers or secondary level interrupt controllers, may require require additional runtime power management control to ensure they are accessible. For such IRQ chips, it makes sense to enable the IRQ chip when interrupts are requested and disabled them again once all interrupts have been freed. When mapping an IRQ, the IRQ type settings are read and then programmed. The mapping of the IRQ happens before the IRQ is requested and so the programming of the type settings occurs before the IRQ is requested. This is a problem for IRQ chips that require additional power management control because they may not be accessible yet. Therefore, when mapping the IRQ, don't program the type settings, just save them and then program these saved settings when the IRQ is requested (so long as if they are not overridden via the call to request the IRQ). Add a stub function for irq_domain_free_irqs() to avoid any compilation errors when CONFIG_IRQ_DOMAIN_HIERARCHY is not selected. Signed-off-by: Jon Hunter <jonathanh@nvidia.com> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
1 parent f35ad08 commit 1e2a7d7

File tree

2 files changed

+21
-5
lines changed

2 files changed

+21
-5
lines changed

include/linux/irqdomain.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,9 @@ static inline int irq_domain_alloc_irqs(struct irq_domain *domain,
452452
return -1;
453453
}
454454

455+
static inline void irq_domain_free_irqs(unsigned int virq,
456+
unsigned int nr_irqs) { }
457+
455458
static inline bool irq_domain_is_hierarchy(struct irq_domain *domain)
456459
{
457460
return false;

kernel/irq/irqdomain.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,7 @@ static void of_phandle_args_to_fwspec(struct of_phandle_args *irq_data,
567567
unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
568568
{
569569
struct irq_domain *domain;
570+
struct irq_data *irq_data;
570571
irq_hw_number_t hwirq;
571572
unsigned int type = IRQ_TYPE_NONE;
572573
int virq;
@@ -614,7 +615,11 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
614615
* it now and return the interrupt number.
615616
*/
616617
if (irq_get_trigger_type(virq) == IRQ_TYPE_NONE) {
617-
irq_set_irq_type(virq, type);
618+
irq_data = irq_get_irq_data(virq);
619+
if (!irq_data)
620+
return 0;
621+
622+
irqd_set_trigger_type(irq_data, type);
618623
return virq;
619624
}
620625

@@ -634,10 +639,18 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
634639
return virq;
635640
}
636641

637-
/* Set type if specified and different than the current one */
638-
if (type != IRQ_TYPE_NONE &&
639-
type != irq_get_trigger_type(virq))
640-
irq_set_irq_type(virq, type);
642+
irq_data = irq_get_irq_data(virq);
643+
if (!irq_data) {
644+
if (irq_domain_is_hierarchy(domain))
645+
irq_domain_free_irqs(virq, 1);
646+
else
647+
irq_dispose_mapping(virq);
648+
return 0;
649+
}
650+
651+
/* Store trigger type */
652+
irqd_set_trigger_type(irq_data, type);
653+
641654
return virq;
642655
}
643656
EXPORT_SYMBOL_GPL(irq_create_fwspec_mapping);

0 commit comments

Comments
 (0)