aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--Documentation/IRQ-domain.txt71
-rw-r--r--include/linux/irq.h5
-rw-r--r--include/linux/irqdomain.h98
-rw-r--r--kernel/irq/Kconfig5
-rw-r--r--kernel/irq/chip.c3
-rw-r--r--kernel/irq/irqdomain.c415
6 files changed, 581 insertions, 16 deletions
diff --git a/Documentation/IRQ-domain.txt b/Documentation/IRQ-domain.txt
index 8a8b82c9ca53..39cfa72732ff 100644
--- a/Documentation/IRQ-domain.txt
+++ b/Documentation/IRQ-domain.txt
@@ -151,3 +151,74 @@ used and no descriptor gets allocated it is very important to make sure
151that the driver using the simple domain call irq_create_mapping() 151that the driver using the simple domain call irq_create_mapping()
152before any irq_find_mapping() since the latter will actually work 152before any irq_find_mapping() since the latter will actually work
153for the static IRQ assignment case. 153for the static IRQ assignment case.
154
155==== Hierarchy IRQ domain ====
156On some architectures, there may be multiple interrupt controllers
157involved in delivering an interrupt from the device to the target CPU.
158Let's look at a typical interrupt delivering path on x86 platforms:
159
160Device --> IOAPIC -> Interrupt remapping Controller -> Local APIC -> CPU
161
162There are three interrupt controllers involved:
1631) IOAPIC controller
1642) Interrupt remapping controller
1653) Local APIC controller
166
167To support such a hardware topology and make software architecture match
168hardware architecture, an irq_domain data structure is built for each
169interrupt controller and those irq_domains are organized into hierarchy.
170When building irq_domain hierarchy, the irq_domain near to the device is
171child and the irq_domain near to CPU is parent. So a hierarchy structure
172as below will be built for the example above.
173 CPU Vector irq_domain (root irq_domain to manage CPU vectors)
174 ^
175 |
176 Interrupt Remapping irq_domain (manage irq_remapping entries)
177 ^
178 |
179 IOAPIC irq_domain (manage IOAPIC delivery entries/pins)
180
181There are four major interfaces to use hierarchy irq_domain:
1821) irq_domain_alloc_irqs(): allocate IRQ descriptors and interrupt
183 controller related resources to deliver these interrupts.
1842) irq_domain_free_irqs(): free IRQ descriptors and interrupt controller
185 related resources associated with these interrupts.
1863) irq_domain_activate_irq(): activate interrupt controller hardware to
187 deliver the interrupt.
1883) irq_domain_deactivate_irq(): deactivate interrupt controller hardware
189 to stop delivering the interrupt.
190
191Following changes are needed to support hierarchy irq_domain.
1921) a new field 'parent' is added to struct irq_domain; it's used to
193 maintain irq_domain hierarchy information.
1942) a new field 'parent_data' is added to struct irq_data; it's used to
195 build hierarchy irq_data to match hierarchy irq_domains. The irq_data
196 is used to store irq_domain pointer and hardware irq number.
1973) new callbacks are added to struct irq_domain_ops to support hierarchy
198 irq_domain operations.
199
200With support of hierarchy irq_domain and hierarchy irq_data ready, an
201irq_domain structure is built for each interrupt controller, and an
202irq_data structure is allocated for each irq_domain associated with an
203IRQ. Now we could go one step further to support stacked(hierarchy)
204irq_chip. That is, an irq_chip is associated with each irq_data along
205the hierarchy. A child irq_chip may implement a required action by
206itself or by cooperating with its parent irq_chip.
207
208With stacked irq_chip, interrupt controller driver only needs to deal
209with the hardware managed by itself and may ask for services from its
210parent irq_chip when needed. So we could achieve a much cleaner
211software architecture.
212
213For an interrupt controller driver to support hierarchy irq_domain, it
214needs to:
2151) Implement irq_domain_ops.alloc and irq_domain_ops.free
2162) Optionally implement irq_domain_ops.activate and
217 irq_domain_ops.deactivate.
2183) Optionally implement an irq_chip to manage the interrupt controller
219 hardware.
2204) No need to implement irq_domain_ops.map and irq_domain_ops.unmap,
221 they are unused with hierarchy irq_domain.
222
223Hierarchy irq_domain may also be used to support other architectures,
224such as ARM, ARM64 etc.
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 03f48d936f66..13ba412ce3a0 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -133,6 +133,8 @@ struct irq_domain;
133 * @chip: low level interrupt hardware access 133 * @chip: low level interrupt hardware access
134 * @domain: Interrupt translation domain; responsible for mapping 134 * @domain: Interrupt translation domain; responsible for mapping
135 * between hwirq number and linux irq number. 135 * between hwirq number and linux irq number.
136 * @parent_data: pointer to parent struct irq_data to support hierarchy
137 * irq_domain
136 * @handler_data: per-IRQ data for the irq_chip methods 138 * @handler_data: per-IRQ data for the irq_chip methods
137 * @chip_data: platform-specific per-chip private data for the chip 139 * @chip_data: platform-specific per-chip private data for the chip
138 * methods, to allow shared chip implementations 140 * methods, to allow shared chip implementations
@@ -151,6 +153,9 @@ struct irq_data {
151 unsigned int state_use_accessors; 153 unsigned int state_use_accessors;
152 struct irq_chip *chip; 154 struct irq_chip *chip;
153 struct irq_domain *domain; 155 struct irq_domain *domain;
156#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
157 struct irq_data *parent_data;
158#endif
154 void *handler_data; 159 void *handler_data;
155 void *chip_data; 160 void *chip_data;
156 struct msi_desc *msi_desc; 161 struct msi_desc *msi_desc;
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index b0f9d16e48f6..f8563dcfd254 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -38,6 +38,8 @@
38struct device_node; 38struct device_node;
39struct irq_domain; 39struct irq_domain;
40struct of_device_id; 40struct of_device_id;
41struct irq_chip;
42struct irq_data;
41 43
42/* Number of irqs reserved for a legacy isa controller */ 44/* Number of irqs reserved for a legacy isa controller */
43#define NUM_ISA_INTERRUPTS 16 45#define NUM_ISA_INTERRUPTS 16
@@ -64,6 +66,16 @@ struct irq_domain_ops {
64 int (*xlate)(struct irq_domain *d, struct device_node *node, 66 int (*xlate)(struct irq_domain *d, struct device_node *node,
65 const u32 *intspec, unsigned int intsize, 67 const u32 *intspec, unsigned int intsize,
66 unsigned long *out_hwirq, unsigned int *out_type); 68 unsigned long *out_hwirq, unsigned int *out_type);
69
70#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
71 /* extended V2 interfaces to support hierarchy irq_domains */
72 int (*alloc)(struct irq_domain *d, unsigned int virq,
73 unsigned int nr_irqs, void *arg);
74 void (*free)(struct irq_domain *d, unsigned int virq,
75 unsigned int nr_irqs);
76 void (*activate)(struct irq_domain *d, struct irq_data *irq_data);
77 void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data);
78#endif
67}; 79};
68 80
69extern struct irq_domain_ops irq_generic_chip_ops; 81extern struct irq_domain_ops irq_generic_chip_ops;
@@ -77,6 +89,7 @@ struct irq_domain_chip_generic;
77 * @ops: pointer to irq_domain methods 89 * @ops: pointer to irq_domain methods
78 * @host_data: private data pointer for use by owner. Not touched by irq_domain 90 * @host_data: private data pointer for use by owner. Not touched by irq_domain
79 * core code. 91 * core code.
92 * @flags: host per irq_domain flags
80 * 93 *
81 * Optional elements 94 * Optional elements
82 * @of_node: Pointer to device tree nodes associated with the irq_domain. Used 95 * @of_node: Pointer to device tree nodes associated with the irq_domain. Used
@@ -84,6 +97,7 @@ struct irq_domain_chip_generic;
84 * @gc: Pointer to a list of generic chips. There is a helper function for 97 * @gc: Pointer to a list of generic chips. There is a helper function for
85 * setting up one or more generic chips for interrupt controllers 98 * setting up one or more generic chips for interrupt controllers
86 * drivers using the generic chip library which uses this pointer. 99 * drivers using the generic chip library which uses this pointer.
100 * @parent: Pointer to parent irq_domain to support hierarchy irq_domains
87 * 101 *
88 * Revmap data, used internally by irq_domain 102 * Revmap data, used internally by irq_domain
89 * @revmap_direct_max_irq: The largest hwirq that can be set for controllers that 103 * @revmap_direct_max_irq: The largest hwirq that can be set for controllers that
@@ -97,10 +111,14 @@ struct irq_domain {
97 const char *name; 111 const char *name;
98 const struct irq_domain_ops *ops; 112 const struct irq_domain_ops *ops;
99 void *host_data; 113 void *host_data;
114 unsigned int flags;
100 115
101 /* Optional data */ 116 /* Optional data */
102 struct device_node *of_node; 117 struct device_node *of_node;
103 struct irq_domain_chip_generic *gc; 118 struct irq_domain_chip_generic *gc;
119#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
120 struct irq_domain *parent;
121#endif
104 122
105 /* reverse map data. The linear map gets appended to the irq_domain */ 123 /* reverse map data. The linear map gets appended to the irq_domain */
106 irq_hw_number_t hwirq_max; 124 irq_hw_number_t hwirq_max;
@@ -110,6 +128,19 @@ struct irq_domain {
110 unsigned int linear_revmap[]; 128 unsigned int linear_revmap[];
111}; 129};
112 130
131/* Irq domain flags */
132enum {
133 /* Irq domain is hierarchical */
134 IRQ_DOMAIN_FLAG_HIERARCHY = (1 << 0),
135
136 /*
137 * Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved
138 * for implementation specific purposes and ignored by the
139 * core code.
140 */
141 IRQ_DOMAIN_FLAG_NONCORE = (1 << 16),
142};
143
113#ifdef CONFIG_IRQ_DOMAIN 144#ifdef CONFIG_IRQ_DOMAIN
114struct irq_domain *__irq_domain_add(struct device_node *of_node, int size, 145struct irq_domain *__irq_domain_add(struct device_node *of_node, int size,
115 irq_hw_number_t hwirq_max, int direct_max, 146 irq_hw_number_t hwirq_max, int direct_max,
@@ -220,8 +251,75 @@ int irq_domain_xlate_onetwocell(struct irq_domain *d, struct device_node *ctrlr,
220 const u32 *intspec, unsigned int intsize, 251 const u32 *intspec, unsigned int intsize,
221 irq_hw_number_t *out_hwirq, unsigned int *out_type); 252 irq_hw_number_t *out_hwirq, unsigned int *out_type);
222 253
254/* V2 interfaces to support hierarchy IRQ domains. */
255extern struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain,
256 unsigned int virq);
257#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
258extern int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
259 unsigned int nr_irqs, int node, void *arg,
260 bool realloc);
261extern void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs);
262extern void irq_domain_activate_irq(struct irq_data *irq_data);
263extern void irq_domain_deactivate_irq(struct irq_data *irq_data);
264
265static inline int irq_domain_alloc_irqs(struct irq_domain *domain,
266 unsigned int nr_irqs, int node, void *arg)
267{
268 return __irq_domain_alloc_irqs(domain, -1, nr_irqs, node, arg, false);
269}
270
271extern int irq_domain_set_hwirq_and_chip(struct irq_domain *domain,
272 unsigned int virq,
273 irq_hw_number_t hwirq,
274 struct irq_chip *chip,
275 void *chip_data);
276extern void irq_domain_reset_irq_data(struct irq_data *irq_data);
277extern void irq_domain_free_irqs_common(struct irq_domain *domain,
278 unsigned int virq,
279 unsigned int nr_irqs);
280extern void irq_domain_free_irqs_top(struct irq_domain *domain,
281 unsigned int virq, unsigned int nr_irqs);
282
283static inline int irq_domain_alloc_irqs_parent(struct irq_domain *domain,
284 unsigned int irq_base,
285 unsigned int nr_irqs, void *arg)
286{
287 if (domain->parent && domain->parent->ops->alloc)
288 return domain->parent->ops->alloc(domain->parent, irq_base,
289 nr_irqs, arg);
290 return -ENOSYS;
291}
292
293static inline void irq_domain_free_irqs_parent(struct irq_domain *domain,
294 unsigned int irq_base, unsigned int nr_irqs)
295{
296 if (domain->parent && domain->parent->ops->free)
297 domain->parent->ops->free(domain->parent, irq_base, nr_irqs);
298}
299
300static inline bool irq_domain_is_hierarchy(struct irq_domain *domain)
301{
302 return domain->flags & IRQ_DOMAIN_FLAG_HIERARCHY;
303}
304#else /* CONFIG_IRQ_DOMAIN_HIERARCHY */
305static inline void irq_domain_activate_irq(struct irq_data *data) { }
306static inline void irq_domain_deactivate_irq(struct irq_data *data) { }
307static inline int irq_domain_alloc_irqs(struct irq_domain *domain,
308 unsigned int nr_irqs, int node, void *arg)
309{
310 return -1;
311}
312
313static inline bool irq_domain_is_hierarchy(struct irq_domain *domain)
314{
315 return false;
316}
317#endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */
318
223#else /* CONFIG_IRQ_DOMAIN */ 319#else /* CONFIG_IRQ_DOMAIN */
224static inline void irq_dispose_mapping(unsigned int virq) { } 320static inline void irq_dispose_mapping(unsigned int virq) { }
321static inline void irq_domain_activate_irq(struct irq_data *data) { }
322static inline void irq_domain_deactivate_irq(struct irq_data *data) { }
225#endif /* !CONFIG_IRQ_DOMAIN */ 323#endif /* !CONFIG_IRQ_DOMAIN */
226 324
227#endif /* _LINUX_IRQDOMAIN_H */ 325#endif /* _LINUX_IRQDOMAIN_H */
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 */