aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/irqdomain.h4
-rw-r--r--kernel/irq/irqdomain.c61
2 files changed, 62 insertions, 3 deletions
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index c65740d76e66..a796dbf80b67 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -141,10 +141,12 @@ static inline struct irq_domain *irq_domain_add_legacy_isa(
141 return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops, 141 return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops,
142 host_data); 142 host_data);
143} 143}
144
145extern void irq_domain_remove(struct irq_domain *host);
146
144extern struct irq_domain *irq_find_host(struct device_node *node); 147extern struct irq_domain *irq_find_host(struct device_node *node);
145extern void irq_set_default_host(struct irq_domain *host); 148extern void irq_set_default_host(struct irq_domain *host);
146 149
147
148extern unsigned int irq_create_mapping(struct irq_domain *host, 150extern unsigned int irq_create_mapping(struct irq_domain *host,
149 irq_hw_number_t hwirq); 151 irq_hw_number_t hwirq);
150extern void irq_dispose_mapping(unsigned int virq); 152extern void irq_dispose_mapping(unsigned int virq);
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 0e0ba5f840b2..9cae0b2f509f 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -56,6 +56,12 @@ static struct irq_domain *irq_domain_alloc(struct device_node *of_node,
56 return domain; 56 return domain;
57} 57}
58 58
59static void irq_domain_free(struct irq_domain *domain)
60{
61 of_node_put(domain->of_node);
62 kfree(domain);
63}
64
59static void irq_domain_add(struct irq_domain *domain) 65static void irq_domain_add(struct irq_domain *domain)
60{ 66{
61 mutex_lock(&irq_domain_mutex); 67 mutex_lock(&irq_domain_mutex);
@@ -65,6 +71,58 @@ static void irq_domain_add(struct irq_domain *domain)
65 domain->revmap_type, domain); 71 domain->revmap_type, domain);
66} 72}
67 73
74/**
75 * irq_domain_remove() - Remove an irq domain.
76 * @domain: domain to remove
77 *
78 * This routine is used to remove an irq domain. The caller must ensure
79 * that all mappings within the domain have been disposed of prior to
80 * use, depending on the revmap type.
81 */
82void irq_domain_remove(struct irq_domain *domain)
83{
84 mutex_lock(&irq_domain_mutex);
85
86 switch (domain->revmap_type) {
87 case IRQ_DOMAIN_MAP_LEGACY:
88 /*
89 * Legacy domains don't manage their own irq_desc
90 * allocations, we expect the caller to handle irq_desc
91 * freeing on their own.
92 */
93 break;
94 case IRQ_DOMAIN_MAP_TREE:
95 /*
96 * radix_tree_delete() takes care of destroying the root
97 * node when all entries are removed. Shout if there are
98 * any mappings left.
99 */
100 WARN_ON(domain->revmap_data.tree.height);
101 break;
102 case IRQ_DOMAIN_MAP_LINEAR:
103 kfree(domain->revmap_data.linear.revmap);
104 domain->revmap_data.linear.size = 0;
105 break;
106 case IRQ_DOMAIN_MAP_NOMAP:
107 break;
108 }
109
110 list_del(&domain->link);
111
112 /*
113 * If the going away domain is the default one, reset it.
114 */
115 if (unlikely(irq_default_domain == domain))
116 irq_set_default_host(NULL);
117
118 mutex_unlock(&irq_domain_mutex);
119
120 pr_debug("irq: Removed domain of type %d @0x%p\n",
121 domain->revmap_type, domain);
122
123 irq_domain_free(domain);
124}
125
68static unsigned int irq_domain_legacy_revmap(struct irq_domain *domain, 126static unsigned int irq_domain_legacy_revmap(struct irq_domain *domain,
69 irq_hw_number_t hwirq) 127 irq_hw_number_t hwirq)
70{ 128{
@@ -117,8 +175,7 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
117 175
118 if (WARN_ON(!irq_data || irq_data->domain)) { 176 if (WARN_ON(!irq_data || irq_data->domain)) {
119 mutex_unlock(&irq_domain_mutex); 177 mutex_unlock(&irq_domain_mutex);
120 of_node_put(domain->of_node); 178 irq_domain_free(domain);
121 kfree(domain);
122 return NULL; 179 return NULL;
123 } 180 }
124 } 181 }