xref: /openbmc/u-boot/board/synopsys/hsdk/env-lib.c (revision cf0bcd7d)
1 /*
2  * Copyright (C) 2018 Synopsys, Inc. All rights reserved.
3  * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
4  *
5  * SPDX-License-Identifier:	GPL-2.0+
6  */
7 
8 #include "env-lib.h"
9 
10 #define MAX_CMD_LEN	25
11 
12 static void env_clear_common(u32 index, const struct env_map_common *map)
13 {
14 	map[index].val->val = 0;
15 	map[index].val->set = false;
16 }
17 
18 static int env_read_common(u32 index, const struct env_map_common *map)
19 {
20 	u32 val;
21 
22 	if (!env_get_yesno(map[index].env_name)) {
23 		if (map[index].type == ENV_HEX) {
24 			val = (u32)env_get_hex(map[index].env_name, 0);
25 			debug("ENV: %s: = %#x\n", map[index].env_name, val);
26 		} else {
27 			val = (u32)env_get_ulong(map[index].env_name, 10, 0);
28 			debug("ENV: %s: = %d\n", map[index].env_name, val);
29 		}
30 
31 		map[index].val->val = val;
32 		map[index].val->set = true;
33 	}
34 
35 	return 0;
36 }
37 
38 static void env_clear_core(u32 index, const struct env_map_percpu *map)
39 {
40 	for (u32 i = 0; i < NR_CPUS; i++) {
41 		(*map[index].val)[i].val = 0;
42 		(*map[index].val)[i].set = false;
43 	}
44 }
45 
46 static int env_read_core(u32 index, const struct env_map_percpu *map)
47 {
48 	u32 val;
49 	char command[MAX_CMD_LEN];
50 
51 	for (u32 i = 0; i < NR_CPUS; i++) {
52 		sprintf(command, "%s_%u", map[index].env_name, i);
53 		if (!env_get_yesno(command)) {
54 			if (map[index].type == ENV_HEX) {
55 				val = (u32)env_get_hex(command, 0);
56 				debug("ENV: %s: = %#x\n", command, val);
57 			} else {
58 				val = (u32)env_get_ulong(command, 10, 0);
59 				debug("ENV: %s: = %d\n", command, val);
60 			}
61 
62 			(*map[index].val)[i].val = val;
63 			(*map[index].val)[i].set = true;
64 		}
65 	}
66 
67 	return 0;
68 }
69 
70 static int env_validate_common(u32 index, const struct env_map_common *map)
71 {
72 	u32 value = map[index].val->val;
73 	bool set = map[index].val->set;
74 	u32 min = map[index].min;
75 	u32 max = map[index].max;
76 
77 	/* Check if environment is mandatory */
78 	if (map[index].mandatory && !set) {
79 		pr_err("Variable \'%s\' is mandatory, but it is not defined\n",
80 		       map[index].env_name);
81 
82 		return -EINVAL;
83 	}
84 
85 	/* Check environment boundary */
86 	if (set && (value < min || value > max)) {
87 		if (map[index].type == ENV_HEX)
88 			pr_err("Variable \'%s\' must be between %#x and %#x\n",
89 			       map[index].env_name, min, max);
90 		else
91 			pr_err("Variable \'%s\' must be between %u and %u\n",
92 			       map[index].env_name, min, max);
93 
94 		return -EINVAL;
95 	}
96 
97 	return 0;
98 }
99 
100 static int env_validate_core(u32 index, const struct env_map_percpu *map,
101 			     bool (*cpu_used)(u32))
102 {
103 	u32 value;
104 	bool set;
105 	bool mandatory = map[index].mandatory;
106 	u32 min, max;
107 
108 	for (u32 i = 0; i < NR_CPUS; i++) {
109 		set = (*map[index].val)[i].set;
110 		value = (*map[index].val)[i].val;
111 
112 		/* Check if environment is mandatory */
113 		if (cpu_used(i) && mandatory && !set) {
114 			pr_err("CPU %u is used, but \'%s_%u\' is not defined\n",
115 			       i, map[index].env_name, i);
116 
117 			return -EINVAL;
118 		}
119 
120 		min = map[index].min[i];
121 		max = map[index].max[i];
122 
123 		/* Check environment boundary */
124 		if (set && (value < min || value > max)) {
125 			if (map[index].type == ENV_HEX)
126 				pr_err("Variable \'%s_%u\' must be between %#x and %#x\n",
127 				       map[index].env_name, i, min, max);
128 			else
129 				pr_err("Variable \'%s_%u\' must be between %d and %d\n",
130 				       map[index].env_name, i, min, max);
131 
132 			return -EINVAL;
133 		}
134 	}
135 
136 	return 0;
137 }
138 
139 void envs_cleanup_core(const struct env_map_percpu *map)
140 {
141 	/* Cleanup env struct first */
142 	for (u32 i = 0; map[i].env_name; i++)
143 		env_clear_core(i, map);
144 }
145 
146 void envs_cleanup_common(const struct env_map_common *map)
147 {
148 	/* Cleanup env struct first */
149 	for (u32 i = 0; map[i].env_name; i++)
150 		env_clear_common(i, map);
151 }
152 
153 int envs_read_common(const struct env_map_common *map)
154 {
155 	int ret;
156 
157 	for (u32 i = 0; map[i].env_name; i++) {
158 		ret = env_read_common(i, map);
159 		if (ret)
160 			return ret;
161 	}
162 
163 	return 0;
164 }
165 
166 int envs_validate_common(const struct env_map_common *map)
167 {
168 	int ret;
169 
170 	for (u32 i = 0; map[i].env_name; i++) {
171 		ret = env_validate_common(i, map);
172 		if (ret)
173 			return ret;
174 	}
175 
176 	return 0;
177 }
178 
179 int envs_read_validate_common(const struct env_map_common *map)
180 {
181 	int ret;
182 
183 	envs_cleanup_common(map);
184 
185 	ret = envs_read_common(map);
186 	if (ret)
187 		return ret;
188 
189 	ret = envs_validate_common(map);
190 	if (ret)
191 		return ret;
192 
193 	return 0;
194 }
195 
196 int envs_read_validate_core(const struct env_map_percpu *map,
197 			    bool (*cpu_used)(u32))
198 {
199 	int ret;
200 
201 	envs_cleanup_core(map);
202 
203 	for (u32 i = 0; map[i].env_name; i++) {
204 		ret = env_read_core(i, map);
205 		if (ret)
206 			return ret;
207 	}
208 
209 	for (u32 i = 0; map[i].env_name; i++) {
210 		ret = env_validate_core(i, map, cpu_used);
211 		if (ret)
212 			return ret;
213 	}
214 
215 	return 0;
216 }
217 
218 int envs_process_and_validate(const struct env_map_common *common,
219 			      const struct env_map_percpu *core,
220 			      bool (*cpu_used)(u32))
221 {
222 	int ret;
223 
224 	ret = envs_read_validate_common(common);
225 	if (ret)
226 		return ret;
227 
228 	ret = envs_read_validate_core(core, cpu_used);
229 	if (ret)
230 		return ret;
231 
232 	return 0;
233 }
234 
235 static int args_envs_read_search(const struct env_map_common *map,
236 				 int argc, char *const argv[])
237 {
238 	for (int i = 0; map[i].env_name; i++) {
239 		if (!strcmp(argv[0], map[i].env_name))
240 			return i;
241 	}
242 
243 	pr_err("Unexpected argument '%s', can't parse\n", argv[0]);
244 
245 	return -ENOENT;
246 }
247 
248 static int arg_read_set(const struct env_map_common *map, u32 i, int argc,
249 			char *const argv[])
250 {
251 	char *endp = argv[1];
252 
253 	if (map[i].type == ENV_HEX)
254 		map[i].val->val = simple_strtoul(argv[1], &endp, 16);
255 	else
256 		map[i].val->val = simple_strtoul(argv[1], &endp, 10);
257 
258 	map[i].val->set = true;
259 
260 	if (*endp == '\0')
261 		return 0;
262 
263 	pr_err("Unexpected argument '%s', can't parse\n", argv[1]);
264 
265 	map[i].val->set = false;
266 
267 	return -EINVAL;
268 }
269 
270 int args_envs_enumerate(const struct env_map_common *map, int enum_by,
271 			int argc, char *const argv[])
272 {
273 	u32 i;
274 
275 	if (argc % enum_by) {
276 		pr_err("unexpected argument number: %d\n", argc);
277 		return -EINVAL;
278 	}
279 
280 	while (argc > 0) {
281 		i = args_envs_read_search(map, argc, argv);
282 		if (i < 0)
283 			return i;
284 
285 		debug("ARG: found '%s' with index %d\n", map[i].env_name, i);
286 
287 		if (i < 0) {
288 			pr_err("unknown arg: %s\n", argv[0]);
289 			return -EINVAL;
290 		}
291 
292 		if (arg_read_set(map, i, argc, argv))
293 			return -EINVAL;
294 
295 		debug("ARG: value.s '%s' == %#x\n", argv[1], map[i].val->val);
296 
297 		argc -= enum_by;
298 		argv += enum_by;
299 	}
300 
301 	return 0;
302 }
303