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 /kernel | |
| 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>
Diffstat (limited to 'kernel')
| -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); |
