xref: /openbmc/u-boot/cmd/ethsw.c (revision 2e192b245ed36a63bab0ef576999a95e23f60ecd)
1*2e192b24SSimon Glass /*
2*2e192b24SSimon Glass  * Copyright 2015 Freescale Semiconductor, Inc.
3*2e192b24SSimon Glass  *
4*2e192b24SSimon Glass  * SPDX-License-Identifier:      GPL-2.0+
5*2e192b24SSimon Glass  *
6*2e192b24SSimon Glass  * Ethernet Switch commands
7*2e192b24SSimon Glass  */
8*2e192b24SSimon Glass 
9*2e192b24SSimon Glass #include <common.h>
10*2e192b24SSimon Glass #include <command.h>
11*2e192b24SSimon Glass #include <errno.h>
12*2e192b24SSimon Glass #include <env_flags.h>
13*2e192b24SSimon Glass #include <ethsw.h>
14*2e192b24SSimon Glass 
15*2e192b24SSimon Glass static const char *ethsw_name;
16*2e192b24SSimon Glass 
17*2e192b24SSimon Glass #define ETHSW_PORT_STATS_HELP "ethsw [port <port_no>] statistics " \
18*2e192b24SSimon Glass "{ [help] | [clear] } - show an l2 switch port's statistics"
19*2e192b24SSimon Glass 
20*2e192b24SSimon Glass static int ethsw_port_stats_help_key_func(struct ethsw_command_def *parsed_cmd)
21*2e192b24SSimon Glass {
22*2e192b24SSimon Glass 	printf(ETHSW_PORT_STATS_HELP"\n");
23*2e192b24SSimon Glass 
24*2e192b24SSimon Glass 	return CMD_RET_SUCCESS;
25*2e192b24SSimon Glass }
26*2e192b24SSimon Glass 
27*2e192b24SSimon Glass #define ETHSW_LEARN_HELP "ethsw [port <port_no>] learning " \
28*2e192b24SSimon Glass "{ [help] | show | auto | disable } " \
29*2e192b24SSimon Glass "- enable/disable/show learning configuration on a port"
30*2e192b24SSimon Glass 
31*2e192b24SSimon Glass static int ethsw_learn_help_key_func(struct ethsw_command_def *parsed_cmd)
32*2e192b24SSimon Glass {
33*2e192b24SSimon Glass 	printf(ETHSW_LEARN_HELP"\n");
34*2e192b24SSimon Glass 
35*2e192b24SSimon Glass 	return CMD_RET_SUCCESS;
36*2e192b24SSimon Glass }
37*2e192b24SSimon Glass 
38*2e192b24SSimon Glass #define ETHSW_FDB_HELP "ethsw [port <port_no>] [vlan <vid>] fdb " \
39*2e192b24SSimon Glass "{ [help] | show | flush | { add | del } <mac> } " \
40*2e192b24SSimon Glass "- Add/delete a mac entry in FDB; use show to see FDB entries; " \
41*2e192b24SSimon Glass "if vlan <vid> is missing, VID 1 will be used"
42*2e192b24SSimon Glass 
43*2e192b24SSimon Glass static int ethsw_fdb_help_key_func(struct ethsw_command_def *parsed_cmd)
44*2e192b24SSimon Glass {
45*2e192b24SSimon Glass 	printf(ETHSW_FDB_HELP"\n");
46*2e192b24SSimon Glass 
47*2e192b24SSimon Glass 	return CMD_RET_SUCCESS;
48*2e192b24SSimon Glass }
49*2e192b24SSimon Glass 
50*2e192b24SSimon Glass #define ETHSW_PVID_HELP "ethsw [port <port_no>] " \
51*2e192b24SSimon Glass "pvid { [help] | show | <pvid> } " \
52*2e192b24SSimon Glass "- set/show PVID (ingress and egress VLAN tagging) for a port"
53*2e192b24SSimon Glass 
54*2e192b24SSimon Glass static int ethsw_pvid_help_key_func(struct ethsw_command_def *parsed_cmd)
55*2e192b24SSimon Glass {
56*2e192b24SSimon Glass 	printf(ETHSW_PVID_HELP"\n");
57*2e192b24SSimon Glass 
58*2e192b24SSimon Glass 	return CMD_RET_SUCCESS;
59*2e192b24SSimon Glass }
60*2e192b24SSimon Glass 
61*2e192b24SSimon Glass #define ETHSW_VLAN_HELP "ethsw [port <port_no>] vlan " \
62*2e192b24SSimon Glass "{ [help] | show | add <vid> | del <vid> } " \
63*2e192b24SSimon Glass "- add a VLAN to a port (VLAN members)"
64*2e192b24SSimon Glass 
65*2e192b24SSimon Glass static int ethsw_vlan_help_key_func(struct ethsw_command_def *parsed_cmd)
66*2e192b24SSimon Glass {
67*2e192b24SSimon Glass 	printf(ETHSW_VLAN_HELP"\n");
68*2e192b24SSimon Glass 
69*2e192b24SSimon Glass 	return CMD_RET_SUCCESS;
70*2e192b24SSimon Glass }
71*2e192b24SSimon Glass 
72*2e192b24SSimon Glass #define ETHSW_PORT_UNTAG_HELP "ethsw [port <port_no>] untagged " \
73*2e192b24SSimon Glass "{ [help] | show | all | none | pvid } " \
74*2e192b24SSimon Glass " - set egress tagging mod for a port"
75*2e192b24SSimon Glass 
76*2e192b24SSimon Glass static int ethsw_port_untag_help_key_func(struct ethsw_command_def *parsed_cmd)
77*2e192b24SSimon Glass {
78*2e192b24SSimon Glass 	printf(ETHSW_PORT_UNTAG_HELP"\n");
79*2e192b24SSimon Glass 
80*2e192b24SSimon Glass 	return CMD_RET_SUCCESS;
81*2e192b24SSimon Glass }
82*2e192b24SSimon Glass 
83*2e192b24SSimon Glass #define ETHSW_EGR_VLAN_TAG_HELP "ethsw [port <port_no>] egress tag " \
84*2e192b24SSimon Glass "{ [help] | show | pvid | classified } " \
85*2e192b24SSimon Glass "- Configure VID source for egress tag. " \
86*2e192b24SSimon Glass "Tag's VID could be the frame's classified VID or the PVID of the port"
87*2e192b24SSimon Glass 
88*2e192b24SSimon Glass static int ethsw_egr_tag_help_key_func(struct ethsw_command_def *parsed_cmd)
89*2e192b24SSimon Glass {
90*2e192b24SSimon Glass 	printf(ETHSW_EGR_VLAN_TAG_HELP"\n");
91*2e192b24SSimon Glass 
92*2e192b24SSimon Glass 	return CMD_RET_SUCCESS;
93*2e192b24SSimon Glass }
94*2e192b24SSimon Glass 
95*2e192b24SSimon Glass #define ETHSW_VLAN_FDB_HELP "ethsw vlan fdb " \
96*2e192b24SSimon Glass "{ [help] | show | shared | private } " \
97*2e192b24SSimon Glass "- make VLAN learning shared or private"
98*2e192b24SSimon Glass 
99*2e192b24SSimon Glass static int ethsw_vlan_learn_help_key_func(struct ethsw_command_def *parsed_cmd)
100*2e192b24SSimon Glass {
101*2e192b24SSimon Glass 	printf(ETHSW_VLAN_FDB_HELP"\n");
102*2e192b24SSimon Glass 
103*2e192b24SSimon Glass 	return CMD_RET_SUCCESS;
104*2e192b24SSimon Glass }
105*2e192b24SSimon Glass 
106*2e192b24SSimon Glass #define ETHSW_PORT_INGR_FLTR_HELP "ethsw [port <port_no>] ingress filtering" \
107*2e192b24SSimon Glass " { [help] | show | enable | disable } " \
108*2e192b24SSimon Glass "- enable/disable VLAN ingress filtering on port"
109*2e192b24SSimon Glass 
110*2e192b24SSimon Glass static int ethsw_ingr_fltr_help_key_func(struct ethsw_command_def *parsed_cmd)
111*2e192b24SSimon Glass {
112*2e192b24SSimon Glass 	printf(ETHSW_PORT_INGR_FLTR_HELP"\n");
113*2e192b24SSimon Glass 
114*2e192b24SSimon Glass 	return CMD_RET_SUCCESS;
115*2e192b24SSimon Glass }
116*2e192b24SSimon Glass 
117*2e192b24SSimon Glass static struct keywords_to_function {
118*2e192b24SSimon Glass 	enum ethsw_keyword_id cmd_keyword[ETHSW_MAX_CMD_PARAMS];
119*2e192b24SSimon Glass 	int cmd_func_offset;
120*2e192b24SSimon Glass 	int (*keyword_function)(struct ethsw_command_def *parsed_cmd);
121*2e192b24SSimon Glass } ethsw_cmd_def[] = {
122*2e192b24SSimon Glass 		{
123*2e192b24SSimon Glass 			.cmd_keyword = {
124*2e192b24SSimon Glass 					ethsw_id_enable,
125*2e192b24SSimon Glass 					ethsw_id_key_end,
126*2e192b24SSimon Glass 			},
127*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
128*2e192b24SSimon Glass 						    port_enable),
129*2e192b24SSimon Glass 			.keyword_function = NULL,
130*2e192b24SSimon Glass 		}, {
131*2e192b24SSimon Glass 			.cmd_keyword = {
132*2e192b24SSimon Glass 					ethsw_id_disable,
133*2e192b24SSimon Glass 					ethsw_id_key_end,
134*2e192b24SSimon Glass 			},
135*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
136*2e192b24SSimon Glass 						    port_disable),
137*2e192b24SSimon Glass 			.keyword_function = NULL,
138*2e192b24SSimon Glass 		}, {
139*2e192b24SSimon Glass 			.cmd_keyword = {
140*2e192b24SSimon Glass 					ethsw_id_show,
141*2e192b24SSimon Glass 					ethsw_id_key_end,
142*2e192b24SSimon Glass 			},
143*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
144*2e192b24SSimon Glass 						    port_show),
145*2e192b24SSimon Glass 			.keyword_function = NULL,
146*2e192b24SSimon Glass 		}, {
147*2e192b24SSimon Glass 			.cmd_keyword = {
148*2e192b24SSimon Glass 					ethsw_id_statistics,
149*2e192b24SSimon Glass 					ethsw_id_help,
150*2e192b24SSimon Glass 					ethsw_id_key_end,
151*2e192b24SSimon Glass 			},
152*2e192b24SSimon Glass 			.cmd_func_offset = -1,
153*2e192b24SSimon Glass 			.keyword_function = &ethsw_port_stats_help_key_func,
154*2e192b24SSimon Glass 		}, {
155*2e192b24SSimon Glass 			.cmd_keyword = {
156*2e192b24SSimon Glass 					ethsw_id_statistics,
157*2e192b24SSimon Glass 					ethsw_id_key_end,
158*2e192b24SSimon Glass 			},
159*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
160*2e192b24SSimon Glass 						    port_stats),
161*2e192b24SSimon Glass 			.keyword_function = NULL,
162*2e192b24SSimon Glass 		}, {
163*2e192b24SSimon Glass 			.cmd_keyword = {
164*2e192b24SSimon Glass 					ethsw_id_statistics,
165*2e192b24SSimon Glass 					ethsw_id_clear,
166*2e192b24SSimon Glass 					ethsw_id_key_end,
167*2e192b24SSimon Glass 			},
168*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
169*2e192b24SSimon Glass 						    port_stats_clear),
170*2e192b24SSimon Glass 			.keyword_function = NULL,
171*2e192b24SSimon Glass 		}, {
172*2e192b24SSimon Glass 			.cmd_keyword = {
173*2e192b24SSimon Glass 					ethsw_id_learning,
174*2e192b24SSimon Glass 					ethsw_id_key_end,
175*2e192b24SSimon Glass 			},
176*2e192b24SSimon Glass 			.cmd_func_offset = -1,
177*2e192b24SSimon Glass 			.keyword_function = &ethsw_learn_help_key_func,
178*2e192b24SSimon Glass 		}, {
179*2e192b24SSimon Glass 			.cmd_keyword = {
180*2e192b24SSimon Glass 					ethsw_id_learning,
181*2e192b24SSimon Glass 					ethsw_id_help,
182*2e192b24SSimon Glass 					ethsw_id_key_end,
183*2e192b24SSimon Glass 			},
184*2e192b24SSimon Glass 			.cmd_func_offset = -1,
185*2e192b24SSimon Glass 			.keyword_function = &ethsw_learn_help_key_func,
186*2e192b24SSimon Glass 		}, {
187*2e192b24SSimon Glass 			.cmd_keyword = {
188*2e192b24SSimon Glass 					ethsw_id_learning,
189*2e192b24SSimon Glass 					ethsw_id_show,
190*2e192b24SSimon Glass 					ethsw_id_key_end,
191*2e192b24SSimon Glass 			},
192*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
193*2e192b24SSimon Glass 						    port_learn_show),
194*2e192b24SSimon Glass 			.keyword_function = NULL,
195*2e192b24SSimon Glass 		}, {
196*2e192b24SSimon Glass 			.cmd_keyword = {
197*2e192b24SSimon Glass 					ethsw_id_learning,
198*2e192b24SSimon Glass 					ethsw_id_auto,
199*2e192b24SSimon Glass 					ethsw_id_key_end,
200*2e192b24SSimon Glass 			},
201*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
202*2e192b24SSimon Glass 						    port_learn),
203*2e192b24SSimon Glass 			.keyword_function = NULL,
204*2e192b24SSimon Glass 		}, {
205*2e192b24SSimon Glass 			.cmd_keyword = {
206*2e192b24SSimon Glass 					ethsw_id_learning,
207*2e192b24SSimon Glass 					ethsw_id_disable,
208*2e192b24SSimon Glass 					ethsw_id_key_end,
209*2e192b24SSimon Glass 			},
210*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
211*2e192b24SSimon Glass 						    port_learn),
212*2e192b24SSimon Glass 			.keyword_function = NULL,
213*2e192b24SSimon Glass 		}, {
214*2e192b24SSimon Glass 			.cmd_keyword = {
215*2e192b24SSimon Glass 					ethsw_id_fdb,
216*2e192b24SSimon Glass 					ethsw_id_key_end,
217*2e192b24SSimon Glass 			},
218*2e192b24SSimon Glass 			.cmd_func_offset = -1,
219*2e192b24SSimon Glass 			.keyword_function = &ethsw_fdb_help_key_func,
220*2e192b24SSimon Glass 		}, {
221*2e192b24SSimon Glass 			.cmd_keyword = {
222*2e192b24SSimon Glass 					ethsw_id_fdb,
223*2e192b24SSimon Glass 					ethsw_id_help,
224*2e192b24SSimon Glass 					ethsw_id_key_end,
225*2e192b24SSimon Glass 			},
226*2e192b24SSimon Glass 			.cmd_func_offset = -1,
227*2e192b24SSimon Glass 			.keyword_function = &ethsw_fdb_help_key_func,
228*2e192b24SSimon Glass 		}, {
229*2e192b24SSimon Glass 			.cmd_keyword = {
230*2e192b24SSimon Glass 					ethsw_id_fdb,
231*2e192b24SSimon Glass 					ethsw_id_show,
232*2e192b24SSimon Glass 					ethsw_id_key_end,
233*2e192b24SSimon Glass 			},
234*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
235*2e192b24SSimon Glass 						    fdb_show),
236*2e192b24SSimon Glass 			.keyword_function = NULL,
237*2e192b24SSimon Glass 		}, {
238*2e192b24SSimon Glass 			.cmd_keyword = {
239*2e192b24SSimon Glass 					ethsw_id_fdb,
240*2e192b24SSimon Glass 					ethsw_id_flush,
241*2e192b24SSimon Glass 					ethsw_id_key_end,
242*2e192b24SSimon Glass 			},
243*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
244*2e192b24SSimon Glass 						    fdb_flush),
245*2e192b24SSimon Glass 			.keyword_function = NULL,
246*2e192b24SSimon Glass 		}, {
247*2e192b24SSimon Glass 			.cmd_keyword = {
248*2e192b24SSimon Glass 					ethsw_id_fdb,
249*2e192b24SSimon Glass 					ethsw_id_add,
250*2e192b24SSimon Glass 					ethsw_id_add_del_mac,
251*2e192b24SSimon Glass 					ethsw_id_key_end,
252*2e192b24SSimon Glass 			},
253*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
254*2e192b24SSimon Glass 						    fdb_entry_add),
255*2e192b24SSimon Glass 			.keyword_function = NULL,
256*2e192b24SSimon Glass 		}, {
257*2e192b24SSimon Glass 			.cmd_keyword = {
258*2e192b24SSimon Glass 					ethsw_id_fdb,
259*2e192b24SSimon Glass 					ethsw_id_del,
260*2e192b24SSimon Glass 					ethsw_id_add_del_mac,
261*2e192b24SSimon Glass 					ethsw_id_key_end,
262*2e192b24SSimon Glass 			},
263*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
264*2e192b24SSimon Glass 						    fdb_entry_del),
265*2e192b24SSimon Glass 			.keyword_function = NULL,
266*2e192b24SSimon Glass 		}, {
267*2e192b24SSimon Glass 			.cmd_keyword = {
268*2e192b24SSimon Glass 					ethsw_id_pvid,
269*2e192b24SSimon Glass 					ethsw_id_key_end,
270*2e192b24SSimon Glass 			},
271*2e192b24SSimon Glass 			.cmd_func_offset = -1,
272*2e192b24SSimon Glass 			.keyword_function = &ethsw_pvid_help_key_func,
273*2e192b24SSimon Glass 		}, {
274*2e192b24SSimon Glass 			.cmd_keyword = {
275*2e192b24SSimon Glass 					ethsw_id_pvid,
276*2e192b24SSimon Glass 					ethsw_id_help,
277*2e192b24SSimon Glass 					ethsw_id_key_end,
278*2e192b24SSimon Glass 			},
279*2e192b24SSimon Glass 			.cmd_func_offset = -1,
280*2e192b24SSimon Glass 			.keyword_function = &ethsw_pvid_help_key_func,
281*2e192b24SSimon Glass 		}, {
282*2e192b24SSimon Glass 			.cmd_keyword = {
283*2e192b24SSimon Glass 					ethsw_id_pvid,
284*2e192b24SSimon Glass 					ethsw_id_show,
285*2e192b24SSimon Glass 					ethsw_id_key_end,
286*2e192b24SSimon Glass 			},
287*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
288*2e192b24SSimon Glass 						    pvid_show),
289*2e192b24SSimon Glass 			.keyword_function = NULL,
290*2e192b24SSimon Glass 		}, {
291*2e192b24SSimon Glass 			.cmd_keyword = {
292*2e192b24SSimon Glass 					ethsw_id_pvid,
293*2e192b24SSimon Glass 					ethsw_id_pvid_no,
294*2e192b24SSimon Glass 					ethsw_id_key_end,
295*2e192b24SSimon Glass 			},
296*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
297*2e192b24SSimon Glass 						    pvid_set),
298*2e192b24SSimon Glass 			.keyword_function = NULL,
299*2e192b24SSimon Glass 		}, {
300*2e192b24SSimon Glass 			.cmd_keyword = {
301*2e192b24SSimon Glass 					ethsw_id_vlan,
302*2e192b24SSimon Glass 					ethsw_id_key_end,
303*2e192b24SSimon Glass 			},
304*2e192b24SSimon Glass 			.cmd_func_offset = -1,
305*2e192b24SSimon Glass 			.keyword_function = &ethsw_vlan_help_key_func,
306*2e192b24SSimon Glass 		}, {
307*2e192b24SSimon Glass 			.cmd_keyword = {
308*2e192b24SSimon Glass 					ethsw_id_vlan,
309*2e192b24SSimon Glass 					ethsw_id_help,
310*2e192b24SSimon Glass 					ethsw_id_key_end,
311*2e192b24SSimon Glass 			},
312*2e192b24SSimon Glass 			.cmd_func_offset = -1,
313*2e192b24SSimon Glass 			.keyword_function = &ethsw_vlan_help_key_func,
314*2e192b24SSimon Glass 		}, {
315*2e192b24SSimon Glass 			.cmd_keyword = {
316*2e192b24SSimon Glass 					ethsw_id_vlan,
317*2e192b24SSimon Glass 					ethsw_id_show,
318*2e192b24SSimon Glass 					ethsw_id_key_end,
319*2e192b24SSimon Glass 			},
320*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
321*2e192b24SSimon Glass 						    vlan_show),
322*2e192b24SSimon Glass 			.keyword_function = NULL,
323*2e192b24SSimon Glass 		}, {
324*2e192b24SSimon Glass 			.cmd_keyword = {
325*2e192b24SSimon Glass 					ethsw_id_vlan,
326*2e192b24SSimon Glass 					ethsw_id_add,
327*2e192b24SSimon Glass 					ethsw_id_add_del_no,
328*2e192b24SSimon Glass 					ethsw_id_key_end,
329*2e192b24SSimon Glass 			},
330*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
331*2e192b24SSimon Glass 						    vlan_set),
332*2e192b24SSimon Glass 			.keyword_function = NULL,
333*2e192b24SSimon Glass 		}, {
334*2e192b24SSimon Glass 			.cmd_keyword = {
335*2e192b24SSimon Glass 					ethsw_id_vlan,
336*2e192b24SSimon Glass 					ethsw_id_del,
337*2e192b24SSimon Glass 					ethsw_id_add_del_no,
338*2e192b24SSimon Glass 					ethsw_id_key_end,
339*2e192b24SSimon Glass 			},
340*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
341*2e192b24SSimon Glass 						    vlan_set),
342*2e192b24SSimon Glass 			.keyword_function = NULL,
343*2e192b24SSimon Glass 		}, {
344*2e192b24SSimon Glass 			.cmd_keyword = {
345*2e192b24SSimon Glass 					ethsw_id_untagged,
346*2e192b24SSimon Glass 					ethsw_id_key_end,
347*2e192b24SSimon Glass 			},
348*2e192b24SSimon Glass 			.cmd_func_offset = -1,
349*2e192b24SSimon Glass 			.keyword_function = &ethsw_port_untag_help_key_func,
350*2e192b24SSimon Glass 		}, {
351*2e192b24SSimon Glass 			.cmd_keyword = {
352*2e192b24SSimon Glass 					ethsw_id_untagged,
353*2e192b24SSimon Glass 					ethsw_id_help,
354*2e192b24SSimon Glass 					ethsw_id_key_end,
355*2e192b24SSimon Glass 			},
356*2e192b24SSimon Glass 			.cmd_func_offset = -1,
357*2e192b24SSimon Glass 			.keyword_function = &ethsw_port_untag_help_key_func,
358*2e192b24SSimon Glass 		}, {
359*2e192b24SSimon Glass 			.cmd_keyword = {
360*2e192b24SSimon Glass 					ethsw_id_untagged,
361*2e192b24SSimon Glass 					ethsw_id_show,
362*2e192b24SSimon Glass 					ethsw_id_key_end,
363*2e192b24SSimon Glass 			},
364*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
365*2e192b24SSimon Glass 						    port_untag_show),
366*2e192b24SSimon Glass 			.keyword_function = NULL,
367*2e192b24SSimon Glass 		}, {
368*2e192b24SSimon Glass 			.cmd_keyword = {
369*2e192b24SSimon Glass 					ethsw_id_untagged,
370*2e192b24SSimon Glass 					ethsw_id_all,
371*2e192b24SSimon Glass 					ethsw_id_key_end,
372*2e192b24SSimon Glass 			},
373*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
374*2e192b24SSimon Glass 						    port_untag_set),
375*2e192b24SSimon Glass 			.keyword_function = NULL,
376*2e192b24SSimon Glass 		}, {
377*2e192b24SSimon Glass 			.cmd_keyword = {
378*2e192b24SSimon Glass 					ethsw_id_untagged,
379*2e192b24SSimon Glass 					ethsw_id_none,
380*2e192b24SSimon Glass 					ethsw_id_key_end,
381*2e192b24SSimon Glass 			},
382*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
383*2e192b24SSimon Glass 						    port_untag_set),
384*2e192b24SSimon Glass 			.keyword_function = NULL,
385*2e192b24SSimon Glass 		}, {
386*2e192b24SSimon Glass 			.cmd_keyword = {
387*2e192b24SSimon Glass 					ethsw_id_untagged,
388*2e192b24SSimon Glass 					ethsw_id_pvid,
389*2e192b24SSimon Glass 					ethsw_id_key_end,
390*2e192b24SSimon Glass 			},
391*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
392*2e192b24SSimon Glass 						    port_untag_set),
393*2e192b24SSimon Glass 			.keyword_function = NULL,
394*2e192b24SSimon Glass 		}, {
395*2e192b24SSimon Glass 			.cmd_keyword = {
396*2e192b24SSimon Glass 					ethsw_id_egress,
397*2e192b24SSimon Glass 					ethsw_id_tag,
398*2e192b24SSimon Glass 					ethsw_id_key_end,
399*2e192b24SSimon Glass 			},
400*2e192b24SSimon Glass 			.cmd_func_offset = -1,
401*2e192b24SSimon Glass 			.keyword_function = &ethsw_egr_tag_help_key_func,
402*2e192b24SSimon Glass 		}, {
403*2e192b24SSimon Glass 			.cmd_keyword = {
404*2e192b24SSimon Glass 					ethsw_id_egress,
405*2e192b24SSimon Glass 					ethsw_id_tag,
406*2e192b24SSimon Glass 					ethsw_id_help,
407*2e192b24SSimon Glass 					ethsw_id_key_end,
408*2e192b24SSimon Glass 			},
409*2e192b24SSimon Glass 			.cmd_func_offset = -1,
410*2e192b24SSimon Glass 			.keyword_function = &ethsw_egr_tag_help_key_func,
411*2e192b24SSimon Glass 		}, {
412*2e192b24SSimon Glass 			.cmd_keyword = {
413*2e192b24SSimon Glass 					ethsw_id_egress,
414*2e192b24SSimon Glass 					ethsw_id_tag,
415*2e192b24SSimon Glass 					ethsw_id_show,
416*2e192b24SSimon Glass 					ethsw_id_key_end,
417*2e192b24SSimon Glass 			},
418*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
419*2e192b24SSimon Glass 						    port_egr_vlan_show),
420*2e192b24SSimon Glass 			.keyword_function = NULL,
421*2e192b24SSimon Glass 		}, {
422*2e192b24SSimon Glass 			.cmd_keyword = {
423*2e192b24SSimon Glass 					ethsw_id_egress,
424*2e192b24SSimon Glass 					ethsw_id_tag,
425*2e192b24SSimon Glass 					ethsw_id_pvid,
426*2e192b24SSimon Glass 					ethsw_id_key_end,
427*2e192b24SSimon Glass 			},
428*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
429*2e192b24SSimon Glass 						    port_egr_vlan_set),
430*2e192b24SSimon Glass 			.keyword_function = NULL,
431*2e192b24SSimon Glass 		}, {
432*2e192b24SSimon Glass 			.cmd_keyword = {
433*2e192b24SSimon Glass 					ethsw_id_egress,
434*2e192b24SSimon Glass 					ethsw_id_tag,
435*2e192b24SSimon Glass 					ethsw_id_classified,
436*2e192b24SSimon Glass 					ethsw_id_key_end,
437*2e192b24SSimon Glass 			},
438*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
439*2e192b24SSimon Glass 						    port_egr_vlan_set),
440*2e192b24SSimon Glass 			.keyword_function = NULL,
441*2e192b24SSimon Glass 		}, {
442*2e192b24SSimon Glass 			.cmd_keyword = {
443*2e192b24SSimon Glass 					ethsw_id_vlan,
444*2e192b24SSimon Glass 					ethsw_id_fdb,
445*2e192b24SSimon Glass 					ethsw_id_key_end,
446*2e192b24SSimon Glass 			},
447*2e192b24SSimon Glass 			.cmd_func_offset = -1,
448*2e192b24SSimon Glass 			.keyword_function = &ethsw_vlan_learn_help_key_func,
449*2e192b24SSimon Glass 		}, {
450*2e192b24SSimon Glass 			.cmd_keyword = {
451*2e192b24SSimon Glass 					ethsw_id_vlan,
452*2e192b24SSimon Glass 					ethsw_id_fdb,
453*2e192b24SSimon Glass 					ethsw_id_help,
454*2e192b24SSimon Glass 					ethsw_id_key_end,
455*2e192b24SSimon Glass 			},
456*2e192b24SSimon Glass 			.cmd_func_offset = -1,
457*2e192b24SSimon Glass 			.keyword_function = &ethsw_vlan_learn_help_key_func,
458*2e192b24SSimon Glass 		}, {
459*2e192b24SSimon Glass 			.cmd_keyword = {
460*2e192b24SSimon Glass 					ethsw_id_vlan,
461*2e192b24SSimon Glass 					ethsw_id_fdb,
462*2e192b24SSimon Glass 					ethsw_id_show,
463*2e192b24SSimon Glass 					ethsw_id_key_end,
464*2e192b24SSimon Glass 			},
465*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
466*2e192b24SSimon Glass 						    vlan_learn_show),
467*2e192b24SSimon Glass 			.keyword_function = NULL,
468*2e192b24SSimon Glass 		}, {
469*2e192b24SSimon Glass 			.cmd_keyword = {
470*2e192b24SSimon Glass 					ethsw_id_vlan,
471*2e192b24SSimon Glass 					ethsw_id_fdb,
472*2e192b24SSimon Glass 					ethsw_id_shared,
473*2e192b24SSimon Glass 					ethsw_id_key_end,
474*2e192b24SSimon Glass 			},
475*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
476*2e192b24SSimon Glass 						    vlan_learn_set),
477*2e192b24SSimon Glass 			.keyword_function = NULL,
478*2e192b24SSimon Glass 		}, {
479*2e192b24SSimon Glass 			.cmd_keyword = {
480*2e192b24SSimon Glass 					ethsw_id_vlan,
481*2e192b24SSimon Glass 					ethsw_id_fdb,
482*2e192b24SSimon Glass 					ethsw_id_private,
483*2e192b24SSimon Glass 					ethsw_id_key_end,
484*2e192b24SSimon Glass 			},
485*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
486*2e192b24SSimon Glass 						    vlan_learn_set),
487*2e192b24SSimon Glass 			.keyword_function = NULL,
488*2e192b24SSimon Glass 		}, {
489*2e192b24SSimon Glass 			.cmd_keyword = {
490*2e192b24SSimon Glass 					ethsw_id_ingress,
491*2e192b24SSimon Glass 					ethsw_id_filtering,
492*2e192b24SSimon Glass 					ethsw_id_key_end,
493*2e192b24SSimon Glass 			},
494*2e192b24SSimon Glass 			.cmd_func_offset = -1,
495*2e192b24SSimon Glass 			.keyword_function = &ethsw_ingr_fltr_help_key_func,
496*2e192b24SSimon Glass 		}, {
497*2e192b24SSimon Glass 			.cmd_keyword = {
498*2e192b24SSimon Glass 					ethsw_id_ingress,
499*2e192b24SSimon Glass 					ethsw_id_filtering,
500*2e192b24SSimon Glass 					ethsw_id_help,
501*2e192b24SSimon Glass 					ethsw_id_key_end,
502*2e192b24SSimon Glass 			},
503*2e192b24SSimon Glass 			.cmd_func_offset = -1,
504*2e192b24SSimon Glass 			.keyword_function = &ethsw_ingr_fltr_help_key_func,
505*2e192b24SSimon Glass 		}, {
506*2e192b24SSimon Glass 			.cmd_keyword = {
507*2e192b24SSimon Glass 					ethsw_id_ingress,
508*2e192b24SSimon Glass 					ethsw_id_filtering,
509*2e192b24SSimon Glass 					ethsw_id_show,
510*2e192b24SSimon Glass 					ethsw_id_key_end,
511*2e192b24SSimon Glass 			},
512*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
513*2e192b24SSimon Glass 						    port_ingr_filt_show),
514*2e192b24SSimon Glass 			.keyword_function = NULL,
515*2e192b24SSimon Glass 		}, {
516*2e192b24SSimon Glass 			.cmd_keyword = {
517*2e192b24SSimon Glass 					ethsw_id_ingress,
518*2e192b24SSimon Glass 					ethsw_id_filtering,
519*2e192b24SSimon Glass 					ethsw_id_enable,
520*2e192b24SSimon Glass 					ethsw_id_key_end,
521*2e192b24SSimon Glass 			},
522*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
523*2e192b24SSimon Glass 						    port_ingr_filt_set),
524*2e192b24SSimon Glass 			.keyword_function = NULL,
525*2e192b24SSimon Glass 		}, {
526*2e192b24SSimon Glass 			.cmd_keyword = {
527*2e192b24SSimon Glass 					ethsw_id_ingress,
528*2e192b24SSimon Glass 					ethsw_id_filtering,
529*2e192b24SSimon Glass 					ethsw_id_disable,
530*2e192b24SSimon Glass 					ethsw_id_key_end,
531*2e192b24SSimon Glass 			},
532*2e192b24SSimon Glass 			.cmd_func_offset = offsetof(struct ethsw_command_func,
533*2e192b24SSimon Glass 						    port_ingr_filt_set),
534*2e192b24SSimon Glass 			.keyword_function = NULL,
535*2e192b24SSimon Glass 		},
536*2e192b24SSimon Glass };
537*2e192b24SSimon Glass 
538*2e192b24SSimon Glass struct keywords_optional {
539*2e192b24SSimon Glass 	int cmd_keyword[ETHSW_MAX_CMD_PARAMS];
540*2e192b24SSimon Glass } cmd_opt_def[] = {
541*2e192b24SSimon Glass 		{
542*2e192b24SSimon Glass 				.cmd_keyword = {
543*2e192b24SSimon Glass 						ethsw_id_port,
544*2e192b24SSimon Glass 						ethsw_id_port_no,
545*2e192b24SSimon Glass 						ethsw_id_key_end,
546*2e192b24SSimon Glass 				},
547*2e192b24SSimon Glass 		}, {
548*2e192b24SSimon Glass 				.cmd_keyword = {
549*2e192b24SSimon Glass 						ethsw_id_vlan,
550*2e192b24SSimon Glass 						ethsw_id_vlan_no,
551*2e192b24SSimon Glass 						ethsw_id_key_end,
552*2e192b24SSimon Glass 				},
553*2e192b24SSimon Glass 		}, {
554*2e192b24SSimon Glass 				.cmd_keyword = {
555*2e192b24SSimon Glass 						ethsw_id_port,
556*2e192b24SSimon Glass 						ethsw_id_port_no,
557*2e192b24SSimon Glass 						ethsw_id_vlan,
558*2e192b24SSimon Glass 						ethsw_id_vlan_no,
559*2e192b24SSimon Glass 						ethsw_id_key_end,
560*2e192b24SSimon Glass 				},
561*2e192b24SSimon Glass 		},
562*2e192b24SSimon Glass };
563*2e192b24SSimon Glass 
564*2e192b24SSimon Glass static int keyword_match_gen(enum ethsw_keyword_id key_id, int argc, char
565*2e192b24SSimon Glass 			     *const argv[], int *argc_nr,
566*2e192b24SSimon Glass 			     struct ethsw_command_def *parsed_cmd);
567*2e192b24SSimon Glass static int keyword_match_port(enum ethsw_keyword_id key_id, int argc,
568*2e192b24SSimon Glass 			      char *const argv[], int *argc_nr,
569*2e192b24SSimon Glass 			      struct ethsw_command_def *parsed_cmd);
570*2e192b24SSimon Glass static int keyword_match_vlan(enum ethsw_keyword_id key_id, int argc,
571*2e192b24SSimon Glass 			      char *const argv[], int *argc_nr,
572*2e192b24SSimon Glass 			      struct ethsw_command_def *parsed_cmd);
573*2e192b24SSimon Glass static int keyword_match_pvid(enum ethsw_keyword_id key_id, int argc,
574*2e192b24SSimon Glass 			      char *const argv[], int *argc_nr,
575*2e192b24SSimon Glass 			      struct ethsw_command_def *parsed_cmd);
576*2e192b24SSimon Glass static int keyword_match_mac_addr(enum ethsw_keyword_id key_id, int argc,
577*2e192b24SSimon Glass 				  char *const argv[], int *argc_nr,
578*2e192b24SSimon Glass 				  struct ethsw_command_def *parsed_cmd);
579*2e192b24SSimon Glass 
580*2e192b24SSimon Glass /*
581*2e192b24SSimon Glass  * Define properties for each keyword;
582*2e192b24SSimon Glass  * keep the order synced with enum ethsw_keyword_id
583*2e192b24SSimon Glass  */
584*2e192b24SSimon Glass struct keyword_def {
585*2e192b24SSimon Glass 	const char *keyword_name;
586*2e192b24SSimon Glass 	int (*match)(enum ethsw_keyword_id key_id, int argc, char *const argv[],
587*2e192b24SSimon Glass 		     int *argc_nr, struct ethsw_command_def *parsed_cmd);
588*2e192b24SSimon Glass } keyword[] = {
589*2e192b24SSimon Glass 		{
590*2e192b24SSimon Glass 				.keyword_name = "help",
591*2e192b24SSimon Glass 				.match = &keyword_match_gen,
592*2e192b24SSimon Glass 		}, {
593*2e192b24SSimon Glass 				.keyword_name = "show",
594*2e192b24SSimon Glass 				.match = &keyword_match_gen,
595*2e192b24SSimon Glass 		}, {
596*2e192b24SSimon Glass 				.keyword_name = "port",
597*2e192b24SSimon Glass 				.match = &keyword_match_port
598*2e192b24SSimon Glass 		},  {
599*2e192b24SSimon Glass 				.keyword_name = "enable",
600*2e192b24SSimon Glass 				.match = &keyword_match_gen,
601*2e192b24SSimon Glass 		}, {
602*2e192b24SSimon Glass 				.keyword_name = "disable",
603*2e192b24SSimon Glass 				.match = &keyword_match_gen,
604*2e192b24SSimon Glass 		}, {
605*2e192b24SSimon Glass 				.keyword_name = "statistics",
606*2e192b24SSimon Glass 				.match = &keyword_match_gen,
607*2e192b24SSimon Glass 		}, {
608*2e192b24SSimon Glass 				.keyword_name = "clear",
609*2e192b24SSimon Glass 				.match = &keyword_match_gen,
610*2e192b24SSimon Glass 		}, {
611*2e192b24SSimon Glass 				.keyword_name = "learning",
612*2e192b24SSimon Glass 				.match = &keyword_match_gen,
613*2e192b24SSimon Glass 		}, {
614*2e192b24SSimon Glass 				.keyword_name = "auto",
615*2e192b24SSimon Glass 				.match = &keyword_match_gen,
616*2e192b24SSimon Glass 		}, {
617*2e192b24SSimon Glass 				.keyword_name = "vlan",
618*2e192b24SSimon Glass 				.match = &keyword_match_vlan,
619*2e192b24SSimon Glass 		}, {
620*2e192b24SSimon Glass 				.keyword_name = "fdb",
621*2e192b24SSimon Glass 				.match = &keyword_match_gen,
622*2e192b24SSimon Glass 		}, {
623*2e192b24SSimon Glass 				.keyword_name = "add",
624*2e192b24SSimon Glass 				.match = &keyword_match_mac_addr,
625*2e192b24SSimon Glass 		}, {
626*2e192b24SSimon Glass 				.keyword_name = "del",
627*2e192b24SSimon Glass 				.match = &keyword_match_mac_addr,
628*2e192b24SSimon Glass 		}, {
629*2e192b24SSimon Glass 				.keyword_name = "flush",
630*2e192b24SSimon Glass 				.match = &keyword_match_gen,
631*2e192b24SSimon Glass 		}, {
632*2e192b24SSimon Glass 				.keyword_name = "pvid",
633*2e192b24SSimon Glass 				.match = &keyword_match_pvid,
634*2e192b24SSimon Glass 		}, {
635*2e192b24SSimon Glass 				.keyword_name = "untagged",
636*2e192b24SSimon Glass 				.match = &keyword_match_gen,
637*2e192b24SSimon Glass 		}, {
638*2e192b24SSimon Glass 				.keyword_name = "all",
639*2e192b24SSimon Glass 				.match = &keyword_match_gen,
640*2e192b24SSimon Glass 		}, {
641*2e192b24SSimon Glass 				.keyword_name = "none",
642*2e192b24SSimon Glass 				.match = &keyword_match_gen,
643*2e192b24SSimon Glass 		}, {
644*2e192b24SSimon Glass 				.keyword_name = "egress",
645*2e192b24SSimon Glass 				.match = &keyword_match_gen,
646*2e192b24SSimon Glass 		}, {
647*2e192b24SSimon Glass 				.keyword_name = "tag",
648*2e192b24SSimon Glass 				.match = &keyword_match_gen,
649*2e192b24SSimon Glass 		}, {
650*2e192b24SSimon Glass 				.keyword_name = "classified",
651*2e192b24SSimon Glass 				.match = &keyword_match_gen,
652*2e192b24SSimon Glass 		}, {
653*2e192b24SSimon Glass 				.keyword_name = "shared",
654*2e192b24SSimon Glass 				.match = &keyword_match_gen,
655*2e192b24SSimon Glass 		}, {
656*2e192b24SSimon Glass 				.keyword_name = "private",
657*2e192b24SSimon Glass 				.match = &keyword_match_gen,
658*2e192b24SSimon Glass 		}, {
659*2e192b24SSimon Glass 				.keyword_name = "ingress",
660*2e192b24SSimon Glass 				.match = &keyword_match_gen,
661*2e192b24SSimon Glass 		}, {
662*2e192b24SSimon Glass 				.keyword_name = "filtering",
663*2e192b24SSimon Glass 				.match = &keyword_match_gen,
664*2e192b24SSimon Glass 		},
665*2e192b24SSimon Glass };
666*2e192b24SSimon Glass 
667*2e192b24SSimon Glass /*
668*2e192b24SSimon Glass  * Function used by an Ethernet Switch driver to set the functions
669*2e192b24SSimon Glass  * that must be called by the parser when an ethsw command is given
670*2e192b24SSimon Glass  */
671*2e192b24SSimon Glass int ethsw_define_functions(const struct ethsw_command_func *cmd_func)
672*2e192b24SSimon Glass {
673*2e192b24SSimon Glass 	int i;
674*2e192b24SSimon Glass 	void **aux_p;
675*2e192b24SSimon Glass 	int (*cmd_func_aux)(struct ethsw_command_def *);
676*2e192b24SSimon Glass 
677*2e192b24SSimon Glass 	if (!cmd_func->ethsw_name)
678*2e192b24SSimon Glass 		return -EINVAL;
679*2e192b24SSimon Glass 
680*2e192b24SSimon Glass 	ethsw_name = cmd_func->ethsw_name;
681*2e192b24SSimon Glass 
682*2e192b24SSimon Glass 	for (i = 0; i < ARRAY_SIZE(ethsw_cmd_def); i++) {
683*2e192b24SSimon Glass 		/*
684*2e192b24SSimon Glass 		 * get the pointer to the function send by the Ethernet Switch
685*2e192b24SSimon Glass 		 * driver that corresponds to the proper ethsw command
686*2e192b24SSimon Glass 		 */
687*2e192b24SSimon Glass 		if (ethsw_cmd_def[i].keyword_function)
688*2e192b24SSimon Glass 			continue;
689*2e192b24SSimon Glass 
690*2e192b24SSimon Glass 		aux_p = (void *)cmd_func + ethsw_cmd_def[i].cmd_func_offset;
691*2e192b24SSimon Glass 
692*2e192b24SSimon Glass 		cmd_func_aux = (int (*)(struct ethsw_command_def *)) *aux_p;
693*2e192b24SSimon Glass 		ethsw_cmd_def[i].keyword_function = cmd_func_aux;
694*2e192b24SSimon Glass 	}
695*2e192b24SSimon Glass 
696*2e192b24SSimon Glass 	return 0;
697*2e192b24SSimon Glass }
698*2e192b24SSimon Glass 
699*2e192b24SSimon Glass /* Generic function used to match a keyword only by a string */
700*2e192b24SSimon Glass static int keyword_match_gen(enum ethsw_keyword_id key_id, int argc,
701*2e192b24SSimon Glass 			     char *const argv[], int *argc_nr,
702*2e192b24SSimon Glass 			     struct ethsw_command_def *parsed_cmd)
703*2e192b24SSimon Glass {
704*2e192b24SSimon Glass 	if (strcmp(argv[*argc_nr], keyword[key_id].keyword_name) == 0) {
705*2e192b24SSimon Glass 		parsed_cmd->cmd_to_keywords[*argc_nr] = key_id;
706*2e192b24SSimon Glass 
707*2e192b24SSimon Glass 		return 1;
708*2e192b24SSimon Glass 	}
709*2e192b24SSimon Glass 	return 0;
710*2e192b24SSimon Glass }
711*2e192b24SSimon Glass 
712*2e192b24SSimon Glass /* Function used to match the command's port */
713*2e192b24SSimon Glass static int keyword_match_port(enum ethsw_keyword_id key_id, int argc,
714*2e192b24SSimon Glass 			      char *const argv[], int *argc_nr,
715*2e192b24SSimon Glass 			      struct ethsw_command_def *parsed_cmd)
716*2e192b24SSimon Glass {
717*2e192b24SSimon Glass 	unsigned long val;
718*2e192b24SSimon Glass 
719*2e192b24SSimon Glass 	if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
720*2e192b24SSimon Glass 		return 0;
721*2e192b24SSimon Glass 
722*2e192b24SSimon Glass 	if (*argc_nr + 1 >= argc)
723*2e192b24SSimon Glass 		return 0;
724*2e192b24SSimon Glass 
725*2e192b24SSimon Glass 	if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) {
726*2e192b24SSimon Glass 		parsed_cmd->port = val;
727*2e192b24SSimon Glass 		(*argc_nr)++;
728*2e192b24SSimon Glass 		parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_port_no;
729*2e192b24SSimon Glass 		return 1;
730*2e192b24SSimon Glass 	}
731*2e192b24SSimon Glass 
732*2e192b24SSimon Glass 	return 0;
733*2e192b24SSimon Glass }
734*2e192b24SSimon Glass 
735*2e192b24SSimon Glass /* Function used to match the command's vlan */
736*2e192b24SSimon Glass static int keyword_match_vlan(enum ethsw_keyword_id key_id, int argc,
737*2e192b24SSimon Glass 			      char *const argv[], int *argc_nr,
738*2e192b24SSimon Glass 			      struct ethsw_command_def *parsed_cmd)
739*2e192b24SSimon Glass {
740*2e192b24SSimon Glass 	unsigned long val;
741*2e192b24SSimon Glass 	int aux;
742*2e192b24SSimon Glass 
743*2e192b24SSimon Glass 	if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
744*2e192b24SSimon Glass 		return 0;
745*2e192b24SSimon Glass 
746*2e192b24SSimon Glass 	if (*argc_nr + 1 >= argc)
747*2e192b24SSimon Glass 		return 0;
748*2e192b24SSimon Glass 
749*2e192b24SSimon Glass 	if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) {
750*2e192b24SSimon Glass 		parsed_cmd->vid = val;
751*2e192b24SSimon Glass 		(*argc_nr)++;
752*2e192b24SSimon Glass 		parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_vlan_no;
753*2e192b24SSimon Glass 		return 1;
754*2e192b24SSimon Glass 	}
755*2e192b24SSimon Glass 
756*2e192b24SSimon Glass 	aux = *argc_nr + 1;
757*2e192b24SSimon Glass 
758*2e192b24SSimon Glass 	if (keyword_match_gen(ethsw_id_add, argc, argv, &aux, parsed_cmd))
759*2e192b24SSimon Glass 		parsed_cmd->cmd_to_keywords[*argc_nr + 1] = ethsw_id_add;
760*2e192b24SSimon Glass 	else if (keyword_match_gen(ethsw_id_del, argc, argv, &aux, parsed_cmd))
761*2e192b24SSimon Glass 		parsed_cmd->cmd_to_keywords[*argc_nr + 1] = ethsw_id_del;
762*2e192b24SSimon Glass 	else
763*2e192b24SSimon Glass 		return 0;
764*2e192b24SSimon Glass 
765*2e192b24SSimon Glass 	if (*argc_nr + 2 >= argc)
766*2e192b24SSimon Glass 		return 0;
767*2e192b24SSimon Glass 
768*2e192b24SSimon Glass 	if (strict_strtoul(argv[*argc_nr + 2], 10, &val) != -EINVAL) {
769*2e192b24SSimon Glass 		parsed_cmd->vid = val;
770*2e192b24SSimon Glass 		(*argc_nr) += 2;
771*2e192b24SSimon Glass 		parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_add_del_no;
772*2e192b24SSimon Glass 		return 1;
773*2e192b24SSimon Glass 	}
774*2e192b24SSimon Glass 
775*2e192b24SSimon Glass 	return 0;
776*2e192b24SSimon Glass }
777*2e192b24SSimon Glass 
778*2e192b24SSimon Glass /* Function used to match the command's pvid */
779*2e192b24SSimon Glass static int keyword_match_pvid(enum ethsw_keyword_id key_id, int argc,
780*2e192b24SSimon Glass 			      char *const argv[], int *argc_nr,
781*2e192b24SSimon Glass 			      struct ethsw_command_def *parsed_cmd)
782*2e192b24SSimon Glass {
783*2e192b24SSimon Glass 	unsigned long val;
784*2e192b24SSimon Glass 
785*2e192b24SSimon Glass 	if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
786*2e192b24SSimon Glass 		return 0;
787*2e192b24SSimon Glass 
788*2e192b24SSimon Glass 	if (*argc_nr + 1 >= argc)
789*2e192b24SSimon Glass 		return 1;
790*2e192b24SSimon Glass 
791*2e192b24SSimon Glass 	if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) {
792*2e192b24SSimon Glass 		parsed_cmd->vid = val;
793*2e192b24SSimon Glass 		(*argc_nr)++;
794*2e192b24SSimon Glass 		parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_pvid_no;
795*2e192b24SSimon Glass 	}
796*2e192b24SSimon Glass 
797*2e192b24SSimon Glass 	return 1;
798*2e192b24SSimon Glass }
799*2e192b24SSimon Glass 
800*2e192b24SSimon Glass /* Function used to match the command's MAC address */
801*2e192b24SSimon Glass static int keyword_match_mac_addr(enum ethsw_keyword_id key_id, int argc,
802*2e192b24SSimon Glass 				     char *const argv[], int *argc_nr,
803*2e192b24SSimon Glass 				     struct ethsw_command_def *parsed_cmd)
804*2e192b24SSimon Glass {
805*2e192b24SSimon Glass 	if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
806*2e192b24SSimon Glass 		return 0;
807*2e192b24SSimon Glass 
808*2e192b24SSimon Glass 	if ((*argc_nr + 1 >= argc) ||
809*2e192b24SSimon Glass 	    !is_broadcast_ethaddr(parsed_cmd->ethaddr))
810*2e192b24SSimon Glass 		return 1;
811*2e192b24SSimon Glass 
812*2e192b24SSimon Glass 	if (eth_validate_ethaddr_str(argv[*argc_nr + 1])) {
813*2e192b24SSimon Glass 		printf("Invalid MAC address: %s\n", argv[*argc_nr + 1]);
814*2e192b24SSimon Glass 		return 0;
815*2e192b24SSimon Glass 	}
816*2e192b24SSimon Glass 
817*2e192b24SSimon Glass 	eth_parse_enetaddr(argv[*argc_nr + 1], parsed_cmd->ethaddr);
818*2e192b24SSimon Glass 
819*2e192b24SSimon Glass 	if (is_broadcast_ethaddr(parsed_cmd->ethaddr)) {
820*2e192b24SSimon Glass 		memset(parsed_cmd->ethaddr, 0xFF, sizeof(parsed_cmd->ethaddr));
821*2e192b24SSimon Glass 		return 0;
822*2e192b24SSimon Glass 	}
823*2e192b24SSimon Glass 
824*2e192b24SSimon Glass 	parsed_cmd->cmd_to_keywords[*argc_nr + 1] = ethsw_id_add_del_mac;
825*2e192b24SSimon Glass 
826*2e192b24SSimon Glass 	return 1;
827*2e192b24SSimon Glass }
828*2e192b24SSimon Glass 
829*2e192b24SSimon Glass /* Finds optional keywords and modifies *argc_va to skip them */
830*2e192b24SSimon Glass static void cmd_keywords_opt_check(const struct ethsw_command_def *parsed_cmd,
831*2e192b24SSimon Glass 				   int *argc_val)
832*2e192b24SSimon Glass {
833*2e192b24SSimon Glass 	int i;
834*2e192b24SSimon Glass 	int keyw_opt_matched;
835*2e192b24SSimon Glass 	int argc_val_max;
836*2e192b24SSimon Glass 	int const *cmd_keyw_p;
837*2e192b24SSimon Glass 	int const *cmd_keyw_opt_p;
838*2e192b24SSimon Glass 
839*2e192b24SSimon Glass 	/* remember the best match */
840*2e192b24SSimon Glass 	argc_val_max = *argc_val;
841*2e192b24SSimon Glass 
842*2e192b24SSimon Glass 	/*
843*2e192b24SSimon Glass 	 * check if our command's optional keywords match the optional
844*2e192b24SSimon Glass 	 * keywords of an available command
845*2e192b24SSimon Glass 	 */
846*2e192b24SSimon Glass 	for (i = 0; i < ARRAY_SIZE(ethsw_cmd_def); i++) {
847*2e192b24SSimon Glass 		keyw_opt_matched = 0;
848*2e192b24SSimon Glass 		cmd_keyw_p = &parsed_cmd->cmd_to_keywords[keyw_opt_matched];
849*2e192b24SSimon Glass 		cmd_keyw_opt_p = &cmd_opt_def[i].cmd_keyword[keyw_opt_matched];
850*2e192b24SSimon Glass 
851*2e192b24SSimon Glass 		/*
852*2e192b24SSimon Glass 		 * increase the number of keywords that
853*2e192b24SSimon Glass 		 * matched with a command
854*2e192b24SSimon Glass 		 */
855*2e192b24SSimon Glass 		while (keyw_opt_matched + *argc_val <
856*2e192b24SSimon Glass 		       parsed_cmd->cmd_keywords_nr &&
857*2e192b24SSimon Glass 		       *cmd_keyw_opt_p != ethsw_id_key_end &&
858*2e192b24SSimon Glass 		       *(cmd_keyw_p + *argc_val) == *cmd_keyw_opt_p) {
859*2e192b24SSimon Glass 			keyw_opt_matched++;
860*2e192b24SSimon Glass 			cmd_keyw_p++;
861*2e192b24SSimon Glass 			cmd_keyw_opt_p++;
862*2e192b24SSimon Glass 		}
863*2e192b24SSimon Glass 
864*2e192b24SSimon Glass 		/*
865*2e192b24SSimon Glass 		 * if all our optional command's keywords perfectly match an
866*2e192b24SSimon Glass 		 * optional pattern, then we can move to the next defined
867*2e192b24SSimon Glass 		 * keywords in our command; remember the one that matched the
868*2e192b24SSimon Glass 		 * greatest number of keywords
869*2e192b24SSimon Glass 		 */
870*2e192b24SSimon Glass 		if (keyw_opt_matched + *argc_val <=
871*2e192b24SSimon Glass 		    parsed_cmd->cmd_keywords_nr &&
872*2e192b24SSimon Glass 		    *cmd_keyw_opt_p == ethsw_id_key_end &&
873*2e192b24SSimon Glass 		    *argc_val + keyw_opt_matched > argc_val_max)
874*2e192b24SSimon Glass 			argc_val_max = *argc_val + keyw_opt_matched;
875*2e192b24SSimon Glass 	}
876*2e192b24SSimon Glass 
877*2e192b24SSimon Glass 	*argc_val = argc_val_max;
878*2e192b24SSimon Glass }
879*2e192b24SSimon Glass 
880*2e192b24SSimon Glass /*
881*2e192b24SSimon Glass  * Finds the function to call based on keywords and
882*2e192b24SSimon Glass  * modifies *argc_va to skip them
883*2e192b24SSimon Glass  */
884*2e192b24SSimon Glass static void cmd_keywords_check(struct ethsw_command_def *parsed_cmd,
885*2e192b24SSimon Glass 			       int *argc_val)
886*2e192b24SSimon Glass {
887*2e192b24SSimon Glass 	int i;
888*2e192b24SSimon Glass 	int keyw_matched;
889*2e192b24SSimon Glass 	int *cmd_keyw_p;
890*2e192b24SSimon Glass 	int *cmd_keyw_def_p;
891*2e192b24SSimon Glass 
892*2e192b24SSimon Glass 	/*
893*2e192b24SSimon Glass 	 * check if our command's keywords match the
894*2e192b24SSimon Glass 	 * keywords of an available command
895*2e192b24SSimon Glass 	 */
896*2e192b24SSimon Glass 	for (i = 0; i < ARRAY_SIZE(ethsw_cmd_def); i++) {
897*2e192b24SSimon Glass 		keyw_matched = 0;
898*2e192b24SSimon Glass 		cmd_keyw_p = &parsed_cmd->cmd_to_keywords[keyw_matched];
899*2e192b24SSimon Glass 		cmd_keyw_def_p = &ethsw_cmd_def[i].cmd_keyword[keyw_matched];
900*2e192b24SSimon Glass 
901*2e192b24SSimon Glass 		/*
902*2e192b24SSimon Glass 		 * increase the number of keywords that
903*2e192b24SSimon Glass 		 * matched with a command
904*2e192b24SSimon Glass 		 */
905*2e192b24SSimon Glass 		while (keyw_matched + *argc_val < parsed_cmd->cmd_keywords_nr &&
906*2e192b24SSimon Glass 		       *cmd_keyw_def_p != ethsw_id_key_end &&
907*2e192b24SSimon Glass 		       *(cmd_keyw_p + *argc_val) == *cmd_keyw_def_p) {
908*2e192b24SSimon Glass 			keyw_matched++;
909*2e192b24SSimon Glass 			cmd_keyw_p++;
910*2e192b24SSimon Glass 			cmd_keyw_def_p++;
911*2e192b24SSimon Glass 		}
912*2e192b24SSimon Glass 
913*2e192b24SSimon Glass 		/*
914*2e192b24SSimon Glass 		 * if all our command's keywords perfectly match an
915*2e192b24SSimon Glass 		 * available command, then we get the function we need to call
916*2e192b24SSimon Glass 		 * to configure the Ethernet Switch
917*2e192b24SSimon Glass 		 */
918*2e192b24SSimon Glass 		if (keyw_matched && keyw_matched + *argc_val ==
919*2e192b24SSimon Glass 		    parsed_cmd->cmd_keywords_nr &&
920*2e192b24SSimon Glass 		    *cmd_keyw_def_p == ethsw_id_key_end) {
921*2e192b24SSimon Glass 			*argc_val += keyw_matched;
922*2e192b24SSimon Glass 			parsed_cmd->cmd_function =
923*2e192b24SSimon Glass 					ethsw_cmd_def[i].keyword_function;
924*2e192b24SSimon Glass 			return;
925*2e192b24SSimon Glass 		}
926*2e192b24SSimon Glass 	}
927*2e192b24SSimon Glass }
928*2e192b24SSimon Glass 
929*2e192b24SSimon Glass /* find all the keywords in the command */
930*2e192b24SSimon Glass static int keywords_find(int argc, char * const argv[],
931*2e192b24SSimon Glass 			 struct ethsw_command_def *parsed_cmd)
932*2e192b24SSimon Glass {
933*2e192b24SSimon Glass 	int i;
934*2e192b24SSimon Glass 	int j;
935*2e192b24SSimon Glass 	int argc_val;
936*2e192b24SSimon Glass 	int rc = CMD_RET_SUCCESS;
937*2e192b24SSimon Glass 
938*2e192b24SSimon Glass 	for (i = 1; i < argc; i++) {
939*2e192b24SSimon Glass 		for (j = 0; j < ethsw_id_count; j++) {
940*2e192b24SSimon Glass 			if (keyword[j].match(j, argc, argv, &i, parsed_cmd))
941*2e192b24SSimon Glass 				break;
942*2e192b24SSimon Glass 		}
943*2e192b24SSimon Glass 	}
944*2e192b24SSimon Glass 
945*2e192b24SSimon Glass 	/* if there is no keyword match for a word, the command is invalid */
946*2e192b24SSimon Glass 	for (i = 1; i < argc; i++)
947*2e192b24SSimon Glass 		if (parsed_cmd->cmd_to_keywords[i] == ethsw_id_key_end)
948*2e192b24SSimon Glass 			rc = CMD_RET_USAGE;
949*2e192b24SSimon Glass 
950*2e192b24SSimon Glass 	parsed_cmd->cmd_keywords_nr = argc;
951*2e192b24SSimon Glass 	argc_val = 1;
952*2e192b24SSimon Glass 
953*2e192b24SSimon Glass 	/* get optional parameters first */
954*2e192b24SSimon Glass 	cmd_keywords_opt_check(parsed_cmd, &argc_val);
955*2e192b24SSimon Glass 
956*2e192b24SSimon Glass 	if (argc_val == parsed_cmd->cmd_keywords_nr)
957*2e192b24SSimon Glass 		return CMD_RET_USAGE;
958*2e192b24SSimon Glass 
959*2e192b24SSimon Glass 	/*
960*2e192b24SSimon Glass 	 * check the keywords and if a match is found,
961*2e192b24SSimon Glass 	 * get the function to call
962*2e192b24SSimon Glass 	 */
963*2e192b24SSimon Glass 	cmd_keywords_check(parsed_cmd, &argc_val);
964*2e192b24SSimon Glass 
965*2e192b24SSimon Glass 	/* error if not all commands' parameters were matched */
966*2e192b24SSimon Glass 	if (argc_val == parsed_cmd->cmd_keywords_nr) {
967*2e192b24SSimon Glass 		if (!parsed_cmd->cmd_function) {
968*2e192b24SSimon Glass 			printf("Command not available for: %s\n", ethsw_name);
969*2e192b24SSimon Glass 			rc = CMD_RET_FAILURE;
970*2e192b24SSimon Glass 		}
971*2e192b24SSimon Glass 	} else {
972*2e192b24SSimon Glass 		rc = CMD_RET_USAGE;
973*2e192b24SSimon Glass 	}
974*2e192b24SSimon Glass 
975*2e192b24SSimon Glass 	return rc;
976*2e192b24SSimon Glass }
977*2e192b24SSimon Glass 
978*2e192b24SSimon Glass static void command_def_init(struct ethsw_command_def *parsed_cmd)
979*2e192b24SSimon Glass {
980*2e192b24SSimon Glass 	int i;
981*2e192b24SSimon Glass 
982*2e192b24SSimon Glass 	for (i = 0; i < ETHSW_MAX_CMD_PARAMS; i++)
983*2e192b24SSimon Glass 		parsed_cmd->cmd_to_keywords[i] = ethsw_id_key_end;
984*2e192b24SSimon Glass 
985*2e192b24SSimon Glass 	parsed_cmd->port = ETHSW_CMD_PORT_ALL;
986*2e192b24SSimon Glass 	parsed_cmd->vid = ETHSW_CMD_VLAN_ALL;
987*2e192b24SSimon Glass 	parsed_cmd->cmd_function = NULL;
988*2e192b24SSimon Glass 
989*2e192b24SSimon Glass 	/* We initialize the MAC address with the Broadcast address */
990*2e192b24SSimon Glass 	memset(parsed_cmd->ethaddr, 0xff, sizeof(parsed_cmd->ethaddr));
991*2e192b24SSimon Glass }
992*2e192b24SSimon Glass 
993*2e192b24SSimon Glass /* function to interpret commands starting with "ethsw " */
994*2e192b24SSimon Glass static int do_ethsw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
995*2e192b24SSimon Glass {
996*2e192b24SSimon Glass 	struct ethsw_command_def parsed_cmd;
997*2e192b24SSimon Glass 	int rc = CMD_RET_SUCCESS;
998*2e192b24SSimon Glass 
999*2e192b24SSimon Glass 	if (argc == 1 || argc >= ETHSW_MAX_CMD_PARAMS)
1000*2e192b24SSimon Glass 		return CMD_RET_USAGE;
1001*2e192b24SSimon Glass 
1002*2e192b24SSimon Glass 	command_def_init(&parsed_cmd);
1003*2e192b24SSimon Glass 
1004*2e192b24SSimon Glass 	rc = keywords_find(argc, argv, &parsed_cmd);
1005*2e192b24SSimon Glass 
1006*2e192b24SSimon Glass 	if (rc == CMD_RET_SUCCESS)
1007*2e192b24SSimon Glass 		rc = parsed_cmd.cmd_function(&parsed_cmd);
1008*2e192b24SSimon Glass 
1009*2e192b24SSimon Glass 	return rc;
1010*2e192b24SSimon Glass }
1011*2e192b24SSimon Glass 
1012*2e192b24SSimon Glass #define ETHSW_PORT_CONF_HELP "[port <port_no>] { enable | disable | show } " \
1013*2e192b24SSimon Glass "- enable/disable a port; show shows a port's configuration"
1014*2e192b24SSimon Glass 
1015*2e192b24SSimon Glass U_BOOT_CMD(ethsw, ETHSW_MAX_CMD_PARAMS, 0, do_ethsw,
1016*2e192b24SSimon Glass 	   "Ethernet l2 switch commands",
1017*2e192b24SSimon Glass 	   ETHSW_PORT_CONF_HELP"\n"
1018*2e192b24SSimon Glass 	   ETHSW_PORT_STATS_HELP"\n"
1019*2e192b24SSimon Glass 	   ETHSW_LEARN_HELP"\n"
1020*2e192b24SSimon Glass 	   ETHSW_FDB_HELP"\n"
1021*2e192b24SSimon Glass 	   ETHSW_PVID_HELP"\n"
1022*2e192b24SSimon Glass 	   ETHSW_VLAN_HELP"\n"
1023*2e192b24SSimon Glass 	   ETHSW_PORT_UNTAG_HELP"\n"
1024*2e192b24SSimon Glass 	   ETHSW_EGR_VLAN_TAG_HELP"\n"
1025*2e192b24SSimon Glass 	   ETHSW_VLAN_FDB_HELP"\n"
1026*2e192b24SSimon Glass 	   ETHSW_PORT_INGR_FLTR_HELP"\n"
1027*2e192b24SSimon Glass );
1028