Commit 107a84e61cdd3406c842a0e4be7efffd3a05dba6 ("of: match by compatible
property first") breaks the gianfar ethernet driver found on various
Freescale PPC chips.

There are, for unfortunate historical reasons, two nodes with a
compatible of "gianfar".  One has a device_type of "network" and the
other has device_type of "mdio".  The match entries look like this:

>         {
>                 .type = "mdio",
>                 .compatible = "gianfar",
>         },

and

>         {
>                 .type = "network",
>                 .compatible = "gianfar",
>         },

With the above patch, both nodes get probed by the first driver, because
nothing else in the match struct is looked at if there's a compatible
match.

Signed-off-by: Scott Wood <scottw...@freescale.com>
---
 drivers/of/base.c |   44 ++++++++++++++++++++++++++++++++------------
 1 file changed, 32 insertions(+), 12 deletions(-)

diff --git a/drivers/of/base.c b/drivers/of/base.c
index bc86ea2..4e707cc 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -511,14 +511,37 @@ out:
 }
 EXPORT_SYMBOL(of_find_node_with_property);
 
-static const struct of_device_id *of_match_compat(const struct of_device_id 
*matches,
-                                                 const char *compat)
+/*
+ * Tell if an device_node matches the non-compatible fields of
+ * a specific of_match element.
+ */
+static bool of_match_one_noncompat(const struct of_device_id *match,
+                                  const struct device_node *node)
+{
+       bool is_match = true;
+
+       if (match->name[0])
+               is_match &= node->name && !strcmp(match->name, node->name);
+       if (match->type[0])
+               is_match &= node->type && !strcmp(match->type, node->type);
+
+       return is_match;
+}
+
+/*
+ * Find an OF match using the supplied compatible string, rather than
+ * the node's entire string list.
+ */
+static const struct of_device_id *of_match_compat(
+       const struct of_device_id *matches, const char *compat,
+       const struct device_node *node)
 {
        while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
                const char *cp = matches->compatible;
                int len = strlen(cp);
 
-               if (len > 0 && of_compat_cmp(compat, cp, len) == 0)
+               if (len > 0 && of_compat_cmp(compat, cp, len) == 0 &&
+                   of_match_one_noncompat(matches, node))
                        return matches;
 
                matches++;
@@ -544,23 +567,20 @@ const struct of_device_id *of_match_node(const struct 
of_device_id *matches,
                return NULL;
 
        of_property_for_each_string(node, "compatible", prop, cp) {
-               const struct of_device_id *match = of_match_compat(matches, cp);
+               const struct of_device_id *match =
+                       of_match_compat(matches, cp, node);
                if (match)
                        return match;
        }
 
        while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
-               int match = 1;
-               if (matches->name[0])
-                       match &= node->name
-                               && !strcmp(matches->name, node->name);
-               if (matches->type[0])
-                       match &= node->type
-                               && !strcmp(matches->type, node->type);
-               if (match && !matches->compatible[0])
+               if (of_match_one_noncompat(matches, node) &&
+                   !matches->compatible[0])
                        return matches;
+
                matches++;
        }
+
        return NULL;
 }
 EXPORT_SYMBOL(of_match_node);
-- 
1.7.9.5

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to