hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/base/property.c
....@@ -18,287 +18,12 @@
1818 #include <linux/etherdevice.h>
1919 #include <linux/phy.h>
2020
21
-struct property_set {
22
- struct device *dev;
23
- struct fwnode_handle fwnode;
24
- const struct property_entry *properties;
25
-};
26
-
27
-static const struct fwnode_operations pset_fwnode_ops;
28
-
29
-static inline bool is_pset_node(const struct fwnode_handle *fwnode)
30
-{
31
- return !IS_ERR_OR_NULL(fwnode) && fwnode->ops == &pset_fwnode_ops;
32
-}
33
-
34
-#define to_pset_node(__fwnode) \
35
- ({ \
36
- typeof(__fwnode) __to_pset_node_fwnode = __fwnode; \
37
- \
38
- is_pset_node(__to_pset_node_fwnode) ? \
39
- container_of(__to_pset_node_fwnode, \
40
- struct property_set, fwnode) : \
41
- NULL; \
42
- })
43
-
44
-static const struct property_entry *
45
-pset_prop_get(const struct property_set *pset, const char *name)
46
-{
47
- const struct property_entry *prop;
48
-
49
- if (!pset || !pset->properties)
50
- return NULL;
51
-
52
- for (prop = pset->properties; prop->name; prop++)
53
- if (!strcmp(name, prop->name))
54
- return prop;
55
-
56
- return NULL;
57
-}
58
-
59
-static const void *property_get_pointer(const struct property_entry *prop)
60
-{
61
- switch (prop->type) {
62
- case DEV_PROP_U8:
63
- if (prop->is_array)
64
- return prop->pointer.u8_data;
65
- return &prop->value.u8_data;
66
- case DEV_PROP_U16:
67
- if (prop->is_array)
68
- return prop->pointer.u16_data;
69
- return &prop->value.u16_data;
70
- case DEV_PROP_U32:
71
- if (prop->is_array)
72
- return prop->pointer.u32_data;
73
- return &prop->value.u32_data;
74
- case DEV_PROP_U64:
75
- if (prop->is_array)
76
- return prop->pointer.u64_data;
77
- return &prop->value.u64_data;
78
- case DEV_PROP_STRING:
79
- if (prop->is_array)
80
- return prop->pointer.str;
81
- return &prop->value.str;
82
- default:
83
- return NULL;
84
- }
85
-}
86
-
87
-static void property_set_pointer(struct property_entry *prop, const void *pointer)
88
-{
89
- switch (prop->type) {
90
- case DEV_PROP_U8:
91
- if (prop->is_array)
92
- prop->pointer.u8_data = pointer;
93
- else
94
- prop->value.u8_data = *((u8 *)pointer);
95
- break;
96
- case DEV_PROP_U16:
97
- if (prop->is_array)
98
- prop->pointer.u16_data = pointer;
99
- else
100
- prop->value.u16_data = *((u16 *)pointer);
101
- break;
102
- case DEV_PROP_U32:
103
- if (prop->is_array)
104
- prop->pointer.u32_data = pointer;
105
- else
106
- prop->value.u32_data = *((u32 *)pointer);
107
- break;
108
- case DEV_PROP_U64:
109
- if (prop->is_array)
110
- prop->pointer.u64_data = pointer;
111
- else
112
- prop->value.u64_data = *((u64 *)pointer);
113
- break;
114
- case DEV_PROP_STRING:
115
- if (prop->is_array)
116
- prop->pointer.str = pointer;
117
- else
118
- prop->value.str = pointer;
119
- break;
120
- default:
121
- break;
122
- }
123
-}
124
-
125
-static const void *pset_prop_find(const struct property_set *pset,
126
- const char *propname, size_t length)
127
-{
128
- const struct property_entry *prop;
129
- const void *pointer;
130
-
131
- prop = pset_prop_get(pset, propname);
132
- if (!prop)
133
- return ERR_PTR(-EINVAL);
134
- pointer = property_get_pointer(prop);
135
- if (!pointer)
136
- return ERR_PTR(-ENODATA);
137
- if (length > prop->length)
138
- return ERR_PTR(-EOVERFLOW);
139
- return pointer;
140
-}
141
-
142
-static int pset_prop_read_u8_array(const struct property_set *pset,
143
- const char *propname,
144
- u8 *values, size_t nval)
145
-{
146
- const void *pointer;
147
- size_t length = nval * sizeof(*values);
148
-
149
- pointer = pset_prop_find(pset, propname, length);
150
- if (IS_ERR(pointer))
151
- return PTR_ERR(pointer);
152
-
153
- memcpy(values, pointer, length);
154
- return 0;
155
-}
156
-
157
-static int pset_prop_read_u16_array(const struct property_set *pset,
158
- const char *propname,
159
- u16 *values, size_t nval)
160
-{
161
- const void *pointer;
162
- size_t length = nval * sizeof(*values);
163
-
164
- pointer = pset_prop_find(pset, propname, length);
165
- if (IS_ERR(pointer))
166
- return PTR_ERR(pointer);
167
-
168
- memcpy(values, pointer, length);
169
- return 0;
170
-}
171
-
172
-static int pset_prop_read_u32_array(const struct property_set *pset,
173
- const char *propname,
174
- u32 *values, size_t nval)
175
-{
176
- const void *pointer;
177
- size_t length = nval * sizeof(*values);
178
-
179
- pointer = pset_prop_find(pset, propname, length);
180
- if (IS_ERR(pointer))
181
- return PTR_ERR(pointer);
182
-
183
- memcpy(values, pointer, length);
184
- return 0;
185
-}
186
-
187
-static int pset_prop_read_u64_array(const struct property_set *pset,
188
- const char *propname,
189
- u64 *values, size_t nval)
190
-{
191
- const void *pointer;
192
- size_t length = nval * sizeof(*values);
193
-
194
- pointer = pset_prop_find(pset, propname, length);
195
- if (IS_ERR(pointer))
196
- return PTR_ERR(pointer);
197
-
198
- memcpy(values, pointer, length);
199
- return 0;
200
-}
201
-
202
-static int pset_prop_count_elems_of_size(const struct property_set *pset,
203
- const char *propname, size_t length)
204
-{
205
- const struct property_entry *prop;
206
-
207
- prop = pset_prop_get(pset, propname);
208
- if (!prop)
209
- return -EINVAL;
210
-
211
- return prop->length / length;
212
-}
213
-
214
-static int pset_prop_read_string_array(const struct property_set *pset,
215
- const char *propname,
216
- const char **strings, size_t nval)
217
-{
218
- const struct property_entry *prop;
219
- const void *pointer;
220
- size_t array_len, length;
221
-
222
- /* Find out the array length. */
223
- prop = pset_prop_get(pset, propname);
224
- if (!prop)
225
- return -EINVAL;
226
-
227
- if (!prop->is_array)
228
- /* The array length for a non-array string property is 1. */
229
- array_len = 1;
230
- else
231
- /* Find the length of an array. */
232
- array_len = pset_prop_count_elems_of_size(pset, propname,
233
- sizeof(const char *));
234
-
235
- /* Return how many there are if strings is NULL. */
236
- if (!strings)
237
- return array_len;
238
-
239
- array_len = min(nval, array_len);
240
- length = array_len * sizeof(*strings);
241
-
242
- pointer = pset_prop_find(pset, propname, length);
243
- if (IS_ERR(pointer))
244
- return PTR_ERR(pointer);
245
-
246
- memcpy(strings, pointer, length);
247
-
248
- return array_len;
249
-}
250
-
25121 struct fwnode_handle *dev_fwnode(struct device *dev)
25222 {
25323 return IS_ENABLED(CONFIG_OF) && dev->of_node ?
25424 &dev->of_node->fwnode : dev->fwnode;
25525 }
25626 EXPORT_SYMBOL_GPL(dev_fwnode);
257
-
258
-static bool pset_fwnode_property_present(const struct fwnode_handle *fwnode,
259
- const char *propname)
260
-{
261
- return !!pset_prop_get(to_pset_node(fwnode), propname);
262
-}
263
-
264
-static int pset_fwnode_read_int_array(const struct fwnode_handle *fwnode,
265
- const char *propname,
266
- unsigned int elem_size, void *val,
267
- size_t nval)
268
-{
269
- const struct property_set *node = to_pset_node(fwnode);
270
-
271
- if (!val)
272
- return pset_prop_count_elems_of_size(node, propname, elem_size);
273
-
274
- switch (elem_size) {
275
- case sizeof(u8):
276
- return pset_prop_read_u8_array(node, propname, val, nval);
277
- case sizeof(u16):
278
- return pset_prop_read_u16_array(node, propname, val, nval);
279
- case sizeof(u32):
280
- return pset_prop_read_u32_array(node, propname, val, nval);
281
- case sizeof(u64):
282
- return pset_prop_read_u64_array(node, propname, val, nval);
283
- }
284
-
285
- return -ENXIO;
286
-}
287
-
288
-static int
289
-pset_fwnode_property_read_string_array(const struct fwnode_handle *fwnode,
290
- const char *propname,
291
- const char **val, size_t nval)
292
-{
293
- return pset_prop_read_string_array(to_pset_node(fwnode), propname,
294
- val, nval);
295
-}
296
-
297
-static const struct fwnode_operations pset_fwnode_ops = {
298
- .property_present = pset_fwnode_property_present,
299
- .property_read_int_array = pset_fwnode_read_int_array,
300
- .property_read_string_array = pset_fwnode_property_read_string_array,
301
-};
30227
30328 /**
30429 * device_property_present - check if a property of a device is present
....@@ -759,223 +484,49 @@
759484 }
760485 EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args);
761486
762
-static void property_entry_free_data(const struct property_entry *p)
763
-{
764
- const void *pointer = property_get_pointer(p);
765
- size_t i, nval;
766
-
767
- if (p->is_array) {
768
- if (p->type == DEV_PROP_STRING && p->pointer.str) {
769
- nval = p->length / sizeof(const char *);
770
- for (i = 0; i < nval; i++)
771
- kfree(p->pointer.str[i]);
772
- }
773
- kfree(pointer);
774
- } else if (p->type == DEV_PROP_STRING) {
775
- kfree(p->value.str);
776
- }
777
- kfree(p->name);
778
-}
779
-
780
-static int property_copy_string_array(struct property_entry *dst,
781
- const struct property_entry *src)
782
-{
783
- const char **d;
784
- size_t nval = src->length / sizeof(*d);
785
- int i;
786
-
787
- d = kcalloc(nval, sizeof(*d), GFP_KERNEL);
788
- if (!d)
789
- return -ENOMEM;
790
-
791
- for (i = 0; i < nval; i++) {
792
- d[i] = kstrdup(src->pointer.str[i], GFP_KERNEL);
793
- if (!d[i] && src->pointer.str[i]) {
794
- while (--i >= 0)
795
- kfree(d[i]);
796
- kfree(d);
797
- return -ENOMEM;
798
- }
799
- }
800
-
801
- dst->pointer.str = d;
802
- return 0;
803
-}
804
-
805
-static int property_entry_copy_data(struct property_entry *dst,
806
- const struct property_entry *src)
807
-{
808
- const void *pointer = property_get_pointer(src);
809
- const void *new;
810
- int error;
811
-
812
- if (src->is_array) {
813
- if (!src->length)
814
- return -ENODATA;
815
-
816
- if (src->type == DEV_PROP_STRING) {
817
- error = property_copy_string_array(dst, src);
818
- if (error)
819
- return error;
820
- new = dst->pointer.str;
821
- } else {
822
- new = kmemdup(pointer, src->length, GFP_KERNEL);
823
- if (!new)
824
- return -ENOMEM;
825
- }
826
- } else if (src->type == DEV_PROP_STRING) {
827
- new = kstrdup(src->value.str, GFP_KERNEL);
828
- if (!new && src->value.str)
829
- return -ENOMEM;
830
- } else {
831
- new = pointer;
832
- }
833
-
834
- dst->length = src->length;
835
- dst->is_array = src->is_array;
836
- dst->type = src->type;
837
-
838
- property_set_pointer(dst, new);
839
-
840
- dst->name = kstrdup(src->name, GFP_KERNEL);
841
- if (!dst->name)
842
- goto out_free_data;
843
-
844
- return 0;
845
-
846
-out_free_data:
847
- property_entry_free_data(dst);
848
- return -ENOMEM;
849
-}
850
-
851487 /**
852
- * property_entries_dup - duplicate array of properties
853
- * @properties: array of properties to copy
488
+ * fwnode_find_reference - Find named reference to a fwnode_handle
489
+ * @fwnode: Firmware node where to look for the reference
490
+ * @name: The name of the reference
491
+ * @index: Index of the reference
854492 *
855
- * This function creates a deep copy of the given NULL-terminated array
856
- * of property entries.
493
+ * @index can be used when the named reference holds a table of references.
494
+ *
495
+ * Returns pointer to the reference fwnode, or ERR_PTR. Caller is responsible to
496
+ * call fwnode_handle_put() on the returned fwnode pointer.
857497 */
858
-struct property_entry *
859
-property_entries_dup(const struct property_entry *properties)
498
+struct fwnode_handle *fwnode_find_reference(const struct fwnode_handle *fwnode,
499
+ const char *name,
500
+ unsigned int index)
860501 {
861
- struct property_entry *p;
862
- int i, n = 0;
502
+ struct fwnode_reference_args args;
503
+ int ret;
863504
864
- while (properties[n].name)
865
- n++;
866
-
867
- p = kcalloc(n + 1, sizeof(*p), GFP_KERNEL);
868
- if (!p)
869
- return ERR_PTR(-ENOMEM);
870
-
871
- for (i = 0; i < n; i++) {
872
- int ret = property_entry_copy_data(&p[i], &properties[i]);
873
- if (ret) {
874
- while (--i >= 0)
875
- property_entry_free_data(&p[i]);
876
- kfree(p);
877
- return ERR_PTR(ret);
878
- }
879
- }
880
-
881
- return p;
505
+ ret = fwnode_property_get_reference_args(fwnode, name, NULL, 0, index,
506
+ &args);
507
+ return ret ? ERR_PTR(ret) : args.fwnode;
882508 }
883
-EXPORT_SYMBOL_GPL(property_entries_dup);
884
-
885
-/**
886
- * property_entries_free - free previously allocated array of properties
887
- * @properties: array of properties to destroy
888
- *
889
- * This function frees given NULL-terminated array of property entries,
890
- * along with their data.
891
- */
892
-void property_entries_free(const struct property_entry *properties)
893
-{
894
- const struct property_entry *p;
895
-
896
- for (p = properties; p->name; p++)
897
- property_entry_free_data(p);
898
-
899
- kfree(properties);
900
-}
901
-EXPORT_SYMBOL_GPL(property_entries_free);
902
-
903
-/**
904
- * pset_free_set - releases memory allocated for copied property set
905
- * @pset: Property set to release
906
- *
907
- * Function takes previously copied property set and releases all the
908
- * memory allocated to it.
909
- */
910
-static void pset_free_set(struct property_set *pset)
911
-{
912
- if (!pset)
913
- return;
914
-
915
- property_entries_free(pset->properties);
916
- kfree(pset);
917
-}
918
-
919
-/**
920
- * pset_copy_set - copies property set
921
- * @pset: Property set to copy
922
- *
923
- * This function takes a deep copy of the given property set and returns
924
- * pointer to the copy. Call device_free_property_set() to free resources
925
- * allocated in this function.
926
- *
927
- * Return: Pointer to the new property set or error pointer.
928
- */
929
-static struct property_set *pset_copy_set(const struct property_set *pset)
930
-{
931
- struct property_entry *properties;
932
- struct property_set *p;
933
-
934
- p = kzalloc(sizeof(*p), GFP_KERNEL);
935
- if (!p)
936
- return ERR_PTR(-ENOMEM);
937
-
938
- properties = property_entries_dup(pset->properties);
939
- if (IS_ERR(properties)) {
940
- kfree(p);
941
- return ERR_CAST(properties);
942
- }
943
-
944
- p->properties = properties;
945
- return p;
946
-}
509
+EXPORT_SYMBOL_GPL(fwnode_find_reference);
947510
948511 /**
949512 * device_remove_properties - Remove properties from a device object.
950513 * @dev: Device whose properties to remove.
951514 *
952515 * The function removes properties previously associated to the device
953
- * secondary firmware node with device_add_properties(). Memory allocated
954
- * to the properties will also be released.
516
+ * firmware node with device_add_properties(). Memory allocated to the
517
+ * properties will also be released.
955518 */
956519 void device_remove_properties(struct device *dev)
957520 {
958
- struct fwnode_handle *fwnode;
959
- struct property_set *pset;
521
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
960522
961
- fwnode = dev_fwnode(dev);
962523 if (!fwnode)
963524 return;
964
- /*
965
- * Pick either primary or secondary node depending which one holds
966
- * the pset. If there is no real firmware node (ACPI/DT) primary
967
- * will hold the pset.
968
- */
969
- pset = to_pset_node(fwnode);
970
- if (pset) {
971
- set_primary_fwnode(dev, NULL);
972
- } else {
973
- pset = to_pset_node(fwnode->secondary);
974
- if (pset && dev == pset->dev)
975
- set_secondary_fwnode(dev, NULL);
525
+
526
+ if (is_software_node(fwnode->secondary)) {
527
+ fwnode_remove_software_node(fwnode->secondary);
528
+ set_secondary_fwnode(dev, NULL);
976529 }
977
- if (pset && dev == pset->dev)
978
- pset_free_set(pset);
979530 }
980531 EXPORT_SYMBOL_GPL(device_remove_properties);
981532
....@@ -985,29 +536,62 @@
985536 * @properties: Collection of properties to add.
986537 *
987538 * Associate a collection of device properties represented by @properties with
988
- * @dev as its secondary firmware node. The function takes a copy of
989
- * @properties.
539
+ * @dev. The function takes a copy of @properties.
540
+ *
541
+ * WARNING: The callers should not use this function if it is known that there
542
+ * is no real firmware node associated with @dev! In that case the callers
543
+ * should create a software node and assign it to @dev directly.
990544 */
991545 int device_add_properties(struct device *dev,
992546 const struct property_entry *properties)
993547 {
994
- struct property_set *p, pset;
548
+ struct fwnode_handle *fwnode;
995549
996
- if (!properties)
997
- return -EINVAL;
550
+ fwnode = fwnode_create_software_node(properties, NULL);
551
+ if (IS_ERR(fwnode))
552
+ return PTR_ERR(fwnode);
998553
999
- pset.properties = properties;
1000
-
1001
- p = pset_copy_set(&pset);
1002
- if (IS_ERR(p))
1003
- return PTR_ERR(p);
1004
-
1005
- p->fwnode.ops = &pset_fwnode_ops;
1006
- set_secondary_fwnode(dev, &p->fwnode);
1007
- p->dev = dev;
554
+ set_secondary_fwnode(dev, fwnode);
1008555 return 0;
1009556 }
1010557 EXPORT_SYMBOL_GPL(device_add_properties);
558
+
559
+/**
560
+ * fwnode_get_name - Return the name of a node
561
+ * @fwnode: The firmware node
562
+ *
563
+ * Returns a pointer to the node name.
564
+ */
565
+const char *fwnode_get_name(const struct fwnode_handle *fwnode)
566
+{
567
+ return fwnode_call_ptr_op(fwnode, get_name);
568
+}
569
+EXPORT_SYMBOL_GPL(fwnode_get_name);
570
+
571
+/**
572
+ * fwnode_get_name_prefix - Return the prefix of node for printing purposes
573
+ * @fwnode: The firmware node
574
+ *
575
+ * Returns the prefix of a node, intended to be printed right before the node.
576
+ * The prefix works also as a separator between the nodes.
577
+ */
578
+const char *fwnode_get_name_prefix(const struct fwnode_handle *fwnode)
579
+{
580
+ return fwnode_call_ptr_op(fwnode, get_name_prefix);
581
+}
582
+
583
+/**
584
+ * fwnode_get_parent - Return parent firwmare node
585
+ * @fwnode: Firmware whose parent is retrieved
586
+ *
587
+ * Return parent firmware node of the given node if possible or %NULL if no
588
+ * parent was available.
589
+ */
590
+struct fwnode_handle *fwnode_get_parent(const struct fwnode_handle *fwnode)
591
+{
592
+ return fwnode_call_ptr_op(fwnode, get_parent);
593
+}
594
+EXPORT_SYMBOL_GPL(fwnode_get_parent);
1011595
1012596 /**
1013597 * fwnode_get_next_parent - Iterate to the node's parent
....@@ -1031,17 +615,102 @@
1031615 EXPORT_SYMBOL_GPL(fwnode_get_next_parent);
1032616
1033617 /**
1034
- * fwnode_get_parent - Return parent firwmare node
1035
- * @fwnode: Firmware whose parent is retrieved
618
+ * fwnode_get_next_parent_dev - Find device of closest ancestor fwnode
619
+ * @fwnode: firmware node
1036620 *
1037
- * Return parent firmware node of the given node if possible or %NULL if no
1038
- * parent was available.
621
+ * Given a firmware node (@fwnode), this function finds its closest ancestor
622
+ * firmware node that has a corresponding struct device and returns that struct
623
+ * device.
624
+ *
625
+ * The caller of this function is expected to call put_device() on the returned
626
+ * device when they are done.
1039627 */
1040
-struct fwnode_handle *fwnode_get_parent(const struct fwnode_handle *fwnode)
628
+struct device *fwnode_get_next_parent_dev(struct fwnode_handle *fwnode)
1041629 {
1042
- return fwnode_call_ptr_op(fwnode, get_parent);
630
+ struct device *dev = NULL;
631
+
632
+ fwnode_handle_get(fwnode);
633
+ do {
634
+ fwnode = fwnode_get_next_parent(fwnode);
635
+ if (fwnode)
636
+ dev = get_dev_from_fwnode(fwnode);
637
+ } while (fwnode && !dev);
638
+ fwnode_handle_put(fwnode);
639
+ return dev;
1043640 }
1044
-EXPORT_SYMBOL_GPL(fwnode_get_parent);
641
+
642
+/**
643
+ * fwnode_count_parents - Return the number of parents a node has
644
+ * @fwnode: The node the parents of which are to be counted
645
+ *
646
+ * Returns the number of parents a node has.
647
+ */
648
+unsigned int fwnode_count_parents(const struct fwnode_handle *fwnode)
649
+{
650
+ struct fwnode_handle *__fwnode;
651
+ unsigned int count;
652
+
653
+ __fwnode = fwnode_get_parent(fwnode);
654
+
655
+ for (count = 0; __fwnode; count++)
656
+ __fwnode = fwnode_get_next_parent(__fwnode);
657
+
658
+ return count;
659
+}
660
+EXPORT_SYMBOL_GPL(fwnode_count_parents);
661
+
662
+/**
663
+ * fwnode_get_nth_parent - Return an nth parent of a node
664
+ * @fwnode: The node the parent of which is requested
665
+ * @depth: Distance of the parent from the node
666
+ *
667
+ * Returns the nth parent of a node. If there is no parent at the requested
668
+ * @depth, %NULL is returned. If @depth is 0, the functionality is equivalent to
669
+ * fwnode_handle_get(). For @depth == 1, it is fwnode_get_parent() and so on.
670
+ *
671
+ * The caller is responsible for calling fwnode_handle_put() for the returned
672
+ * node.
673
+ */
674
+struct fwnode_handle *fwnode_get_nth_parent(struct fwnode_handle *fwnode,
675
+ unsigned int depth)
676
+{
677
+ unsigned int i;
678
+
679
+ fwnode_handle_get(fwnode);
680
+
681
+ for (i = 0; i < depth && fwnode; i++)
682
+ fwnode = fwnode_get_next_parent(fwnode);
683
+
684
+ return fwnode;
685
+}
686
+EXPORT_SYMBOL_GPL(fwnode_get_nth_parent);
687
+
688
+/**
689
+ * fwnode_is_ancestor_of - Test if @test_ancestor is ancestor of @test_child
690
+ * @test_ancestor: Firmware which is tested for being an ancestor
691
+ * @test_child: Firmware which is tested for being the child
692
+ *
693
+ * A node is considered an ancestor of itself too.
694
+ *
695
+ * Returns true if @test_ancestor is an ancestor of @test_child.
696
+ * Otherwise, returns false.
697
+ */
698
+bool fwnode_is_ancestor_of(struct fwnode_handle *test_ancestor,
699
+ struct fwnode_handle *test_child)
700
+{
701
+ if (!test_ancestor)
702
+ return false;
703
+
704
+ fwnode_handle_get(test_child);
705
+ while (test_child) {
706
+ if (test_child == test_ancestor) {
707
+ fwnode_handle_put(test_child);
708
+ return true;
709
+ }
710
+ test_child = fwnode_get_next_parent(test_child);
711
+ }
712
+ return false;
713
+}
1045714
1046715 /**
1047716 * fwnode_get_next_child_node - Return the next child node handle for a node
....@@ -1091,14 +760,23 @@
1091760 struct fwnode_handle *child)
1092761 {
1093762 struct acpi_device *adev = ACPI_COMPANION(dev);
1094
- struct fwnode_handle *fwnode = NULL;
763
+ struct fwnode_handle *fwnode = NULL, *next;
1095764
1096765 if (dev->of_node)
1097766 fwnode = &dev->of_node->fwnode;
1098767 else if (adev)
1099768 fwnode = acpi_fwnode_handle(adev);
1100769
1101
- return fwnode_get_next_child_node(fwnode, child);
770
+ /* Try to find a child in primary fwnode */
771
+ next = fwnode_get_next_child_node(fwnode, child);
772
+ if (next)
773
+ return next;
774
+
775
+ /* When no more children in primary, continue with secondary */
776
+ if (fwnode && !IS_ERR_OR_NULL(fwnode->secondary))
777
+ next = fwnode_get_next_child_node(fwnode->secondary, child);
778
+
779
+ return next;
1102780 }
1103781 EXPORT_SYMBOL_GPL(device_get_next_child_node);
1104782
....@@ -1341,7 +1019,7 @@
13411019 EXPORT_SYMBOL(fwnode_irq_get);
13421020
13431021 /**
1344
- * device_graph_get_next_endpoint - Get next endpoint firmware node
1022
+ * fwnode_graph_get_next_endpoint - Get next endpoint firmware node
13451023 * @fwnode: Pointer to the parent firmware node
13461024 * @prev: Previous endpoint node or %NULL to get the first
13471025 *
....@@ -1461,6 +1139,81 @@
14611139 EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_node);
14621140
14631141 /**
1142
+ * fwnode_graph_get_endpoint_by_id - get endpoint by port and endpoint numbers
1143
+ * @fwnode: parent fwnode_handle containing the graph
1144
+ * @port: identifier of the port node
1145
+ * @endpoint: identifier of the endpoint node under the port node
1146
+ * @flags: fwnode lookup flags
1147
+ *
1148
+ * Return the fwnode handle of the local endpoint corresponding the port and
1149
+ * endpoint IDs or NULL if not found.
1150
+ *
1151
+ * If FWNODE_GRAPH_ENDPOINT_NEXT is passed in @flags and the specified endpoint
1152
+ * has not been found, look for the closest endpoint ID greater than the
1153
+ * specified one and return the endpoint that corresponds to it, if present.
1154
+ *
1155
+ * Do not return endpoints that belong to disabled devices, unless
1156
+ * FWNODE_GRAPH_DEVICE_DISABLED is passed in @flags.
1157
+ *
1158
+ * The returned endpoint needs to be released by calling fwnode_handle_put() on
1159
+ * it when it is not needed any more.
1160
+ */
1161
+struct fwnode_handle *
1162
+fwnode_graph_get_endpoint_by_id(const struct fwnode_handle *fwnode,
1163
+ u32 port, u32 endpoint, unsigned long flags)
1164
+{
1165
+ struct fwnode_handle *ep = NULL, *best_ep = NULL;
1166
+ unsigned int best_ep_id = 0;
1167
+ bool endpoint_next = flags & FWNODE_GRAPH_ENDPOINT_NEXT;
1168
+ bool enabled_only = !(flags & FWNODE_GRAPH_DEVICE_DISABLED);
1169
+
1170
+ while ((ep = fwnode_graph_get_next_endpoint(fwnode, ep))) {
1171
+ struct fwnode_endpoint fwnode_ep = { 0 };
1172
+ int ret;
1173
+
1174
+ if (enabled_only) {
1175
+ struct fwnode_handle *dev_node;
1176
+ bool available;
1177
+
1178
+ dev_node = fwnode_graph_get_remote_port_parent(ep);
1179
+ available = fwnode_device_is_available(dev_node);
1180
+ fwnode_handle_put(dev_node);
1181
+ if (!available)
1182
+ continue;
1183
+ }
1184
+
1185
+ ret = fwnode_graph_parse_endpoint(ep, &fwnode_ep);
1186
+ if (ret < 0)
1187
+ continue;
1188
+
1189
+ if (fwnode_ep.port != port)
1190
+ continue;
1191
+
1192
+ if (fwnode_ep.id == endpoint)
1193
+ return ep;
1194
+
1195
+ if (!endpoint_next)
1196
+ continue;
1197
+
1198
+ /*
1199
+ * If the endpoint that has just been found is not the first
1200
+ * matching one and the ID of the one found previously is closer
1201
+ * to the requested endpoint ID, skip it.
1202
+ */
1203
+ if (fwnode_ep.id < endpoint ||
1204
+ (best_ep && best_ep_id < fwnode_ep.id))
1205
+ continue;
1206
+
1207
+ fwnode_handle_put(best_ep);
1208
+ best_ep = fwnode_handle_get(ep);
1209
+ best_ep_id = fwnode_ep.id;
1210
+ }
1211
+
1212
+ return best_ep;
1213
+}
1214
+EXPORT_SYMBOL_GPL(fwnode_graph_get_endpoint_by_id);
1215
+
1216
+/**
14641217 * fwnode_graph_parse_endpoint - parse common endpoint node properties
14651218 * @fwnode: pointer to endpoint fwnode_handle
14661219 * @endpoint: pointer to the fwnode endpoint data structure
....@@ -1483,3 +1236,78 @@
14831236 return fwnode_call_ptr_op(dev_fwnode(dev), device_get_match_data, dev);
14841237 }
14851238 EXPORT_SYMBOL_GPL(device_get_match_data);
1239
+
1240
+static void *
1241
+fwnode_graph_devcon_match(struct fwnode_handle *fwnode, const char *con_id,
1242
+ void *data, devcon_match_fn_t match)
1243
+{
1244
+ struct fwnode_handle *node;
1245
+ struct fwnode_handle *ep;
1246
+ void *ret;
1247
+
1248
+ fwnode_graph_for_each_endpoint(fwnode, ep) {
1249
+ node = fwnode_graph_get_remote_port_parent(ep);
1250
+ if (!fwnode_device_is_available(node)) {
1251
+ fwnode_handle_put(node);
1252
+ continue;
1253
+ }
1254
+
1255
+ ret = match(node, con_id, data);
1256
+ fwnode_handle_put(node);
1257
+ if (ret) {
1258
+ fwnode_handle_put(ep);
1259
+ return ret;
1260
+ }
1261
+ }
1262
+ return NULL;
1263
+}
1264
+
1265
+static void *
1266
+fwnode_devcon_match(struct fwnode_handle *fwnode, const char *con_id,
1267
+ void *data, devcon_match_fn_t match)
1268
+{
1269
+ struct fwnode_handle *node;
1270
+ void *ret;
1271
+ int i;
1272
+
1273
+ for (i = 0; ; i++) {
1274
+ node = fwnode_find_reference(fwnode, con_id, i);
1275
+ if (IS_ERR(node))
1276
+ break;
1277
+
1278
+ ret = match(node, NULL, data);
1279
+ fwnode_handle_put(node);
1280
+ if (ret)
1281
+ return ret;
1282
+ }
1283
+
1284
+ return NULL;
1285
+}
1286
+
1287
+/**
1288
+ * fwnode_connection_find_match - Find connection from a device node
1289
+ * @fwnode: Device node with the connection
1290
+ * @con_id: Identifier for the connection
1291
+ * @data: Data for the match function
1292
+ * @match: Function to check and convert the connection description
1293
+ *
1294
+ * Find a connection with unique identifier @con_id between @fwnode and another
1295
+ * device node. @match will be used to convert the connection description to
1296
+ * data the caller is expecting to be returned.
1297
+ */
1298
+void *fwnode_connection_find_match(struct fwnode_handle *fwnode,
1299
+ const char *con_id, void *data,
1300
+ devcon_match_fn_t match)
1301
+{
1302
+ void *ret;
1303
+
1304
+ if (!fwnode || !match)
1305
+ return NULL;
1306
+
1307
+ ret = fwnode_graph_devcon_match(fwnode, con_id, data, match);
1308
+ if (ret)
1309
+ return ret;
1310
+
1311
+ return fwnode_devcon_match(fwnode, con_id, data, match);
1312
+}
1313
+EXPORT_SYMBOL_GPL(fwnode_connection_find_match);