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 | ||