aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2016-04-11 04:57:51 -0400
committerThomas Gleixner <tglx@linutronix.de>2016-05-02 07:42:50 -0400
commit651e8b54abdeeaa36f5f54ffa05c18707a3cc1d0 (patch)
tree61c85560b32b720e5f1ec99b1c8980ea02d346bd
parent7cec18a3906b52e855c9386650c0226bbe594a4c (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.h15
-rw-r--r--kernel/irq/irqdomain.c19
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 {
96struct irq_domain_ops { 96struct 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);
214extern struct irq_domain *irq_find_matching_fwnode(struct fwnode_handle *fwnode, 216extern 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);
216extern void irq_set_default_host(struct irq_domain *host); 218extern void irq_set_default_host(struct irq_domain *host);
217extern int irq_domain_alloc_descs(int virq, unsigned int nr_irqs, 219extern 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
232static inline
233struct 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
230static inline struct irq_domain *irq_find_matching_host(struct device_node *node, 243static 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,
243EXPORT_SYMBOL_GPL(irq_domain_add_legacy); 243EXPORT_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 */
250struct irq_domain *irq_find_matching_fwnode(struct fwnode_handle *fwnode, 250struct 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}
282EXPORT_SYMBOL_GPL(irq_find_matching_fwnode); 285EXPORT_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 }