UPSTREAM: irqdomain: Allow domain matching on irq_fwspec
authorMarc Zyngier <marc.zyngier@arm.com>
Mon, 11 Apr 2016 08:57:51 +0000 (09:57 +0100)
committerHuang, Tao <huangtao@rock-chips.com>
Fri, 1 Jul 2016 06:20:47 +0000 (14:20 +0800)
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.

Change-Id: I07df9af068d114c80cd97b9cb987a70c0e24afda
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>
Signed-off-by: Caesar Wang <wxt@rock-chips.com>
(cherry picked from commit 651e8b54abdeeaa36f5f54ffa05c18707a3cc1d0)

include/linux/irqdomain.h
kernel/irq/irqdomain.c

index 8b60c95f4417d36e4f495ea92d3a9a2fa38e5165..8f031ce06a76190ef23a73ac07aaa5781245856c 100644 (file)
@@ -94,6 +94,8 @@ enum irq_domain_bus_token {
 struct irq_domain_ops {
        int (*match)(struct irq_domain *d, struct device_node *node,
                     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);
        void (*unmap)(struct irq_domain *d, unsigned int virq);
        int (*xlate)(struct irq_domain *d, struct device_node *node,
@@ -203,7 +205,7 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
                                         irq_hw_number_t first_hwirq,
                                         const struct irq_domain_ops *ops,
                                         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);
 extern void irq_set_default_host(struct irq_domain *host);
 
@@ -217,6 +219,17 @@ static inline bool is_fwnode_irqchip(struct fwnode_handle *fwnode)
        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,
                                                        enum irq_domain_bus_token bus_token)
 {
index 6ca9bda5777c466c49853b42256733601fd4e3c5..5c1b646a6e7dd99767172b7e535ceac07968e26b 100644 (file)
@@ -243,14 +243,15 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
 EXPORT_SYMBOL_GPL(irq_domain_add_legacy);
 
 /**
- * irq_find_matching_fwnode() - Locates a domain for a given fwnode
- * @fwnode: FW descriptor of the interrupt controller
+ * irq_find_matching_fwspec() - Locates a domain for a given fwspec
+ * @fwspec: FW specifier for an interrupt
  * @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)
 {
        struct irq_domain *h, *found = NULL;
+       struct fwnode_handle *fwnode = fwspec->fwnode;
        int rc;
 
        /* 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,
         */
        mutex_lock(&irq_domain_mutex);
        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);
                else
                        rc = ((fwnode != NULL) && (h->fwnode == fwnode) &&
@@ -279,7 +282,7 @@ struct irq_domain *irq_find_matching_fwnode(struct fwnode_handle *fwnode,
        mutex_unlock(&irq_domain_mutex);
        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
@@ -574,11 +577,9 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
        int virq;
 
        if (fwspec->fwnode) {
-               domain = irq_find_matching_fwnode(fwspec->fwnode,
-                                                 DOMAIN_BUS_WIRED);
+               domain = irq_find_matching_fwspec(fwspec, DOMAIN_BUS_WIRED);
                if (!domain)
-                       domain = irq_find_matching_fwnode(fwspec->fwnode,
-                                                         DOMAIN_BUS_ANY);
+                       domain = irq_find_matching_fwspec(fwspec, DOMAIN_BUS_ANY);
        } else {
                domain = irq_default_domain;
        }