aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux
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 /include/linux
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 'include/linux')
-rw-r--r--include/linux/irq.h5
-rw-r--r--include/linux/irqdomain.h98
2 files changed, 103 insertions, 0 deletions
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 */