Skip to content

Commit 215a14c

Browse files
haokexinglikely
authored andcommitted
of: reimplement the matching method for __of_match_node()
In the current implementation of __of_match_node(), it will compare each given match entry against all the node's compatible strings with of_device_is_compatible(). To achieve multiple compatible strings per node with ordering from specific to generic, this requires given matches to be ordered from specific to generic. For most of the drivers this is not true and also an alphabetical ordering is more sane there. Therefore, we define a following priority order for the match, and then scan all the entries to find the best match. 1. specific compatible && type && name 2. specific compatible && type 3. specific compatible && name 4. specific compatible 5. general compatible && type && name 6. general compatible && type 7. general compatible && name 8. general compatible 9. type && name 10. type 11. name v5: Fix nested locking bug v4: Short-circuit failure cases instead of mucking with score, and remove extra __of_device_is_compatible() wrapper stub. Move scoring logic directly into __of_device_is_compatible() v3: Also need to bail out when there does have a compatible member in match entry, but it doesn't match with the device node's compatible. v2: Fix the bug such as we get the same score for the following two match entries with the empty node 'name2 { };' struct of_device_id matches[] = { {.name = "name2", }, {.name = "name2", .type = "type1", }, {} }; Signed-off-by: Kevin Hao <[email protected]> [grant.likely: added v4 changes] Signed-off-by: Grant Likely <[email protected]> Tested-by: Paul Gortmaker <[email protected]> Tested-by: Stephen Chivers <[email protected]> Tested-by: Sachin Kamat <[email protected]>
1 parent 71c5498 commit 215a14c

File tree

1 file changed

+75
-36
lines changed

1 file changed

+75
-36
lines changed

drivers/of/base.c

Lines changed: 75 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -342,27 +342,72 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
342342
}
343343
EXPORT_SYMBOL(of_get_cpu_node);
344344

345-
/** Checks if the given "compat" string matches one of the strings in
346-
* the device's "compatible" property
345+
/**
346+
* __of_device_is_compatible() - Check if the node matches given constraints
347+
* @device: pointer to node
348+
* @compat: required compatible string, NULL or "" for any match
349+
* @type: required device_type value, NULL or "" for any match
350+
* @name: required node name, NULL or "" for any match
351+
*
352+
* Checks if the given @compat, @type and @name strings match the
353+
* properties of the given @device. A constraints can be skipped by
354+
* passing NULL or an empty string as the constraint.
355+
*
356+
* Returns 0 for no match, and a positive integer on match. The return
357+
* value is a relative score with larger values indicating better
358+
* matches. The score is weighted for the most specific compatible value
359+
* to get the highest score. Matching type is next, followed by matching
360+
* name. Practically speaking, this results in the following priority
361+
* order for matches:
362+
*
363+
* 1. specific compatible && type && name
364+
* 2. specific compatible && type
365+
* 3. specific compatible && name
366+
* 4. specific compatible
367+
* 5. general compatible && type && name
368+
* 6. general compatible && type
369+
* 7. general compatible && name
370+
* 8. general compatible
371+
* 9. type && name
372+
* 10. type
373+
* 11. name
347374
*/
348375
static int __of_device_is_compatible(const struct device_node *device,
349-
const char *compat)
350-
{
351-
const char* cp;
352-
int cplen, l;
376+
const char *compat, const char *type, const char *name)
377+
{
378+
struct property *prop;
379+
const char *cp;
380+
int index = 0, score = 0;
381+
382+
/* Compatible match has highest priority */
383+
if (compat && compat[0]) {
384+
prop = __of_find_property(device, "compatible", NULL);
385+
for (cp = of_prop_next_string(prop, NULL); cp;
386+
cp = of_prop_next_string(prop, cp), index++) {
387+
if (of_compat_cmp(cp, compat, strlen(compat)) == 0) {
388+
score = INT_MAX/2 - (index << 2);
389+
break;
390+
}
391+
}
392+
if (!score)
393+
return 0;
394+
}
353395

354-
cp = __of_get_property(device, "compatible", &cplen);
355-
if (cp == NULL)
356-
return 0;
357-
while (cplen > 0) {
358-
if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
359-
return 1;
360-
l = strlen(cp) + 1;
361-
cp += l;
362-
cplen -= l;
396+
/* Matching type is better than matching name */
397+
if (type && type[0]) {
398+
if (!device->type || of_node_cmp(type, device->type))
399+
return 0;
400+
score += 2;
363401
}
364402

365-
return 0;
403+
/* Matching name is a bit better than not */
404+
if (name && name[0]) {
405+
if (!device->name || of_node_cmp(name, device->name))
406+
return 0;
407+
score++;
408+
}
409+
410+
return score;
366411
}
367412

368413
/** Checks if the given "compat" string matches one of the strings in
@@ -375,7 +420,7 @@ int of_device_is_compatible(const struct device_node *device,
375420
int res;
376421

377422
raw_spin_lock_irqsave(&devtree_lock, flags);
378-
res = __of_device_is_compatible(device, compat);
423+
res = __of_device_is_compatible(device, compat, NULL, NULL);
379424
raw_spin_unlock_irqrestore(&devtree_lock, flags);
380425
return res;
381426
}
@@ -681,10 +726,7 @@ struct device_node *of_find_compatible_node(struct device_node *from,
681726
raw_spin_lock_irqsave(&devtree_lock, flags);
682727
np = from ? from->allnext : of_allnodes;
683728
for (; np; np = np->allnext) {
684-
if (type
685-
&& !(np->type && (of_node_cmp(np->type, type) == 0)))
686-
continue;
687-
if (__of_device_is_compatible(np, compatible) &&
729+
if (__of_device_is_compatible(np, compatible, type, NULL) &&
688730
of_node_get(np))
689731
break;
690732
}
@@ -734,25 +776,22 @@ static
734776
const struct of_device_id *__of_match_node(const struct of_device_id *matches,
735777
const struct device_node *node)
736778
{
779+
const struct of_device_id *best_match = NULL;
780+
int score, best_score = 0;
781+
737782
if (!matches)
738783
return NULL;
739784

740-
while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
741-
int match = 1;
742-
if (matches->name[0])
743-
match &= node->name
744-
&& !strcmp(matches->name, node->name);
745-
if (matches->type[0])
746-
match &= node->type
747-
&& !strcmp(matches->type, node->type);
748-
if (matches->compatible[0])
749-
match &= __of_device_is_compatible(node,
750-
matches->compatible);
751-
if (match)
752-
return matches;
753-
matches++;
785+
for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++) {
786+
score = __of_device_is_compatible(node, matches->compatible,
787+
matches->type, matches->name);
788+
if (score > best_score) {
789+
best_match = matches;
790+
best_score = score;
791+
}
754792
}
755-
return NULL;
793+
794+
return best_match;
756795
}
757796

758797
/**

0 commit comments

Comments
 (0)