diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2016-04-11 04:57:51 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2016-05-02 07:42:50 -0400 |
commit | 651e8b54abdeeaa36f5f54ffa05c18707a3cc1d0 (patch) | |
tree | 61c85560b32b720e5f1ec99b1c8980ea02d346bd | |
parent | 7cec18a3906b52e855c9386650c0226bbe594a4c (diff) |
irqdomain: Allow domain matching on irq_fwspec
When iterating over the irq domain list, we try to match a domain
either by calling a match() function or by comparing a number
of fields passed as parameters.
Both approaches are a bit restrictive:
- match() is DT specific and only takes a device node
- the fallback case only deals with the fwnode_handle
It would be useful if we had a per-domain function that would
actually perform the matching check on the whole of the
irq_fwspec structure. This would allow for a domain to triage
matching attempts that need to extend beyond the fwnode.
Let's introduce irq_find_matching_fwspec(), which takes a full
blown irq_fwspec structure, and call into a select() function
implemented by the irqdomain. irq_find_matching_fwnode() is
made a wrapper around irq_find_matching_fwspec in order to
preserve compatibility.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: devicetree@vger.kernel.org
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Rob Herring <robh+dt@kernel.org>
Link: http://lkml.kernel.org/r/1460365075-7316-2-git-send-email-marc.zyngier@arm.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | include/linux/irqdomain.h | 15 | ||||
-rw-r--r-- | kernel/irq/irqdomain.c | 19 |
2 files changed, 24 insertions, 10 deletions
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 736abd74c135..f1f36e04d885 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h | |||
@@ -96,6 +96,8 @@ enum irq_domain_bus_token { | |||
96 | struct irq_domain_ops { | 96 | struct irq_domain_ops { |
97 | int (*match)(struct irq_domain *d, struct device_node *node, | 97 | int (*match)(struct irq_domain *d, struct device_node *node, |
98 | enum irq_domain_bus_token bus_token); | 98 | enum irq_domain_bus_token bus_token); |
99 | int (*select)(struct irq_domain *d, struct irq_fwspec *fwspec, | ||
100 | enum irq_domain_bus_token bus_token); | ||
99 | int (*map)(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw); | 101 | int (*map)(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw); |
100 | void (*unmap)(struct irq_domain *d, unsigned int virq); | 102 | void (*unmap)(struct irq_domain *d, unsigned int virq); |
101 | int (*xlate)(struct irq_domain *d, struct device_node *node, | 103 | int (*xlate)(struct irq_domain *d, struct device_node *node, |
@@ -211,7 +213,7 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node, | |||
211 | irq_hw_number_t first_hwirq, | 213 | irq_hw_number_t first_hwirq, |
212 | const struct irq_domain_ops *ops, | 214 | const struct irq_domain_ops *ops, |
213 | void *host_data); | 215 | void *host_data); |
214 | extern struct irq_domain *irq_find_matching_fwnode(struct fwnode_handle *fwnode, | 216 | extern struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec, |
215 | enum irq_domain_bus_token bus_token); | 217 | enum irq_domain_bus_token bus_token); |
216 | extern void irq_set_default_host(struct irq_domain *host); | 218 | extern void irq_set_default_host(struct irq_domain *host); |
217 | extern int irq_domain_alloc_descs(int virq, unsigned int nr_irqs, | 219 | extern int irq_domain_alloc_descs(int virq, unsigned int nr_irqs, |
@@ -227,6 +229,17 @@ static inline bool is_fwnode_irqchip(struct fwnode_handle *fwnode) | |||
227 | return fwnode && fwnode->type == FWNODE_IRQCHIP; | 229 | return fwnode && fwnode->type == FWNODE_IRQCHIP; |
228 | } | 230 | } |
229 | 231 | ||
232 | static inline | ||
233 | struct irq_domain *irq_find_matching_fwnode(struct fwnode_handle *fwnode, | ||
234 | enum irq_domain_bus_token bus_token) | ||
235 | { | ||
236 | struct irq_fwspec fwspec = { | ||
237 | .fwnode = fwnode, | ||
238 | }; | ||
239 | |||
240 | return irq_find_matching_fwspec(&fwspec, bus_token); | ||
241 | } | ||
242 | |||
230 | static inline struct irq_domain *irq_find_matching_host(struct device_node *node, | 243 | static inline struct irq_domain *irq_find_matching_host(struct device_node *node, |
231 | enum irq_domain_bus_token bus_token) | 244 | enum irq_domain_bus_token bus_token) |
232 | { | 245 | { |
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 3a519a01118b..503c5b9dd030 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c | |||
@@ -243,14 +243,15 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node, | |||
243 | EXPORT_SYMBOL_GPL(irq_domain_add_legacy); | 243 | EXPORT_SYMBOL_GPL(irq_domain_add_legacy); |
244 | 244 | ||
245 | /** | 245 | /** |
246 | * irq_find_matching_fwnode() - Locates a domain for a given fwnode | 246 | * irq_find_matching_fwspec() - Locates a domain for a given fwspec |
247 | * @fwnode: FW descriptor of the interrupt controller | 247 | * @fwspec: FW specifier for an interrupt |
248 | * @bus_token: domain-specific data | 248 | * @bus_token: domain-specific data |
249 | */ | 249 | */ |
250 | struct irq_domain *irq_find_matching_fwnode(struct fwnode_handle *fwnode, | 250 | struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec, |
251 | enum irq_domain_bus_token bus_token) | 251 | enum irq_domain_bus_token bus_token) |
252 | { | 252 | { |
253 | struct irq_domain *h, *found = NULL; | 253 | struct irq_domain *h, *found = NULL; |
254 | struct fwnode_handle *fwnode = fwspec->fwnode; | ||
254 | int rc; | 255 | int rc; |
255 | 256 | ||
256 | /* We might want to match the legacy controller last since | 257 | /* We might want to match the legacy controller last since |
@@ -264,7 +265,9 @@ struct irq_domain *irq_find_matching_fwnode(struct fwnode_handle *fwnode, | |||
264 | */ | 265 | */ |
265 | mutex_lock(&irq_domain_mutex); | 266 | mutex_lock(&irq_domain_mutex); |
266 | list_for_each_entry(h, &irq_domain_list, link) { | 267 | list_for_each_entry(h, &irq_domain_list, link) { |
267 | if (h->ops->match) | 268 | if (h->ops->select && fwspec->param_count) |
269 | rc = h->ops->select(h, fwspec, bus_token); | ||
270 | else if (h->ops->match) | ||
268 | rc = h->ops->match(h, to_of_node(fwnode), bus_token); | 271 | rc = h->ops->match(h, to_of_node(fwnode), bus_token); |
269 | else | 272 | else |
270 | rc = ((fwnode != NULL) && (h->fwnode == fwnode) && | 273 | rc = ((fwnode != NULL) && (h->fwnode == fwnode) && |
@@ -279,7 +282,7 @@ struct irq_domain *irq_find_matching_fwnode(struct fwnode_handle *fwnode, | |||
279 | mutex_unlock(&irq_domain_mutex); | 282 | mutex_unlock(&irq_domain_mutex); |
280 | return found; | 283 | return found; |
281 | } | 284 | } |
282 | EXPORT_SYMBOL_GPL(irq_find_matching_fwnode); | 285 | EXPORT_SYMBOL_GPL(irq_find_matching_fwspec); |
283 | 286 | ||
284 | /** | 287 | /** |
285 | * irq_set_default_host() - Set a "default" irq domain | 288 | * irq_set_default_host() - Set a "default" irq domain |
@@ -574,11 +577,9 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec) | |||
574 | int virq; | 577 | int virq; |
575 | 578 | ||
576 | if (fwspec->fwnode) { | 579 | if (fwspec->fwnode) { |
577 | domain = irq_find_matching_fwnode(fwspec->fwnode, | 580 | domain = irq_find_matching_fwspec(fwspec, DOMAIN_BUS_WIRED); |
578 | DOMAIN_BUS_WIRED); | ||
579 | if (!domain) | 581 | if (!domain) |
580 | domain = irq_find_matching_fwnode(fwspec->fwnode, | 582 | domain = irq_find_matching_fwspec(fwspec, DOMAIN_BUS_ANY); |
581 | DOMAIN_BUS_ANY); | ||
582 | } else { | 583 | } else { |
583 | domain = irq_default_domain; | 584 | domain = irq_default_domain; |
584 | } | 585 | } |