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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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