aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/of
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-03-05 20:32:02 -0500
committerDavid S. Miller <davem@davemloft.net>2014-03-05 20:32:02 -0500
commit67ddc87f162e2d0e29db2b6b21c5a3fbcb8be206 (patch)
treec83ac73e3d569156d4b7f3dab3e7e27e0054cd0d /drivers/of
parent6092c79fd00ce48ee8698955ea6419cc5cd65641 (diff)
parentc3bebc71c4bcdafa24b506adf0c1de3c1f77e2e0 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Conflicts: drivers/net/wireless/ath/ath9k/recv.c drivers/net/wireless/mwifiex/pcie.c net/ipv6/sit.c The SIT driver conflict consists of a bug fix being done by hand in 'net' (missing u64_stats_init()) whilst in 'net-next' a helper was created (netdev_alloc_pcpu_stats()) which takes care of this. The two wireless conflicts were overlapping changes. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/of')
-rw-r--r--drivers/of/base.c150
-rw-r--r--drivers/of/selftest.c67
-rw-r--r--drivers/of/testcase-data/testcases.dtsi3
-rw-r--r--drivers/of/testcase-data/tests-interrupts.dtsi58
-rw-r--r--drivers/of/testcase-data/tests-match.dtsi19
-rw-r--r--drivers/of/testcase-data/tests-phandle.dtsi39
6 files changed, 260 insertions, 76 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 10b51106c854..89e888a78899 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -342,27 +342,72 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
342} 342}
343EXPORT_SYMBOL(of_get_cpu_node); 343EXPORT_SYMBOL(of_get_cpu_node);
344 344
345/** Checks if the given "compat" string matches one of the strings in 345/**
346 * the device's "compatible" property 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 */
348static int __of_device_is_compatible(const struct device_node *device, 375static 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; 378 struct property *prop;
352 int cplen, l; 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 }
353 395
354 cp = __of_get_property(device, "compatible", &cplen); 396 /* Matching type is better than matching name */
355 if (cp == NULL) 397 if (type && type[0]) {
356 return 0; 398 if (!device->type || of_node_cmp(type, device->type))
357 while (cplen > 0) { 399 return 0;
358 if (of_compat_cmp(cp, compat, strlen(compat)) == 0) 400 score += 2;
359 return 1;
360 l = strlen(cp) + 1;
361 cp += l;
362 cplen -= l;
363 } 401 }
364 402
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;
366} 411}
367 412
368/** Checks if the given "compat" string matches one of the strings in 413/** 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,
375 int res; 420 int res;
376 421
377 raw_spin_lock_irqsave(&devtree_lock, flags); 422 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);
379 raw_spin_unlock_irqrestore(&devtree_lock, flags); 424 raw_spin_unlock_irqrestore(&devtree_lock, flags);
380 return res; 425 return res;
381} 426}
@@ -681,10 +726,7 @@ struct device_node *of_find_compatible_node(struct device_node *from,
681 raw_spin_lock_irqsave(&devtree_lock, flags); 726 raw_spin_lock_irqsave(&devtree_lock, flags);
682 np = from ? from->allnext : of_allnodes; 727 np = from ? from->allnext : of_allnodes;
683 for (; np; np = np->allnext) { 728 for (; np; np = np->allnext) {
684 if (type 729 if (__of_device_is_compatible(np, compatible, type, NULL) &&
685 && !(np->type && (of_node_cmp(np->type, type) == 0)))
686 continue;
687 if (__of_device_is_compatible(np, compatible) &&
688 of_node_get(np)) 730 of_node_get(np))
689 break; 731 break;
690 } 732 }
@@ -730,65 +772,26 @@ out:
730} 772}
731EXPORT_SYMBOL(of_find_node_with_property); 773EXPORT_SYMBOL(of_find_node_with_property);
732 774
733static const struct of_device_id *
734of_match_compatible(const struct of_device_id *matches,
735 const struct device_node *node)
736{
737 const char *cp;
738 int cplen, l;
739 const struct of_device_id *m;
740
741 cp = __of_get_property(node, "compatible", &cplen);
742 while (cp && (cplen > 0)) {
743 m = matches;
744 while (m->name[0] || m->type[0] || m->compatible[0]) {
745 /* Only match for the entries without type and name */
746 if (m->name[0] || m->type[0] ||
747 of_compat_cmp(m->compatible, cp,
748 strlen(m->compatible)))
749 m++;
750 else
751 return m;
752 }
753
754 /* Get node's next compatible string */
755 l = strlen(cp) + 1;
756 cp += l;
757 cplen -= l;
758 }
759
760 return NULL;
761}
762
763static 775static
764const struct of_device_id *__of_match_node(const struct of_device_id *matches, 776const struct of_device_id *__of_match_node(const struct of_device_id *matches,
765 const struct device_node *node) 777 const struct device_node *node)
766{ 778{
767 const struct of_device_id *m; 779 const struct of_device_id *best_match = NULL;
780 int score, best_score = 0;
768 781
769 if (!matches) 782 if (!matches)
770 return NULL; 783 return NULL;
771 784
772 m = of_match_compatible(matches, node); 785 for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++) {
773 if (m) 786 score = __of_device_is_compatible(node, matches->compatible,
774 return m; 787 matches->type, matches->name);
775 788 if (score > best_score) {
776 while (matches->name[0] || matches->type[0] || matches->compatible[0]) { 789 best_match = matches;
777 int match = 1; 790 best_score = score;
778 if (matches->name[0]) 791 }
779 match &= node->name
780 && !strcmp(matches->name, node->name);
781 if (matches->type[0])
782 match &= node->type
783 && !strcmp(matches->type, node->type);
784 if (matches->compatible[0])
785 match &= __of_device_is_compatible(node,
786 matches->compatible);
787 if (match)
788 return matches;
789 matches++;
790 } 792 }
791 return NULL; 793
794 return best_match;
792} 795}
793 796
794/** 797/**
@@ -796,12 +799,7 @@ const struct of_device_id *__of_match_node(const struct of_device_id *matches,
796 * @matches: array of of device match structures to search in 799 * @matches: array of of device match structures to search in
797 * @node: the of device structure to match against 800 * @node: the of device structure to match against
798 * 801 *
799 * Low level utility function used by device matching. We have two ways 802 * Low level utility function used by device matching.
800 * of matching:
801 * - Try to find the best compatible match by comparing each compatible
802 * string of device node with all the given matches respectively.
803 * - If the above method failed, then try to match the compatible by using
804 * __of_device_is_compatible() besides the match in type and name.
805 */ 803 */
806const struct of_device_id *of_match_node(const struct of_device_id *matches, 804const struct of_device_id *of_match_node(const struct of_device_id *matches,
807 const struct device_node *node) 805 const struct device_node *node)
diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c
index e21012bde639..6643d1920985 100644
--- a/drivers/of/selftest.c
+++ b/drivers/of/selftest.c
@@ -300,6 +300,72 @@ static void __init of_selftest_parse_interrupts_extended(void)
300 of_node_put(np); 300 of_node_put(np);
301} 301}
302 302
303static 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
320static 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
338static 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
303static int __init of_selftest(void) 369static int __init of_selftest(void)
304{ 370{
305 struct device_node *np; 371 struct device_node *np;
@@ -316,6 +382,7 @@ static int __init of_selftest(void)
316 of_selftest_property_match_string(); 382 of_selftest_property_match_string();
317 of_selftest_parse_interrupts(); 383 of_selftest_parse_interrupts();
318 of_selftest_parse_interrupts_extended(); 384 of_selftest_parse_interrupts_extended();
385 of_selftest_match_node();
319 pr_info("end of selftest - %i passed, %i failed\n", 386 pr_info("end of selftest - %i passed, %i failed\n",
320 selftest_results.passed, selftest_results.failed); 387 selftest_results.passed, selftest_results.failed);
321 return 0; 388 return 0;
diff --git a/drivers/of/testcase-data/testcases.dtsi b/drivers/of/testcase-data/testcases.dtsi
new file mode 100644
index 000000000000..3a5b75a8e4d7
--- /dev/null
+++ b/drivers/of/testcase-data/testcases.dtsi
@@ -0,0 +1,3 @@
1#include "tests-phandle.dtsi"
2#include "tests-interrupts.dtsi"
3#include "tests-match.dtsi"
diff --git a/drivers/of/testcase-data/tests-interrupts.dtsi b/drivers/of/testcase-data/tests-interrupts.dtsi
new file mode 100644
index 000000000000..c843720bd3e5
--- /dev/null
+++ b/drivers/of/testcase-data/tests-interrupts.dtsi
@@ -0,0 +1,58 @@
1
2/ {
3 testcase-data {
4 interrupts {
5 #address-cells = <1>;
6 #size-cells = <1>;
7 test_intc0: intc0 {
8 interrupt-controller;
9 #interrupt-cells = <1>;
10 };
11
12 test_intc1: intc1 {
13 interrupt-controller;
14 #interrupt-cells = <3>;
15 };
16
17 test_intc2: intc2 {
18 interrupt-controller;
19 #interrupt-cells = <2>;
20 };
21
22 test_intmap0: intmap0 {
23 #interrupt-cells = <1>;
24 #address-cells = <0>;
25 interrupt-map = <1 &test_intc0 9>,
26 <2 &test_intc1 10 11 12>,
27 <3 &test_intc2 13 14>,
28 <4 &test_intc2 15 16>;
29 };
30
31 test_intmap1: intmap1 {
32 #interrupt-cells = <2>;
33 interrupt-map = <0x5000 1 2 &test_intc0 15>;
34 };
35
36 interrupts0 {
37 interrupt-parent = <&test_intc0>;
38 interrupts = <1>, <2>, <3>, <4>;
39 };
40
41 interrupts1 {
42 interrupt-parent = <&test_intmap0>;
43 interrupts = <1>, <2>, <3>, <4>;
44 };
45
46 interrupts-extended0 {
47 reg = <0x5000 0x100>;
48 interrupts-extended = <&test_intc0 1>,
49 <&test_intc1 2 3 4>,
50 <&test_intc2 5 6>,
51 <&test_intmap0 1>,
52 <&test_intmap0 2>,
53 <&test_intmap0 3>,
54 <&test_intmap1 1 2>;
55 };
56 };
57 };
58};
diff --git a/drivers/of/testcase-data/tests-match.dtsi b/drivers/of/testcase-data/tests-match.dtsi
new file mode 100644
index 000000000000..c9e541129534
--- /dev/null
+++ b/drivers/of/testcase-data/tests-match.dtsi
@@ -0,0 +1,19 @@
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};
diff --git a/drivers/of/testcase-data/tests-phandle.dtsi b/drivers/of/testcase-data/tests-phandle.dtsi
new file mode 100644
index 000000000000..0007d3cd7dc2
--- /dev/null
+++ b/drivers/of/testcase-data/tests-phandle.dtsi
@@ -0,0 +1,39 @@
1
2/ {
3 testcase-data {
4 phandle-tests {
5 provider0: provider0 {
6 #phandle-cells = <0>;
7 };
8
9 provider1: provider1 {
10 #phandle-cells = <1>;
11 };
12
13 provider2: provider2 {
14 #phandle-cells = <2>;
15 };
16
17 provider3: provider3 {
18 #phandle-cells = <3>;
19 };
20
21 consumer-a {
22 phandle-list = <&provider1 1>,
23 <&provider2 2 0>,
24 <0>,
25 <&provider3 4 4 3>,
26 <&provider2 5 100>,
27 <&provider0>,
28 <&provider1 7>;
29 phandle-list-names = "first", "second", "third";
30
31 phandle-list-bad-phandle = <12345678 0 0>;
32 phandle-list-bad-args = <&provider2 1 0>,
33 <&provider3 0>;
34 empty-property;
35 unterminated-string = [40 41 42 43];
36 };
37 };
38 };
39};