aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2012-05-19 02:11:41 -0400
committerGrant Likely <grant.likely@secretlab.ca>2012-05-19 14:32:35 -0400
commit58ee99ada293b5ed971a023304fcfbc1a0ccdb1c (patch)
tree29faab64364615dda0cb373ee7dbd483ff89ce9c /kernel
parent36be50515fe2aef61533b516fa2576a2c7fe7664 (diff)
irqdomain: Support removal of IRQ domains.
Now that IRQ domains are being used by modules it's necessary to support removing them, too. This adds a new irq_domain_remove() routine for doing the bulk of the heavy lifting. It's left as an exercise to the caller to ensure all mappings have been appropriatey disposed of before attempting to remove the domain. Signed-off-by: Paul Mundt <lethal@linux-sh.org> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/irq/irqdomain.c61
1 files changed, 59 insertions, 2 deletions
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 }