@@ -62,7 +62,7 @@ enum irq_domain_bus_token {
/**
* struct irq_domain_ops - Methods for irq_domain objects
* @match: Match an interrupt controller device node to a host, returns
- * 1 on a match
+ * a ranking (non-zero) on a match
* @map: Create or update a mapping between a virtual irq number and a hw
* irq number. This is called only once for a given mapping.
* @unmap: Dispose of such a mapping
@@ -197,30 +197,46 @@ struct irq_domain *irq_find_matching_host(struct device_node *node,
void *bus_data)
{
struct irq_domain *h, *found = NULL;
- int rc;
+ int match_rank = 0x7fffffff;
+ int found_rank = 0;
+ int rank;
+ int pass;
/* We might want to match the legacy controller last since
* it might potentially be set to match all interrupts in
- * the absence of a device node. This isn't a problem so far
- * yet though...
+ * the absence of a device node. In this case, the match
+ * of highest rank is returned.
*
* bus_token == DOMAIN_BUS_ANY matches any domain, any other
* values must generate an exact match for the domain to be
* selected.
*/
mutex_lock(&irq_domain_mutex);
- list_for_each_entry(h, &irq_domain_list, link) {
- if (h->ops->match)
- rc = h->ops->match(h, node, bus_token, bus_data);
- else
- rc = ((h->of_node != NULL) && (h->of_node == node) &&
- ((bus_token == DOMAIN_BUS_ANY) ||
- (h->bus_token == bus_token)));
-
- if (rc) {
- found = h;
- break;
+ for (pass = 0; pass < 2; pass++) {
+ list_for_each_entry(h, &irq_domain_list, link) {
+ if (h->ops->match)
+ rank = h->ops->match(h, node, bus_token,
+ bus_data);
+ else
+ if ((h->of_node != NULL) &&
+ (h->of_node == node) &&
+ ((bus_token == DOMAIN_BUS_ANY) ||
+ (h->bus_token == bus_token)))
+ rank = 1;
+ else
+ rank = 0;
+
+ if (rank > found_rank)
+ found_rank = rank;
+
+ if (found_rank == match_rank) {
+ found = h;
+ break;
+ }
}
+
+ if (found_rank != 0)
+ match_rank = found_rank;
}
mutex_unlock(&irq_domain_mutex);
return found;