diff options
-rw-r--r-- | include/linux/irqdomain.h | 4 | ||||
-rw-r--r-- | kernel/irq/irqdomain.c | 61 |
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 | |||
145 | extern void irq_domain_remove(struct irq_domain *host); | ||
146 | |||
144 | extern struct irq_domain *irq_find_host(struct device_node *node); | 147 | extern struct irq_domain *irq_find_host(struct device_node *node); |
145 | extern void irq_set_default_host(struct irq_domain *host); | 148 | extern void irq_set_default_host(struct irq_domain *host); |
146 | 149 | ||
147 | |||
148 | extern unsigned int irq_create_mapping(struct irq_domain *host, | 150 | extern unsigned int irq_create_mapping(struct irq_domain *host, |
149 | irq_hw_number_t hwirq); | 151 | irq_hw_number_t hwirq); |
150 | extern void irq_dispose_mapping(unsigned int virq); | 152 | extern 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 | ||
59 | static void irq_domain_free(struct irq_domain *domain) | ||
60 | { | ||
61 | of_node_put(domain->of_node); | ||
62 | kfree(domain); | ||
63 | } | ||
64 | |||
59 | static void irq_domain_add(struct irq_domain *domain) | 65 | static 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 | */ | ||
82 | void 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 | |||
68 | static unsigned int irq_domain_legacy_revmap(struct irq_domain *domain, | 126 | static 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 | } |