Commit 651e8b54 authored by Marc Zyngier's avatar Marc Zyngier Committed by Thomas Gleixner

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: default avatarMarc 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.comSigned-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 7cec18a3
...@@ -96,6 +96,8 @@ enum irq_domain_bus_token { ...@@ -96,6 +96,8 @@ enum irq_domain_bus_token {
struct irq_domain_ops { struct irq_domain_ops {
int (*match)(struct irq_domain *d, struct device_node *node, int (*match)(struct irq_domain *d, struct device_node *node,
enum irq_domain_bus_token bus_token); enum irq_domain_bus_token bus_token);
int (*select)(struct irq_domain *d, struct irq_fwspec *fwspec,
enum irq_domain_bus_token bus_token);
int (*map)(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw); int (*map)(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw);
void (*unmap)(struct irq_domain *d, unsigned int virq); void (*unmap)(struct irq_domain *d, unsigned int virq);
int (*xlate)(struct irq_domain *d, struct device_node *node, 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,7 +213,7 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
irq_hw_number_t first_hwirq, irq_hw_number_t first_hwirq,
const struct irq_domain_ops *ops, const struct irq_domain_ops *ops,
void *host_data); void *host_data);
extern struct irq_domain *irq_find_matching_fwnode(struct fwnode_handle *fwnode, extern struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec,
enum irq_domain_bus_token bus_token); enum irq_domain_bus_token bus_token);
extern void irq_set_default_host(struct irq_domain *host); extern void irq_set_default_host(struct irq_domain *host);
extern int irq_domain_alloc_descs(int virq, unsigned int nr_irqs, 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,6 +229,17 @@ static inline bool is_fwnode_irqchip(struct fwnode_handle *fwnode)
return fwnode && fwnode->type == FWNODE_IRQCHIP; return fwnode && fwnode->type == FWNODE_IRQCHIP;
} }
static inline
struct irq_domain *irq_find_matching_fwnode(struct fwnode_handle *fwnode,
enum irq_domain_bus_token bus_token)
{
struct irq_fwspec fwspec = {
.fwnode = fwnode,
};
return irq_find_matching_fwspec(&fwspec, bus_token);
}
static inline struct irq_domain *irq_find_matching_host(struct device_node *node, static inline struct irq_domain *irq_find_matching_host(struct device_node *node,
enum irq_domain_bus_token bus_token) enum irq_domain_bus_token bus_token)
{ {
......
...@@ -243,14 +243,15 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node, ...@@ -243,14 +243,15 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
EXPORT_SYMBOL_GPL(irq_domain_add_legacy); EXPORT_SYMBOL_GPL(irq_domain_add_legacy);
/** /**
* irq_find_matching_fwnode() - Locates a domain for a given fwnode * irq_find_matching_fwspec() - Locates a domain for a given fwspec
* @fwnode: FW descriptor of the interrupt controller * @fwspec: FW specifier for an interrupt
* @bus_token: domain-specific data * @bus_token: domain-specific data
*/ */
struct irq_domain *irq_find_matching_fwnode(struct fwnode_handle *fwnode, struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec,
enum irq_domain_bus_token bus_token) enum irq_domain_bus_token bus_token)
{ {
struct irq_domain *h, *found = NULL; struct irq_domain *h, *found = NULL;
struct fwnode_handle *fwnode = fwspec->fwnode;
int rc; int rc;
/* We might want to match the legacy controller last since /* 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,7 +265,9 @@ struct irq_domain *irq_find_matching_fwnode(struct fwnode_handle *fwnode,
*/ */
mutex_lock(&irq_domain_mutex); mutex_lock(&irq_domain_mutex);
list_for_each_entry(h, &irq_domain_list, link) { list_for_each_entry(h, &irq_domain_list, link) {
if (h->ops->match) if (h->ops->select && fwspec->param_count)
rc = h->ops->select(h, fwspec, bus_token);
else if (h->ops->match)
rc = h->ops->match(h, to_of_node(fwnode), bus_token); rc = h->ops->match(h, to_of_node(fwnode), bus_token);
else else
rc = ((fwnode != NULL) && (h->fwnode == fwnode) && rc = ((fwnode != NULL) && (h->fwnode == fwnode) &&
...@@ -279,7 +282,7 @@ struct irq_domain *irq_find_matching_fwnode(struct fwnode_handle *fwnode, ...@@ -279,7 +282,7 @@ struct irq_domain *irq_find_matching_fwnode(struct fwnode_handle *fwnode,
mutex_unlock(&irq_domain_mutex); mutex_unlock(&irq_domain_mutex);
return found; return found;
} }
EXPORT_SYMBOL_GPL(irq_find_matching_fwnode); EXPORT_SYMBOL_GPL(irq_find_matching_fwspec);
/** /**
* irq_set_default_host() - Set a "default" irq domain * irq_set_default_host() - Set a "default" irq domain
...@@ -574,11 +577,9 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec) ...@@ -574,11 +577,9 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
int virq; int virq;
if (fwspec->fwnode) { if (fwspec->fwnode) {
domain = irq_find_matching_fwnode(fwspec->fwnode, domain = irq_find_matching_fwspec(fwspec, DOMAIN_BUS_WIRED);
DOMAIN_BUS_WIRED);
if (!domain) if (!domain)
domain = irq_find_matching_fwnode(fwspec->fwnode, domain = irq_find_matching_fwspec(fwspec, DOMAIN_BUS_ANY);
DOMAIN_BUS_ANY);
} else { } else {
domain = irq_default_domain; domain = irq_default_domain;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment