diff options
author | Jiang Liu <jiang.liu@linux.intel.com> | 2014-11-15 09:24:01 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2014-11-23 07:01:46 -0500 |
commit | 36d727310cb9f85efb5ac089ffb1797e7c3538e1 (patch) | |
tree | e58639a6b10598f89db6adc66b03145ab1841f45 /kernel/irq | |
parent | 1b5377087cb4e68d719a875120894fddfbcbf0f9 (diff) |
irqdomain: Implement a method to automatically call parent domains alloc/free
Add a flags to irq_domain.flags to control whether the irqdomain core
should automatically call parent irqdomain's alloc/free callbacks. It
help to reduce hierarchy irqdomains users' code size.
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Grant Likely <grant.likely@linaro.org>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Yijing Wang <wangyijing@huawei.com>
Cc: Yingjoe Chen <yingjoe.chen@mediatek.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Matthias Brugger <matthias.bgg@gmail.com>
Link: http://lkml.kernel.org/r/1416061447-9472-4-git-send-email-jiang.liu@linux.intel.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/irq')
-rw-r--r-- | kernel/irq/irqdomain.c | 82 |
1 files changed, 80 insertions, 2 deletions
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 4e62832ace82..9c88db7056d4 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c | |||
@@ -960,6 +960,43 @@ void irq_domain_free_irqs_top(struct irq_domain *domain, unsigned int virq, | |||
960 | irq_domain_free_irqs_common(domain, virq, nr_irqs); | 960 | irq_domain_free_irqs_common(domain, virq, nr_irqs); |
961 | } | 961 | } |
962 | 962 | ||
963 | static bool irq_domain_is_auto_recursive(struct irq_domain *domain) | ||
964 | { | ||
965 | return domain->flags & IRQ_DOMAIN_FLAG_AUTO_RECURSIVE; | ||
966 | } | ||
967 | |||
968 | static void irq_domain_free_irqs_recursive(struct irq_domain *domain, | ||
969 | unsigned int irq_base, | ||
970 | unsigned int nr_irqs) | ||
971 | { | ||
972 | domain->ops->free(domain, irq_base, nr_irqs); | ||
973 | if (irq_domain_is_auto_recursive(domain)) { | ||
974 | BUG_ON(!domain->parent); | ||
975 | irq_domain_free_irqs_recursive(domain->parent, irq_base, | ||
976 | nr_irqs); | ||
977 | } | ||
978 | } | ||
979 | |||
980 | static int irq_domain_alloc_irqs_recursive(struct irq_domain *domain, | ||
981 | unsigned int irq_base, | ||
982 | unsigned int nr_irqs, void *arg) | ||
983 | { | ||
984 | int ret = 0; | ||
985 | struct irq_domain *parent = domain->parent; | ||
986 | bool recursive = irq_domain_is_auto_recursive(domain); | ||
987 | |||
988 | BUG_ON(recursive && !parent); | ||
989 | if (recursive) | ||
990 | ret = irq_domain_alloc_irqs_recursive(parent, irq_base, | ||
991 | nr_irqs, arg); | ||
992 | if (ret >= 0) | ||
993 | ret = domain->ops->alloc(domain, irq_base, nr_irqs, arg); | ||
994 | if (ret < 0 && recursive) | ||
995 | irq_domain_free_irqs_recursive(parent, irq_base, nr_irqs); | ||
996 | |||
997 | return ret; | ||
998 | } | ||
999 | |||
963 | /** | 1000 | /** |
964 | * __irq_domain_alloc_irqs - Allocate IRQs from domain | 1001 | * __irq_domain_alloc_irqs - Allocate IRQs from domain |
965 | * @domain: domain to allocate from | 1002 | * @domain: domain to allocate from |
@@ -1016,7 +1053,7 @@ int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base, | |||
1016 | } | 1053 | } |
1017 | 1054 | ||
1018 | mutex_lock(&irq_domain_mutex); | 1055 | mutex_lock(&irq_domain_mutex); |
1019 | ret = domain->ops->alloc(domain, virq, nr_irqs, arg); | 1056 | ret = irq_domain_alloc_irqs_recursive(domain, virq, nr_irqs, arg); |
1020 | if (ret < 0) { | 1057 | if (ret < 0) { |
1021 | mutex_unlock(&irq_domain_mutex); | 1058 | mutex_unlock(&irq_domain_mutex); |
1022 | goto out_free_irq_data; | 1059 | goto out_free_irq_data; |
@@ -1051,7 +1088,7 @@ void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs) | |||
1051 | mutex_lock(&irq_domain_mutex); | 1088 | mutex_lock(&irq_domain_mutex); |
1052 | for (i = 0; i < nr_irqs; i++) | 1089 | for (i = 0; i < nr_irqs; i++) |
1053 | irq_domain_remove_irq(virq + i); | 1090 | irq_domain_remove_irq(virq + i); |
1054 | data->domain->ops->free(data->domain, virq, nr_irqs); | 1091 | irq_domain_free_irqs_recursive(data->domain, virq, nr_irqs); |
1055 | mutex_unlock(&irq_domain_mutex); | 1092 | mutex_unlock(&irq_domain_mutex); |
1056 | 1093 | ||
1057 | irq_domain_free_irq_data(virq, nr_irqs); | 1094 | irq_domain_free_irq_data(virq, nr_irqs); |
@@ -1059,6 +1096,47 @@ void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs) | |||
1059 | } | 1096 | } |
1060 | 1097 | ||
1061 | /** | 1098 | /** |
1099 | * irq_domain_alloc_irqs_parent - Allocate interrupts from parent domain | ||
1100 | * @irq_base: Base IRQ number | ||
1101 | * @nr_irqs: Number of IRQs to allocate | ||
1102 | * @arg: Allocation data (arch/domain specific) | ||
1103 | * | ||
1104 | * Check whether the domain has been setup recursive. If not allocate | ||
1105 | * through the parent domain. | ||
1106 | */ | ||
1107 | int irq_domain_alloc_irqs_parent(struct irq_domain *domain, | ||
1108 | unsigned int irq_base, unsigned int nr_irqs, | ||
1109 | void *arg) | ||
1110 | { | ||
1111 | /* irq_domain_alloc_irqs_recursive() has called parent's alloc() */ | ||
1112 | if (irq_domain_is_auto_recursive(domain)) | ||
1113 | return 0; | ||
1114 | |||
1115 | domain = domain->parent; | ||
1116 | if (domain) | ||
1117 | return irq_domain_alloc_irqs_recursive(domain, irq_base, | ||
1118 | nr_irqs, arg); | ||
1119 | return -ENOSYS; | ||
1120 | } | ||
1121 | |||
1122 | /** | ||
1123 | * irq_domain_free_irqs_parent - Free interrupts from parent domain | ||
1124 | * @irq_base: Base IRQ number | ||
1125 | * @nr_irqs: Number of IRQs to free | ||
1126 | * | ||
1127 | * Check whether the domain has been setup recursive. If not free | ||
1128 | * through the parent domain. | ||
1129 | */ | ||
1130 | void irq_domain_free_irqs_parent(struct irq_domain *domain, | ||
1131 | unsigned int irq_base, unsigned int nr_irqs) | ||
1132 | { | ||
1133 | /* irq_domain_free_irqs_recursive() will call parent's free */ | ||
1134 | if (!irq_domain_is_auto_recursive(domain) && domain->parent) | ||
1135 | irq_domain_free_irqs_recursive(domain->parent, irq_base, | ||
1136 | nr_irqs); | ||
1137 | } | ||
1138 | |||
1139 | /** | ||
1062 | * irq_domain_activate_irq - Call domain_ops->activate recursively to activate | 1140 | * irq_domain_activate_irq - Call domain_ops->activate recursively to activate |
1063 | * interrupt | 1141 | * interrupt |
1064 | * @irq_data: outermost irq_data associated with interrupt | 1142 | * @irq_data: outermost irq_data associated with interrupt |