cmd_ethsw.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /*
  2. * Copyright 2015 Freescale Semiconductor, Inc.
  3. *
  4. * SPDX-License-Identifier: GPL-2.0+
  5. *
  6. * Ethernet Switch commands
  7. */
  8. #include <common.h>
  9. #include <command.h>
  10. #include <errno.h>
  11. #include <ethsw.h>
  12. static const char *ethsw_name;
  13. static struct keywords_to_function {
  14. enum ethsw_keyword_id cmd_keyword[ETHSW_MAX_CMD_PARAMS];
  15. int cmd_func_offset;
  16. int (*keyword_function)(struct ethsw_command_def *parsed_cmd);
  17. } ethsw_cmd_def[] = {
  18. {
  19. .cmd_keyword = {
  20. ethsw_id_enable,
  21. ethsw_id_key_end,
  22. },
  23. .cmd_func_offset = offsetof(struct ethsw_command_func,
  24. port_enable),
  25. .keyword_function = NULL,
  26. }, {
  27. .cmd_keyword = {
  28. ethsw_id_disable,
  29. ethsw_id_key_end,
  30. },
  31. .cmd_func_offset = offsetof(struct ethsw_command_func,
  32. port_disable),
  33. .keyword_function = NULL,
  34. }, {
  35. .cmd_keyword = {
  36. ethsw_id_show,
  37. ethsw_id_key_end,
  38. },
  39. .cmd_func_offset = offsetof(struct ethsw_command_func,
  40. port_show),
  41. .keyword_function = NULL,
  42. },
  43. };
  44. struct keywords_optional {
  45. int cmd_keyword[ETHSW_MAX_CMD_PARAMS];
  46. } cmd_opt_def[] = {
  47. {
  48. .cmd_keyword = {
  49. ethsw_id_port,
  50. ethsw_id_port_no,
  51. ethsw_id_key_end,
  52. },
  53. },
  54. };
  55. static int keyword_match_gen(enum ethsw_keyword_id key_id, int argc, char
  56. *const argv[], int *argc_nr,
  57. struct ethsw_command_def *parsed_cmd);
  58. static int keyword_match_port(enum ethsw_keyword_id key_id, int argc,
  59. char *const argv[], int *argc_nr,
  60. struct ethsw_command_def *parsed_cmd);
  61. /*
  62. * Define properties for each keyword;
  63. * keep the order synced with enum ethsw_keyword_id
  64. */
  65. struct keyword_def {
  66. const char *keyword_name;
  67. int (*match)(enum ethsw_keyword_id key_id, int argc, char *const argv[],
  68. int *argc_nr, struct ethsw_command_def *parsed_cmd);
  69. } keyword[] = {
  70. {
  71. .keyword_name = "help",
  72. .match = &keyword_match_gen,
  73. }, {
  74. .keyword_name = "show",
  75. .match = &keyword_match_gen,
  76. }, {
  77. .keyword_name = "port",
  78. .match = &keyword_match_port
  79. }, {
  80. .keyword_name = "enable",
  81. .match = &keyword_match_gen,
  82. }, {
  83. .keyword_name = "disable",
  84. .match = &keyword_match_gen,
  85. },
  86. };
  87. /*
  88. * Function used by an Ethernet Switch driver to set the functions
  89. * that must be called by the parser when an ethsw command is given
  90. */
  91. int ethsw_define_functions(const struct ethsw_command_func *cmd_func)
  92. {
  93. int i;
  94. void **aux_p;
  95. int (*cmd_func_aux)(struct ethsw_command_def *);
  96. if (!cmd_func->ethsw_name)
  97. return -EINVAL;
  98. ethsw_name = cmd_func->ethsw_name;
  99. for (i = 0; i < ARRAY_SIZE(ethsw_cmd_def); i++) {
  100. /*
  101. * get the pointer to the function send by the Ethernet Switch
  102. * driver that corresponds to the proper ethsw command
  103. */
  104. if (ethsw_cmd_def[i].keyword_function)
  105. continue;
  106. aux_p = (void *)cmd_func + ethsw_cmd_def[i].cmd_func_offset;
  107. cmd_func_aux = (int (*)(struct ethsw_command_def *)) *aux_p;
  108. ethsw_cmd_def[i].keyword_function = cmd_func_aux;
  109. }
  110. return 0;
  111. }
  112. /* Generic function used to match a keyword only by a string */
  113. static int keyword_match_gen(enum ethsw_keyword_id key_id, int argc,
  114. char *const argv[], int *argc_nr,
  115. struct ethsw_command_def *parsed_cmd)
  116. {
  117. if (strcmp(argv[*argc_nr], keyword[key_id].keyword_name) == 0) {
  118. parsed_cmd->cmd_to_keywords[*argc_nr] = key_id;
  119. return 1;
  120. }
  121. return 0;
  122. }
  123. /* Function used to match the command's port */
  124. static int keyword_match_port(enum ethsw_keyword_id key_id, int argc,
  125. char *const argv[], int *argc_nr,
  126. struct ethsw_command_def *parsed_cmd)
  127. {
  128. unsigned long val;
  129. if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
  130. return 0;
  131. if (*argc_nr + 1 >= argc)
  132. return 0;
  133. if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) {
  134. parsed_cmd->port = val;
  135. (*argc_nr)++;
  136. parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_port_no;
  137. return 1;
  138. }
  139. return 0;
  140. }
  141. /* Finds optional keywords and modifies *argc_va to skip them */
  142. static void cmd_keywords_opt_check(const struct ethsw_command_def *parsed_cmd,
  143. int *argc_val)
  144. {
  145. int i;
  146. int keyw_opt_matched;
  147. int argc_val_max;
  148. int const *cmd_keyw_p;
  149. int const *cmd_keyw_opt_p;
  150. /* remember the best match */
  151. argc_val_max = *argc_val;
  152. /*
  153. * check if our command's optional keywords match the optional
  154. * keywords of an available command
  155. */
  156. for (i = 0; i < ARRAY_SIZE(ethsw_cmd_def); i++) {
  157. keyw_opt_matched = 0;
  158. cmd_keyw_p = &parsed_cmd->cmd_to_keywords[keyw_opt_matched];
  159. cmd_keyw_opt_p = &cmd_opt_def[i].cmd_keyword[keyw_opt_matched];
  160. /*
  161. * increase the number of keywords that
  162. * matched with a command
  163. */
  164. while (keyw_opt_matched + *argc_val <
  165. parsed_cmd->cmd_keywords_nr &&
  166. *cmd_keyw_opt_p != ethsw_id_key_end &&
  167. *(cmd_keyw_p + *argc_val) == *cmd_keyw_opt_p) {
  168. keyw_opt_matched++;
  169. cmd_keyw_p++;
  170. cmd_keyw_opt_p++;
  171. }
  172. /*
  173. * if all our optional command's keywords perfectly match an
  174. * optional pattern, then we can move to the next defined
  175. * keywords in our command; remember the one that matched the
  176. * greatest number of keywords
  177. */
  178. if (keyw_opt_matched + *argc_val <=
  179. parsed_cmd->cmd_keywords_nr &&
  180. *cmd_keyw_opt_p == ethsw_id_key_end &&
  181. *argc_val + keyw_opt_matched > argc_val_max)
  182. argc_val_max = *argc_val + keyw_opt_matched;
  183. }
  184. *argc_val = argc_val_max;
  185. }
  186. /*
  187. * Finds the function to call based on keywords and
  188. * modifies *argc_va to skip them
  189. */
  190. static void cmd_keywords_check(struct ethsw_command_def *parsed_cmd,
  191. int *argc_val)
  192. {
  193. int i;
  194. int keyw_matched;
  195. int *cmd_keyw_p;
  196. int *cmd_keyw_def_p;
  197. /*
  198. * check if our command's keywords match the
  199. * keywords of an available command
  200. */
  201. for (i = 0; i < ARRAY_SIZE(ethsw_cmd_def); i++) {
  202. keyw_matched = 0;
  203. cmd_keyw_p = &parsed_cmd->cmd_to_keywords[keyw_matched];
  204. cmd_keyw_def_p = &ethsw_cmd_def[i].cmd_keyword[keyw_matched];
  205. /*
  206. * increase the number of keywords that
  207. * matched with a command
  208. */
  209. while (keyw_matched + *argc_val < parsed_cmd->cmd_keywords_nr &&
  210. *cmd_keyw_def_p != ethsw_id_key_end &&
  211. *(cmd_keyw_p + *argc_val) == *cmd_keyw_def_p) {
  212. keyw_matched++;
  213. cmd_keyw_p++;
  214. cmd_keyw_def_p++;
  215. }
  216. /*
  217. * if all our command's keywords perfectly match an
  218. * available command, then we get the function we need to call
  219. * to configure the Ethernet Switch
  220. */
  221. if (keyw_matched && keyw_matched + *argc_val ==
  222. parsed_cmd->cmd_keywords_nr &&
  223. *cmd_keyw_def_p == ethsw_id_key_end) {
  224. *argc_val += keyw_matched;
  225. parsed_cmd->cmd_function =
  226. ethsw_cmd_def[i].keyword_function;
  227. return;
  228. }
  229. }
  230. }
  231. /* find all the keywords in the command */
  232. static int keywords_find(int argc, char * const argv[],
  233. struct ethsw_command_def *parsed_cmd)
  234. {
  235. int i;
  236. int j;
  237. int argc_val;
  238. int rc = CMD_RET_SUCCESS;
  239. for (i = 1; i < argc; i++) {
  240. for (j = 0; j < ethsw_id_count; j++) {
  241. if (keyword[j].match(j, argc, argv, &i, parsed_cmd))
  242. break;
  243. }
  244. }
  245. /* if there is no keyword match for a word, the command is invalid */
  246. for (i = 1; i < argc; i++)
  247. if (parsed_cmd->cmd_to_keywords[i] == ethsw_id_key_end)
  248. rc = CMD_RET_USAGE;
  249. parsed_cmd->cmd_keywords_nr = argc;
  250. argc_val = 1;
  251. /* get optional parameters first */
  252. cmd_keywords_opt_check(parsed_cmd, &argc_val);
  253. if (argc_val == parsed_cmd->cmd_keywords_nr)
  254. return CMD_RET_USAGE;
  255. /*
  256. * check the keywords and if a match is found,
  257. * get the function to call
  258. */
  259. cmd_keywords_check(parsed_cmd, &argc_val);
  260. /* error if not all commands' parameters were matched */
  261. if (argc_val == parsed_cmd->cmd_keywords_nr) {
  262. if (!parsed_cmd->cmd_function) {
  263. printf("Command not available for: %s\n", ethsw_name);
  264. rc = CMD_RET_FAILURE;
  265. }
  266. } else {
  267. rc = CMD_RET_USAGE;
  268. }
  269. return rc;
  270. }
  271. static void command_def_init(struct ethsw_command_def *parsed_cmd)
  272. {
  273. int i;
  274. for (i = 0; i < ETHSW_MAX_CMD_PARAMS; i++)
  275. parsed_cmd->cmd_to_keywords[i] = ethsw_id_key_end;
  276. parsed_cmd->port = ETHSW_CMD_PORT_ALL;
  277. parsed_cmd->cmd_function = NULL;
  278. }
  279. /* function to interpret commands starting with "ethsw " */
  280. static int do_ethsw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  281. {
  282. struct ethsw_command_def parsed_cmd;
  283. int rc = CMD_RET_SUCCESS;
  284. if (argc == 1 || argc >= ETHSW_MAX_CMD_PARAMS)
  285. return CMD_RET_USAGE;
  286. command_def_init(&parsed_cmd);
  287. rc = keywords_find(argc, argv, &parsed_cmd);
  288. if (rc == CMD_RET_SUCCESS)
  289. rc = parsed_cmd.cmd_function(&parsed_cmd);
  290. return rc;
  291. }
  292. #define ETHSW_PORT_CONF_HELP "[port <port_no>] { enable | disable | show } " \
  293. "- enable/disable a port; show shows a port's configuration"
  294. U_BOOT_CMD(ethsw, ETHSW_MAX_CMD_PARAMS, 0, do_ethsw,
  295. "Ethernet l2 switch commands",
  296. ETHSW_PORT_CONF_HELP"\n"
  297. );