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