summaryrefslogtreecommitdiffstats
path: root/kernel/irq/irqdomain.c
diff options
context:
space:
mode:
authorJon Hunter <jonathanh@nvidia.com>2016-06-07 11:12:28 -0400
committerMarc Zyngier <marc.zyngier@arm.com>2016-06-13 06:53:51 -0400
commit1e2a7d78499ec8859d2b469051b7b80bad3b08aa (patch)
treeb2b3b3b0c3e45173838c83d1b3181097a4c7bc23 /kernel/irq/irqdomain.c
parentf35ad083783e8ed6ac030f5feb209f864875b413 (diff)
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>
Diffstat (limited to 'kernel/irq/irqdomain.c')
-rw-r--r--kernel/irq/irqdomain.c23
1 files changed, 18 insertions, 5 deletions
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index f3ff1eb8dd09..caa6a63d26f0 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -567,6 +567,7 @@ static void of_phandle_args_to_fwspec(struct of_phandle_args *irq_data,
567unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec) 567unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
568{ 568{
569 struct irq_domain *domain; 569 struct irq_domain *domain;
570 struct irq_data *irq_data;
570 irq_hw_number_t hwirq; 571 irq_hw_number_t hwirq;
571 unsigned int type = IRQ_TYPE_NONE; 572 unsigned int type = IRQ_TYPE_NONE;
572 int virq; 573 int virq;
@@ -614,7 +615,11 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
614 * it now and return the interrupt number. 615 * it now and return the interrupt number.
615 */ 616 */
616 if (irq_get_trigger_type(virq) == IRQ_TYPE_NONE) { 617 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);
618 return virq; 623 return virq;
619 } 624 }
620 625
@@ -634,10 +639,18 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
634 return virq; 639 return virq;
635 } 640 }
636 641
637 /* Set type if specified and different than the current one */ 642 irq_data = irq_get_irq_data(virq);
638 if (type != IRQ_TYPE_NONE && 643 if (!irq_data) {
639 type != irq_get_trigger_type(virq)) 644 if (irq_domain_is_hierarchy(domain))
640 irq_set_irq_type(virq, type); 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
641 return virq; 654 return virq;
642} 655}
643EXPORT_SYMBOL_GPL(irq_create_fwspec_mapping); 656EXPORT_SYMBOL_GPL(irq_create_fwspec_mapping);