diff options
author | Grant Likely <grant.likely@secretlab.ca> | 2012-06-04 01:04:35 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2012-07-11 11:15:34 -0400 |
commit | 913af2070731bfc1bd39bb35c5cd2fd66f5eff12 (patch) | |
tree | 26e177b59bdc23aa5d0ef75a51cc76abdfd1281e | |
parent | 80c1834fc86c2bbacb54a8fc3c04a8b0066b0996 (diff) |
irqdomain: Split disassociating code into separate function
This patch moves the irq disassociation code out into a separate
function in preparation to extend irq_setup_virq to handle multiple
irqs and rename it for use by interrupt controller drivers. The new
function will be used by irq_setup_virq() in its error path.
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mundt <lethal@linux-sh.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Rob Herring <rob.herring@calxeda.com>
-rw-r--r-- | kernel/irq/irqdomain.c | 75 |
1 files changed, 47 insertions, 28 deletions
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 622fdf4b82b6..17634f2c9f6c 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c | |||
@@ -364,6 +364,52 @@ void irq_set_default_host(struct irq_domain *domain) | |||
364 | } | 364 | } |
365 | EXPORT_SYMBOL_GPL(irq_set_default_host); | 365 | EXPORT_SYMBOL_GPL(irq_set_default_host); |
366 | 366 | ||
367 | static void irq_domain_disassociate_many(struct irq_domain *domain, | ||
368 | unsigned int irq_base, int count) | ||
369 | { | ||
370 | /* | ||
371 | * disassociate in reverse order; | ||
372 | * not strictly necessary, but nice for unwinding | ||
373 | */ | ||
374 | while (count--) { | ||
375 | int irq = irq_base + count; | ||
376 | struct irq_data *irq_data = irq_get_irq_data(irq); | ||
377 | irq_hw_number_t hwirq = irq_data->hwirq; | ||
378 | |||
379 | if (WARN_ON(!irq_data || irq_data->domain != domain)) | ||
380 | continue; | ||
381 | |||
382 | irq_set_status_flags(irq, IRQ_NOREQUEST); | ||
383 | |||
384 | /* remove chip and handler */ | ||
385 | irq_set_chip_and_handler(irq, NULL, NULL); | ||
386 | |||
387 | /* Make sure it's completed */ | ||
388 | synchronize_irq(irq); | ||
389 | |||
390 | /* Tell the PIC about it */ | ||
391 | if (domain->ops->unmap) | ||
392 | domain->ops->unmap(domain, irq); | ||
393 | smp_mb(); | ||
394 | |||
395 | irq_data->domain = NULL; | ||
396 | irq_data->hwirq = 0; | ||
397 | |||
398 | /* Clear reverse map */ | ||
399 | switch(domain->revmap_type) { | ||
400 | case IRQ_DOMAIN_MAP_LINEAR: | ||
401 | if (hwirq < domain->revmap_data.linear.size) | ||
402 | domain->revmap_data.linear.revmap[hwirq] = 0; | ||
403 | break; | ||
404 | case IRQ_DOMAIN_MAP_TREE: | ||
405 | mutex_lock(&revmap_trees_mutex); | ||
406 | radix_tree_delete(&domain->revmap_data.tree, hwirq); | ||
407 | mutex_unlock(&revmap_trees_mutex); | ||
408 | break; | ||
409 | } | ||
410 | } | ||
411 | } | ||
412 | |||
367 | static int irq_setup_virq(struct irq_domain *domain, unsigned int virq, | 413 | static int irq_setup_virq(struct irq_domain *domain, unsigned int virq, |
368 | irq_hw_number_t hwirq) | 414 | irq_hw_number_t hwirq) |
369 | { | 415 | { |
@@ -544,7 +590,6 @@ void irq_dispose_mapping(unsigned int virq) | |||
544 | { | 590 | { |
545 | struct irq_data *irq_data = irq_get_irq_data(virq); | 591 | struct irq_data *irq_data = irq_get_irq_data(virq); |
546 | struct irq_domain *domain; | 592 | struct irq_domain *domain; |
547 | irq_hw_number_t hwirq; | ||
548 | 593 | ||
549 | if (!virq || !irq_data) | 594 | if (!virq || !irq_data) |
550 | return; | 595 | return; |
@@ -557,33 +602,7 @@ void irq_dispose_mapping(unsigned int virq) | |||
557 | if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY) | 602 | if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY) |
558 | return; | 603 | return; |
559 | 604 | ||
560 | irq_set_status_flags(virq, IRQ_NOREQUEST); | 605 | irq_domain_disassociate_many(domain, virq, 1); |
561 | |||
562 | /* remove chip and handler */ | ||
563 | irq_set_chip_and_handler(virq, NULL, NULL); | ||
564 | |||
565 | /* Make sure it's completed */ | ||
566 | synchronize_irq(virq); | ||
567 | |||
568 | /* Tell the PIC about it */ | ||
569 | if (domain->ops->unmap) | ||
570 | domain->ops->unmap(domain, virq); | ||
571 | smp_mb(); | ||
572 | |||
573 | /* Clear reverse map */ | ||
574 | hwirq = irq_data->hwirq; | ||
575 | switch(domain->revmap_type) { | ||
576 | case IRQ_DOMAIN_MAP_LINEAR: | ||
577 | if (hwirq < domain->revmap_data.linear.size) | ||
578 | domain->revmap_data.linear.revmap[hwirq] = 0; | ||
579 | break; | ||
580 | case IRQ_DOMAIN_MAP_TREE: | ||
581 | mutex_lock(&revmap_trees_mutex); | ||
582 | radix_tree_delete(&domain->revmap_data.tree, hwirq); | ||
583 | mutex_unlock(&revmap_trees_mutex); | ||
584 | break; | ||
585 | } | ||
586 | |||
587 | irq_free_desc(virq); | 606 | irq_free_desc(virq); |
588 | } | 607 | } |
589 | EXPORT_SYMBOL_GPL(irq_dispose_mapping); | 608 | EXPORT_SYMBOL_GPL(irq_dispose_mapping); |