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