aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq
diff options
context:
space:
mode:
authorJiang Liu <jiang.liu@linux.intel.com>2014-11-06 09:20:14 -0500
committerThomas Gleixner <tglx@linutronix.de>2014-11-23 07:01:45 -0500
commitf8264e34965aaf43203912ed8f7b543c00c8d70f (patch)
tree1b037da27ec42cd9a2120f0f6dfb645731fb89ec /kernel/irq
parentd31eb342409b24e3d2e1989c775f3361e93acc08 (diff)
irqdomain: Introduce new interfaces to support hierarchy irqdomains
We plan to use hierarchy irqdomain to suppport CPU vector assignment, interrupt remapping controller, IO-APIC controller, MSI interrupt and hypertransport interrupt etc on x86 platforms. So extend irqdomain interfaces to support hierarchy irqdomain. There are already many clients of current irqdomain interfaces. To minimize the changes, we choose to introduce new version 2 interfaces to support hierarchy instead of extending existing irqdomain interfaces. According to Thomas's suggestion, the most important design decision is to build hierarchy struct irq_data to support hierarchy irqdomain, so hierarchy irqdomain related data could be saved in struct irq_data. With support of hierarchy irq_data, we could also support stacked irq_chips. This is most useful in case of set_affinity(). The new hierarchy irqdomain introduces following interfaces: 1) irq_domain_alloc_irqs()/irq_domain_free_irqs(): allocate/release IRQ and related resources. 2) __irq_domain_alloc_irqs(): a special version to support legacy IRQs. 3) irq_domain_activate_irq()/irq_domain_deactivate_irq(): program interrupt controllers to activate/deactivate interrupt. There are also several help functions to ease irqdomain implemenations: 1) irq_domain_get_irq_data(): get irq_data associated with a specific irqdomain. 2) irq_domain_set_hwirq_and_chip(): save irqdomain specific data into irq_data. 3) irq_domain_alloc_irqs_parent()/irq_domain_free_irqs_parent(): invoke parent irqdomain's alloc/free callbacks. We also changed irq_startup()/irq_shutdown() to invoke irq_domain_activate_irq()/irq_domain_deactivate_irq() to program interrupt controller when start/stop interrupts. [ tglx: Folded parts of the later patch series in ] Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com> Cc: Bjorn Helgaas <bhelgaas@google.com> Cc: Grant Likely <grant.likely@linaro.org> Cc: Marc Zyngier <marc.zyngier@arm.com> Cc: Yingjoe Chen <yingjoe.chen@mediatek.com> Cc: Yijing Wang <wangyijing@huawei.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/irq')
-rw-r--r--kernel/irq/Kconfig5
-rw-r--r--kernel/irq/chip.c3
-rw-r--r--kernel/irq/irqdomain.c415
3 files changed, 407 insertions, 16 deletions
diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig
index 225086b2652e..4f2eb2b1f23b 100644
--- a/kernel/irq/Kconfig
+++ b/kernel/irq/Kconfig
@@ -55,6 +55,11 @@ config GENERIC_IRQ_CHIP
55config IRQ_DOMAIN 55config IRQ_DOMAIN
56 bool 56 bool
57 57
58# Support for hierarchical irq domains
59config IRQ_DOMAIN_HIERARCHY
60 bool
61 select IRQ_DOMAIN
62
58config HANDLE_DOMAIN_IRQ 63config HANDLE_DOMAIN_IRQ
59 bool 64 bool
60 65
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index e5202f00cabc..72a93086216b 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -15,6 +15,7 @@
15#include <linux/module.h> 15#include <linux/module.h>
16#include <linux/interrupt.h> 16#include <linux/interrupt.h>
17#include <linux/kernel_stat.h> 17#include <linux/kernel_stat.h>
18#include <linux/irqdomain.h>
18 19
19#include <trace/events/irq.h> 20#include <trace/events/irq.h>
20 21
@@ -178,6 +179,7 @@ int irq_startup(struct irq_desc *desc, bool resend)
178 irq_state_clr_disabled(desc); 179 irq_state_clr_disabled(desc);
179 desc->depth = 0; 180 desc->depth = 0;
180 181
182 irq_domain_activate_irq(&desc->irq_data);
181 if (desc->irq_data.chip->irq_startup) { 183 if (desc->irq_data.chip->irq_startup) {
182 ret = desc->irq_data.chip->irq_startup(&desc->irq_data); 184 ret = desc->irq_data.chip->irq_startup(&desc->irq_data);
183 irq_state_clr_masked(desc); 185 irq_state_clr_masked(desc);
@@ -199,6 +201,7 @@ void irq_shutdown(struct irq_desc *desc)
199 desc->irq_data.chip->irq_disable(&desc->irq_data); 201 desc->irq_data.chip->irq_disable(&desc->irq_data);
200 else 202 else
201 desc->irq_data.chip->irq_mask(&desc->irq_data); 203 desc->irq_data.chip->irq_mask(&desc->irq_data);
204 irq_domain_deactivate_irq(&desc->irq_data);
202 irq_state_set_masked(desc); 205 irq_state_set_masked(desc);
203} 206}
204 207
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 6534ff6ce02e..43f3be6fac70 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -23,6 +23,10 @@ static DEFINE_MUTEX(irq_domain_mutex);
23static DEFINE_MUTEX(revmap_trees_mutex); 23static DEFINE_MUTEX(revmap_trees_mutex);
24static struct irq_domain *irq_default_domain; 24static struct irq_domain *irq_default_domain;
25 25
26static int irq_domain_alloc_descs(int virq, unsigned int nr_irqs,
27 irq_hw_number_t hwirq, int node);
28static void irq_domain_check_hierarchy(struct irq_domain *domain);
29
26/** 30/**
27 * __irq_domain_add() - Allocate a new irq_domain data structure 31 * __irq_domain_add() - Allocate a new irq_domain data structure
28 * @of_node: optional device-tree node of the interrupt controller 32 * @of_node: optional device-tree node of the interrupt controller
@@ -30,7 +34,7 @@ static struct irq_domain *irq_default_domain;
30 * @hwirq_max: Maximum number of interrupts supported by controller 34 * @hwirq_max: Maximum number of interrupts supported by controller
31 * @direct_max: Maximum value of direct maps; Use ~0 for no limit; 0 for no 35 * @direct_max: Maximum value of direct maps; Use ~0 for no limit; 0 for no
32 * direct mapping 36 * direct mapping
33 * @ops: map/unmap domain callbacks 37 * @ops: domain callbacks
34 * @host_data: Controller private data pointer 38 * @host_data: Controller private data pointer
35 * 39 *
36 * Allocates and initialize and irq_domain structure. 40 * Allocates and initialize and irq_domain structure.
@@ -56,6 +60,7 @@ struct irq_domain *__irq_domain_add(struct device_node *of_node, int size,
56 domain->hwirq_max = hwirq_max; 60 domain->hwirq_max = hwirq_max;
57 domain->revmap_size = size; 61 domain->revmap_size = size;
58 domain->revmap_direct_max_irq = direct_max; 62 domain->revmap_direct_max_irq = direct_max;
63 irq_domain_check_hierarchy(domain);
59 64
60 mutex_lock(&irq_domain_mutex); 65 mutex_lock(&irq_domain_mutex);
61 list_add(&domain->link, &irq_domain_list); 66 list_add(&domain->link, &irq_domain_list);
@@ -109,7 +114,7 @@ EXPORT_SYMBOL_GPL(irq_domain_remove);
109 * @first_irq: first number of irq block assigned to the domain, 114 * @first_irq: first number of irq block assigned to the domain,
110 * pass zero to assign irqs on-the-fly. If first_irq is non-zero, then 115 * pass zero to assign irqs on-the-fly. If first_irq is non-zero, then
111 * pre-map all of the irqs in the domain to virqs starting at first_irq. 116 * pre-map all of the irqs in the domain to virqs starting at first_irq.
112 * @ops: map/unmap domain callbacks 117 * @ops: domain callbacks
113 * @host_data: Controller private data pointer 118 * @host_data: Controller private data pointer
114 * 119 *
115 * Allocates an irq_domain, and optionally if first_irq is positive then also 120 * Allocates an irq_domain, and optionally if first_irq is positive then also
@@ -174,10 +179,8 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
174 179
175 domain = __irq_domain_add(of_node, first_hwirq + size, 180 domain = __irq_domain_add(of_node, first_hwirq + size,
176 first_hwirq + size, 0, ops, host_data); 181 first_hwirq + size, 0, ops, host_data);
177 if (!domain) 182 if (domain)
178 return NULL; 183 irq_domain_associate_many(domain, first_irq, first_hwirq, size);
179
180 irq_domain_associate_many(domain, first_irq, first_hwirq, size);
181 184
182 return domain; 185 return domain;
183} 186}
@@ -388,7 +391,6 @@ EXPORT_SYMBOL_GPL(irq_create_direct_mapping);
388unsigned int irq_create_mapping(struct irq_domain *domain, 391unsigned int irq_create_mapping(struct irq_domain *domain,
389 irq_hw_number_t hwirq) 392 irq_hw_number_t hwirq)
390{ 393{
391 unsigned int hint;
392 int virq; 394 int virq;
393 395
394 pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq); 396 pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);
@@ -410,12 +412,8 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
410 } 412 }
411 413
412 /* Allocate a virtual interrupt number */ 414 /* Allocate a virtual interrupt number */
413 hint = hwirq % nr_irqs; 415 virq = irq_domain_alloc_descs(-1, 1, hwirq,
414 if (hint == 0) 416 of_node_to_nid(domain->of_node));
415 hint++;
416 virq = irq_alloc_desc_from(hint, of_node_to_nid(domain->of_node));
417 if (virq <= 0)
418 virq = irq_alloc_desc_from(1, of_node_to_nid(domain->of_node));
419 if (virq <= 0) { 417 if (virq <= 0) {
420 pr_debug("-> virq allocation failed\n"); 418 pr_debug("-> virq allocation failed\n");
421 return 0; 419 return 0;
@@ -471,7 +469,7 @@ unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data)
471 struct irq_domain *domain; 469 struct irq_domain *domain;
472 irq_hw_number_t hwirq; 470 irq_hw_number_t hwirq;
473 unsigned int type = IRQ_TYPE_NONE; 471 unsigned int type = IRQ_TYPE_NONE;
474 unsigned int virq; 472 int virq;
475 473
476 domain = irq_data->np ? irq_find_host(irq_data->np) : irq_default_domain; 474 domain = irq_data->np ? irq_find_host(irq_data->np) : irq_default_domain;
477 if (!domain) { 475 if (!domain) {
@@ -480,6 +478,11 @@ unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data)
480 return 0; 478 return 0;
481 } 479 }
482 480
481 if (irq_domain_is_hierarchy(domain)) {
482 virq = irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, irq_data);
483 return virq <= 0 ? 0 : virq;
484 }
485
483 /* If domain has no translation, then we assume interrupt line */ 486 /* If domain has no translation, then we assume interrupt line */
484 if (domain->ops->xlate == NULL) 487 if (domain->ops->xlate == NULL)
485 hwirq = irq_data->args[0]; 488 hwirq = irq_data->args[0];
@@ -540,8 +543,8 @@ unsigned int irq_find_mapping(struct irq_domain *domain,
540 return 0; 543 return 0;
541 544
542 if (hwirq < domain->revmap_direct_max_irq) { 545 if (hwirq < domain->revmap_direct_max_irq) {
543 data = irq_get_irq_data(hwirq); 546 data = irq_domain_get_irq_data(domain, hwirq);
544 if (data && (data->domain == domain) && (data->hwirq == hwirq)) 547 if (data && data->hwirq == hwirq)
545 return hwirq; 548 return hwirq;
546 } 549 }
547 550
@@ -709,3 +712,383 @@ const struct irq_domain_ops irq_domain_simple_ops = {
709 .xlate = irq_domain_xlate_onetwocell, 712 .xlate = irq_domain_xlate_onetwocell,
710}; 713};
711EXPORT_SYMBOL_GPL(irq_domain_simple_ops); 714EXPORT_SYMBOL_GPL(irq_domain_simple_ops);
715
716static int irq_domain_alloc_descs(int virq, unsigned int cnt,
717 irq_hw_number_t hwirq, int node)
718{
719 unsigned int hint;
720
721 if (virq >= 0) {
722 virq = irq_alloc_descs(virq, virq, cnt, node);
723 } else {
724 hint = hwirq % nr_irqs;
725 if (hint == 0)
726 hint++;
727 virq = irq_alloc_descs_from(hint, cnt, node);
728 if (virq <= 0 && hint > 1)
729 virq = irq_alloc_descs_from(1, cnt, node);
730 }
731
732 return virq;
733}
734
735#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
736static void irq_domain_insert_irq(int virq)
737{
738 struct irq_data *data;
739
740 for (data = irq_get_irq_data(virq); data; data = data->parent_data) {
741 struct irq_domain *domain = data->domain;
742 irq_hw_number_t hwirq = data->hwirq;
743
744 if (hwirq < domain->revmap_size) {
745 domain->linear_revmap[hwirq] = virq;
746 } else {
747 mutex_lock(&revmap_trees_mutex);
748 radix_tree_insert(&domain->revmap_tree, hwirq, data);
749 mutex_unlock(&revmap_trees_mutex);
750 }
751
752 /* If not already assigned, give the domain the chip's name */
753 if (!domain->name && data->chip)
754 domain->name = data->chip->name;
755 }
756
757 irq_clear_status_flags(virq, IRQ_NOREQUEST);
758}
759
760static void irq_domain_remove_irq(int virq)
761{
762 struct irq_data *data;
763
764 irq_set_status_flags(virq, IRQ_NOREQUEST);
765 irq_set_chip_and_handler(virq, NULL, NULL);
766 synchronize_irq(virq);
767 smp_mb();
768
769 for (data = irq_get_irq_data(virq); data; data = data->parent_data) {
770 struct irq_domain *domain = data->domain;
771 irq_hw_number_t hwirq = data->hwirq;
772
773 if (hwirq < domain->revmap_size) {
774 domain->linear_revmap[hwirq] = 0;
775 } else {
776 mutex_lock(&revmap_trees_mutex);
777 radix_tree_delete(&domain->revmap_tree, hwirq);
778 mutex_unlock(&revmap_trees_mutex);
779 }
780 }
781}
782
783static struct irq_data *irq_domain_insert_irq_data(struct irq_domain *domain,
784 struct irq_data *child)
785{
786 struct irq_data *irq_data;
787
788 irq_data = kzalloc_node(sizeof(*irq_data), GFP_KERNEL, child->node);
789 if (irq_data) {
790 child->parent_data = irq_data;
791 irq_data->irq = child->irq;
792 irq_data->node = child->node;
793 irq_data->domain = domain;
794 }
795
796 return irq_data;
797}
798
799static void irq_domain_free_irq_data(unsigned int virq, unsigned int nr_irqs)
800{
801 struct irq_data *irq_data, *tmp;
802 int i;
803
804 for (i = 0; i < nr_irqs; i++) {
805 irq_data = irq_get_irq_data(virq + i);
806 tmp = irq_data->parent_data;
807 irq_data->parent_data = NULL;
808 irq_data->domain = NULL;
809
810 while (tmp) {
811 irq_data = tmp;
812 tmp = tmp->parent_data;
813 kfree(irq_data);
814 }
815 }
816}
817
818static int irq_domain_alloc_irq_data(struct irq_domain *domain,
819 unsigned int virq, unsigned int nr_irqs)
820{
821 struct irq_data *irq_data;
822 struct irq_domain *parent;
823 int i;
824
825 /* The outermost irq_data is embedded in struct irq_desc */
826 for (i = 0; i < nr_irqs; i++) {
827 irq_data = irq_get_irq_data(virq + i);
828 irq_data->domain = domain;
829
830 for (parent = domain->parent; parent; parent = parent->parent) {
831 irq_data = irq_domain_insert_irq_data(parent, irq_data);
832 if (!irq_data) {
833 irq_domain_free_irq_data(virq, i + 1);
834 return -ENOMEM;
835 }
836 }
837 }
838
839 return 0;
840}
841
842/**
843 * irq_domain_get_irq_data - Get irq_data associated with @virq and @domain
844 * @domain: domain to match
845 * @virq: IRQ number to get irq_data
846 */
847struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain,
848 unsigned int virq)
849{
850 struct irq_data *irq_data;
851
852 for (irq_data = irq_get_irq_data(virq); irq_data;
853 irq_data = irq_data->parent_data)
854 if (irq_data->domain == domain)
855 return irq_data;
856
857 return NULL;
858}
859
860/**
861 * irq_domain_set_hwirq_and_chip - Set hwirq and irqchip of @virq at @domain
862 * @domain: Interrupt domain to match
863 * @virq: IRQ number
864 * @hwirq: The hwirq number
865 * @chip: The associated interrupt chip
866 * @chip_data: The associated chip data
867 */
868int irq_domain_set_hwirq_and_chip(struct irq_domain *domain, unsigned int virq,
869 irq_hw_number_t hwirq, struct irq_chip *chip,
870 void *chip_data)
871{
872 struct irq_data *irq_data = irq_domain_get_irq_data(domain, virq);
873
874 if (!irq_data)
875 return -ENOENT;
876
877 irq_data->hwirq = hwirq;
878 irq_data->chip = chip ? chip : &no_irq_chip;
879 irq_data->chip_data = chip_data;
880
881 return 0;
882}
883
884/**
885 * irq_domain_reset_irq_data - Clear hwirq, chip and chip_data in @irq_data
886 * @irq_data: The pointer to irq_data
887 */
888void irq_domain_reset_irq_data(struct irq_data *irq_data)
889{
890 irq_data->hwirq = 0;
891 irq_data->chip = &no_irq_chip;
892 irq_data->chip_data = NULL;
893}
894
895/**
896 * irq_domain_free_irqs_common - Clear irq_data and free the parent
897 * @domain: Interrupt domain to match
898 * @virq: IRQ number to start with
899 * @nr_irqs: The number of irqs to free
900 */
901void irq_domain_free_irqs_common(struct irq_domain *domain, unsigned int virq,
902 unsigned int nr_irqs)
903{
904 struct irq_data *irq_data;
905 int i;
906
907 for (i = 0; i < nr_irqs; i++) {
908 irq_data = irq_domain_get_irq_data(domain, virq + i);
909 if (irq_data)
910 irq_domain_reset_irq_data(irq_data);
911 }
912 irq_domain_free_irqs_parent(domain, virq, nr_irqs);
913}
914
915/**
916 * irq_domain_free_irqs_top - Clear handler and handler data, clear irqdata and free parent
917 * @domain: Interrupt domain to match
918 * @virq: IRQ number to start with
919 * @nr_irqs: The number of irqs to free
920 */
921void irq_domain_free_irqs_top(struct irq_domain *domain, unsigned int virq,
922 unsigned int nr_irqs)
923{
924 int i;
925
926 for (i = 0; i < nr_irqs; i++) {
927 irq_set_handler_data(virq + i, NULL);
928 irq_set_handler(virq + i, NULL);
929 }
930 irq_domain_free_irqs_common(domain, virq, nr_irqs);
931}
932
933/**
934 * __irq_domain_alloc_irqs - Allocate IRQs from domain
935 * @domain: domain to allocate from
936 * @irq_base: allocate specified IRQ nubmer if irq_base >= 0
937 * @nr_irqs: number of IRQs to allocate
938 * @node: NUMA node id for memory allocation
939 * @arg: domain specific argument
940 * @realloc: IRQ descriptors have already been allocated if true
941 *
942 * Allocate IRQ numbers and initialized all data structures to support
943 * hierarchy IRQ domains.
944 * Parameter @realloc is mainly to support legacy IRQs.
945 * Returns error code or allocated IRQ number
946 *
947 * The whole process to setup an IRQ has been split into two steps.
948 * The first step, __irq_domain_alloc_irqs(), is to allocate IRQ
949 * descriptor and required hardware resources. The second step,
950 * irq_domain_activate_irq(), is to program hardwares with preallocated
951 * resources. In this way, it's easier to rollback when failing to
952 * allocate resources.
953 */
954int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
955 unsigned int nr_irqs, int node, void *arg,
956 bool realloc)
957{
958 int i, ret, virq;
959
960 if (domain == NULL) {
961 domain = irq_default_domain;
962 if (WARN(!domain, "domain is NULL; cannot allocate IRQ\n"))
963 return -EINVAL;
964 }
965
966 if (!domain->ops->alloc) {
967 pr_debug("domain->ops->alloc() is NULL\n");
968 return -ENOSYS;
969 }
970
971 if (realloc && irq_base >= 0) {
972 virq = irq_base;
973 } else {
974 virq = irq_domain_alloc_descs(irq_base, nr_irqs, 0, node);
975 if (virq < 0) {
976 pr_debug("cannot allocate IRQ(base %d, count %d)\n",
977 irq_base, nr_irqs);
978 return virq;
979 }
980 }
981
982 if (irq_domain_alloc_irq_data(domain, virq, nr_irqs)) {
983 pr_debug("cannot allocate memory for IRQ%d\n", virq);
984 ret = -ENOMEM;
985 goto out_free_desc;
986 }
987
988 mutex_lock(&irq_domain_mutex);
989 ret = domain->ops->alloc(domain, virq, nr_irqs, arg);
990 if (ret < 0) {
991 mutex_unlock(&irq_domain_mutex);
992 goto out_free_irq_data;
993 }
994 for (i = 0; i < nr_irqs; i++)
995 irq_domain_insert_irq(virq + i);
996 mutex_unlock(&irq_domain_mutex);
997
998 return virq;
999
1000out_free_irq_data:
1001 irq_domain_free_irq_data(virq, nr_irqs);
1002out_free_desc:
1003 irq_free_descs(virq, nr_irqs);
1004 return ret;
1005}
1006
1007/**
1008 * irq_domain_free_irqs - Free IRQ number and associated data structures
1009 * @virq: base IRQ number
1010 * @nr_irqs: number of IRQs to free
1011 */
1012void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs)
1013{
1014 struct irq_data *data = irq_get_irq_data(virq);
1015 int i;
1016
1017 if (WARN(!data || !data->domain || !data->domain->ops->free,
1018 "NULL pointer, cannot free irq\n"))
1019 return;
1020
1021 mutex_lock(&irq_domain_mutex);
1022 for (i = 0; i < nr_irqs; i++)
1023 irq_domain_remove_irq(virq + i);
1024 data->domain->ops->free(data->domain, virq, nr_irqs);
1025 mutex_unlock(&irq_domain_mutex);
1026
1027 irq_domain_free_irq_data(virq, nr_irqs);
1028 irq_free_descs(virq, nr_irqs);
1029}
1030
1031/**
1032 * irq_domain_activate_irq - Call domain_ops->activate recursively to activate
1033 * interrupt
1034 * @irq_data: outermost irq_data associated with interrupt
1035 *
1036 * This is the second step to call domain_ops->activate to program interrupt
1037 * controllers, so the interrupt could actually get delivered.
1038 */
1039void irq_domain_activate_irq(struct irq_data *irq_data)
1040{
1041 if (irq_data && irq_data->domain) {
1042 struct irq_domain *domain = irq_data->domain;
1043
1044 if (irq_data->parent_data)
1045 irq_domain_activate_irq(irq_data->parent_data);
1046 if (domain->ops->activate)
1047 domain->ops->activate(domain, irq_data);
1048 }
1049}
1050
1051/**
1052 * irq_domain_deactivate_irq - Call domain_ops->deactivate recursively to
1053 * deactivate interrupt
1054 * @irq_data: outermost irq_data associated with interrupt
1055 *
1056 * It calls domain_ops->deactivate to program interrupt controllers to disable
1057 * interrupt delivery.
1058 */
1059void irq_domain_deactivate_irq(struct irq_data *irq_data)
1060{
1061 if (irq_data && irq_data->domain) {
1062 struct irq_domain *domain = irq_data->domain;
1063
1064 if (domain->ops->deactivate)
1065 domain->ops->deactivate(domain, irq_data);
1066 if (irq_data->parent_data)
1067 irq_domain_deactivate_irq(irq_data->parent_data);
1068 }
1069}
1070
1071static void irq_domain_check_hierarchy(struct irq_domain *domain)
1072{
1073 /* Hierarchy irq_domains must implement callback alloc() */
1074 if (domain->ops->alloc)
1075 domain->flags |= IRQ_DOMAIN_FLAG_HIERARCHY;
1076}
1077#else /* CONFIG_IRQ_DOMAIN_HIERARCHY */
1078/**
1079 * irq_domain_get_irq_data - Get irq_data associated with @virq and @domain
1080 * @domain: domain to match
1081 * @virq: IRQ number to get irq_data
1082 */
1083struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain,
1084 unsigned int virq)
1085{
1086 struct irq_data *irq_data = irq_get_irq_data(virq);
1087
1088 return (irq_data && irq_data->domain == domain) ? irq_data : NULL;
1089}
1090
1091static void irq_domain_check_hierarchy(struct irq_domain *domain)
1092{
1093}
1094#endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */