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