diff options
| -rw-r--r-- | kernel/irq/irqdomain.c | 65 |
1 files changed, 25 insertions, 40 deletions
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index c0e638ba9c2a..170724a07a2c 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c | |||
| @@ -686,16 +686,11 @@ EXPORT_SYMBOL_GPL(irq_dispose_mapping); | |||
| 686 | * irq_find_mapping() - Find a linux irq from an hw irq number. | 686 | * irq_find_mapping() - Find a linux irq from an hw irq number. |
| 687 | * @domain: domain owning this hardware interrupt | 687 | * @domain: domain owning this hardware interrupt |
| 688 | * @hwirq: hardware irq number in that domain space | 688 | * @hwirq: hardware irq number in that domain space |
| 689 | * | ||
| 690 | * This is a slow path, for use by generic code. It's expected that an | ||
| 691 | * irq controller implementation directly calls the appropriate low level | ||
| 692 | * mapping function. | ||
| 693 | */ | 689 | */ |
| 694 | unsigned int irq_find_mapping(struct irq_domain *domain, | 690 | unsigned int irq_find_mapping(struct irq_domain *domain, |
| 695 | irq_hw_number_t hwirq) | 691 | irq_hw_number_t hwirq) |
| 696 | { | 692 | { |
| 697 | unsigned int i; | 693 | struct irq_data *data; |
| 698 | unsigned int hint = hwirq % nr_irqs; | ||
| 699 | 694 | ||
| 700 | /* Look for default domain if nececssary */ | 695 | /* Look for default domain if nececssary */ |
| 701 | if (domain == NULL) | 696 | if (domain == NULL) |
| @@ -703,22 +698,25 @@ unsigned int irq_find_mapping(struct irq_domain *domain, | |||
| 703 | if (domain == NULL) | 698 | if (domain == NULL) |
| 704 | return 0; | 699 | return 0; |
| 705 | 700 | ||
| 706 | /* legacy -> bail early */ | 701 | switch (domain->revmap_type) { |
| 707 | if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY) | 702 | case IRQ_DOMAIN_MAP_LEGACY: |
| 708 | return irq_domain_legacy_revmap(domain, hwirq); | 703 | return irq_domain_legacy_revmap(domain, hwirq); |
| 709 | 704 | case IRQ_DOMAIN_MAP_LINEAR: | |
| 710 | /* Slow path does a linear search of the map */ | 705 | return irq_linear_revmap(domain, hwirq); |
| 711 | if (hint == 0) | 706 | case IRQ_DOMAIN_MAP_TREE: |
| 712 | hint = 1; | 707 | rcu_read_lock(); |
| 713 | i = hint; | 708 | data = radix_tree_lookup(&domain->revmap_data.tree, hwirq); |
| 714 | do { | 709 | rcu_read_unlock(); |
| 715 | struct irq_data *data = irq_get_irq_data(i); | 710 | if (data) |
| 711 | return data->irq; | ||
| 712 | break; | ||
| 713 | case IRQ_DOMAIN_MAP_NOMAP: | ||
| 714 | data = irq_get_irq_data(hwirq); | ||
| 716 | if (data && (data->domain == domain) && (data->hwirq == hwirq)) | 715 | if (data && (data->domain == domain) && (data->hwirq == hwirq)) |
| 717 | return i; | 716 | return hwirq; |
| 718 | i++; | 717 | break; |
| 719 | if (i >= nr_irqs) | 718 | } |
| 720 | i = 1; | 719 | |
| 721 | } while(i != hint); | ||
| 722 | return 0; | 720 | return 0; |
| 723 | } | 721 | } |
| 724 | EXPORT_SYMBOL_GPL(irq_find_mapping); | 722 | EXPORT_SYMBOL_GPL(irq_find_mapping); |
| @@ -728,32 +726,19 @@ EXPORT_SYMBOL_GPL(irq_find_mapping); | |||
| 728 | * @domain: domain owning this hardware interrupt | 726 | * @domain: domain owning this hardware interrupt |
| 729 | * @hwirq: hardware irq number in that domain space | 727 | * @hwirq: hardware irq number in that domain space |
| 730 | * | 728 | * |
| 731 | * This is a fast path, for use by irq controller code that uses linear | 729 | * This is a fast path that can be called directly by irq controller code to |
| 732 | * revmaps. It does fallback to the slow path if the revmap doesn't exist | 730 | * save a handful of instructions. |
| 733 | * yet and will create the revmap entry with appropriate locking | ||
| 734 | */ | 731 | */ |
| 735 | unsigned int irq_linear_revmap(struct irq_domain *domain, | 732 | unsigned int irq_linear_revmap(struct irq_domain *domain, |
| 736 | irq_hw_number_t hwirq) | 733 | irq_hw_number_t hwirq) |
| 737 | { | 734 | { |
| 738 | unsigned int *revmap; | 735 | BUG_ON(domain->revmap_type != IRQ_DOMAIN_MAP_LINEAR); |
| 739 | 736 | ||
| 740 | if (WARN_ON_ONCE(domain->revmap_type != IRQ_DOMAIN_MAP_LINEAR)) | 737 | /* Check revmap bounds; complain if exceeded */ |
| 741 | return irq_find_mapping(domain, hwirq); | 738 | if (WARN_ON(hwirq >= domain->revmap_data.linear.size)) |
| 742 | 739 | return 0; | |
| 743 | /* Check revmap bounds */ | ||
| 744 | if (unlikely(hwirq >= domain->revmap_data.linear.size)) | ||
| 745 | return irq_find_mapping(domain, hwirq); | ||
| 746 | |||
| 747 | /* Check if revmap was allocated */ | ||
| 748 | revmap = domain->revmap_data.linear.revmap; | ||
| 749 | if (unlikely(revmap == NULL)) | ||
| 750 | return irq_find_mapping(domain, hwirq); | ||
| 751 | |||
| 752 | /* Fill up revmap with slow path if no mapping found */ | ||
| 753 | if (unlikely(!revmap[hwirq])) | ||
| 754 | revmap[hwirq] = irq_find_mapping(domain, hwirq); | ||
| 755 | 740 | ||
| 756 | return revmap[hwirq]; | 741 | return domain->revmap_data.linear.revmap[hwirq]; |
| 757 | } | 742 | } |
| 758 | EXPORT_SYMBOL_GPL(irq_linear_revmap); | 743 | EXPORT_SYMBOL_GPL(irq_linear_revmap); |
| 759 | 744 | ||
