aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq/irqdomain.c
diff options
context:
space:
mode:
authorGrant Likely <grant.likely@secretlab.ca>2012-06-04 01:04:39 -0400
committerGrant Likely <grant.likely@secretlab.ca>2012-07-25 00:37:23 -0400
commit4c0946c47463defa681b83294383dc996d255bb7 (patch)
tree97443f85088db0aac64bda73d3e7e4d2261623ba /kernel/irq/irqdomain.c
parent6aeea3ecc33b1f36dbc3b80461d15a7052ae424f (diff)
irqdomain: eliminate slow-path revmap lookups
With the current state of irq_domain, the reverse map is always updated when new IRQs get mapped. This means that the irq_find_mapping() function can be simplified to execute the revmap lookup functions unconditionally This patch adds lookup functions for the revmaps that don't yet have one and removes the slow path lookup code path. v8: Broke out unrelated changes into separate patches. Rebased on Paul's irq association patches. v7: Rebased to irqdomain/next for v3.4 and applied before the removal of 'hint' v6: Remove the slow path entirely. The only place where the slow path could get called is for a linear mapping if the hwirq number is larger than the linear revmap size. There shouldn't be any interrupt controllers that do that. v5: rewrite to not use a ->revmap() callback. It is simpler, smaller, safer and faster to open code each of the revmap lookups directly into irq_find_mapping() via a switch statement. v4: Fix build failure on incorrect variable reference. Signed-off-by: Grant Likely <grant.likely@secretlab.ca> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Milton Miller <miltonm@bga.com> Cc: Paul Mundt <lethal@linux-sh.org> Cc: Rob Herring <rob.herring@calxeda.com>
Diffstat (limited to 'kernel/irq/irqdomain.c')
-rw-r--r--kernel/irq/irqdomain.c65
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 */
694unsigned int irq_find_mapping(struct irq_domain *domain, 690unsigned 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}
724EXPORT_SYMBOL_GPL(irq_find_mapping); 722EXPORT_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 */
735unsigned int irq_linear_revmap(struct irq_domain *domain, 732unsigned 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}
758EXPORT_SYMBOL_GPL(irq_linear_revmap); 743EXPORT_SYMBOL_GPL(irq_linear_revmap);
759 744