Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'dt-for-linus' of git://git.secretlab.ca/git/linux

Pull devicetree fixes from Grant Likely:
"Device tree compatible match order bug fix

This branch contains a bug fix for the way devicetree code identifies
the type of device. Device drivers can contain a list of
of_device_ids, but it more than one entry will match, then the device
driver may choose the wrong one. Commit 105353145e, "match each node
compatible against all given matches first", was queued for v3.14 but
ended up causing other bugs. Commit 06b29e76a7 attempted to fix it
but it had other bugs. Merely reverting the fix and waiting until
v3.15 isn't a good option because there is code in v3.14 that depends
on the revised behaviour to boot.

This branch should finally fixes the problem correctly. This time
instead of just hoping that the patch is correct, this branch also
adds new testcases that validate the behaviour.

The changes in this branch are larger than I would like for a -rc
pull, but moving the test case data out of out of arch/arm so that it
could be validated on other architectures was important"

* tag 'dt-for-linus' of git://git.secretlab.ca/git/linux:
of: Add self test for of_match_node()
of: Move testcase FDT data into drivers/of
of: reimplement the matching method for __of_match_node()
Revert "of: search the best compatible match first in __of_match_node()"

+166 -80
arch/arm/boot/dts/testcases/tests-interrupts.dtsi drivers/of/testcase-data/tests-interrupts.dtsi
arch/arm/boot/dts/testcases/tests-phandle.dtsi drivers/of/testcase-data/tests-phandle.dtsi
-2
arch/arm/boot/dts/testcases/tests.dtsi
··· 1 - /include/ "tests-phandle.dtsi" 2 - /include/ "tests-interrupts.dtsi"
+2 -2
arch/arm/boot/dts/versatile-pb.dts
··· 1 - /include/ "versatile-ab.dts" 1 + #include <versatile-ab.dts> 2 2 3 3 / { 4 4 model = "ARM Versatile PB"; ··· 47 47 }; 48 48 }; 49 49 50 - /include/ "testcases/tests.dtsi" 50 + #include <testcases.dtsi>
+74 -76
drivers/of/base.c
··· 342 342 } 343 343 EXPORT_SYMBOL(of_get_cpu_node); 344 344 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 347 374 */ 348 375 static int __of_device_is_compatible(const struct device_node *device, 349 - const char *compat) 376 + const char *compat, const char *type, const char *name) 350 377 { 351 - const char* cp; 352 - int cplen, l; 378 + struct property *prop; 379 + const char *cp; 380 + int index = 0, score = 0; 353 381 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; 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; 363 394 } 364 395 365 - return 0; 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; 401 + } 402 + 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; 366 411 } 367 412 368 413 /** Checks if the given "compat" string matches one of the strings in ··· 420 375 int res; 421 376 422 377 raw_spin_lock_irqsave(&devtree_lock, flags); 423 - res = __of_device_is_compatible(device, compat); 378 + res = __of_device_is_compatible(device, compat, NULL, NULL); 424 379 raw_spin_unlock_irqrestore(&devtree_lock, flags); 425 380 return res; 426 381 } ··· 726 681 raw_spin_lock_irqsave(&devtree_lock, flags); 727 682 np = from ? from->allnext : of_allnodes; 728 683 for (; np; np = np->allnext) { 729 - if (type 730 - && !(np->type && (of_node_cmp(np->type, type) == 0))) 731 - continue; 732 - if (__of_device_is_compatible(np, compatible) && 684 + if (__of_device_is_compatible(np, compatible, type, NULL) && 733 685 of_node_get(np)) 734 686 break; 735 687 } ··· 772 730 } 773 731 EXPORT_SYMBOL(of_find_node_with_property); 774 732 775 - static const struct of_device_id * 776 - of_match_compatible(const struct of_device_id *matches, 777 - const struct device_node *node) 778 - { 779 - const char *cp; 780 - int cplen, l; 781 - const struct of_device_id *m; 782 - 783 - cp = __of_get_property(node, "compatible", &cplen); 784 - while (cp && (cplen > 0)) { 785 - m = matches; 786 - while (m->name[0] || m->type[0] || m->compatible[0]) { 787 - /* Only match for the entries without type and name */ 788 - if (m->name[0] || m->type[0] || 789 - of_compat_cmp(m->compatible, cp, 790 - strlen(m->compatible))) 791 - m++; 792 - else 793 - return m; 794 - } 795 - 796 - /* Get node's next compatible string */ 797 - l = strlen(cp) + 1; 798 - cp += l; 799 - cplen -= l; 800 - } 801 - 802 - return NULL; 803 - } 804 - 805 733 static 806 734 const struct of_device_id *__of_match_node(const struct of_device_id *matches, 807 735 const struct device_node *node) 808 736 { 809 - const struct of_device_id *m; 737 + const struct of_device_id *best_match = NULL; 738 + int score, best_score = 0; 810 739 811 740 if (!matches) 812 741 return NULL; 813 742 814 - m = of_match_compatible(matches, node); 815 - if (m) 816 - return m; 817 - 818 - while (matches->name[0] || matches->type[0] || matches->compatible[0]) { 819 - int match = 1; 820 - if (matches->name[0]) 821 - match &= node->name 822 - && !strcmp(matches->name, node->name); 823 - if (matches->type[0]) 824 - match &= node->type 825 - && !strcmp(matches->type, node->type); 826 - if (matches->compatible[0]) 827 - match &= __of_device_is_compatible(node, 828 - matches->compatible); 829 - if (match) 830 - return matches; 831 - matches++; 743 + for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++) { 744 + score = __of_device_is_compatible(node, matches->compatible, 745 + matches->type, matches->name); 746 + if (score > best_score) { 747 + best_match = matches; 748 + best_score = score; 749 + } 832 750 } 833 - return NULL; 751 + 752 + return best_match; 834 753 } 835 754 836 755 /** ··· 799 796 * @matches: array of of device match structures to search in 800 797 * @node: the of device structure to match against 801 798 * 802 - * Low level utility function used by device matching. We have two ways 803 - * of matching: 804 - * - Try to find the best compatible match by comparing each compatible 805 - * string of device node with all the given matches respectively. 806 - * - If the above method failed, then try to match the compatible by using 807 - * __of_device_is_compatible() besides the match in type and name. 799 + * Low level utility function used by device matching. 808 800 */ 809 801 const struct of_device_id *of_match_node(const struct of_device_id *matches, 810 802 const struct device_node *node)
+67
drivers/of/selftest.c
··· 300 300 of_node_put(np); 301 301 } 302 302 303 + static struct of_device_id match_node_table[] = { 304 + { .data = "A", .name = "name0", }, /* Name alone is lowest priority */ 305 + { .data = "B", .type = "type1", }, /* followed by type alone */ 306 + 307 + { .data = "Ca", .name = "name2", .type = "type1", }, /* followed by both together */ 308 + { .data = "Cb", .name = "name2", }, /* Only match when type doesn't match */ 309 + { .data = "Cc", .name = "name2", .type = "type2", }, 310 + 311 + { .data = "E", .compatible = "compat3" }, 312 + { .data = "G", .compatible = "compat2", }, 313 + { .data = "H", .compatible = "compat2", .name = "name5", }, 314 + { .data = "I", .compatible = "compat2", .type = "type1", }, 315 + { .data = "J", .compatible = "compat2", .type = "type1", .name = "name8", }, 316 + { .data = "K", .compatible = "compat2", .name = "name9", }, 317 + {} 318 + }; 319 + 320 + static struct { 321 + const char *path; 322 + const char *data; 323 + } match_node_tests[] = { 324 + { .path = "/testcase-data/match-node/name0", .data = "A", }, 325 + { .path = "/testcase-data/match-node/name1", .data = "B", }, 326 + { .path = "/testcase-data/match-node/a/name2", .data = "Ca", }, 327 + { .path = "/testcase-data/match-node/b/name2", .data = "Cb", }, 328 + { .path = "/testcase-data/match-node/c/name2", .data = "Cc", }, 329 + { .path = "/testcase-data/match-node/name3", .data = "E", }, 330 + { .path = "/testcase-data/match-node/name4", .data = "G", }, 331 + { .path = "/testcase-data/match-node/name5", .data = "H", }, 332 + { .path = "/testcase-data/match-node/name6", .data = "G", }, 333 + { .path = "/testcase-data/match-node/name7", .data = "I", }, 334 + { .path = "/testcase-data/match-node/name8", .data = "J", }, 335 + { .path = "/testcase-data/match-node/name9", .data = "K", }, 336 + }; 337 + 338 + static void __init of_selftest_match_node(void) 339 + { 340 + struct device_node *np; 341 + const struct of_device_id *match; 342 + int i; 343 + 344 + for (i = 0; i < ARRAY_SIZE(match_node_tests); i++) { 345 + np = of_find_node_by_path(match_node_tests[i].path); 346 + if (!np) { 347 + selftest(0, "missing testcase node %s\n", 348 + match_node_tests[i].path); 349 + continue; 350 + } 351 + 352 + match = of_match_node(match_node_table, np); 353 + if (!match) { 354 + selftest(0, "%s didn't match anything\n", 355 + match_node_tests[i].path); 356 + continue; 357 + } 358 + 359 + if (strcmp(match->data, match_node_tests[i].data) != 0) { 360 + selftest(0, "%s got wrong match. expected %s, got %s\n", 361 + match_node_tests[i].path, match_node_tests[i].data, 362 + (const char *)match->data); 363 + continue; 364 + } 365 + selftest(1, "passed"); 366 + } 367 + } 368 + 303 369 static int __init of_selftest(void) 304 370 { 305 371 struct device_node *np; ··· 382 316 of_selftest_property_match_string(); 383 317 of_selftest_parse_interrupts(); 384 318 of_selftest_parse_interrupts_extended(); 319 + of_selftest_match_node(); 385 320 pr_info("end of selftest - %i passed, %i failed\n", 386 321 selftest_results.passed, selftest_results.failed); 387 322 return 0;
+3
drivers/of/testcase-data/testcases.dtsi
··· 1 + #include "tests-phandle.dtsi" 2 + #include "tests-interrupts.dtsi" 3 + #include "tests-match.dtsi"
+19
drivers/of/testcase-data/tests-match.dtsi
··· 1 + 2 + / { 3 + testcase-data { 4 + match-node { 5 + name0 { }; 6 + name1 { device_type = "type1"; }; 7 + a { name2 { device_type = "type1"; }; }; 8 + b { name2 { }; }; 9 + c { name2 { device_type = "type2"; }; }; 10 + name3 { compatible = "compat3"; }; 11 + name4 { compatible = "compat2", "compat3"; }; 12 + name5 { compatible = "compat2", "compat3"; }; 13 + name6 { compatible = "compat1", "compat2", "compat3"; }; 14 + name7 { compatible = "compat2"; device_type = "type1"; }; 15 + name8 { compatible = "compat2"; device_type = "type1"; }; 16 + name9 { compatible = "compat2"; }; 17 + }; 18 + }; 19 + };
+1
scripts/Makefile.lib
··· 152 152 dtc_cpp_flags = -Wp,-MD,$(depfile).pre.tmp -nostdinc \ 153 153 -I$(srctree)/arch/$(SRCARCH)/boot/dts \ 154 154 -I$(srctree)/arch/$(SRCARCH)/boot/dts/include \ 155 + -I$(srctree)/drivers/of/testcase-data \ 155 156 -undef -D__DTS__ 156 157 157 158 # Finds the multi-part object the current object will be linked into