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
10 #define MAX_CMD_LEN 25
11
env_clear_common(u32 index,const struct env_map_common * map)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
env_read_common(u32 index,const struct env_map_common * map)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
env_clear_core(u32 index,const struct env_map_percpu * map)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
env_read_core(u32 index,const struct env_map_percpu * map)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
env_validate_common(u32 index,const struct env_map_common * map)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
env_validate_core(u32 index,const struct env_map_percpu * map,bool (* cpu_used)(u32))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
envs_cleanup_core(const struct env_map_percpu * map)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
envs_cleanup_common(const struct env_map_common * map)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
envs_read_common(const struct env_map_common * map)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
envs_validate_common(const struct env_map_common * map)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
envs_read_validate_common(const struct env_map_common * map)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
envs_read_validate_core(const struct env_map_percpu * map,bool (* cpu_used)(u32))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
envs_process_and_validate(const struct env_map_common * common,const struct env_map_percpu * core,bool (* cpu_used)(u32))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
args_envs_read_search(const struct env_map_common * map,int argc,char * const argv[])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
arg_read_set(const struct env_map_common * map,u32 i,int argc,char * const argv[])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
args_envs_enumerate(const struct env_map_common * map,int enum_by,int argc,char * const argv[])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