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