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