]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/blob - drivers/of/plugin-manager.c
of: plugin-manager: fix section mismatch error
[sojka/nv-tegra/linux-3.10.git] / drivers / of / plugin-manager.c
1 /*
2  * Copyright (c) 2015, NVIDIA CORPORATION.  All rights reserved.
3  *
4  * Author: Laxman Dewangan<ldewangan@nvidia.com>
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  */
15
16 #include <linux/init.h>
17 #include <linux/spinlock.h>
18 #include <linux/slab.h>
19 #include <linux/string.h>
20 #include <linux/proc_fs.h>
21 #include <linux/of.h>
22 #include <linux/of_fdt.h>
23
24 static struct property *__of_copy_property(const struct property *prop,
25                 gfp_t flags)
26 {
27         struct property *propn;
28
29         propn = kzalloc(sizeof(*prop), flags);
30         if (propn == NULL)
31                 return NULL;
32
33         propn->name = kstrdup(prop->name, flags);
34         if (propn->name == NULL)
35                 goto err_fail_name;
36
37         if (prop->length > 0) {
38                 propn->value = kmalloc(prop->length, flags);
39                 if (propn->value == NULL)
40                         goto err_fail_value;
41                 memcpy(propn->value, prop->value, prop->length);
42                 propn->length = prop->length;
43         }
44         return propn;
45
46 err_fail_value:
47         kfree(propn->name);
48 err_fail_name:
49         kfree(propn);
50         return NULL;
51 }
52
53
54 static int __init update_target_node_from_overlay(
55                 struct device_node *target, struct device_node *overlay)
56 {
57         struct property *prop;
58         struct property *tprop;
59         struct property *new_prop;
60         const char *pval;
61         int lenp = 0;
62         int ret;
63
64         for_each_property_of_node(overlay, prop) {
65                 /* Skip those we do not want to proceed */
66                 if (!strcmp(prop->name, "name") ||
67                         !strcmp(prop->name, "phandle") ||
68                         !strcmp(prop->name, "linux,phandle"))
69                                 continue;
70                 if (!strcmp(prop->name, "delete-target-property")) {
71                         if (prop->length <= 0)
72                                 continue;
73                         pval = (const char *)prop->value;
74                         pr_info("Removing Prop %s from target %s\n",
75                                 pval, target->full_name);
76                         tprop = of_find_property(target, pval, &lenp);
77                         if (tprop)
78                                 of_remove_property(target, tprop);
79                         continue;
80                 }
81
82                 new_prop = __of_copy_property(prop, GFP_KERNEL);
83                 if (!new_prop) {
84                         pr_err("Prop %s can not be duplicated\n",
85                                 prop->name);
86                         return -EINVAL;
87                 }
88
89                 tprop = of_find_property(target, prop->name, &lenp);
90                 if (!tprop) {
91                         ret = of_add_property(target, new_prop);
92                         if (ret < 0) {
93                                 pr_err("Prop %s can not be added on node %s\n",
94                                         new_prop->name, target->full_name);
95                                 return ret;
96                         }
97                 } else {
98                         ret = of_update_property(target, new_prop);
99                         if (ret < 0) {
100                                 pr_err("Prop %s can not be updated on node %s\n",
101                                         new_prop->name, target->full_name);
102                                 return ret;
103                         }
104                 }
105         }
106         return 0;
107 }
108
109 static int __init update_target_node(struct device_node *target,
110         struct device_node *overlay)
111 {
112         struct device_node *tchild, *ochild;
113         int ret;
114
115         ret = update_target_node_from_overlay(target, overlay);
116         if (ret < 0) {
117                 pr_err("Target %s update with overlay %s failed: %d\n",
118                         target->name, overlay->name, ret);
119                 return ret;
120         }
121
122         for_each_child_of_node(overlay, ochild) {
123                 tchild = of_get_child_by_name(target, ochild->name);
124                 if (!tchild) {
125                         pr_err("Overlay child %s not found on target %s\n",
126                                 ochild->full_name, tchild->full_name);
127                         continue;
128                 }
129
130                 ret = update_target_node(tchild, ochild);
131                 if (ret < 0) {
132                         pr_err("Target %s update with overlay %s failed: %d\n",
133                                 tchild->name, ochild->name, ret);
134                         return ret;
135                 }
136         }
137         return 0;
138 }
139
140 static int __init parse_fragment(struct device_node *np)
141 {
142         struct device_node *board_np, *odm_np, *overlay, *target, *cnp;
143         const char *bname;
144         struct property *prop;
145         int board_count;
146         int odm_count;
147         int nchild;
148         bool found = false;
149         int ret;
150
151         board_count = of_property_count_strings(np, "ids");
152         odm_count = of_property_count_strings(np, "odm-data");
153         if ((board_count <= 0) && (odm_count <= 0)) {
154                 pr_err("Node %s does not have property ids and odm data\n",
155                         np->name);
156                 return -EINVAL;
157         }
158
159         nchild = of_get_child_count(np);
160         if (!nchild) {
161                 pr_err("Node %s does not have Overlay child\n", np->name);
162                 return -EINVAL;
163         }
164
165         /* Match the IDs or odm data */
166         board_np = of_find_node_by_path("/chosen/plugin-manager/ids");
167         odm_np = of_find_node_by_path("/chosen/plugin-manager/odm-data");
168         if (!board_np && !odm_np) {
169                 pr_err("chosen/plugin-manager does'nt have ids and odm-data\n");
170                 return -EINVAL;
171         }
172
173         if ((board_count > 0) && board_np) {
174                 of_property_for_each_string(np, "ids", prop, bname) {
175                         found = of_property_read_bool(board_np, bname);
176                         if (found) {
177                                 pr_info("node %s match with board %s\n",
178                                         np->full_name, bname);
179                                 break;
180                         }
181                 }
182         }
183
184         if (!found && (odm_count > 0) && odm_np) {
185                 of_property_for_each_string(np, "odm-data", prop, bname) {
186                         found = of_property_read_bool(odm_np, bname);
187                         if (found) {
188                                 pr_info("node %s match with odm-data %s\n",
189                                         np->full_name, bname);
190                                 break;
191                         }
192                 }
193         }
194
195         if (!found)
196                 return 0;
197
198         for_each_child_of_node(np, cnp) {
199                 target = of_parse_phandle(cnp, "target", 0);
200                 if (!target) {
201                         pr_err("Node %s does not have targer node\n",
202                                 cnp->name);
203                         continue;
204                 }
205
206                 overlay = of_get_child_by_name(cnp, "_overlay_");
207                 if (!overlay) {
208                         pr_err("Node %s does not have Overlay\n", cnp->name);
209                         continue;
210                 }
211
212                 ret = update_target_node(target, overlay);
213                 if (ret < 0) {
214                         pr_err("Target %s update with overlay %s failed: %d\n",
215                                 target->name, overlay->name, ret);
216                         continue;
217                 }
218         }
219         return 0;
220 }
221
222 static int __init plugin_manager_init(void)
223 {
224         struct device_node *pm_node;
225         struct device_node *child;
226         int ret;
227
228         pr_info("Initializing plugin-manager\n");
229
230         pm_node = of_find_node_by_path("/plugin-manager");
231         if (!pm_node) {
232                 pr_info("Plugin-manager not available\n");
233                 return 0;
234         }
235
236         if (!of_device_is_available(pm_node)) {
237                 pr_info("Plugin-manager status disabled\n");
238                 return 0;
239         }
240
241         for_each_child_of_node(pm_node, child) {
242                 if (!of_device_is_available(child)) {
243                         pr_info("Plugin-manager child %s status disabled\n",
244                                 child->name);
245                         continue;
246                 }
247                 ret = parse_fragment(child);
248                 if (ret < 0)
249                         pr_err("Error in parsing node %s: %d\n",
250                                 child->full_name, ret);
251         }
252         return 0;
253 }
254 core_initcall(plugin_manager_init);