Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

irq_domain: Move irq_domain code from powerpc to kernel/irq

This patch only moves the code. It doesn't make any changes, and the
code is still only compiled for powerpc. Follow-on patches will generalize
the code for other architectures.

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>
Tested-by: Olof Johansson <olof@lixom.net>

+643 -650
+1
arch/powerpc/Kconfig
··· 135 135 select HAVE_GENERIC_HARDIRQS 136 136 select HAVE_SPARSE_IRQ 137 137 select IRQ_PER_CPU 138 + select IRQ_DOMAIN 138 139 select GENERIC_IRQ_SHOW 139 140 select GENERIC_IRQ_SHOW_LEVEL 140 141 select IRQ_FORCED_THREADING
-144
arch/powerpc/include/asm/irq.h
··· 42 42 /* Same thing, used by the generic IRQ code */ 43 43 #define NR_IRQS_LEGACY NUM_ISA_INTERRUPTS 44 44 45 - /* 46 - * The host code and data structures are fairly agnostic to the fact that 47 - * we use an open firmware device-tree. We do have references to struct 48 - * device_node in two places: in irq_find_host() to find the host matching 49 - * a given interrupt controller node, and of course as an argument to its 50 - * counterpart host->ops->match() callback. However, those are treated as 51 - * generic pointers by the core and the fact that it's actually a device-node 52 - * pointer is purely a convention between callers and implementation. This 53 - * code could thus be used on other architectures by replacing those two 54 - * by some sort of arch-specific void * "token" used to identify interrupt 55 - * controllers. 56 - */ 57 - 58 45 struct irq_data; 59 46 extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d); 60 47 extern irq_hw_number_t virq_to_hw(unsigned int virq); 61 - 62 - /** 63 - * irq_alloc_host - Allocate a new irq_domain data structure 64 - * @of_node: optional device-tree node of the interrupt controller 65 - * @revmap_type: type of reverse mapping to use 66 - * @revmap_arg: for IRQ_DOMAIN_MAP_LINEAR linear only: size of the map 67 - * @ops: map/unmap host callbacks 68 - * @inval_irq: provide a hw number in that host space that is always invalid 69 - * 70 - * Allocates and initialize and irq_domain structure. Note that in the case of 71 - * IRQ_DOMAIN_MAP_LEGACY, the map() callback will be called before this returns 72 - * for all legacy interrupts except 0 (which is always the invalid irq for 73 - * a legacy controller). For a IRQ_DOMAIN_MAP_LINEAR, the map is allocated by 74 - * this call as well. For a IRQ_DOMAIN_MAP_TREE, the radix tree will be allocated 75 - * later during boot automatically (the reverse mapping will use the slow path 76 - * until that happens). 77 - */ 78 - extern struct irq_domain *irq_alloc_host(struct device_node *of_node, 79 - unsigned int revmap_type, 80 - unsigned int revmap_arg, 81 - struct irq_domain_ops *ops, 82 - irq_hw_number_t inval_irq); 83 - 84 - 85 - /** 86 - * irq_find_host - Locates a host for a given device node 87 - * @node: device-tree node of the interrupt controller 88 - */ 89 - extern struct irq_domain *irq_find_host(struct device_node *node); 90 - 91 - 92 - /** 93 - * irq_set_default_host - Set a "default" host 94 - * @host: default host pointer 95 - * 96 - * For convenience, it's possible to set a "default" host that will be used 97 - * whenever NULL is passed to irq_create_mapping(). It makes life easier for 98 - * platforms that want to manipulate a few hard coded interrupt numbers that 99 - * aren't properly represented in the device-tree. 100 - */ 101 - extern void irq_set_default_host(struct irq_domain *host); 102 - 103 - 104 - /** 105 - * irq_set_virq_count - Set the maximum number of virt irqs 106 - * @count: number of linux virtual irqs, capped with NR_IRQS 107 - * 108 - * This is mainly for use by platforms like iSeries who want to program 109 - * the virtual irq number in the controller to avoid the reverse mapping 110 - */ 111 - extern void irq_set_virq_count(unsigned int count); 112 - 113 - 114 - /** 115 - * irq_create_mapping - Map a hardware interrupt into linux virq space 116 - * @host: host owning this hardware interrupt or NULL for default host 117 - * @hwirq: hardware irq number in that host space 118 - * 119 - * Only one mapping per hardware interrupt is permitted. Returns a linux 120 - * virq number. 121 - * If the sense/trigger is to be specified, set_irq_type() should be called 122 - * on the number returned from that call. 123 - */ 124 - extern unsigned int irq_create_mapping(struct irq_domain *host, 125 - irq_hw_number_t hwirq); 126 - 127 - 128 - /** 129 - * irq_dispose_mapping - Unmap an interrupt 130 - * @virq: linux virq number of the interrupt to unmap 131 - */ 132 - extern void irq_dispose_mapping(unsigned int virq); 133 - 134 - /** 135 - * irq_find_mapping - Find a linux virq from an hw irq number. 136 - * @host: host owning this hardware interrupt 137 - * @hwirq: hardware irq number in that host space 138 - * 139 - * This is a slow path, for use by generic code. It's expected that an 140 - * irq controller implementation directly calls the appropriate low level 141 - * mapping function. 142 - */ 143 - extern unsigned int irq_find_mapping(struct irq_domain *host, 144 - irq_hw_number_t hwirq); 145 - 146 - /** 147 - * irq_create_direct_mapping - Allocate a virq for direct mapping 148 - * @host: host to allocate the virq for or NULL for default host 149 - * 150 - * This routine is used for irq controllers which can choose the hardware 151 - * interrupt numbers they generate. In such a case it's simplest to use 152 - * the linux virq as the hardware interrupt number. 153 - */ 154 - extern unsigned int irq_create_direct_mapping(struct irq_domain *host); 155 - 156 - /** 157 - * irq_radix_revmap_insert - Insert a hw irq to linux virq number mapping. 158 - * @host: host owning this hardware interrupt 159 - * @virq: linux irq number 160 - * @hwirq: hardware irq number in that host space 161 - * 162 - * This is for use by irq controllers that use a radix tree reverse 163 - * mapping for fast lookup. 164 - */ 165 - extern void irq_radix_revmap_insert(struct irq_domain *host, unsigned int virq, 166 - irq_hw_number_t hwirq); 167 - 168 - /** 169 - * irq_radix_revmap_lookup - Find a linux virq from a hw irq number. 170 - * @host: host owning this hardware interrupt 171 - * @hwirq: hardware irq number in that host space 172 - * 173 - * This is a fast path, for use by irq controller code that uses radix tree 174 - * revmaps 175 - */ 176 - extern unsigned int irq_radix_revmap_lookup(struct irq_domain *host, 177 - irq_hw_number_t hwirq); 178 - 179 - /** 180 - * irq_linear_revmap - Find a linux virq from a hw irq number. 181 - * @host: host owning this hardware interrupt 182 - * @hwirq: hardware irq number in that host space 183 - * 184 - * This is a fast path, for use by irq controller code that uses linear 185 - * revmaps. It does fallback to the slow path if the revmap doesn't exist 186 - * yet and will create the revmap entry with appropriate locking 187 - */ 188 - 189 - extern unsigned int irq_linear_revmap(struct irq_domain *host, 190 - irq_hw_number_t hwirq); 191 - 192 48 193 49 /** 194 50 * irq_early_init - Init irq remapping subsystem
-502
arch/powerpc/kernel/irq.c
··· 486 486 local_irq_restore(flags); 487 487 } 488 488 489 - 490 - /* 491 - * IRQ controller and virtual interrupts 492 - */ 493 - 494 - static LIST_HEAD(irq_domain_list); 495 - static DEFINE_MUTEX(irq_domain_mutex); 496 - static DEFINE_MUTEX(revmap_trees_mutex); 497 - static unsigned int irq_virq_count = NR_IRQS; 498 - static struct irq_domain *irq_default_host; 499 - 500 489 irq_hw_number_t irqd_to_hwirq(struct irq_data *d) 501 490 { 502 491 return d->hwirq; ··· 498 509 return WARN_ON(!irq_data) ? 0 : irq_data->hwirq; 499 510 } 500 511 EXPORT_SYMBOL_GPL(virq_to_hw); 501 - 502 - static int default_irq_host_match(struct irq_domain *h, struct device_node *np) 503 - { 504 - return h->of_node != NULL && h->of_node == np; 505 - } 506 - 507 - struct irq_domain *irq_alloc_host(struct device_node *of_node, 508 - unsigned int revmap_type, 509 - unsigned int revmap_arg, 510 - struct irq_domain_ops *ops, 511 - irq_hw_number_t inval_irq) 512 - { 513 - struct irq_domain *host, *h; 514 - unsigned int size = sizeof(struct irq_domain); 515 - unsigned int i; 516 - unsigned int *rmap; 517 - 518 - /* Allocate structure and revmap table if using linear mapping */ 519 - if (revmap_type == IRQ_DOMAIN_MAP_LINEAR) 520 - size += revmap_arg * sizeof(unsigned int); 521 - host = kzalloc(size, GFP_KERNEL); 522 - if (host == NULL) 523 - return NULL; 524 - 525 - /* Fill structure */ 526 - host->revmap_type = revmap_type; 527 - host->inval_irq = inval_irq; 528 - host->ops = ops; 529 - host->of_node = of_node_get(of_node); 530 - 531 - if (host->ops->match == NULL) 532 - host->ops->match = default_irq_host_match; 533 - 534 - mutex_lock(&irq_domain_mutex); 535 - /* Make sure only one legacy controller can be created */ 536 - if (revmap_type == IRQ_DOMAIN_MAP_LEGACY) { 537 - list_for_each_entry(h, &irq_domain_list, link) { 538 - if (WARN_ON(h->revmap_type == IRQ_DOMAIN_MAP_LEGACY)) { 539 - mutex_unlock(&irq_domain_mutex); 540 - of_node_put(host->of_node); 541 - kfree(host); 542 - return NULL; 543 - } 544 - } 545 - } 546 - list_add(&host->link, &irq_domain_list); 547 - mutex_unlock(&irq_domain_mutex); 548 - 549 - /* Additional setups per revmap type */ 550 - switch(revmap_type) { 551 - case IRQ_DOMAIN_MAP_LEGACY: 552 - /* 0 is always the invalid number for legacy */ 553 - host->inval_irq = 0; 554 - /* setup us as the host for all legacy interrupts */ 555 - for (i = 1; i < NUM_ISA_INTERRUPTS; i++) { 556 - struct irq_data *irq_data = irq_get_irq_data(i); 557 - irq_data->hwirq = i; 558 - irq_data->domain = host; 559 - 560 - /* Legacy flags are left to default at this point, 561 - * one can then use irq_create_mapping() to 562 - * explicitly change them 563 - */ 564 - ops->map(host, i, i); 565 - 566 - /* Clear norequest flags */ 567 - irq_clear_status_flags(i, IRQ_NOREQUEST); 568 - } 569 - break; 570 - case IRQ_DOMAIN_MAP_LINEAR: 571 - rmap = (unsigned int *)(host + 1); 572 - for (i = 0; i < revmap_arg; i++) 573 - rmap[i] = NO_IRQ; 574 - host->revmap_data.linear.size = revmap_arg; 575 - host->revmap_data.linear.revmap = rmap; 576 - break; 577 - case IRQ_DOMAIN_MAP_TREE: 578 - INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL); 579 - break; 580 - default: 581 - break; 582 - } 583 - 584 - pr_debug("irq: Allocated host of type %d @0x%p\n", revmap_type, host); 585 - 586 - return host; 587 - } 588 - 589 - struct irq_domain *irq_find_host(struct device_node *node) 590 - { 591 - struct irq_domain *h, *found = NULL; 592 - 593 - /* We might want to match the legacy controller last since 594 - * it might potentially be set to match all interrupts in 595 - * the absence of a device node. This isn't a problem so far 596 - * yet though... 597 - */ 598 - mutex_lock(&irq_domain_mutex); 599 - list_for_each_entry(h, &irq_domain_list, link) 600 - if (h->ops->match(h, node)) { 601 - found = h; 602 - break; 603 - } 604 - mutex_unlock(&irq_domain_mutex); 605 - return found; 606 - } 607 - EXPORT_SYMBOL_GPL(irq_find_host); 608 - 609 - void irq_set_default_host(struct irq_domain *host) 610 - { 611 - pr_debug("irq: Default host set to @0x%p\n", host); 612 - 613 - irq_default_host = host; 614 - } 615 - 616 - void irq_set_virq_count(unsigned int count) 617 - { 618 - pr_debug("irq: Trying to set virq count to %d\n", count); 619 - 620 - BUG_ON(count < NUM_ISA_INTERRUPTS); 621 - if (count < NR_IRQS) 622 - irq_virq_count = count; 623 - } 624 - 625 - static int irq_setup_virq(struct irq_domain *host, unsigned int virq, 626 - irq_hw_number_t hwirq) 627 - { 628 - struct irq_data *irq_data = irq_get_irq_data(virq); 629 - 630 - irq_data->hwirq = hwirq; 631 - irq_data->domain = host; 632 - if (host->ops->map(host, virq, hwirq)) { 633 - pr_debug("irq: -> mapping failed, freeing\n"); 634 - irq_data->domain = NULL; 635 - irq_data->hwirq = 0; 636 - return -1; 637 - } 638 - 639 - irq_clear_status_flags(virq, IRQ_NOREQUEST); 640 - 641 - return 0; 642 - } 643 - 644 - unsigned int irq_create_direct_mapping(struct irq_domain *host) 645 - { 646 - unsigned int virq; 647 - 648 - if (host == NULL) 649 - host = irq_default_host; 650 - 651 - BUG_ON(host == NULL); 652 - WARN_ON(host->revmap_type != IRQ_DOMAIN_MAP_NOMAP); 653 - 654 - virq = irq_alloc_desc_from(1, 0); 655 - if (virq == NO_IRQ) { 656 - pr_debug("irq: create_direct virq allocation failed\n"); 657 - return NO_IRQ; 658 - } 659 - if (virq >= irq_virq_count) { 660 - pr_err("ERROR: no free irqs available below %i maximum\n", 661 - irq_virq_count); 662 - irq_free_desc(virq); 663 - return 0; 664 - } 665 - 666 - pr_debug("irq: create_direct obtained virq %d\n", virq); 667 - 668 - if (irq_setup_virq(host, virq, virq)) { 669 - irq_free_desc(virq); 670 - return NO_IRQ; 671 - } 672 - 673 - return virq; 674 - } 675 - 676 - unsigned int irq_create_mapping(struct irq_domain *host, 677 - irq_hw_number_t hwirq) 678 - { 679 - unsigned int virq, hint; 680 - 681 - pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", host, hwirq); 682 - 683 - /* Look for default host if nececssary */ 684 - if (host == NULL) 685 - host = irq_default_host; 686 - if (host == NULL) { 687 - printk(KERN_WARNING "irq_create_mapping called for" 688 - " NULL host, hwirq=%lx\n", hwirq); 689 - WARN_ON(1); 690 - return NO_IRQ; 691 - } 692 - pr_debug("irq: -> using host @%p\n", host); 693 - 694 - /* Check if mapping already exists */ 695 - virq = irq_find_mapping(host, hwirq); 696 - if (virq != NO_IRQ) { 697 - pr_debug("irq: -> existing mapping on virq %d\n", virq); 698 - return virq; 699 - } 700 - 701 - /* Get a virtual interrupt number */ 702 - if (host->revmap_type == IRQ_DOMAIN_MAP_LEGACY) { 703 - /* Handle legacy */ 704 - virq = (unsigned int)hwirq; 705 - if (virq == 0 || virq >= NUM_ISA_INTERRUPTS) 706 - return NO_IRQ; 707 - return virq; 708 - } else { 709 - /* Allocate a virtual interrupt number */ 710 - hint = hwirq % irq_virq_count; 711 - if (hint == 0) 712 - hint = 1; 713 - virq = irq_alloc_desc_from(hint, 0); 714 - if (!virq) 715 - virq = irq_alloc_desc_from(1, 0); 716 - if (virq == NO_IRQ) { 717 - pr_debug("irq: -> virq allocation failed\n"); 718 - return NO_IRQ; 719 - } 720 - } 721 - 722 - if (irq_setup_virq(host, virq, hwirq)) { 723 - if (host->revmap_type != IRQ_DOMAIN_MAP_LEGACY) 724 - irq_free_desc(virq); 725 - return NO_IRQ; 726 - } 727 - 728 - pr_debug("irq: irq %lu on host %s mapped to virtual irq %u\n", 729 - hwirq, host->of_node ? host->of_node->full_name : "null", virq); 730 - 731 - return virq; 732 - } 733 - EXPORT_SYMBOL_GPL(irq_create_mapping); 734 - 735 - unsigned int irq_create_of_mapping(struct device_node *controller, 736 - const u32 *intspec, unsigned int intsize) 737 - { 738 - struct irq_domain *host; 739 - irq_hw_number_t hwirq; 740 - unsigned int type = IRQ_TYPE_NONE; 741 - unsigned int virq; 742 - 743 - if (controller == NULL) 744 - host = irq_default_host; 745 - else 746 - host = irq_find_host(controller); 747 - if (host == NULL) { 748 - printk(KERN_WARNING "irq: no irq host found for %s !\n", 749 - controller->full_name); 750 - return NO_IRQ; 751 - } 752 - 753 - /* If host has no translation, then we assume interrupt line */ 754 - if (host->ops->xlate == NULL) 755 - hwirq = intspec[0]; 756 - else { 757 - if (host->ops->xlate(host, controller, intspec, intsize, 758 - &hwirq, &type)) 759 - return NO_IRQ; 760 - } 761 - 762 - /* Create mapping */ 763 - virq = irq_create_mapping(host, hwirq); 764 - if (virq == NO_IRQ) 765 - return virq; 766 - 767 - /* Set type if specified and different than the current one */ 768 - if (type != IRQ_TYPE_NONE && 769 - type != (irqd_get_trigger_type(irq_get_irq_data(virq)))) 770 - irq_set_irq_type(virq, type); 771 - return virq; 772 - } 773 - EXPORT_SYMBOL_GPL(irq_create_of_mapping); 774 - 775 - void irq_dispose_mapping(unsigned int virq) 776 - { 777 - struct irq_data *irq_data = irq_get_irq_data(virq); 778 - struct irq_domain *host; 779 - irq_hw_number_t hwirq; 780 - 781 - if (virq == NO_IRQ || !irq_data) 782 - return; 783 - 784 - host = irq_data->domain; 785 - if (WARN_ON(host == NULL)) 786 - return; 787 - 788 - /* Never unmap legacy interrupts */ 789 - if (host->revmap_type == IRQ_DOMAIN_MAP_LEGACY) 790 - return; 791 - 792 - irq_set_status_flags(virq, IRQ_NOREQUEST); 793 - 794 - /* remove chip and handler */ 795 - irq_set_chip_and_handler(virq, NULL, NULL); 796 - 797 - /* Make sure it's completed */ 798 - synchronize_irq(virq); 799 - 800 - /* Tell the PIC about it */ 801 - if (host->ops->unmap) 802 - host->ops->unmap(host, virq); 803 - smp_mb(); 804 - 805 - /* Clear reverse map */ 806 - hwirq = irq_data->hwirq; 807 - switch(host->revmap_type) { 808 - case IRQ_DOMAIN_MAP_LINEAR: 809 - if (hwirq < host->revmap_data.linear.size) 810 - host->revmap_data.linear.revmap[hwirq] = NO_IRQ; 811 - break; 812 - case IRQ_DOMAIN_MAP_TREE: 813 - mutex_lock(&revmap_trees_mutex); 814 - radix_tree_delete(&host->revmap_data.tree, hwirq); 815 - mutex_unlock(&revmap_trees_mutex); 816 - break; 817 - } 818 - 819 - /* Destroy map */ 820 - irq_data->hwirq = host->inval_irq; 821 - 822 - irq_free_desc(virq); 823 - } 824 - EXPORT_SYMBOL_GPL(irq_dispose_mapping); 825 - 826 - unsigned int irq_find_mapping(struct irq_domain *host, 827 - irq_hw_number_t hwirq) 828 - { 829 - unsigned int i; 830 - unsigned int hint = hwirq % irq_virq_count; 831 - 832 - /* Look for default host if nececssary */ 833 - if (host == NULL) 834 - host = irq_default_host; 835 - if (host == NULL) 836 - return NO_IRQ; 837 - 838 - /* legacy -> bail early */ 839 - if (host->revmap_type == IRQ_DOMAIN_MAP_LEGACY) 840 - return hwirq; 841 - 842 - /* Slow path does a linear search of the map */ 843 - if (hint == 0) 844 - hint = 1; 845 - i = hint; 846 - do { 847 - struct irq_data *data = irq_get_irq_data(i); 848 - if (data && (data->domain == host) && (data->hwirq == hwirq)) 849 - return i; 850 - i++; 851 - if (i >= irq_virq_count) 852 - i = 1; 853 - } while(i != hint); 854 - return NO_IRQ; 855 - } 856 - EXPORT_SYMBOL_GPL(irq_find_mapping); 857 512 858 513 #ifdef CONFIG_SMP 859 514 int irq_choose_cpu(const struct cpumask *mask) ··· 535 902 } 536 903 #endif 537 904 538 - unsigned int irq_radix_revmap_lookup(struct irq_domain *host, 539 - irq_hw_number_t hwirq) 540 - { 541 - struct irq_data *irq_data; 542 - 543 - if (WARN_ON_ONCE(host->revmap_type != IRQ_DOMAIN_MAP_TREE)) 544 - return irq_find_mapping(host, hwirq); 545 - 546 - /* 547 - * Freeing an irq can delete nodes along the path to 548 - * do the lookup via call_rcu. 549 - */ 550 - rcu_read_lock(); 551 - irq_data = radix_tree_lookup(&host->revmap_data.tree, hwirq); 552 - rcu_read_unlock(); 553 - 554 - /* 555 - * If found in radix tree, then fine. 556 - * Else fallback to linear lookup - this should not happen in practice 557 - * as it means that we failed to insert the node in the radix tree. 558 - */ 559 - return irq_data ? irq_data->irq : irq_find_mapping(host, hwirq); 560 - } 561 - 562 - void irq_radix_revmap_insert(struct irq_domain *host, unsigned int virq, 563 - irq_hw_number_t hwirq) 564 - { 565 - struct irq_data *irq_data = irq_get_irq_data(virq); 566 - 567 - if (WARN_ON(host->revmap_type != IRQ_DOMAIN_MAP_TREE)) 568 - return; 569 - 570 - if (virq != NO_IRQ) { 571 - mutex_lock(&revmap_trees_mutex); 572 - radix_tree_insert(&host->revmap_data.tree, hwirq, irq_data); 573 - mutex_unlock(&revmap_trees_mutex); 574 - } 575 - } 576 - 577 - unsigned int irq_linear_revmap(struct irq_domain *host, 578 - irq_hw_number_t hwirq) 579 - { 580 - unsigned int *revmap; 581 - 582 - if (WARN_ON_ONCE(host->revmap_type != IRQ_DOMAIN_MAP_LINEAR)) 583 - return irq_find_mapping(host, hwirq); 584 - 585 - /* Check revmap bounds */ 586 - if (unlikely(hwirq >= host->revmap_data.linear.size)) 587 - return irq_find_mapping(host, hwirq); 588 - 589 - /* Check if revmap was allocated */ 590 - revmap = host->revmap_data.linear.revmap; 591 - if (unlikely(revmap == NULL)) 592 - return irq_find_mapping(host, hwirq); 593 - 594 - /* Fill up revmap with slow path if no mapping found */ 595 - if (unlikely(revmap[hwirq] == NO_IRQ)) 596 - revmap[hwirq] = irq_find_mapping(host, hwirq); 597 - 598 - return revmap[hwirq]; 599 - } 600 - 601 905 int arch_early_irq_init(void) 602 906 { 603 907 return 0; 604 908 } 605 - 606 - #ifdef CONFIG_VIRQ_DEBUG 607 - static int virq_debug_show(struct seq_file *m, void *private) 608 - { 609 - unsigned long flags; 610 - struct irq_desc *desc; 611 - const char *p; 612 - static const char none[] = "none"; 613 - void *data; 614 - int i; 615 - 616 - seq_printf(m, "%-5s %-7s %-15s %-18s %s\n", "virq", "hwirq", 617 - "chip name", "chip data", "host name"); 618 - 619 - for (i = 1; i < nr_irqs; i++) { 620 - desc = irq_to_desc(i); 621 - if (!desc) 622 - continue; 623 - 624 - raw_spin_lock_irqsave(&desc->lock, flags); 625 - 626 - if (desc->action && desc->action->handler) { 627 - struct irq_chip *chip; 628 - 629 - seq_printf(m, "%5d ", i); 630 - seq_printf(m, "0x%05lx ", desc->irq_data.hwirq); 631 - 632 - chip = irq_desc_get_chip(desc); 633 - if (chip && chip->name) 634 - p = chip->name; 635 - else 636 - p = none; 637 - seq_printf(m, "%-15s ", p); 638 - 639 - data = irq_desc_get_chip_data(desc); 640 - seq_printf(m, "0x%16p ", data); 641 - 642 - if (desc->irq_data.domain->of_node) 643 - p = desc->irq_data.domain->of_node->full_name; 644 - else 645 - p = none; 646 - seq_printf(m, "%s\n", p); 647 - } 648 - 649 - raw_spin_unlock_irqrestore(&desc->lock, flags); 650 - } 651 - 652 - return 0; 653 - } 654 - 655 - static int virq_debug_open(struct inode *inode, struct file *file) 656 - { 657 - return single_open(file, virq_debug_show, inode->i_private); 658 - } 659 - 660 - static const struct file_operations virq_debug_fops = { 661 - .open = virq_debug_open, 662 - .read = seq_read, 663 - .llseek = seq_lseek, 664 - .release = single_release, 665 - }; 666 - 667 - static int __init irq_debugfs_init(void) 668 - { 669 - if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root, 670 - NULL, &virq_debug_fops) == NULL) 671 - return -ENOMEM; 672 - 673 - return 0; 674 - } 675 - __initcall(irq_debugfs_init); 676 - #endif /* CONFIG_VIRQ_DEBUG */ 677 909 678 910 #ifdef CONFIG_PPC64 679 911 static int __init setup_noirqdistrib(char *str)
+42 -4
include/linux/irqdomain.h
··· 16 16 * (though a domain can cover more than one PIC if they have a flat number 17 17 * model). It's the domain callbacks that are responsible for setting the 18 18 * irq_chip on a given irq_desc after it's been mapped. 19 + * 20 + * The host code and data structures are agnostic to whether or not 21 + * we use an open firmware device-tree. We do have references to struct 22 + * device_node in two places: in irq_find_host() to find the host matching 23 + * a given interrupt controller node, and of course as an argument to its 24 + * counterpart domain->ops->match() callback. However, those are treated as 25 + * generic pointers by the core and the fact that it's actually a device-node 26 + * pointer is purely a convention between callers and implementation. This 27 + * code could thus be used on other architectures by replacing those two 28 + * by some sort of arch-specific void * "token" used to identify interrupt 29 + * controllers. 19 30 */ 20 31 21 32 #ifndef _LINUX_IRQDOMAIN_H ··· 119 108 }; 120 109 121 110 #ifdef CONFIG_IRQ_DOMAIN 111 + #ifdef CONFIG_PPC 112 + extern struct irq_domain *irq_alloc_host(struct device_node *of_node, 113 + unsigned int revmap_type, 114 + unsigned int revmap_arg, 115 + struct irq_domain_ops *ops, 116 + irq_hw_number_t inval_irq); 117 + extern struct irq_domain *irq_find_host(struct device_node *node); 118 + extern void irq_set_default_host(struct irq_domain *host); 119 + extern void irq_set_virq_count(unsigned int count); 120 + 121 + 122 + extern unsigned int irq_create_mapping(struct irq_domain *host, 123 + irq_hw_number_t hwirq); 124 + extern void irq_dispose_mapping(unsigned int virq); 125 + extern unsigned int irq_find_mapping(struct irq_domain *host, 126 + irq_hw_number_t hwirq); 127 + extern unsigned int irq_create_direct_mapping(struct irq_domain *host); 128 + extern void irq_radix_revmap_insert(struct irq_domain *host, unsigned int virq, 129 + irq_hw_number_t hwirq); 130 + extern unsigned int irq_radix_revmap_lookup(struct irq_domain *host, 131 + irq_hw_number_t hwirq); 132 + extern unsigned int irq_linear_revmap(struct irq_domain *host, 133 + irq_hw_number_t hwirq); 134 + 135 + #else /* CONFIG_PPC */ 136 + 122 137 /** 123 138 * irq_domain_to_irq() - Translate from a hardware irq to a linux irq number 124 139 * ··· 174 137 extern void irq_domain_del(struct irq_domain *domain); 175 138 176 139 extern struct irq_domain_ops irq_domain_simple_ops; 177 - #endif /* CONFIG_IRQ_DOMAIN */ 178 140 179 - #if defined(CONFIG_IRQ_DOMAIN) && defined(CONFIG_OF_IRQ) 141 + #if defined(CONFIG_OF_IRQ) 180 142 extern void irq_domain_add_simple(struct device_node *controller, int irq_base); 181 143 extern void irq_domain_generate_simple(const struct of_device_id *match, 182 144 u64 phys_base, unsigned int irq_start); 183 - #else /* CONFIG_IRQ_DOMAIN && CONFIG_OF_IRQ */ 145 + #else /* CONFIG_OF_IRQ */ 184 146 static inline void irq_domain_generate_simple(const struct of_device_id *match, 185 147 u64 phys_base, unsigned int irq_start) { } 186 - #endif /* CONFIG_IRQ_DOMAIN && CONFIG_OF_IRQ */ 148 + #endif /* !CONFIG_OF_IRQ */ 149 + #endif /* !CONFIG_PPC */ 150 + #endif /* CONFIG_IRQ_DOMAIN */ 187 151 188 152 #endif /* _LINUX_IRQDOMAIN_H */
+600
kernel/irq/irqdomain.c
··· 1 + #include <linux/debugfs.h> 2 + #include <linux/hardirq.h> 3 + #include <linux/interrupt.h> 1 4 #include <linux/irq.h> 5 + #include <linux/irqdesc.h> 2 6 #include <linux/irqdomain.h> 3 7 #include <linux/module.h> 4 8 #include <linux/mutex.h> 5 9 #include <linux/of.h> 6 10 #include <linux/of_address.h> 11 + #include <linux/seq_file.h> 7 12 #include <linux/slab.h> 13 + #include <linux/smp.h> 14 + #include <linux/fs.h> 8 15 9 16 static LIST_HEAD(irq_domain_list); 10 17 static DEFINE_MUTEX(irq_domain_mutex); 18 + 19 + #ifdef CONFIG_PPC 20 + static DEFINE_MUTEX(revmap_trees_mutex); 21 + static unsigned int irq_virq_count = NR_IRQS; 22 + static struct irq_domain *irq_default_host; 23 + 24 + static int default_irq_host_match(struct irq_domain *h, struct device_node *np) 25 + { 26 + return h->of_node != NULL && h->of_node == np; 27 + } 28 + 29 + /** 30 + * irq_alloc_host() - Allocate a new irq_domain data structure 31 + * @of_node: optional device-tree node of the interrupt controller 32 + * @revmap_type: type of reverse mapping to use 33 + * @revmap_arg: for IRQ_DOMAIN_MAP_LINEAR linear only: size of the map 34 + * @ops: map/unmap host callbacks 35 + * @inval_irq: provide a hw number in that host space that is always invalid 36 + * 37 + * Allocates and initialize and irq_domain structure. Note that in the case of 38 + * IRQ_DOMAIN_MAP_LEGACY, the map() callback will be called before this returns 39 + * for all legacy interrupts except 0 (which is always the invalid irq for 40 + * a legacy controller). For a IRQ_DOMAIN_MAP_LINEAR, the map is allocated by 41 + * this call as well. For a IRQ_DOMAIN_MAP_TREE, the radix tree will be 42 + * allocated later during boot automatically (the reverse mapping will use the 43 + * slow path until that happens). 44 + */ 45 + struct irq_domain *irq_alloc_host(struct device_node *of_node, 46 + unsigned int revmap_type, 47 + unsigned int revmap_arg, 48 + struct irq_domain_ops *ops, 49 + irq_hw_number_t inval_irq) 50 + { 51 + struct irq_domain *host, *h; 52 + unsigned int size = sizeof(struct irq_domain); 53 + unsigned int i; 54 + unsigned int *rmap; 55 + 56 + /* Allocate structure and revmap table if using linear mapping */ 57 + if (revmap_type == IRQ_DOMAIN_MAP_LINEAR) 58 + size += revmap_arg * sizeof(unsigned int); 59 + host = kzalloc(size, GFP_KERNEL); 60 + if (host == NULL) 61 + return NULL; 62 + 63 + /* Fill structure */ 64 + host->revmap_type = revmap_type; 65 + host->inval_irq = inval_irq; 66 + host->ops = ops; 67 + host->of_node = of_node_get(of_node); 68 + 69 + if (host->ops->match == NULL) 70 + host->ops->match = default_irq_host_match; 71 + 72 + mutex_lock(&irq_domain_mutex); 73 + /* Make sure only one legacy controller can be created */ 74 + if (revmap_type == IRQ_DOMAIN_MAP_LEGACY) { 75 + list_for_each_entry(h, &irq_domain_list, link) { 76 + if (WARN_ON(h->revmap_type == IRQ_DOMAIN_MAP_LEGACY)) { 77 + mutex_unlock(&irq_domain_mutex); 78 + of_node_put(host->of_node); 79 + kfree(host); 80 + return NULL; 81 + } 82 + } 83 + } 84 + list_add(&host->link, &irq_domain_list); 85 + mutex_unlock(&irq_domain_mutex); 86 + 87 + /* Additional setups per revmap type */ 88 + switch(revmap_type) { 89 + case IRQ_DOMAIN_MAP_LEGACY: 90 + /* 0 is always the invalid number for legacy */ 91 + host->inval_irq = 0; 92 + /* setup us as the host for all legacy interrupts */ 93 + for (i = 1; i < NUM_ISA_INTERRUPTS; i++) { 94 + struct irq_data *irq_data = irq_get_irq_data(i); 95 + irq_data->hwirq = i; 96 + irq_data->domain = host; 97 + 98 + /* Legacy flags are left to default at this point, 99 + * one can then use irq_create_mapping() to 100 + * explicitly change them 101 + */ 102 + ops->map(host, i, i); 103 + 104 + /* Clear norequest flags */ 105 + irq_clear_status_flags(i, IRQ_NOREQUEST); 106 + } 107 + break; 108 + case IRQ_DOMAIN_MAP_LINEAR: 109 + rmap = (unsigned int *)(host + 1); 110 + for (i = 0; i < revmap_arg; i++) 111 + rmap[i] = NO_IRQ; 112 + host->revmap_data.linear.size = revmap_arg; 113 + host->revmap_data.linear.revmap = rmap; 114 + break; 115 + case IRQ_DOMAIN_MAP_TREE: 116 + INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL); 117 + break; 118 + default: 119 + break; 120 + } 121 + 122 + pr_debug("irq: Allocated host of type %d @0x%p\n", revmap_type, host); 123 + 124 + return host; 125 + } 126 + 127 + /** 128 + * irq_find_host() - Locates a domain for a given device node 129 + * @node: device-tree node of the interrupt controller 130 + */ 131 + struct irq_domain *irq_find_host(struct device_node *node) 132 + { 133 + struct irq_domain *h, *found = NULL; 134 + 135 + /* We might want to match the legacy controller last since 136 + * it might potentially be set to match all interrupts in 137 + * the absence of a device node. This isn't a problem so far 138 + * yet though... 139 + */ 140 + mutex_lock(&irq_domain_mutex); 141 + list_for_each_entry(h, &irq_domain_list, link) 142 + if (h->ops->match(h, node)) { 143 + found = h; 144 + break; 145 + } 146 + mutex_unlock(&irq_domain_mutex); 147 + return found; 148 + } 149 + EXPORT_SYMBOL_GPL(irq_find_host); 150 + 151 + /** 152 + * irq_set_default_host() - Set a "default" irq domain 153 + * @host: default host pointer 154 + * 155 + * For convenience, it's possible to set a "default" domain that will be used 156 + * whenever NULL is passed to irq_create_mapping(). It makes life easier for 157 + * platforms that want to manipulate a few hard coded interrupt numbers that 158 + * aren't properly represented in the device-tree. 159 + */ 160 + void irq_set_default_host(struct irq_domain *host) 161 + { 162 + pr_debug("irq: Default host set to @0x%p\n", host); 163 + 164 + irq_default_host = host; 165 + } 166 + 167 + /** 168 + * irq_set_virq_count() - Set the maximum number of linux irqs 169 + * @count: number of linux irqs, capped with NR_IRQS 170 + * 171 + * This is mainly for use by platforms like iSeries who want to program 172 + * the virtual irq number in the controller to avoid the reverse mapping 173 + */ 174 + void irq_set_virq_count(unsigned int count) 175 + { 176 + pr_debug("irq: Trying to set virq count to %d\n", count); 177 + 178 + BUG_ON(count < NUM_ISA_INTERRUPTS); 179 + if (count < NR_IRQS) 180 + irq_virq_count = count; 181 + } 182 + 183 + static int irq_setup_virq(struct irq_domain *host, unsigned int virq, 184 + irq_hw_number_t hwirq) 185 + { 186 + struct irq_data *irq_data = irq_get_irq_data(virq); 187 + 188 + irq_data->hwirq = hwirq; 189 + irq_data->domain = host; 190 + if (host->ops->map(host, virq, hwirq)) { 191 + pr_debug("irq: -> mapping failed, freeing\n"); 192 + irq_data->domain = NULL; 193 + irq_data->hwirq = 0; 194 + return -1; 195 + } 196 + 197 + irq_clear_status_flags(virq, IRQ_NOREQUEST); 198 + 199 + return 0; 200 + } 201 + 202 + /** 203 + * irq_create_direct_mapping() - Allocate an irq for direct mapping 204 + * @host: domain to allocate the irq for or NULL for default host 205 + * 206 + * This routine is used for irq controllers which can choose the hardware 207 + * interrupt numbers they generate. In such a case it's simplest to use 208 + * the linux irq as the hardware interrupt number. 209 + */ 210 + unsigned int irq_create_direct_mapping(struct irq_domain *host) 211 + { 212 + unsigned int virq; 213 + 214 + if (host == NULL) 215 + host = irq_default_host; 216 + 217 + BUG_ON(host == NULL); 218 + WARN_ON(host->revmap_type != IRQ_DOMAIN_MAP_NOMAP); 219 + 220 + virq = irq_alloc_desc_from(1, 0); 221 + if (virq == NO_IRQ) { 222 + pr_debug("irq: create_direct virq allocation failed\n"); 223 + return NO_IRQ; 224 + } 225 + if (virq >= irq_virq_count) { 226 + pr_err("ERROR: no free irqs available below %i maximum\n", 227 + irq_virq_count); 228 + irq_free_desc(virq); 229 + return 0; 230 + } 231 + 232 + pr_debug("irq: create_direct obtained virq %d\n", virq); 233 + 234 + if (irq_setup_virq(host, virq, virq)) { 235 + irq_free_desc(virq); 236 + return NO_IRQ; 237 + } 238 + 239 + return virq; 240 + } 241 + 242 + /** 243 + * irq_create_mapping() - Map a hardware interrupt into linux irq space 244 + * @host: host owning this hardware interrupt or NULL for default host 245 + * @hwirq: hardware irq number in that host space 246 + * 247 + * Only one mapping per hardware interrupt is permitted. Returns a linux 248 + * irq number. 249 + * If the sense/trigger is to be specified, set_irq_type() should be called 250 + * on the number returned from that call. 251 + */ 252 + unsigned int irq_create_mapping(struct irq_domain *host, 253 + irq_hw_number_t hwirq) 254 + { 255 + unsigned int virq, hint; 256 + 257 + pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", host, hwirq); 258 + 259 + /* Look for default host if nececssary */ 260 + if (host == NULL) 261 + host = irq_default_host; 262 + if (host == NULL) { 263 + printk(KERN_WARNING "irq_create_mapping called for" 264 + " NULL host, hwirq=%lx\n", hwirq); 265 + WARN_ON(1); 266 + return NO_IRQ; 267 + } 268 + pr_debug("irq: -> using host @%p\n", host); 269 + 270 + /* Check if mapping already exists */ 271 + virq = irq_find_mapping(host, hwirq); 272 + if (virq != NO_IRQ) { 273 + pr_debug("irq: -> existing mapping on virq %d\n", virq); 274 + return virq; 275 + } 276 + 277 + /* Get a virtual interrupt number */ 278 + if (host->revmap_type == IRQ_DOMAIN_MAP_LEGACY) { 279 + /* Handle legacy */ 280 + virq = (unsigned int)hwirq; 281 + if (virq == 0 || virq >= NUM_ISA_INTERRUPTS) 282 + return NO_IRQ; 283 + return virq; 284 + } else { 285 + /* Allocate a virtual interrupt number */ 286 + hint = hwirq % irq_virq_count; 287 + if (hint == 0) 288 + hint++; 289 + virq = irq_alloc_desc_from(hint, 0); 290 + if (!virq) 291 + virq = irq_alloc_desc_from(1, 0); 292 + if (virq == NO_IRQ) { 293 + pr_debug("irq: -> virq allocation failed\n"); 294 + return NO_IRQ; 295 + } 296 + } 297 + 298 + if (irq_setup_virq(host, virq, hwirq)) { 299 + if (host->revmap_type != IRQ_DOMAIN_MAP_LEGACY) 300 + irq_free_desc(virq); 301 + return NO_IRQ; 302 + } 303 + 304 + pr_debug("irq: irq %lu on host %s mapped to virtual irq %u\n", 305 + hwirq, host->of_node ? host->of_node->full_name : "null", virq); 306 + 307 + return virq; 308 + } 309 + EXPORT_SYMBOL_GPL(irq_create_mapping); 310 + 311 + unsigned int irq_create_of_mapping(struct device_node *controller, 312 + const u32 *intspec, unsigned int intsize) 313 + { 314 + struct irq_domain *host; 315 + irq_hw_number_t hwirq; 316 + unsigned int type = IRQ_TYPE_NONE; 317 + unsigned int virq; 318 + 319 + if (controller == NULL) 320 + host = irq_default_host; 321 + else 322 + host = irq_find_host(controller); 323 + if (host == NULL) { 324 + printk(KERN_WARNING "irq: no irq host found for %s !\n", 325 + controller->full_name); 326 + return NO_IRQ; 327 + } 328 + 329 + /* If host has no translation, then we assume interrupt line */ 330 + if (host->ops->xlate == NULL) 331 + hwirq = intspec[0]; 332 + else { 333 + if (host->ops->xlate(host, controller, intspec, intsize, 334 + &hwirq, &type)) 335 + return NO_IRQ; 336 + } 337 + 338 + /* Create mapping */ 339 + virq = irq_create_mapping(host, hwirq); 340 + if (virq == NO_IRQ) 341 + return virq; 342 + 343 + /* Set type if specified and different than the current one */ 344 + if (type != IRQ_TYPE_NONE && 345 + type != (irqd_get_trigger_type(irq_get_irq_data(virq)))) 346 + irq_set_irq_type(virq, type); 347 + return virq; 348 + } 349 + EXPORT_SYMBOL_GPL(irq_create_of_mapping); 350 + 351 + /** 352 + * irq_dispose_mapping() - Unmap an interrupt 353 + * @virq: linux irq number of the interrupt to unmap 354 + */ 355 + void irq_dispose_mapping(unsigned int virq) 356 + { 357 + struct irq_data *irq_data = irq_get_irq_data(virq); 358 + struct irq_domain *host; 359 + irq_hw_number_t hwirq; 360 + 361 + if (virq == NO_IRQ || !irq_data) 362 + return; 363 + 364 + host = irq_data->domain; 365 + if (WARN_ON(host == NULL)) 366 + return; 367 + 368 + /* Never unmap legacy interrupts */ 369 + if (host->revmap_type == IRQ_DOMAIN_MAP_LEGACY) 370 + return; 371 + 372 + irq_set_status_flags(virq, IRQ_NOREQUEST); 373 + 374 + /* remove chip and handler */ 375 + irq_set_chip_and_handler(virq, NULL, NULL); 376 + 377 + /* Make sure it's completed */ 378 + synchronize_irq(virq); 379 + 380 + /* Tell the PIC about it */ 381 + if (host->ops->unmap) 382 + host->ops->unmap(host, virq); 383 + smp_mb(); 384 + 385 + /* Clear reverse map */ 386 + hwirq = irq_data->hwirq; 387 + switch(host->revmap_type) { 388 + case IRQ_DOMAIN_MAP_LINEAR: 389 + if (hwirq < host->revmap_data.linear.size) 390 + host->revmap_data.linear.revmap[hwirq] = NO_IRQ; 391 + break; 392 + case IRQ_DOMAIN_MAP_TREE: 393 + mutex_lock(&revmap_trees_mutex); 394 + radix_tree_delete(&host->revmap_data.tree, hwirq); 395 + mutex_unlock(&revmap_trees_mutex); 396 + break; 397 + } 398 + 399 + /* Destroy map */ 400 + irq_data->hwirq = host->inval_irq; 401 + 402 + irq_free_desc(virq); 403 + } 404 + EXPORT_SYMBOL_GPL(irq_dispose_mapping); 405 + 406 + /** 407 + * irq_find_mapping() - Find a linux irq from an hw irq number. 408 + * @host: domain owning this hardware interrupt 409 + * @hwirq: hardware irq number in that host space 410 + * 411 + * This is a slow path, for use by generic code. It's expected that an 412 + * irq controller implementation directly calls the appropriate low level 413 + * mapping function. 414 + */ 415 + unsigned int irq_find_mapping(struct irq_domain *host, 416 + irq_hw_number_t hwirq) 417 + { 418 + unsigned int i; 419 + unsigned int hint = hwirq % irq_virq_count; 420 + 421 + /* Look for default host if nececssary */ 422 + if (host == NULL) 423 + host = irq_default_host; 424 + if (host == NULL) 425 + return NO_IRQ; 426 + 427 + /* legacy -> bail early */ 428 + if (host->revmap_type == IRQ_DOMAIN_MAP_LEGACY) 429 + return hwirq; 430 + 431 + /* Slow path does a linear search of the map */ 432 + if (hint == 0) 433 + hint = 1; 434 + i = hint; 435 + do { 436 + struct irq_data *data = irq_get_irq_data(i); 437 + if (data && (data->domain == host) && (data->hwirq == hwirq)) 438 + return i; 439 + i++; 440 + if (i >= irq_virq_count) 441 + i = 1; 442 + } while(i != hint); 443 + return NO_IRQ; 444 + } 445 + EXPORT_SYMBOL_GPL(irq_find_mapping); 446 + 447 + /** 448 + * irq_radix_revmap_lookup() - Find a linux irq from a hw irq number. 449 + * @host: host owning this hardware interrupt 450 + * @hwirq: hardware irq number in that host space 451 + * 452 + * This is a fast path, for use by irq controller code that uses radix tree 453 + * revmaps 454 + */ 455 + unsigned int irq_radix_revmap_lookup(struct irq_domain *host, 456 + irq_hw_number_t hwirq) 457 + { 458 + struct irq_data *irq_data; 459 + 460 + if (WARN_ON_ONCE(host->revmap_type != IRQ_DOMAIN_MAP_TREE)) 461 + return irq_find_mapping(host, hwirq); 462 + 463 + /* 464 + * Freeing an irq can delete nodes along the path to 465 + * do the lookup via call_rcu. 466 + */ 467 + rcu_read_lock(); 468 + irq_data = radix_tree_lookup(&host->revmap_data.tree, hwirq); 469 + rcu_read_unlock(); 470 + 471 + /* 472 + * If found in radix tree, then fine. 473 + * Else fallback to linear lookup - this should not happen in practice 474 + * as it means that we failed to insert the node in the radix tree. 475 + */ 476 + return irq_data ? irq_data->irq : irq_find_mapping(host, hwirq); 477 + } 478 + 479 + /** 480 + * irq_radix_revmap_insert() - Insert a hw irq to linux irq number mapping. 481 + * @host: host owning this hardware interrupt 482 + * @virq: linux irq number 483 + * @hwirq: hardware irq number in that host space 484 + * 485 + * This is for use by irq controllers that use a radix tree reverse 486 + * mapping for fast lookup. 487 + */ 488 + void irq_radix_revmap_insert(struct irq_domain *host, unsigned int virq, 489 + irq_hw_number_t hwirq) 490 + { 491 + struct irq_data *irq_data = irq_get_irq_data(virq); 492 + 493 + if (WARN_ON(host->revmap_type != IRQ_DOMAIN_MAP_TREE)) 494 + return; 495 + 496 + if (virq != NO_IRQ) { 497 + mutex_lock(&revmap_trees_mutex); 498 + radix_tree_insert(&host->revmap_data.tree, hwirq, irq_data); 499 + mutex_unlock(&revmap_trees_mutex); 500 + } 501 + } 502 + 503 + /** 504 + * irq_linear_revmap() - Find a linux irq from a hw irq number. 505 + * @host: host owning this hardware interrupt 506 + * @hwirq: hardware irq number in that host space 507 + * 508 + * This is a fast path, for use by irq controller code that uses linear 509 + * revmaps. It does fallback to the slow path if the revmap doesn't exist 510 + * yet and will create the revmap entry with appropriate locking 511 + */ 512 + unsigned int irq_linear_revmap(struct irq_domain *host, 513 + irq_hw_number_t hwirq) 514 + { 515 + unsigned int *revmap; 516 + 517 + if (WARN_ON_ONCE(host->revmap_type != IRQ_DOMAIN_MAP_LINEAR)) 518 + return irq_find_mapping(host, hwirq); 519 + 520 + /* Check revmap bounds */ 521 + if (unlikely(hwirq >= host->revmap_data.linear.size)) 522 + return irq_find_mapping(host, hwirq); 523 + 524 + /* Check if revmap was allocated */ 525 + revmap = host->revmap_data.linear.revmap; 526 + if (unlikely(revmap == NULL)) 527 + return irq_find_mapping(host, hwirq); 528 + 529 + /* Fill up revmap with slow path if no mapping found */ 530 + if (unlikely(revmap[hwirq] == NO_IRQ)) 531 + revmap[hwirq] = irq_find_mapping(host, hwirq); 532 + 533 + return revmap[hwirq]; 534 + } 535 + 536 + #ifdef CONFIG_VIRQ_DEBUG 537 + static int virq_debug_show(struct seq_file *m, void *private) 538 + { 539 + unsigned long flags; 540 + struct irq_desc *desc; 541 + const char *p; 542 + static const char none[] = "none"; 543 + void *data; 544 + int i; 545 + 546 + seq_printf(m, "%-5s %-7s %-15s %-18s %s\n", "virq", "hwirq", 547 + "chip name", "chip data", "host name"); 548 + 549 + for (i = 1; i < nr_irqs; i++) { 550 + desc = irq_to_desc(i); 551 + if (!desc) 552 + continue; 553 + 554 + raw_spin_lock_irqsave(&desc->lock, flags); 555 + 556 + if (desc->action && desc->action->handler) { 557 + struct irq_chip *chip; 558 + 559 + seq_printf(m, "%5d ", i); 560 + seq_printf(m, "0x%05lx ", desc->irq_data.hwirq); 561 + 562 + chip = irq_desc_get_chip(desc); 563 + if (chip && chip->name) 564 + p = chip->name; 565 + else 566 + p = none; 567 + seq_printf(m, "%-15s ", p); 568 + 569 + data = irq_desc_get_chip_data(desc); 570 + seq_printf(m, "0x%16p ", data); 571 + 572 + if (desc->irq_data.domain->of_node) 573 + p = desc->irq_data.domain->of_node->full_name; 574 + else 575 + p = none; 576 + seq_printf(m, "%s\n", p); 577 + } 578 + 579 + raw_spin_unlock_irqrestore(&desc->lock, flags); 580 + } 581 + 582 + return 0; 583 + } 584 + 585 + static int virq_debug_open(struct inode *inode, struct file *file) 586 + { 587 + return single_open(file, virq_debug_show, inode->i_private); 588 + } 589 + 590 + static const struct file_operations virq_debug_fops = { 591 + .open = virq_debug_open, 592 + .read = seq_read, 593 + .llseek = seq_lseek, 594 + .release = single_release, 595 + }; 596 + 597 + static int __init irq_debugfs_init(void) 598 + { 599 + if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root, 600 + NULL, &virq_debug_fops) == NULL) 601 + return -ENOMEM; 602 + 603 + return 0; 604 + } 605 + __initcall(irq_debugfs_init); 606 + #endif /* CONFIG_VIRQ_DEBUG */ 607 + 608 + #else /* CONFIG_PPC */ 11 609 12 610 /** 13 611 * irq_domain_add() - Register an irq_domain ··· 783 185 #endif /* CONFIG_OF_IRQ */ 784 186 }; 785 187 EXPORT_SYMBOL_GPL(irq_domain_simple_ops); 188 + 189 + #endif /* !CONFIG_PPC */