diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-24 16:55:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-24 16:55:24 -0400 |
commit | b343c8beec664ef6f0e9964d3001c7c7966331ae (patch) | |
tree | c61be2147a700ff83704164686e1db23461d0bb3 /kernel | |
parent | 745914df47053c758f3d7999dfa82df184c2e5af (diff) | |
parent | a87487e687ceafdc696b8cb1fb27e37cc463586b (diff) |
Merge tag 'irqdomain-for-linus' of git://git.secretlab.ca/git/linux-2.6
Pull irqdomain changes from Grant Likely:
"Minor changes and fixups for irqdomain infrastructure. The most
important change adds the ability to remove a registered irqdomain."
* tag 'irqdomain-for-linus' of git://git.secretlab.ca/git/linux-2.6:
irqdomain: Document size parameter of irq_domain_add_linear()
irqdomain: trivial pr_fmt conversion.
irqdomain: Kill off duplicate definitions.
irqdomain: Make irq_domain_simple_map() static.
irqdomain: Export remaining public API symbols.
irqdomain: Support removal of IRQ domains.
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/irq/irqdomain.c | 106 |
1 files changed, 88 insertions, 18 deletions
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 0e0ba5f840b2..41c1564103f1 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c | |||
@@ -1,3 +1,5 @@ | |||
1 | #define pr_fmt(fmt) "irq: " fmt | ||
2 | |||
1 | #include <linux/debugfs.h> | 3 | #include <linux/debugfs.h> |
2 | #include <linux/hardirq.h> | 4 | #include <linux/hardirq.h> |
3 | #include <linux/interrupt.h> | 5 | #include <linux/interrupt.h> |
@@ -56,14 +58,73 @@ static struct irq_domain *irq_domain_alloc(struct device_node *of_node, | |||
56 | return domain; | 58 | return domain; |
57 | } | 59 | } |
58 | 60 | ||
61 | static void irq_domain_free(struct irq_domain *domain) | ||
62 | { | ||
63 | of_node_put(domain->of_node); | ||
64 | kfree(domain); | ||
65 | } | ||
66 | |||
59 | static void irq_domain_add(struct irq_domain *domain) | 67 | static void irq_domain_add(struct irq_domain *domain) |
60 | { | 68 | { |
61 | mutex_lock(&irq_domain_mutex); | 69 | mutex_lock(&irq_domain_mutex); |
62 | list_add(&domain->link, &irq_domain_list); | 70 | list_add(&domain->link, &irq_domain_list); |
63 | mutex_unlock(&irq_domain_mutex); | 71 | mutex_unlock(&irq_domain_mutex); |
64 | pr_debug("irq: Allocated domain of type %d @0x%p\n", | 72 | pr_debug("Allocated domain of type %d @0x%p\n", |
73 | domain->revmap_type, domain); | ||
74 | } | ||
75 | |||
76 | /** | ||
77 | * irq_domain_remove() - Remove an irq domain. | ||
78 | * @domain: domain to remove | ||
79 | * | ||
80 | * This routine is used to remove an irq domain. The caller must ensure | ||
81 | * that all mappings within the domain have been disposed of prior to | ||
82 | * use, depending on the revmap type. | ||
83 | */ | ||
84 | void irq_domain_remove(struct irq_domain *domain) | ||
85 | { | ||
86 | mutex_lock(&irq_domain_mutex); | ||
87 | |||
88 | switch (domain->revmap_type) { | ||
89 | case IRQ_DOMAIN_MAP_LEGACY: | ||
90 | /* | ||
91 | * Legacy domains don't manage their own irq_desc | ||
92 | * allocations, we expect the caller to handle irq_desc | ||
93 | * freeing on their own. | ||
94 | */ | ||
95 | break; | ||
96 | case IRQ_DOMAIN_MAP_TREE: | ||
97 | /* | ||
98 | * radix_tree_delete() takes care of destroying the root | ||
99 | * node when all entries are removed. Shout if there are | ||
100 | * any mappings left. | ||
101 | */ | ||
102 | WARN_ON(domain->revmap_data.tree.height); | ||
103 | break; | ||
104 | case IRQ_DOMAIN_MAP_LINEAR: | ||
105 | kfree(domain->revmap_data.linear.revmap); | ||
106 | domain->revmap_data.linear.size = 0; | ||
107 | break; | ||
108 | case IRQ_DOMAIN_MAP_NOMAP: | ||
109 | break; | ||
110 | } | ||
111 | |||
112 | list_del(&domain->link); | ||
113 | |||
114 | /* | ||
115 | * If the going away domain is the default one, reset it. | ||
116 | */ | ||
117 | if (unlikely(irq_default_domain == domain)) | ||
118 | irq_set_default_host(NULL); | ||
119 | |||
120 | mutex_unlock(&irq_domain_mutex); | ||
121 | |||
122 | pr_debug("Removed domain of type %d @0x%p\n", | ||
65 | domain->revmap_type, domain); | 123 | domain->revmap_type, domain); |
124 | |||
125 | irq_domain_free(domain); | ||
66 | } | 126 | } |
127 | EXPORT_SYMBOL_GPL(irq_domain_remove); | ||
67 | 128 | ||
68 | static unsigned int irq_domain_legacy_revmap(struct irq_domain *domain, | 129 | static unsigned int irq_domain_legacy_revmap(struct irq_domain *domain, |
69 | irq_hw_number_t hwirq) | 130 | irq_hw_number_t hwirq) |
@@ -117,8 +178,7 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node, | |||
117 | 178 | ||
118 | if (WARN_ON(!irq_data || irq_data->domain)) { | 179 | if (WARN_ON(!irq_data || irq_data->domain)) { |
119 | mutex_unlock(&irq_domain_mutex); | 180 | mutex_unlock(&irq_domain_mutex); |
120 | of_node_put(domain->of_node); | 181 | irq_domain_free(domain); |
121 | kfree(domain); | ||
122 | return NULL; | 182 | return NULL; |
123 | } | 183 | } |
124 | } | 184 | } |
@@ -152,10 +212,12 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node, | |||
152 | irq_domain_add(domain); | 212 | irq_domain_add(domain); |
153 | return domain; | 213 | return domain; |
154 | } | 214 | } |
215 | EXPORT_SYMBOL_GPL(irq_domain_add_legacy); | ||
155 | 216 | ||
156 | /** | 217 | /** |
157 | * irq_domain_add_linear() - Allocate and register a legacy revmap irq_domain. | 218 | * irq_domain_add_linear() - Allocate and register a legacy revmap irq_domain. |
158 | * @of_node: pointer to interrupt controller's device tree node. | 219 | * @of_node: pointer to interrupt controller's device tree node. |
220 | * @size: Number of interrupts in the domain. | ||
159 | * @ops: map/unmap domain callbacks | 221 | * @ops: map/unmap domain callbacks |
160 | * @host_data: Controller private data pointer | 222 | * @host_data: Controller private data pointer |
161 | */ | 223 | */ |
@@ -181,6 +243,7 @@ struct irq_domain *irq_domain_add_linear(struct device_node *of_node, | |||
181 | irq_domain_add(domain); | 243 | irq_domain_add(domain); |
182 | return domain; | 244 | return domain; |
183 | } | 245 | } |
246 | EXPORT_SYMBOL_GPL(irq_domain_add_linear); | ||
184 | 247 | ||
185 | struct irq_domain *irq_domain_add_nomap(struct device_node *of_node, | 248 | struct irq_domain *irq_domain_add_nomap(struct device_node *of_node, |
186 | unsigned int max_irq, | 249 | unsigned int max_irq, |
@@ -195,6 +258,7 @@ struct irq_domain *irq_domain_add_nomap(struct device_node *of_node, | |||
195 | } | 258 | } |
196 | return domain; | 259 | return domain; |
197 | } | 260 | } |
261 | EXPORT_SYMBOL_GPL(irq_domain_add_nomap); | ||
198 | 262 | ||
199 | /** | 263 | /** |
200 | * irq_domain_add_tree() | 264 | * irq_domain_add_tree() |
@@ -216,6 +280,7 @@ struct irq_domain *irq_domain_add_tree(struct device_node *of_node, | |||
216 | } | 280 | } |
217 | return domain; | 281 | return domain; |
218 | } | 282 | } |
283 | EXPORT_SYMBOL_GPL(irq_domain_add_tree); | ||
219 | 284 | ||
220 | /** | 285 | /** |
221 | * irq_find_host() - Locates a domain for a given device node | 286 | * irq_find_host() - Locates a domain for a given device node |
@@ -259,10 +324,11 @@ EXPORT_SYMBOL_GPL(irq_find_host); | |||
259 | */ | 324 | */ |
260 | void irq_set_default_host(struct irq_domain *domain) | 325 | void irq_set_default_host(struct irq_domain *domain) |
261 | { | 326 | { |
262 | pr_debug("irq: Default domain set to @0x%p\n", domain); | 327 | pr_debug("Default domain set to @0x%p\n", domain); |
263 | 328 | ||
264 | irq_default_domain = domain; | 329 | irq_default_domain = domain; |
265 | } | 330 | } |
331 | EXPORT_SYMBOL_GPL(irq_set_default_host); | ||
266 | 332 | ||
267 | static int irq_setup_virq(struct irq_domain *domain, unsigned int virq, | 333 | static int irq_setup_virq(struct irq_domain *domain, unsigned int virq, |
268 | irq_hw_number_t hwirq) | 334 | irq_hw_number_t hwirq) |
@@ -272,7 +338,7 @@ static int irq_setup_virq(struct irq_domain *domain, unsigned int virq, | |||
272 | irq_data->hwirq = hwirq; | 338 | irq_data->hwirq = hwirq; |
273 | irq_data->domain = domain; | 339 | irq_data->domain = domain; |
274 | if (domain->ops->map(domain, virq, hwirq)) { | 340 | if (domain->ops->map(domain, virq, hwirq)) { |
275 | pr_debug("irq: -> mapping failed, freeing\n"); | 341 | pr_debug("irq-%i==>hwirq-0x%lx mapping failed\n", virq, hwirq); |
276 | irq_data->domain = NULL; | 342 | irq_data->domain = NULL; |
277 | irq_data->hwirq = 0; | 343 | irq_data->hwirq = 0; |
278 | return -1; | 344 | return -1; |
@@ -303,7 +369,7 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain) | |||
303 | 369 | ||
304 | virq = irq_alloc_desc_from(1, 0); | 370 | virq = irq_alloc_desc_from(1, 0); |
305 | if (!virq) { | 371 | if (!virq) { |
306 | pr_debug("irq: create_direct virq allocation failed\n"); | 372 | pr_debug("create_direct virq allocation failed\n"); |
307 | return 0; | 373 | return 0; |
308 | } | 374 | } |
309 | if (virq >= domain->revmap_data.nomap.max_irq) { | 375 | if (virq >= domain->revmap_data.nomap.max_irq) { |
@@ -312,7 +378,7 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain) | |||
312 | irq_free_desc(virq); | 378 | irq_free_desc(virq); |
313 | return 0; | 379 | return 0; |
314 | } | 380 | } |
315 | pr_debug("irq: create_direct obtained virq %d\n", virq); | 381 | pr_debug("create_direct obtained virq %d\n", virq); |
316 | 382 | ||
317 | if (irq_setup_virq(domain, virq, virq)) { | 383 | if (irq_setup_virq(domain, virq, virq)) { |
318 | irq_free_desc(virq); | 384 | irq_free_desc(virq); |
@@ -321,6 +387,7 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain) | |||
321 | 387 | ||
322 | return virq; | 388 | return virq; |
323 | } | 389 | } |
390 | EXPORT_SYMBOL_GPL(irq_create_direct_mapping); | ||
324 | 391 | ||
325 | /** | 392 | /** |
326 | * irq_create_mapping() - Map a hardware interrupt into linux irq space | 393 | * irq_create_mapping() - Map a hardware interrupt into linux irq space |
@@ -338,23 +405,23 @@ unsigned int irq_create_mapping(struct irq_domain *domain, | |||
338 | unsigned int hint; | 405 | unsigned int hint; |
339 | int virq; | 406 | int virq; |
340 | 407 | ||
341 | pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq); | 408 | pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq); |
342 | 409 | ||
343 | /* Look for default domain if nececssary */ | 410 | /* Look for default domain if nececssary */ |
344 | if (domain == NULL) | 411 | if (domain == NULL) |
345 | domain = irq_default_domain; | 412 | domain = irq_default_domain; |
346 | if (domain == NULL) { | 413 | if (domain == NULL) { |
347 | printk(KERN_WARNING "irq_create_mapping called for" | 414 | pr_warning("irq_create_mapping called for" |
348 | " NULL domain, hwirq=%lx\n", hwirq); | 415 | " NULL domain, hwirq=%lx\n", hwirq); |
349 | WARN_ON(1); | 416 | WARN_ON(1); |
350 | return 0; | 417 | return 0; |
351 | } | 418 | } |
352 | pr_debug("irq: -> using domain @%p\n", domain); | 419 | pr_debug("-> using domain @%p\n", domain); |
353 | 420 | ||
354 | /* Check if mapping already exists */ | 421 | /* Check if mapping already exists */ |
355 | virq = irq_find_mapping(domain, hwirq); | 422 | virq = irq_find_mapping(domain, hwirq); |
356 | if (virq) { | 423 | if (virq) { |
357 | pr_debug("irq: -> existing mapping on virq %d\n", virq); | 424 | pr_debug("-> existing mapping on virq %d\n", virq); |
358 | return virq; | 425 | return virq; |
359 | } | 426 | } |
360 | 427 | ||
@@ -370,7 +437,7 @@ unsigned int irq_create_mapping(struct irq_domain *domain, | |||
370 | if (virq <= 0) | 437 | if (virq <= 0) |
371 | virq = irq_alloc_desc_from(1, 0); | 438 | virq = irq_alloc_desc_from(1, 0); |
372 | if (virq <= 0) { | 439 | if (virq <= 0) { |
373 | pr_debug("irq: -> virq allocation failed\n"); | 440 | pr_debug("-> virq allocation failed\n"); |
374 | return 0; | 441 | return 0; |
375 | } | 442 | } |
376 | 443 | ||
@@ -380,7 +447,7 @@ unsigned int irq_create_mapping(struct irq_domain *domain, | |||
380 | return 0; | 447 | return 0; |
381 | } | 448 | } |
382 | 449 | ||
383 | pr_debug("irq: irq %lu on domain %s mapped to virtual irq %u\n", | 450 | pr_debug("irq %lu on domain %s mapped to virtual irq %u\n", |
384 | hwirq, domain->of_node ? domain->of_node->full_name : "null", virq); | 451 | hwirq, domain->of_node ? domain->of_node->full_name : "null", virq); |
385 | 452 | ||
386 | return virq; | 453 | return virq; |
@@ -409,8 +476,8 @@ unsigned int irq_create_of_mapping(struct device_node *controller, | |||
409 | if (intsize > 0) | 476 | if (intsize > 0) |
410 | return intspec[0]; | 477 | return intspec[0]; |
411 | #endif | 478 | #endif |
412 | printk(KERN_WARNING "irq: no irq domain found for %s !\n", | 479 | pr_warning("no irq domain found for %s !\n", |
413 | controller->full_name); | 480 | controller->full_name); |
414 | return 0; | 481 | return 0; |
415 | } | 482 | } |
416 | 483 | ||
@@ -560,6 +627,7 @@ unsigned int irq_radix_revmap_lookup(struct irq_domain *domain, | |||
560 | */ | 627 | */ |
561 | return irq_data ? irq_data->irq : irq_find_mapping(domain, hwirq); | 628 | return irq_data ? irq_data->irq : irq_find_mapping(domain, hwirq); |
562 | } | 629 | } |
630 | EXPORT_SYMBOL_GPL(irq_radix_revmap_lookup); | ||
563 | 631 | ||
564 | /** | 632 | /** |
565 | * irq_radix_revmap_insert() - Insert a hw irq to linux irq number mapping. | 633 | * irq_radix_revmap_insert() - Insert a hw irq to linux irq number mapping. |
@@ -584,6 +652,7 @@ void irq_radix_revmap_insert(struct irq_domain *domain, unsigned int virq, | |||
584 | mutex_unlock(&revmap_trees_mutex); | 652 | mutex_unlock(&revmap_trees_mutex); |
585 | } | 653 | } |
586 | } | 654 | } |
655 | EXPORT_SYMBOL_GPL(irq_radix_revmap_insert); | ||
587 | 656 | ||
588 | /** | 657 | /** |
589 | * irq_linear_revmap() - Find a linux irq from a hw irq number. | 658 | * irq_linear_revmap() - Find a linux irq from a hw irq number. |
@@ -617,6 +686,7 @@ unsigned int irq_linear_revmap(struct irq_domain *domain, | |||
617 | 686 | ||
618 | return revmap[hwirq]; | 687 | return revmap[hwirq]; |
619 | } | 688 | } |
689 | EXPORT_SYMBOL_GPL(irq_linear_revmap); | ||
620 | 690 | ||
621 | #ifdef CONFIG_IRQ_DOMAIN_DEBUG | 691 | #ifdef CONFIG_IRQ_DOMAIN_DEBUG |
622 | static int virq_debug_show(struct seq_file *m, void *private) | 692 | static int virq_debug_show(struct seq_file *m, void *private) |
@@ -691,8 +761,8 @@ static int __init irq_debugfs_init(void) | |||
691 | __initcall(irq_debugfs_init); | 761 | __initcall(irq_debugfs_init); |
692 | #endif /* CONFIG_IRQ_DOMAIN_DEBUG */ | 762 | #endif /* CONFIG_IRQ_DOMAIN_DEBUG */ |
693 | 763 | ||
694 | int irq_domain_simple_map(struct irq_domain *d, unsigned int irq, | 764 | static int irq_domain_simple_map(struct irq_domain *d, unsigned int irq, |
695 | irq_hw_number_t hwirq) | 765 | irq_hw_number_t hwirq) |
696 | { | 766 | { |
697 | return 0; | 767 | return 0; |
698 | } | 768 | } |