1 /*
2  * Copyright 2025 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_DECLARE(net_shell);
9 
10 #include <zephyr/shell/shell.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <zephyr/sys/util.h>
14 #include <zephyr/devicetree.h>
15 #include <zephyr/net/ethernet.h>
16 #include <zephyr/net/ethernet_mgmt.h>
17 
18 #include "net_shell_private.h"
19 
20 #if defined(CONFIG_NET_QBV) && defined(CONFIG_NET_L2_ETHERNET_MGMT)
get_iface_from_shell(const struct shell * sh,size_t argc,char ** argv)21 static struct net_if *get_iface_from_shell(const struct shell *sh, size_t argc, char **argv)
22 {
23 	int idx;
24 	struct net_if *iface;
25 
26 	idx = get_iface_idx(sh, argv[1]);
27 	if (idx < 0) {
28 		return NULL;
29 	}
30 
31 	iface = net_if_get_by_index(idx);
32 	if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) {
33 		PR_WARNING("No such interface in index %d\n", idx);
34 		return NULL;
35 	}
36 
37 	return iface;
38 }
39 #endif
40 
41 /* qbv enable <iface_index> <value(off, on)> */
cmd_net_qbv(const struct shell * sh,size_t argc,char ** argv)42 static int cmd_net_qbv(const struct shell *sh, size_t argc, char **argv)
43 {
44 	ARG_UNUSED(argc);
45 	ARG_UNUSED(argv);
46 
47 #if defined(CONFIG_NET_QBV) && defined(CONFIG_NET_L2_ETHERNET_MGMT)
48 	shell_print(sh, "To set Qbv config:");
49 	shell_print(sh, "  1. Run enable to on");
50 	shell_print(sh, "  2. Run set_config to set base_time/cycle_time/cycle_time_ext/list_len");
51 	shell_print(sh, "  3. Run set_gc to set gate control");
52 	shell_print(sh, "For example:");
53 	shell_print(sh, "  1. net qbv enable 1 on");
54 	shell_print(sh, "  2. net qbv set_config 1 200 0 0 10000000 0 2");
55 	shell_print(sh, "  3. qbv set_gc 1 0 0x1 5000000");
56 	shell_print(sh, "  4. qbv set_gc 1 0 0x2 5000000");
57 #else
58 	shell_print(sh, "Set %s to enable %s support.\n", "CONFIG_NET_QBV", "qbv");
59 	shell_print(sh, "Set %s to enable %s support.\n", "CONFIG_NET_L2_ETHERNET_MGMT",
60 		    "Ethernet network management interface");
61 #endif
62 
63 	return 0;
64 }
65 
66 /* qbv enable <iface_index> <value(off, on)> */
cmd_qbv_enable(const struct shell * sh,size_t argc,char ** argv)67 static int cmd_qbv_enable(const struct shell *sh, size_t argc, char **argv)
68 {
69 #if defined(CONFIG_NET_QBV) && defined(CONFIG_NET_L2_ETHERNET_MGMT)
70 	struct net_if *iface;
71 	struct ethernet_req_params params;
72 	int ret;
73 	bool enable;
74 
75 	iface = get_iface_from_shell(sh, argc, argv);
76 	if (!iface) {
77 		return -ENOEXEC;
78 	}
79 
80 	enable = shell_strtobool(argv[2], 0, &ret);
81 	if (ret < 0) {
82 		return ret;
83 	}
84 
85 	params.qbv_param.type = ETHERNET_QBV_PARAM_TYPE_STATUS;
86 	params.qbv_param.state = ETHERNET_QBV_STATE_TYPE_ADMIN;
87 	params.qbv_param.enabled = enable;
88 
89 	ret = net_mgmt(NET_REQUEST_ETHERNET_SET_QBV_PARAM,
90 		       iface,
91 		       &params, sizeof(struct ethernet_req_params));
92 	if (ret < 0) {
93 		shell_error(sh, "failed to set %s", argv[1]);
94 		return ret;
95 	}
96 #else
97 	ARG_UNUSED(argc);
98 	ARG_UNUSED(argv);
99 	shell_print(sh, "Set %s to enable %s support.\n", "CONFIG_NET_QBV", "qbv");
100 	shell_print(sh, "Set %s to enable %s support.\n", "CONFIG_NET_L2_ETHERNET_MGMT",
101 		    "Ethernet network management interface");
102 #endif
103 
104 	return 0;
105 }
106 
107 /*
108  * qbv set_config <iface_index> <base_time(s)> <base_time(2*(-16)ns)>
109  * <cycle_time(s)> <cycle_time(ns)> <cycle_time_ext> <list_len>
110  */
cmd_qbv_set_config(const struct shell * sh,size_t argc,char ** argv)111 static int cmd_qbv_set_config(const struct shell *sh, size_t argc, char **argv)
112 {
113 #if defined(CONFIG_NET_QBV) && defined(CONFIG_NET_L2_ETHERNET_MGMT)
114 	struct net_if *iface;
115 	struct ethernet_req_params params;
116 	uint32_t list_len;
117 	int ret;
118 
119 	iface = get_iface_from_shell(sh, argc, argv);
120 	if (!iface) {
121 		return -ENOEXEC;
122 	}
123 
124 	params.qbv_param.type = ETHERNET_QBV_PARAM_TYPE_TIME;
125 	params.qbv_param.state = ETHERNET_QBV_STATE_TYPE_ADMIN;
126 
127 	params.qbv_param.base_time.second = shell_strtoull(argv[2], 10, &ret);
128 	if (ret < 0) {
129 		return ret;
130 	}
131 
132 	params.qbv_param.base_time.fract_nsecond = shell_strtoull(argv[3], 10, &ret);
133 	if (ret < 0) {
134 		return ret;
135 	}
136 
137 	params.qbv_param.cycle_time.second = shell_strtoull(argv[4], 10, &ret);
138 	if (ret < 0) {
139 		return ret;
140 	}
141 
142 	params.qbv_param.cycle_time.nanosecond = shell_strtoul(argv[5], 10, &ret);
143 	if (ret < 0) {
144 		return ret;
145 	}
146 
147 	params.qbv_param.extension_time = shell_strtoul(argv[6], 10, &ret);
148 	if (ret < 0) {
149 		return ret;
150 	}
151 
152 	ret = net_mgmt(NET_REQUEST_ETHERNET_SET_QBV_PARAM,
153 		       iface,
154 		       &params, sizeof(struct ethernet_req_params));
155 
156 	list_len = shell_strtol(argv[7], 10, &ret);
157 	if (ret < 0) {
158 		shell_print(sh, "failed to set times");
159 		return ret;
160 	}
161 
162 	params.qbv_param.type =
163 		ETHERNET_QBV_PARAM_TYPE_GATE_CONTROL_LIST_LEN;
164 	params.qbv_param.gate_control_list_len = list_len;
165 	ret = net_mgmt(NET_REQUEST_ETHERNET_SET_QBV_PARAM,
166 		       iface,
167 		       &params, sizeof(struct ethernet_req_params));
168 	if (ret < 0) {
169 		shell_print(sh, "failed to set list length");
170 		return ret;
171 	}
172 #else
173 	ARG_UNUSED(argc);
174 	ARG_UNUSED(argv);
175 	shell_print(sh, "Set %s to enable %s support.\n", "CONFIG_NET_QBV", "qbv");
176 	shell_print(sh, "Set %s to enable %s support.\n", "CONFIG_NET_L2_ETHERNET_MGMT",
177 		    "Ethernet network management interface");
178 #endif
179 
180 	return 0;
181 }
182 
183 /* qbv set_config <iface_index> <row> <gate_control> <interval> */
cmd_qbv_set_gc(const struct shell * sh,size_t argc,char ** argv)184 static int cmd_qbv_set_gc(const struct shell *sh, size_t argc, char **argv)
185 {
186 #if defined(CONFIG_NET_QBV) && defined(CONFIG_NET_L2_ETHERNET_MGMT)
187 	struct net_if *iface;
188 	struct ethernet_req_params params;
189 	uint32_t row;
190 	uint32_t interval;
191 	uint32_t gc;
192 	int ret;
193 
194 	iface = get_iface_from_shell(sh, argc, argv);
195 	if (!iface) {
196 		return -ENOEXEC;
197 	}
198 
199 	row = shell_strtoul(argv[2], 10, &ret);
200 	if (ret < 0) {
201 		return ret;
202 	}
203 
204 	gc = shell_strtoul(argv[3], 16, &ret);
205 	if (ret < 0) {
206 		return ret;
207 	}
208 
209 	interval = shell_strtoul(argv[4], 10, &ret);
210 	if (ret < 0) {
211 		return ret;
212 	}
213 	params.qbv_param.type = ETHERNET_QBV_PARAM_TYPE_GATE_CONTROL_LIST;
214 	params.qbv_param.state = ETHERNET_QBV_STATE_TYPE_ADMIN;
215 
216 	params.qbv_param.gate_control.time_interval = interval;
217 	params.qbv_param.gate_control.row = row;
218 	for (int i = 0; i < CONFIG_NET_TC_TX_COUNT; i++) {
219 		params.qbv_param.gate_control.gate_status[i] = ((gc & BIT(i)) != 0);
220 	}
221 
222 	ret = net_mgmt(NET_REQUEST_ETHERNET_SET_QBV_PARAM,
223 		       iface,
224 		       &params, sizeof(struct ethernet_req_params));
225 	if (ret < 0) {
226 		return ret;
227 	}
228 #else
229 	ARG_UNUSED(argc);
230 	ARG_UNUSED(argv);
231 	shell_print(sh, "Set %s to enable %s support.\n", "CONFIG_NET_QBV", "qbv");
232 	shell_print(sh, "Set %s to enable %s support.\n", "CONFIG_NET_L2_ETHERNET_MGMT",
233 		    "Ethernet network management interface");
234 #endif
235 
236 	return 0;
237 }
238 
239 /* qbv get_info <iface_index> */
cmd_qbv_get_info(const struct shell * sh,size_t argc,char ** argv)240 static int cmd_qbv_get_info(const struct shell *sh, size_t argc, char **argv)
241 {
242 #if defined(CONFIG_NET_QBV) && defined(CONFIG_NET_L2_ETHERNET_MGMT)
243 	struct net_if *iface;
244 	struct ethernet_req_params params;
245 	int ret;
246 	uint32_t list_len;
247 	uint32_t gate_status;
248 
249 	iface = get_iface_from_shell(sh, argc, argv);
250 	if (!iface) {
251 		return -ENOEXEC;
252 	}
253 
254 	params.qbv_param.type = ETHERNET_QBV_PARAM_TYPE_STATUS;
255 	params.qbv_param.state = ETHERNET_QBV_STATE_TYPE_ADMIN;
256 
257 	ret = net_mgmt(NET_REQUEST_ETHERNET_GET_QBV_PARAM,
258 		       iface,
259 		       &params, sizeof(struct ethernet_req_params));
260 	if (ret < 0) {
261 		shell_error(sh, "failed to get %s status", argv[1]);
262 		return ret;
263 	}
264 	shell_print(sh, "status: %s", (params.qbv_param.enabled ? "on" : "off"));
265 
266 	params.qbv_param.type = ETHERNET_QBV_PARAM_TYPE_TIME;
267 	ret = net_mgmt(NET_REQUEST_ETHERNET_GET_QBV_PARAM,
268 		       iface,
269 		       &params, sizeof(struct ethernet_req_params));
270 	if (ret < 0) {
271 		shell_error(sh, "failed to get %s time", argv[1]);
272 		return ret;
273 	}
274 	shell_print(sh, "base_time(s): %"PRIu64, params.qbv_param.base_time.second);
275 	shell_print(sh, "base_time(fract_ns): %"PRIu64, params.qbv_param.base_time.fract_nsecond);
276 	shell_print(sh, "cycle_time(s): %"PRIu64, params.qbv_param.cycle_time.second);
277 	shell_print(sh, "cycle_time(ns): %"PRIu32, params.qbv_param.cycle_time.nanosecond);
278 	shell_print(sh, "extension_time(ns): %"PRIu32, params.qbv_param.extension_time);
279 
280 	params.qbv_param.type =	ETHERNET_QBV_PARAM_TYPE_GATE_CONTROL_LIST_LEN;
281 	ret = net_mgmt(NET_REQUEST_ETHERNET_GET_QBV_PARAM,
282 		       iface,
283 		       &params, sizeof(struct ethernet_req_params));
284 	if (ret < 0) {
285 		shell_error(sh, "failed to get %s list length", argv[1]);
286 		return ret;
287 	}
288 	shell_print(sh, "list len: %"PRIu32, params.qbv_param.gate_control_list_len);
289 
290 	list_len = params.qbv_param.gate_control_list_len;
291 	params.qbv_param.type = ETHERNET_QBV_PARAM_TYPE_GATE_CONTROL_LIST;
292 	for (uint16_t i = 0; i < list_len; i++) {
293 		params.qbv_param.gate_control.row = i;
294 		ret = net_mgmt(NET_REQUEST_ETHERNET_GET_QBV_PARAM,
295 			       iface,
296 			       &params, sizeof(struct ethernet_req_params));
297 		if (ret < 0) {
298 			shell_error(sh, "failed to get %s gate control", argv[1]);
299 			return ret;
300 		}
301 		gate_status = 0;
302 		for (int j = 0; j < CONFIG_NET_TC_TX_COUNT; j++) {
303 			gate_status |= params.qbv_param.gate_control.gate_status[j] << j;
304 		}
305 		shell_print(sh, "row: %"PRIu16" interval: %"PRIu32" gate_status: 0x%x",
306 			    i, params.qbv_param.gate_control.time_interval, gate_status);
307 	}
308 #else
309 	ARG_UNUSED(argc);
310 	ARG_UNUSED(argv);
311 	shell_print(sh, "Set %s to enable %s support.\n", "CONFIG_NET_QBV", "qbv");
312 	shell_print(sh, "Set %s to enable %s support.\n", "CONFIG_NET_L2_ETHERNET_MGMT",
313 		    "Ethernet network management interface");
314 #endif
315 
316 	return 0;
317 }
318 
319 SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_qbv,
320 	SHELL_CMD_ARG(enable, NULL,
321 		"Enable: enable <iface_index> <value(off, on)>",
322 		cmd_qbv_enable, 3, 0),
323 	SHELL_CMD_ARG(set_config, NULL,
324 		"Set config: set <iface_index> <base_time(s)> <base_time(2*(-16)ns)> <cycle_time(s)> <cycle_time(ns)> <cycle_time_ext(ns)> <list_len>",
325 		cmd_qbv_set_config, 8, 0),
326 	SHELL_CMD_ARG(set_gc, NULL,
327 		"Set gate control: set <iface_index> <row> <gate_control> <interval>",
328 		cmd_qbv_set_gc, 5, 0),
329 	SHELL_CMD_ARG(get_info, NULL,
330 		"Get info: get_info <iface_index>",
331 		cmd_qbv_get_info, 2, 0),
332 	SHELL_SUBCMD_SET_END     /* Array terminated. */
333 );
334 
335 SHELL_SUBCMD_ADD((net), qbv, &net_cmd_qbv,
336 		 "Qbv commands",
337 		 cmd_net_qbv, 1, 0);
338