1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/string.h> |
3 | #include <linux/err.h> |
4 | #include <linux/slab.h> |
5 | #include <linux/of.h> |
6 | #include <asm/prom.h> |
7 | |
8 | #include "of_helpers.h" |
9 | |
10 | /** |
11 | * pseries_of_derive_parent - basically like dirname(1) |
12 | * @path: the full_name of a node to be added to the tree |
13 | * |
14 | * Returns the node which should be the parent of the node |
15 | * described by path. E.g., for path = "/foo/bar", returns |
16 | * the node with full_name = "/foo". |
17 | */ |
18 | struct device_node *pseries_of_derive_parent(const char *path) |
19 | { |
20 | struct device_node *parent; |
21 | char *parent_path = "/" ; |
22 | const char *tail; |
23 | |
24 | /* We do not want the trailing '/' character */ |
25 | tail = kbasename(path) - 1; |
26 | |
27 | /* reject if path is "/" */ |
28 | if (!strcmp(path, "/" )) |
29 | return ERR_PTR(error: -EINVAL); |
30 | |
31 | if (tail > path) { |
32 | parent_path = kstrndup(s: path, len: tail - path, GFP_KERNEL); |
33 | if (!parent_path) |
34 | return ERR_PTR(error: -ENOMEM); |
35 | } |
36 | parent = of_find_node_by_path(path: parent_path); |
37 | if (strcmp(parent_path, "/" )) |
38 | kfree(objp: parent_path); |
39 | return parent ? parent : ERR_PTR(error: -EINVAL); |
40 | } |
41 | |
42 | |
43 | /* Helper Routines to convert between drc_index to cpu numbers */ |
44 | |
45 | int of_read_drc_info_cell(struct property **prop, const __be32 **curval, |
46 | struct of_drc_info *data) |
47 | { |
48 | const char *p = (char *)(*curval); |
49 | const __be32 *p2; |
50 | |
51 | if (!data) |
52 | return -EINVAL; |
53 | |
54 | /* Get drc-type:encode-string */ |
55 | data->drc_type = (char *)p; |
56 | p = of_prop_next_string(prop: *prop, cur: p); |
57 | if (!p) |
58 | return -EINVAL; |
59 | |
60 | /* Get drc-name-prefix:encode-string */ |
61 | data->drc_name_prefix = (char *)p; |
62 | p = of_prop_next_string(prop: *prop, cur: p); |
63 | if (!p) |
64 | return -EINVAL; |
65 | |
66 | /* Get drc-index-start:encode-int */ |
67 | p2 = (const __be32 *)p; |
68 | data->drc_index_start = be32_to_cpu(*p2); |
69 | |
70 | /* Get drc-name-suffix-start:encode-int */ |
71 | p2 = of_prop_next_u32(prop: *prop, cur: p2, pu: &data->drc_name_suffix_start); |
72 | if (!p2) |
73 | return -EINVAL; |
74 | |
75 | /* Get number-sequential-elements:encode-int */ |
76 | p2 = of_prop_next_u32(prop: *prop, cur: p2, pu: &data->num_sequential_elems); |
77 | if (!p2) |
78 | return -EINVAL; |
79 | |
80 | /* Get sequential-increment:encode-int */ |
81 | p2 = of_prop_next_u32(prop: *prop, cur: p2, pu: &data->sequential_inc); |
82 | if (!p2) |
83 | return -EINVAL; |
84 | |
85 | /* Get drc-power-domain:encode-int */ |
86 | p2 = of_prop_next_u32(prop: *prop, cur: p2, pu: &data->drc_power_domain); |
87 | if (!p2) |
88 | return -EINVAL; |
89 | |
90 | /* Should now know end of current entry */ |
91 | (*curval) = (void *)(++p2); |
92 | data->last_drc_index = data->drc_index_start + |
93 | ((data->num_sequential_elems - 1) * data->sequential_inc); |
94 | |
95 | return 0; |
96 | } |
97 | EXPORT_SYMBOL(of_read_drc_info_cell); |
98 | |