xref: /aosp_15_r20/external/ethtool/ethtool.c (revision 1b481fc3bb1b45d4cf28d1ec12969dc1055f555d)
1*1b481fc3SMaciej Żenczykowski /*
2*1b481fc3SMaciej Żenczykowski  * ethtool.c: Linux ethernet device configuration tool.
3*1b481fc3SMaciej Żenczykowski  *
4*1b481fc3SMaciej Żenczykowski  * Copyright (C) 1998 David S. Miller ([email protected])
5*1b481fc3SMaciej Żenczykowski  * Portions Copyright 2001 Sun Microsystems
6*1b481fc3SMaciej Żenczykowski  * Kernel 2.4 update Copyright 2001 Jeff Garzik <[email protected]>
7*1b481fc3SMaciej Żenczykowski  * Wake-on-LAN,natsemi,misc support by Tim Hockin <[email protected]>
8*1b481fc3SMaciej Żenczykowski  * Portions Copyright 2002 Intel
9*1b481fc3SMaciej Żenczykowski  * Portions Copyright (C) Sun Microsystems 2008
10*1b481fc3SMaciej Żenczykowski  * do_test support by Eli Kupermann <[email protected]>
11*1b481fc3SMaciej Żenczykowski  * ETHTOOL_PHYS_ID support by Chris Leech <[email protected]>
12*1b481fc3SMaciej Żenczykowski  * e1000 support by Scott Feldman <[email protected]>
13*1b481fc3SMaciej Żenczykowski  * e100 support by Wen Tao <[email protected]>
14*1b481fc3SMaciej Żenczykowski  * ixgb support by Nicholas Nunley <[email protected]>
15*1b481fc3SMaciej Żenczykowski  * amd8111e support by Reeja John <[email protected]>
16*1b481fc3SMaciej Żenczykowski  * long arguments by Andi Kleen.
17*1b481fc3SMaciej Żenczykowski  * SMSC LAN911x support by Steve Glendinning <[email protected]>
18*1b481fc3SMaciej Żenczykowski  * Rx Network Flow Control configuration support <[email protected]>
19*1b481fc3SMaciej Żenczykowski  * Various features by Ben Hutchings <[email protected]>;
20*1b481fc3SMaciej Żenczykowski  *	Copyright 2009, 2010 Solarflare Communications
21*1b481fc3SMaciej Żenczykowski  * MDI-X set support by Jesse Brandeburg <[email protected]>
22*1b481fc3SMaciej Żenczykowski  *	Copyright 2012 Intel Corporation
23*1b481fc3SMaciej Żenczykowski  * vmxnet3 support by Shrikrishna Khare <[email protected]>
24*1b481fc3SMaciej Żenczykowski  * Various features by Ben Hutchings <[email protected]>;
25*1b481fc3SMaciej Żenczykowski  *	Copyright 2008-2010, 2013-2016 Ben Hutchings
26*1b481fc3SMaciej Żenczykowski  * QSFP+/QSFP28 DOM support by Vidya Sagar Ravipati <[email protected]>
27*1b481fc3SMaciej Żenczykowski  *
28*1b481fc3SMaciej Żenczykowski  * TODO:
29*1b481fc3SMaciej Żenczykowski  *   * show settings for all devices
30*1b481fc3SMaciej Żenczykowski  */
31*1b481fc3SMaciej Żenczykowski 
32*1b481fc3SMaciej Żenczykowski #include "internal.h"
33*1b481fc3SMaciej Żenczykowski #include <string.h>
34*1b481fc3SMaciej Żenczykowski #include <strings.h>
35*1b481fc3SMaciej Żenczykowski #include <stdlib.h>
36*1b481fc3SMaciej Żenczykowski #include <sys/stat.h>
37*1b481fc3SMaciej Żenczykowski #include <stdio.h>
38*1b481fc3SMaciej Żenczykowski #include <stddef.h>
39*1b481fc3SMaciej Żenczykowski #include <stdbool.h>
40*1b481fc3SMaciej Żenczykowski #include <errno.h>
41*1b481fc3SMaciej Żenczykowski #include <sys/utsname.h>
42*1b481fc3SMaciej Żenczykowski #include <limits.h>
43*1b481fc3SMaciej Żenczykowski #include <ctype.h>
44*1b481fc3SMaciej Żenczykowski #include <inttypes.h>
45*1b481fc3SMaciej Żenczykowski 
46*1b481fc3SMaciej Żenczykowski #include <sys/socket.h>
47*1b481fc3SMaciej Żenczykowski #include <netinet/in.h>
48*1b481fc3SMaciej Żenczykowski #include <arpa/inet.h>
49*1b481fc3SMaciej Żenczykowski 
50*1b481fc3SMaciej Żenczykowski #include <linux/ioctl.h>
51*1b481fc3SMaciej Żenczykowski #include <linux/sockios.h>
52*1b481fc3SMaciej Żenczykowski #include <linux/netlink.h>
53*1b481fc3SMaciej Żenczykowski 
54*1b481fc3SMaciej Żenczykowski #include "common.h"
55*1b481fc3SMaciej Żenczykowski #include "netlink/extapi.h"
56*1b481fc3SMaciej Żenczykowski 
57*1b481fc3SMaciej Żenczykowski #ifndef MAX_ADDR_LEN
58*1b481fc3SMaciej Żenczykowski #define MAX_ADDR_LEN	32
59*1b481fc3SMaciej Żenczykowski #endif
60*1b481fc3SMaciej Żenczykowski 
61*1b481fc3SMaciej Żenczykowski #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
62*1b481fc3SMaciej Żenczykowski 
63*1b481fc3SMaciej Żenczykowski static void exit_bad_args(void) __attribute__((noreturn));
64*1b481fc3SMaciej Żenczykowski 
exit_bad_args(void)65*1b481fc3SMaciej Żenczykowski static void exit_bad_args(void)
66*1b481fc3SMaciej Żenczykowski {
67*1b481fc3SMaciej Żenczykowski 	fprintf(stderr,
68*1b481fc3SMaciej Żenczykowski 		"ethtool: bad command line argument(s)\n"
69*1b481fc3SMaciej Żenczykowski 		"For more information run ethtool -h\n");
70*1b481fc3SMaciej Żenczykowski 	exit(1);
71*1b481fc3SMaciej Żenczykowski }
72*1b481fc3SMaciej Żenczykowski 
73*1b481fc3SMaciej Żenczykowski static void exit_nlonly_param(const char *name) __attribute__((noreturn));
74*1b481fc3SMaciej Żenczykowski 
exit_nlonly_param(const char * name)75*1b481fc3SMaciej Żenczykowski static void exit_nlonly_param(const char *name)
76*1b481fc3SMaciej Żenczykowski {
77*1b481fc3SMaciej Żenczykowski 	fprintf(stderr,
78*1b481fc3SMaciej Żenczykowski 		"ethtool: parameter '%s' can be used only with netlink\n",
79*1b481fc3SMaciej Żenczykowski 		name);
80*1b481fc3SMaciej Żenczykowski 	exit(1);
81*1b481fc3SMaciej Żenczykowski }
82*1b481fc3SMaciej Żenczykowski 
83*1b481fc3SMaciej Żenczykowski typedef enum {
84*1b481fc3SMaciej Żenczykowski 	CMDL_NONE,
85*1b481fc3SMaciej Żenczykowski 	CMDL_BOOL,
86*1b481fc3SMaciej Żenczykowski 	CMDL_S32,
87*1b481fc3SMaciej Żenczykowski 	CMDL_U8,
88*1b481fc3SMaciej Żenczykowski 	CMDL_U16,
89*1b481fc3SMaciej Żenczykowski 	CMDL_U32,
90*1b481fc3SMaciej Żenczykowski 	CMDL_U64,
91*1b481fc3SMaciej Żenczykowski 	CMDL_BE16,
92*1b481fc3SMaciej Żenczykowski 	CMDL_IP4,
93*1b481fc3SMaciej Żenczykowski 	CMDL_STR,
94*1b481fc3SMaciej Żenczykowski 	CMDL_FLAG,
95*1b481fc3SMaciej Żenczykowski 	CMDL_MAC,
96*1b481fc3SMaciej Żenczykowski } cmdline_type_t;
97*1b481fc3SMaciej Żenczykowski 
98*1b481fc3SMaciej Żenczykowski struct cmdline_info {
99*1b481fc3SMaciej Żenczykowski 	const char *name;
100*1b481fc3SMaciej Żenczykowski 	cmdline_type_t type;
101*1b481fc3SMaciej Żenczykowski 	/* Points to int (BOOL), s32, u16, u32 (U32/FLAG/IP4), u64,
102*1b481fc3SMaciej Żenczykowski 	 * char * (STR) or u8[6] (MAC).  For FLAG, the value accumulates
103*1b481fc3SMaciej Żenczykowski 	 * all flags to be set. */
104*1b481fc3SMaciej Żenczykowski 	void *wanted_val;
105*1b481fc3SMaciej Żenczykowski 	void *ioctl_val;
106*1b481fc3SMaciej Żenczykowski 	/* For FLAG, the flag value to be set/cleared */
107*1b481fc3SMaciej Żenczykowski 	u32 flag_val;
108*1b481fc3SMaciej Żenczykowski 	/* For FLAG, points to u32 and accumulates all flags seen.
109*1b481fc3SMaciej Żenczykowski 	 * For anything else, points to int and is set if the option is
110*1b481fc3SMaciej Żenczykowski 	 * seen. */
111*1b481fc3SMaciej Żenczykowski 	void *seen_val;
112*1b481fc3SMaciej Żenczykowski };
113*1b481fc3SMaciej Żenczykowski 
114*1b481fc3SMaciej Żenczykowski struct feature_def {
115*1b481fc3SMaciej Żenczykowski 	char name[ETH_GSTRING_LEN];
116*1b481fc3SMaciej Żenczykowski 	int off_flag_index; /* index in off_flag_def; negative if none match */
117*1b481fc3SMaciej Żenczykowski };
118*1b481fc3SMaciej Żenczykowski 
119*1b481fc3SMaciej Żenczykowski struct feature_defs {
120*1b481fc3SMaciej Żenczykowski 	size_t n_features;
121*1b481fc3SMaciej Żenczykowski 	/* Number of features each offload flag is associated with */
122*1b481fc3SMaciej Żenczykowski 	unsigned int off_flag_matched[OFF_FLAG_DEF_SIZE];
123*1b481fc3SMaciej Żenczykowski 	/* Name and offload flag index for each feature */
124*1b481fc3SMaciej Żenczykowski 	struct feature_def def[0];
125*1b481fc3SMaciej Żenczykowski };
126*1b481fc3SMaciej Żenczykowski 
127*1b481fc3SMaciej Żenczykowski #define FEATURE_BITS_TO_BLOCKS(n_bits)		DIV_ROUND_UP(n_bits, 32U)
128*1b481fc3SMaciej Żenczykowski #define FEATURE_WORD(blocks, index, field)	((blocks)[(index) / 32U].field)
129*1b481fc3SMaciej Żenczykowski #define FEATURE_FIELD_FLAG(index)		(1U << (index) % 32U)
130*1b481fc3SMaciej Żenczykowski #define FEATURE_BIT_SET(blocks, index, field)			\
131*1b481fc3SMaciej Żenczykowski 	(FEATURE_WORD(blocks, index, field) |= FEATURE_FIELD_FLAG(index))
132*1b481fc3SMaciej Żenczykowski #define FEATURE_BIT_CLEAR(blocks, index, field)			\
133*1b481fc3SMaciej Żenczykowski 	(FEATURE_WORD(blocks, index, filed) &= ~FEATURE_FIELD_FLAG(index))
134*1b481fc3SMaciej Żenczykowski #define FEATURE_BIT_IS_SET(blocks, index, field)		\
135*1b481fc3SMaciej Żenczykowski 	(FEATURE_WORD(blocks, index, field) & FEATURE_FIELD_FLAG(index))
136*1b481fc3SMaciej Żenczykowski 
137*1b481fc3SMaciej Żenczykowski static long long
get_int_range(char * str,int base,long long min,long long max)138*1b481fc3SMaciej Żenczykowski get_int_range(char *str, int base, long long min, long long max)
139*1b481fc3SMaciej Żenczykowski {
140*1b481fc3SMaciej Żenczykowski 	long long v;
141*1b481fc3SMaciej Żenczykowski 	char *endp;
142*1b481fc3SMaciej Żenczykowski 
143*1b481fc3SMaciej Żenczykowski 	if (!str)
144*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
145*1b481fc3SMaciej Żenczykowski 	errno = 0;
146*1b481fc3SMaciej Żenczykowski 	v = strtoll(str, &endp, base);
147*1b481fc3SMaciej Żenczykowski 	if (errno || *endp || v < min || v > max)
148*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
149*1b481fc3SMaciej Żenczykowski 	return v;
150*1b481fc3SMaciej Żenczykowski }
151*1b481fc3SMaciej Żenczykowski 
152*1b481fc3SMaciej Żenczykowski static unsigned long long
get_uint_range(char * str,int base,unsigned long long max)153*1b481fc3SMaciej Żenczykowski get_uint_range(char *str, int base, unsigned long long max)
154*1b481fc3SMaciej Żenczykowski {
155*1b481fc3SMaciej Żenczykowski 	unsigned long long v;
156*1b481fc3SMaciej Żenczykowski 	char *endp;
157*1b481fc3SMaciej Żenczykowski 
158*1b481fc3SMaciej Żenczykowski 	if (!str)
159*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
160*1b481fc3SMaciej Żenczykowski 	errno = 0;
161*1b481fc3SMaciej Żenczykowski 	v = strtoull(str, &endp, base);
162*1b481fc3SMaciej Żenczykowski 	if (errno || *endp || v > max)
163*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
164*1b481fc3SMaciej Żenczykowski 	return v;
165*1b481fc3SMaciej Żenczykowski }
166*1b481fc3SMaciej Żenczykowski 
get_int(char * str,int base)167*1b481fc3SMaciej Żenczykowski static int get_int(char *str, int base)
168*1b481fc3SMaciej Żenczykowski {
169*1b481fc3SMaciej Żenczykowski 	return get_int_range(str, base, INT_MIN, INT_MAX);
170*1b481fc3SMaciej Żenczykowski }
171*1b481fc3SMaciej Żenczykowski 
get_u32(char * str,int base)172*1b481fc3SMaciej Żenczykowski static u32 get_u32(char *str, int base)
173*1b481fc3SMaciej Żenczykowski {
174*1b481fc3SMaciej Żenczykowski 	return get_uint_range(str, base, 0xffffffff);
175*1b481fc3SMaciej Żenczykowski }
176*1b481fc3SMaciej Żenczykowski 
get_mac_addr(char * src,unsigned char * dest)177*1b481fc3SMaciej Żenczykowski static void get_mac_addr(char *src, unsigned char *dest)
178*1b481fc3SMaciej Żenczykowski {
179*1b481fc3SMaciej Żenczykowski 	int count;
180*1b481fc3SMaciej Żenczykowski 	int i;
181*1b481fc3SMaciej Żenczykowski 	int buf[ETH_ALEN];
182*1b481fc3SMaciej Żenczykowski 
183*1b481fc3SMaciej Żenczykowski 	count = sscanf(src, "%2x:%2x:%2x:%2x:%2x:%2x",
184*1b481fc3SMaciej Żenczykowski 		&buf[0], &buf[1], &buf[2], &buf[3], &buf[4], &buf[5]);
185*1b481fc3SMaciej Żenczykowski 	if (count != ETH_ALEN)
186*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
187*1b481fc3SMaciej Żenczykowski 
188*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < count; i++)
189*1b481fc3SMaciej Żenczykowski 		dest[i] = buf[i];
190*1b481fc3SMaciej Żenczykowski }
191*1b481fc3SMaciej Żenczykowski 
parse_hex_u32_bitmap(const char * s,unsigned int nbits,u32 * result)192*1b481fc3SMaciej Żenczykowski static int parse_hex_u32_bitmap(const char *s,
193*1b481fc3SMaciej Żenczykowski 				unsigned int nbits, u32 *result)
194*1b481fc3SMaciej Żenczykowski {
195*1b481fc3SMaciej Żenczykowski 	const unsigned int nwords = __KERNEL_DIV_ROUND_UP(nbits, 32);
196*1b481fc3SMaciej Żenczykowski 	size_t slen = strlen(s);
197*1b481fc3SMaciej Żenczykowski 	size_t i;
198*1b481fc3SMaciej Żenczykowski 
199*1b481fc3SMaciej Żenczykowski 	/* ignore optional '0x' prefix */
200*1b481fc3SMaciej Żenczykowski 	if ((slen > 2) && (strncasecmp(s, "0x", 2) == 0)) {
201*1b481fc3SMaciej Żenczykowski 		slen -= 2;
202*1b481fc3SMaciej Żenczykowski 		s += 2;
203*1b481fc3SMaciej Żenczykowski 	}
204*1b481fc3SMaciej Żenczykowski 
205*1b481fc3SMaciej Żenczykowski 	if (slen > 8 * nwords)  /* up to 2 digits per byte */
206*1b481fc3SMaciej Żenczykowski 		return -1;
207*1b481fc3SMaciej Żenczykowski 
208*1b481fc3SMaciej Żenczykowski 	memset(result, 0, 4 * nwords);
209*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < slen; ++i) {
210*1b481fc3SMaciej Żenczykowski 		const unsigned int shift = (slen - 1 - i) * 4;
211*1b481fc3SMaciej Żenczykowski 		u32 *dest = &result[shift / 32];
212*1b481fc3SMaciej Żenczykowski 		u32 nibble;
213*1b481fc3SMaciej Żenczykowski 
214*1b481fc3SMaciej Żenczykowski 		if ('a' <= s[i] && s[i] <= 'f')
215*1b481fc3SMaciej Żenczykowski 			nibble = 0xa + (s[i] - 'a');
216*1b481fc3SMaciej Żenczykowski 		else if ('A' <= s[i] && s[i] <= 'F')
217*1b481fc3SMaciej Żenczykowski 			nibble = 0xa + (s[i] - 'A');
218*1b481fc3SMaciej Żenczykowski 		else if ('0' <= s[i] && s[i] <= '9')
219*1b481fc3SMaciej Żenczykowski 			nibble = (s[i] - '0');
220*1b481fc3SMaciej Żenczykowski 		else
221*1b481fc3SMaciej Żenczykowski 			return -1;
222*1b481fc3SMaciej Żenczykowski 
223*1b481fc3SMaciej Żenczykowski 		*dest |= (nibble << (shift % 32));
224*1b481fc3SMaciej Żenczykowski 	}
225*1b481fc3SMaciej Żenczykowski 
226*1b481fc3SMaciej Żenczykowski 	return 0;
227*1b481fc3SMaciej Żenczykowski }
228*1b481fc3SMaciej Żenczykowski 
parse_generic_cmdline(struct cmd_context * ctx,int * changed,struct cmdline_info * info,unsigned int n_info)229*1b481fc3SMaciej Żenczykowski static void parse_generic_cmdline(struct cmd_context *ctx,
230*1b481fc3SMaciej Żenczykowski 				  int *changed,
231*1b481fc3SMaciej Żenczykowski 				  struct cmdline_info *info,
232*1b481fc3SMaciej Żenczykowski 				  unsigned int n_info)
233*1b481fc3SMaciej Żenczykowski {
234*1b481fc3SMaciej Żenczykowski 	unsigned int argc = ctx->argc;
235*1b481fc3SMaciej Żenczykowski 	char **argp = ctx->argp;
236*1b481fc3SMaciej Żenczykowski 	unsigned int i, idx;
237*1b481fc3SMaciej Żenczykowski 	int found;
238*1b481fc3SMaciej Żenczykowski 
239*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < argc; i++) {
240*1b481fc3SMaciej Żenczykowski 		found = 0;
241*1b481fc3SMaciej Żenczykowski 		for (idx = 0; idx < n_info; idx++) {
242*1b481fc3SMaciej Żenczykowski 			if (!strcmp(info[idx].name, argp[i])) {
243*1b481fc3SMaciej Żenczykowski 				found = 1;
244*1b481fc3SMaciej Żenczykowski 				*changed = 1;
245*1b481fc3SMaciej Żenczykowski 				if (info[idx].type != CMDL_FLAG &&
246*1b481fc3SMaciej Żenczykowski 				    info[idx].seen_val)
247*1b481fc3SMaciej Żenczykowski 					*(int *)info[idx].seen_val = 1;
248*1b481fc3SMaciej Żenczykowski 				i += 1;
249*1b481fc3SMaciej Żenczykowski 				if (i >= argc)
250*1b481fc3SMaciej Żenczykowski 					exit_bad_args();
251*1b481fc3SMaciej Żenczykowski 				switch (info[idx].type) {
252*1b481fc3SMaciej Żenczykowski 				case CMDL_BOOL: {
253*1b481fc3SMaciej Żenczykowski 					int *p = info[idx].wanted_val;
254*1b481fc3SMaciej Żenczykowski 					if (!strcmp(argp[i], "on"))
255*1b481fc3SMaciej Żenczykowski 						*p = 1;
256*1b481fc3SMaciej Żenczykowski 					else if (!strcmp(argp[i], "off"))
257*1b481fc3SMaciej Żenczykowski 						*p = 0;
258*1b481fc3SMaciej Żenczykowski 					else
259*1b481fc3SMaciej Żenczykowski 						exit_bad_args();
260*1b481fc3SMaciej Żenczykowski 					break;
261*1b481fc3SMaciej Żenczykowski 				}
262*1b481fc3SMaciej Żenczykowski 				case CMDL_S32: {
263*1b481fc3SMaciej Żenczykowski 					s32 *p = info[idx].wanted_val;
264*1b481fc3SMaciej Żenczykowski 					*p = get_int_range(argp[i], 0,
265*1b481fc3SMaciej Żenczykowski 							   -0x80000000LL,
266*1b481fc3SMaciej Żenczykowski 							   0x7fffffff);
267*1b481fc3SMaciej Żenczykowski 					break;
268*1b481fc3SMaciej Żenczykowski 				}
269*1b481fc3SMaciej Żenczykowski 				case CMDL_U8: {
270*1b481fc3SMaciej Żenczykowski 					u8 *p = info[idx].wanted_val;
271*1b481fc3SMaciej Żenczykowski 					*p = get_uint_range(argp[i], 0, 0xff);
272*1b481fc3SMaciej Żenczykowski 					break;
273*1b481fc3SMaciej Żenczykowski 				}
274*1b481fc3SMaciej Żenczykowski 				case CMDL_U16: {
275*1b481fc3SMaciej Żenczykowski 					u16 *p = info[idx].wanted_val;
276*1b481fc3SMaciej Żenczykowski 					*p = get_uint_range(argp[i], 0, 0xffff);
277*1b481fc3SMaciej Żenczykowski 					break;
278*1b481fc3SMaciej Żenczykowski 				}
279*1b481fc3SMaciej Żenczykowski 				case CMDL_U32: {
280*1b481fc3SMaciej Żenczykowski 					u32 *p = info[idx].wanted_val;
281*1b481fc3SMaciej Żenczykowski 					*p = get_uint_range(argp[i], 0,
282*1b481fc3SMaciej Żenczykowski 							    0xffffffff);
283*1b481fc3SMaciej Żenczykowski 					break;
284*1b481fc3SMaciej Żenczykowski 				}
285*1b481fc3SMaciej Żenczykowski 				case CMDL_U64: {
286*1b481fc3SMaciej Żenczykowski 					u64 *p = info[idx].wanted_val;
287*1b481fc3SMaciej Żenczykowski 					*p = get_uint_range(
288*1b481fc3SMaciej Żenczykowski 						argp[i], 0,
289*1b481fc3SMaciej Żenczykowski 						0xffffffffffffffffLL);
290*1b481fc3SMaciej Żenczykowski 					break;
291*1b481fc3SMaciej Żenczykowski 				}
292*1b481fc3SMaciej Żenczykowski 				case CMDL_BE16: {
293*1b481fc3SMaciej Żenczykowski 					u16 *p = info[idx].wanted_val;
294*1b481fc3SMaciej Żenczykowski 					*p = cpu_to_be16(
295*1b481fc3SMaciej Żenczykowski 						get_uint_range(argp[i], 0,
296*1b481fc3SMaciej Żenczykowski 							       0xffff));
297*1b481fc3SMaciej Żenczykowski 					break;
298*1b481fc3SMaciej Żenczykowski 				}
299*1b481fc3SMaciej Żenczykowski 				case CMDL_IP4: {
300*1b481fc3SMaciej Żenczykowski 					u32 *p = info[idx].wanted_val;
301*1b481fc3SMaciej Żenczykowski 					struct in_addr in;
302*1b481fc3SMaciej Żenczykowski 					if (!inet_pton(AF_INET, argp[i], &in))
303*1b481fc3SMaciej Żenczykowski 						exit_bad_args();
304*1b481fc3SMaciej Żenczykowski 					*p = in.s_addr;
305*1b481fc3SMaciej Żenczykowski 					break;
306*1b481fc3SMaciej Żenczykowski 				}
307*1b481fc3SMaciej Żenczykowski 				case CMDL_MAC:
308*1b481fc3SMaciej Żenczykowski 					get_mac_addr(argp[i],
309*1b481fc3SMaciej Żenczykowski 						     info[idx].wanted_val);
310*1b481fc3SMaciej Żenczykowski 					break;
311*1b481fc3SMaciej Żenczykowski 				case CMDL_FLAG: {
312*1b481fc3SMaciej Żenczykowski 					u32 *p;
313*1b481fc3SMaciej Żenczykowski 					p = info[idx].seen_val;
314*1b481fc3SMaciej Żenczykowski 					*p |= info[idx].flag_val;
315*1b481fc3SMaciej Żenczykowski 					if (!strcmp(argp[i], "on")) {
316*1b481fc3SMaciej Żenczykowski 						p = info[idx].wanted_val;
317*1b481fc3SMaciej Żenczykowski 						*p |= info[idx].flag_val;
318*1b481fc3SMaciej Żenczykowski 					} else if (strcmp(argp[i], "off")) {
319*1b481fc3SMaciej Żenczykowski 						exit_bad_args();
320*1b481fc3SMaciej Żenczykowski 					}
321*1b481fc3SMaciej Żenczykowski 					break;
322*1b481fc3SMaciej Żenczykowski 				}
323*1b481fc3SMaciej Żenczykowski 				case CMDL_STR: {
324*1b481fc3SMaciej Żenczykowski 					char **s = info[idx].wanted_val;
325*1b481fc3SMaciej Żenczykowski 					*s = strdup(argp[i]);
326*1b481fc3SMaciej Żenczykowski 					break;
327*1b481fc3SMaciej Żenczykowski 				}
328*1b481fc3SMaciej Żenczykowski 				default:
329*1b481fc3SMaciej Żenczykowski 					exit_bad_args();
330*1b481fc3SMaciej Żenczykowski 				}
331*1b481fc3SMaciej Żenczykowski 				break;
332*1b481fc3SMaciej Żenczykowski 			}
333*1b481fc3SMaciej Żenczykowski 		}
334*1b481fc3SMaciej Żenczykowski 		if (!found)
335*1b481fc3SMaciej Żenczykowski 			exit_bad_args();
336*1b481fc3SMaciej Żenczykowski 	}
337*1b481fc3SMaciej Żenczykowski }
338*1b481fc3SMaciej Żenczykowski 
flag_to_cmdline_info(const char * name,u32 value,u32 * wanted,u32 * mask,struct cmdline_info * cli)339*1b481fc3SMaciej Żenczykowski static void flag_to_cmdline_info(const char *name, u32 value,
340*1b481fc3SMaciej Żenczykowski 				 u32 *wanted, u32 *mask,
341*1b481fc3SMaciej Żenczykowski 				 struct cmdline_info *cli)
342*1b481fc3SMaciej Żenczykowski {
343*1b481fc3SMaciej Żenczykowski 	memset(cli, 0, sizeof(*cli));
344*1b481fc3SMaciej Żenczykowski 	cli->name = name;
345*1b481fc3SMaciej Żenczykowski 	cli->type = CMDL_FLAG;
346*1b481fc3SMaciej Żenczykowski 	cli->flag_val = value;
347*1b481fc3SMaciej Żenczykowski 	cli->wanted_val = wanted;
348*1b481fc3SMaciej Żenczykowski 	cli->seen_val = mask;
349*1b481fc3SMaciej Żenczykowski }
350*1b481fc3SMaciej Żenczykowski 
rxflow_str_to_type(const char * str)351*1b481fc3SMaciej Żenczykowski static int rxflow_str_to_type(const char *str)
352*1b481fc3SMaciej Żenczykowski {
353*1b481fc3SMaciej Żenczykowski 	int flow_type = 0;
354*1b481fc3SMaciej Żenczykowski 
355*1b481fc3SMaciej Żenczykowski 	if (!strcmp(str, "tcp4"))
356*1b481fc3SMaciej Żenczykowski 		flow_type = TCP_V4_FLOW;
357*1b481fc3SMaciej Żenczykowski 	else if (!strcmp(str, "udp4"))
358*1b481fc3SMaciej Żenczykowski 		flow_type = UDP_V4_FLOW;
359*1b481fc3SMaciej Żenczykowski 	else if (!strcmp(str, "ah4") || !strcmp(str, "esp4"))
360*1b481fc3SMaciej Żenczykowski 		flow_type = AH_ESP_V4_FLOW;
361*1b481fc3SMaciej Żenczykowski 	else if (!strcmp(str, "sctp4"))
362*1b481fc3SMaciej Żenczykowski 		flow_type = SCTP_V4_FLOW;
363*1b481fc3SMaciej Żenczykowski 	else if (!strcmp(str, "tcp6"))
364*1b481fc3SMaciej Żenczykowski 		flow_type = TCP_V6_FLOW;
365*1b481fc3SMaciej Żenczykowski 	else if (!strcmp(str, "udp6"))
366*1b481fc3SMaciej Żenczykowski 		flow_type = UDP_V6_FLOW;
367*1b481fc3SMaciej Żenczykowski 	else if (!strcmp(str, "ah6") || !strcmp(str, "esp6"))
368*1b481fc3SMaciej Żenczykowski 		flow_type = AH_ESP_V6_FLOW;
369*1b481fc3SMaciej Żenczykowski 	else if (!strcmp(str, "sctp6"))
370*1b481fc3SMaciej Żenczykowski 		flow_type = SCTP_V6_FLOW;
371*1b481fc3SMaciej Żenczykowski 	else if (!strcmp(str, "ether"))
372*1b481fc3SMaciej Żenczykowski 		flow_type = ETHER_FLOW;
373*1b481fc3SMaciej Żenczykowski 
374*1b481fc3SMaciej Żenczykowski 	return flow_type;
375*1b481fc3SMaciej Żenczykowski }
376*1b481fc3SMaciej Żenczykowski 
do_version(struct cmd_context * ctx __maybe_unused)377*1b481fc3SMaciej Żenczykowski static int do_version(struct cmd_context *ctx __maybe_unused)
378*1b481fc3SMaciej Żenczykowski {
379*1b481fc3SMaciej Żenczykowski 	fprintf(stdout,
380*1b481fc3SMaciej Żenczykowski 		PACKAGE " version " VERSION
381*1b481fc3SMaciej Żenczykowski #ifndef ETHTOOL_ENABLE_PRETTY_DUMP
382*1b481fc3SMaciej Żenczykowski 		" (pretty dumps disabled)"
383*1b481fc3SMaciej Żenczykowski #endif
384*1b481fc3SMaciej Żenczykowski 		"\n");
385*1b481fc3SMaciej Żenczykowski 	return 0;
386*1b481fc3SMaciej Żenczykowski }
387*1b481fc3SMaciej Żenczykowski 
388*1b481fc3SMaciej Żenczykowski /* link mode routines */
389*1b481fc3SMaciej Żenczykowski 
390*1b481fc3SMaciej Żenczykowski static ETHTOOL_DECLARE_LINK_MODE_MASK(all_advertised_modes);
391*1b481fc3SMaciej Żenczykowski static ETHTOOL_DECLARE_LINK_MODE_MASK(all_advertised_flags);
392*1b481fc3SMaciej Żenczykowski 
init_global_link_mode_masks(void)393*1b481fc3SMaciej Żenczykowski static void init_global_link_mode_masks(void)
394*1b481fc3SMaciej Żenczykowski {
395*1b481fc3SMaciej Żenczykowski 	static const enum ethtool_link_mode_bit_indices
396*1b481fc3SMaciej Żenczykowski 		all_advertised_modes_bits[] = {
397*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_10baseT_Half_BIT,
398*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_10baseT_Full_BIT,
399*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_100baseT_Half_BIT,
400*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_100baseT_Full_BIT,
401*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
402*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
403*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
404*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
405*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
406*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
407*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
408*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
409*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT,
410*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT,
411*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
412*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
413*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
414*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
415*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT,
416*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT,
417*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT,
418*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT,
419*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
420*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
421*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
422*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
423*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
424*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
425*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
426*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
427*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
428*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
429*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
430*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
431*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
432*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
433*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
434*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
435*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
436*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
437*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
438*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
439*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
440*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
441*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_50000baseDR_Full_BIT,
442*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
443*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
444*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
445*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
446*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT,
447*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT,
448*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT,
449*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT,
450*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT,
451*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT,
452*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_100baseT1_Full_BIT,
453*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_1000baseT1_Full_BIT,
454*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT,
455*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT,
456*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT,
457*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT,
458*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT,
459*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_100000baseKR_Full_BIT,
460*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_100000baseSR_Full_BIT,
461*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_100000baseLR_ER_FR_Full_BIT,
462*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_100000baseCR_Full_BIT,
463*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_100000baseDR_Full_BIT,
464*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_200000baseKR2_Full_BIT,
465*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT,
466*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT,
467*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_200000baseDR2_Full_BIT,
468*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT,
469*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_400000baseKR4_Full_BIT,
470*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_400000baseSR4_Full_BIT,
471*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT,
472*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_400000baseDR4_Full_BIT,
473*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT,
474*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_100baseFX_Half_BIT,
475*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_100baseFX_Full_BIT,
476*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_10baseT1L_Full_BIT,
477*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_800000baseCR8_Full_BIT,
478*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_800000baseKR8_Full_BIT,
479*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_800000baseDR8_Full_BIT,
480*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_800000baseDR8_2_Full_BIT,
481*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_800000baseSR8_Full_BIT,
482*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_800000baseVR8_Full_BIT,
483*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_10baseT1S_Full_BIT,
484*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_10baseT1S_Half_BIT,
485*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT,
486*1b481fc3SMaciej Żenczykowski 	};
487*1b481fc3SMaciej Żenczykowski 	static const enum ethtool_link_mode_bit_indices
488*1b481fc3SMaciej Żenczykowski 		additional_advertised_flags_bits[] = {
489*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_Autoneg_BIT,
490*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_TP_BIT,
491*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_AUI_BIT,
492*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_MII_BIT,
493*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_FIBRE_BIT,
494*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_BNC_BIT,
495*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_Pause_BIT,
496*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_Asym_Pause_BIT,
497*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_Backplane_BIT,
498*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_FEC_NONE_BIT,
499*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_FEC_RS_BIT,
500*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_FEC_BASER_BIT,
501*1b481fc3SMaciej Żenczykowski 		ETHTOOL_LINK_MODE_FEC_LLRS_BIT,
502*1b481fc3SMaciej Żenczykowski 	};
503*1b481fc3SMaciej Żenczykowski 	unsigned int i;
504*1b481fc3SMaciej Żenczykowski 
505*1b481fc3SMaciej Żenczykowski 	ethtool_link_mode_zero(all_advertised_modes);
506*1b481fc3SMaciej Żenczykowski 	ethtool_link_mode_zero(all_advertised_flags);
507*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < ARRAY_SIZE(all_advertised_modes_bits); ++i) {
508*1b481fc3SMaciej Żenczykowski 		ethtool_link_mode_set_bit(all_advertised_modes_bits[i],
509*1b481fc3SMaciej Żenczykowski 					  all_advertised_modes);
510*1b481fc3SMaciej Żenczykowski 		ethtool_link_mode_set_bit(all_advertised_modes_bits[i],
511*1b481fc3SMaciej Żenczykowski 					  all_advertised_flags);
512*1b481fc3SMaciej Żenczykowski 	}
513*1b481fc3SMaciej Żenczykowski 
514*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < ARRAY_SIZE(additional_advertised_flags_bits); ++i) {
515*1b481fc3SMaciej Żenczykowski 		ethtool_link_mode_set_bit(
516*1b481fc3SMaciej Żenczykowski 			additional_advertised_flags_bits[i],
517*1b481fc3SMaciej Żenczykowski 			all_advertised_flags);
518*1b481fc3SMaciej Żenczykowski 	}
519*1b481fc3SMaciej Żenczykowski }
520*1b481fc3SMaciej Żenczykowski 
521*1b481fc3SMaciej Żenczykowski static void dump_link_caps(const char *prefix, const char *an_prefix,
522*1b481fc3SMaciej Żenczykowski 			   const u32 *mask, int link_mode_only);
523*1b481fc3SMaciej Żenczykowski 
dump_supported(const struct ethtool_link_usettings * link_usettings)524*1b481fc3SMaciej Żenczykowski static void dump_supported(const struct ethtool_link_usettings *link_usettings)
525*1b481fc3SMaciej Żenczykowski {
526*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "	Supported ports: [ ");
527*1b481fc3SMaciej Żenczykowski 	if (ethtool_link_mode_test_bit(
528*1b481fc3SMaciej Żenczykowski 		    ETHTOOL_LINK_MODE_TP_BIT,
529*1b481fc3SMaciej Żenczykowski 		    link_usettings->link_modes.supported))
530*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "TP ");
531*1b481fc3SMaciej Żenczykowski 	if (ethtool_link_mode_test_bit(
532*1b481fc3SMaciej Żenczykowski 		    ETHTOOL_LINK_MODE_AUI_BIT,
533*1b481fc3SMaciej Żenczykowski 		    link_usettings->link_modes.supported))
534*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "AUI ");
535*1b481fc3SMaciej Żenczykowski 	if (ethtool_link_mode_test_bit(
536*1b481fc3SMaciej Żenczykowski 		    ETHTOOL_LINK_MODE_BNC_BIT,
537*1b481fc3SMaciej Żenczykowski 		    link_usettings->link_modes.supported))
538*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "BNC ");
539*1b481fc3SMaciej Żenczykowski 	if (ethtool_link_mode_test_bit(
540*1b481fc3SMaciej Żenczykowski 		    ETHTOOL_LINK_MODE_MII_BIT,
541*1b481fc3SMaciej Żenczykowski 		    link_usettings->link_modes.supported))
542*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "MII ");
543*1b481fc3SMaciej Żenczykowski 	if (ethtool_link_mode_test_bit(
544*1b481fc3SMaciej Żenczykowski 		    ETHTOOL_LINK_MODE_FIBRE_BIT,
545*1b481fc3SMaciej Żenczykowski 		    link_usettings->link_modes.supported))
546*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "FIBRE ");
547*1b481fc3SMaciej Żenczykowski 	if (ethtool_link_mode_test_bit(
548*1b481fc3SMaciej Żenczykowski 		    ETHTOOL_LINK_MODE_Backplane_BIT,
549*1b481fc3SMaciej Żenczykowski 		    link_usettings->link_modes.supported))
550*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "Backplane ");
551*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "]\n");
552*1b481fc3SMaciej Żenczykowski 
553*1b481fc3SMaciej Żenczykowski 	dump_link_caps("Supported", "Supports",
554*1b481fc3SMaciej Żenczykowski 		       link_usettings->link_modes.supported, 0);
555*1b481fc3SMaciej Żenczykowski }
556*1b481fc3SMaciej Żenczykowski 
557*1b481fc3SMaciej Żenczykowski /* Print link capability flags (supported, advertised or lp_advertised).
558*1b481fc3SMaciej Żenczykowski  * Assumes that the corresponding SUPPORTED and ADVERTISED flags are equal.
559*1b481fc3SMaciej Żenczykowski  */
dump_link_caps(const char * prefix,const char * an_prefix,const u32 * mask,int link_mode_only)560*1b481fc3SMaciej Żenczykowski static void dump_link_caps(const char *prefix, const char *an_prefix,
561*1b481fc3SMaciej Żenczykowski 			   const u32 *mask, int link_mode_only)
562*1b481fc3SMaciej Żenczykowski {
563*1b481fc3SMaciej Żenczykowski 	static const struct {
564*1b481fc3SMaciej Żenczykowski 		int same_line; /* print on same line as previous */
565*1b481fc3SMaciej Żenczykowski 		unsigned int bit_index;
566*1b481fc3SMaciej Żenczykowski 		const char *name;
567*1b481fc3SMaciej Żenczykowski 	} mode_defs[] = {
568*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_10baseT_Half_BIT,
569*1b481fc3SMaciej Żenczykowski 		  "10baseT/Half" },
570*1b481fc3SMaciej Żenczykowski 		{ 1, ETHTOOL_LINK_MODE_10baseT_Full_BIT,
571*1b481fc3SMaciej Żenczykowski 		  "10baseT/Full" },
572*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_100baseT_Half_BIT,
573*1b481fc3SMaciej Żenczykowski 		  "100baseT/Half" },
574*1b481fc3SMaciej Żenczykowski 		{ 1, ETHTOOL_LINK_MODE_100baseT_Full_BIT,
575*1b481fc3SMaciej Żenczykowski 		  "100baseT/Full" },
576*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
577*1b481fc3SMaciej Żenczykowski 		  "1000baseT/Half" },
578*1b481fc3SMaciej Żenczykowski 		{ 1, ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
579*1b481fc3SMaciej Żenczykowski 		  "1000baseT/Full" },
580*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
581*1b481fc3SMaciej Żenczykowski 		  "10000baseT/Full" },
582*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
583*1b481fc3SMaciej Żenczykowski 		  "2500baseX/Full" },
584*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
585*1b481fc3SMaciej Żenczykowski 		  "1000baseKX/Full" },
586*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
587*1b481fc3SMaciej Żenczykowski 		  "10000baseKX4/Full" },
588*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
589*1b481fc3SMaciej Żenczykowski 		  "10000baseKR/Full" },
590*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
591*1b481fc3SMaciej Żenczykowski 		  "10000baseR_FEC" },
592*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT,
593*1b481fc3SMaciej Żenczykowski 		  "20000baseMLD2/Full" },
594*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT,
595*1b481fc3SMaciej Żenczykowski 		  "20000baseKR2/Full" },
596*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
597*1b481fc3SMaciej Żenczykowski 		  "40000baseKR4/Full" },
598*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
599*1b481fc3SMaciej Żenczykowski 		  "40000baseCR4/Full" },
600*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
601*1b481fc3SMaciej Żenczykowski 		  "40000baseSR4/Full" },
602*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
603*1b481fc3SMaciej Żenczykowski 		  "40000baseLR4/Full" },
604*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT,
605*1b481fc3SMaciej Żenczykowski 		  "56000baseKR4/Full" },
606*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT,
607*1b481fc3SMaciej Żenczykowski 		  "56000baseCR4/Full" },
608*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT,
609*1b481fc3SMaciej Żenczykowski 		  "56000baseSR4/Full" },
610*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT,
611*1b481fc3SMaciej Żenczykowski 		  "56000baseLR4/Full" },
612*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
613*1b481fc3SMaciej Żenczykowski 		  "25000baseCR/Full" },
614*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
615*1b481fc3SMaciej Żenczykowski 		  "25000baseKR/Full" },
616*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
617*1b481fc3SMaciej Żenczykowski 		  "25000baseSR/Full" },
618*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
619*1b481fc3SMaciej Żenczykowski 		  "50000baseCR2/Full" },
620*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
621*1b481fc3SMaciej Żenczykowski 		  "50000baseKR2/Full" },
622*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
623*1b481fc3SMaciej Żenczykowski 		  "100000baseKR4/Full" },
624*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
625*1b481fc3SMaciej Żenczykowski 		  "100000baseSR4/Full" },
626*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
627*1b481fc3SMaciej Żenczykowski 		  "100000baseCR4/Full" },
628*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
629*1b481fc3SMaciej Żenczykowski 		  "100000baseLR4_ER4/Full" },
630*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
631*1b481fc3SMaciej Żenczykowski 		  "50000baseSR2/Full" },
632*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
633*1b481fc3SMaciej Żenczykowski 		  "1000baseX/Full" },
634*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
635*1b481fc3SMaciej Żenczykowski 		  "10000baseCR/Full" },
636*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
637*1b481fc3SMaciej Żenczykowski 		  "10000baseSR/Full" },
638*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
639*1b481fc3SMaciej Żenczykowski 		  "10000baseLR/Full" },
640*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
641*1b481fc3SMaciej Żenczykowski 		  "10000baseLRM/Full" },
642*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
643*1b481fc3SMaciej Żenczykowski 		  "10000baseER/Full" },
644*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
645*1b481fc3SMaciej Żenczykowski 		  "2500baseT/Full" },
646*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
647*1b481fc3SMaciej Żenczykowski 		  "5000baseT/Full" },
648*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
649*1b481fc3SMaciej Żenczykowski 		  "50000baseKR/Full" },
650*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
651*1b481fc3SMaciej Żenczykowski 		  "50000baseSR/Full" },
652*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
653*1b481fc3SMaciej Żenczykowski 		  "50000baseCR/Full" },
654*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
655*1b481fc3SMaciej Żenczykowski 		  "50000baseLR_ER_FR/Full" },
656*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_50000baseDR_Full_BIT,
657*1b481fc3SMaciej Żenczykowski 		  "50000baseDR/Full" },
658*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
659*1b481fc3SMaciej Żenczykowski 		  "100000baseKR2/Full" },
660*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
661*1b481fc3SMaciej Żenczykowski 		  "100000baseSR2/Full" },
662*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
663*1b481fc3SMaciej Żenczykowski 		  "100000baseCR2/Full" },
664*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
665*1b481fc3SMaciej Żenczykowski 		  "100000baseLR2_ER2_FR2/Full" },
666*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT,
667*1b481fc3SMaciej Żenczykowski 		  "100000baseDR2/Full" },
668*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT,
669*1b481fc3SMaciej Żenczykowski 		  "200000baseKR4/Full" },
670*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT,
671*1b481fc3SMaciej Żenczykowski 		  "200000baseSR4/Full" },
672*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT,
673*1b481fc3SMaciej Żenczykowski 		  "200000baseLR4_ER4_FR4/Full" },
674*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT,
675*1b481fc3SMaciej Żenczykowski 		  "200000baseDR4/Full" },
676*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT,
677*1b481fc3SMaciej Żenczykowski 		  "200000baseCR4/Full" },
678*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_100baseT1_Full_BIT,
679*1b481fc3SMaciej Żenczykowski 		  "100baseT1/Full" },
680*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_1000baseT1_Full_BIT,
681*1b481fc3SMaciej Żenczykowski 		  "1000baseT1/Full" },
682*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT,
683*1b481fc3SMaciej Żenczykowski 		  "400000baseKR8/Full" },
684*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT,
685*1b481fc3SMaciej Żenczykowski 		  "400000baseSR8/Full" },
686*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT,
687*1b481fc3SMaciej Żenczykowski 		  "400000baseLR8_ER8_FR8/Full" },
688*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT,
689*1b481fc3SMaciej Żenczykowski 		  "400000baseDR8/Full" },
690*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT,
691*1b481fc3SMaciej Żenczykowski 		  "400000baseCR8/Full" },
692*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_100000baseKR_Full_BIT,
693*1b481fc3SMaciej Żenczykowski 		  "100000baseKR/Full" },
694*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_100000baseSR_Full_BIT,
695*1b481fc3SMaciej Żenczykowski 		  "100000baseSR/Full" },
696*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_100000baseLR_ER_FR_Full_BIT,
697*1b481fc3SMaciej Żenczykowski 		  "100000baseLR_ER_FR/Full" },
698*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_100000baseDR_Full_BIT,
699*1b481fc3SMaciej Żenczykowski 		  "100000baseDR/Full" },
700*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_100000baseCR_Full_BIT,
701*1b481fc3SMaciej Żenczykowski 		  "100000baseCR/Full" },
702*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_200000baseKR2_Full_BIT,
703*1b481fc3SMaciej Żenczykowski 		  "200000baseKR2/Full" },
704*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT,
705*1b481fc3SMaciej Żenczykowski 		  "200000baseSR2/Full" },
706*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT,
707*1b481fc3SMaciej Żenczykowski 		  "200000baseLR2_ER2_FR2/Full" },
708*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_200000baseDR2_Full_BIT,
709*1b481fc3SMaciej Żenczykowski 		  "200000baseDR2/Full" },
710*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT,
711*1b481fc3SMaciej Żenczykowski 		  "200000baseCR2/Full" },
712*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_400000baseKR4_Full_BIT,
713*1b481fc3SMaciej Żenczykowski 		  "400000baseKR4/Full" },
714*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_400000baseSR4_Full_BIT,
715*1b481fc3SMaciej Żenczykowski 		  "400000baseSR4/Full" },
716*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT,
717*1b481fc3SMaciej Żenczykowski 		  "400000baseLR4_ER4_FR4/Full" },
718*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_400000baseDR4_Full_BIT,
719*1b481fc3SMaciej Żenczykowski 		  "400000baseDR4/Full" },
720*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT,
721*1b481fc3SMaciej Żenczykowski 		  "400000baseCR4/Full" },
722*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_100baseFX_Half_BIT,
723*1b481fc3SMaciej Żenczykowski 		  "100baseFX/Half" },
724*1b481fc3SMaciej Żenczykowski 		{ 1, ETHTOOL_LINK_MODE_100baseFX_Full_BIT,
725*1b481fc3SMaciej Żenczykowski 		  "100baseFX/Full" },
726*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_10baseT1L_Full_BIT,
727*1b481fc3SMaciej Żenczykowski 		  "10baseT1L/Full" },
728*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_800000baseCR8_Full_BIT,
729*1b481fc3SMaciej Żenczykowski 		  "800000baseCR8/Full" },
730*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_800000baseKR8_Full_BIT,
731*1b481fc3SMaciej Żenczykowski 		  "800000baseKR8/Full" },
732*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_800000baseDR8_Full_BIT,
733*1b481fc3SMaciej Żenczykowski 		  "800000baseDR8/Full" },
734*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_800000baseDR8_2_Full_BIT,
735*1b481fc3SMaciej Żenczykowski 		  "800000baseDR8_2/Full" },
736*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_800000baseSR8_Full_BIT,
737*1b481fc3SMaciej Żenczykowski 		  "800000baseSR8/Full" },
738*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_800000baseVR8_Full_BIT,
739*1b481fc3SMaciej Żenczykowski 		  "800000baseVR8/Full" },
740*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_10baseT1S_Full_BIT,
741*1b481fc3SMaciej Żenczykowski 		  "10baseT1S/Full" },
742*1b481fc3SMaciej Żenczykowski 		{ 1, ETHTOOL_LINK_MODE_10baseT1S_Half_BIT,
743*1b481fc3SMaciej Żenczykowski 		  "10baseT1S/Half" },
744*1b481fc3SMaciej Żenczykowski 		{ 0, ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT,
745*1b481fc3SMaciej Żenczykowski 		  "10baseT1S/Half" },
746*1b481fc3SMaciej Żenczykowski 	};
747*1b481fc3SMaciej Żenczykowski 	int indent;
748*1b481fc3SMaciej Żenczykowski 	int did1, new_line_pend;
749*1b481fc3SMaciej Żenczykowski 	int fecreported = 0;
750*1b481fc3SMaciej Żenczykowski 	unsigned int i;
751*1b481fc3SMaciej Żenczykowski 
752*1b481fc3SMaciej Żenczykowski 	/* Indent just like the separate functions used to */
753*1b481fc3SMaciej Żenczykowski 	indent = strlen(prefix) + 14;
754*1b481fc3SMaciej Żenczykowski 	if (indent < 24)
755*1b481fc3SMaciej Żenczykowski 		indent = 24;
756*1b481fc3SMaciej Żenczykowski 
757*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "	%s link modes:%*s", prefix,
758*1b481fc3SMaciej Żenczykowski 		indent - (int)strlen(prefix) - 12, "");
759*1b481fc3SMaciej Żenczykowski 	did1 = 0;
760*1b481fc3SMaciej Żenczykowski 	new_line_pend = 0;
761*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < ARRAY_SIZE(mode_defs); i++) {
762*1b481fc3SMaciej Żenczykowski 		if (did1 && !mode_defs[i].same_line)
763*1b481fc3SMaciej Żenczykowski 			new_line_pend = 1;
764*1b481fc3SMaciej Żenczykowski 		if (ethtool_link_mode_test_bit(mode_defs[i].bit_index,
765*1b481fc3SMaciej Żenczykowski 					       mask)) {
766*1b481fc3SMaciej Żenczykowski 			if (new_line_pend) {
767*1b481fc3SMaciej Żenczykowski 				fprintf(stdout, "\n");
768*1b481fc3SMaciej Żenczykowski 				fprintf(stdout, "	%*s", indent, "");
769*1b481fc3SMaciej Żenczykowski 				new_line_pend = 0;
770*1b481fc3SMaciej Żenczykowski 			}
771*1b481fc3SMaciej Żenczykowski 			did1++;
772*1b481fc3SMaciej Żenczykowski 			fprintf(stdout, "%s ", mode_defs[i].name);
773*1b481fc3SMaciej Żenczykowski 		}
774*1b481fc3SMaciej Żenczykowski 	}
775*1b481fc3SMaciej Żenczykowski 	if (did1 == 0)
776*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "Not reported");
777*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "\n");
778*1b481fc3SMaciej Żenczykowski 
779*1b481fc3SMaciej Żenczykowski 	if (!link_mode_only) {
780*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "	%s pause frame use: ", prefix);
781*1b481fc3SMaciej Żenczykowski 		if (ethtool_link_mode_test_bit(
782*1b481fc3SMaciej Żenczykowski 			    ETHTOOL_LINK_MODE_Pause_BIT, mask)) {
783*1b481fc3SMaciej Żenczykowski 			fprintf(stdout, "Symmetric");
784*1b481fc3SMaciej Żenczykowski 			if (ethtool_link_mode_test_bit(
785*1b481fc3SMaciej Żenczykowski 				    ETHTOOL_LINK_MODE_Asym_Pause_BIT, mask))
786*1b481fc3SMaciej Żenczykowski 				fprintf(stdout, " Receive-only");
787*1b481fc3SMaciej Żenczykowski 			fprintf(stdout, "\n");
788*1b481fc3SMaciej Żenczykowski 		} else {
789*1b481fc3SMaciej Żenczykowski 			if (ethtool_link_mode_test_bit(
790*1b481fc3SMaciej Żenczykowski 				    ETHTOOL_LINK_MODE_Asym_Pause_BIT, mask))
791*1b481fc3SMaciej Żenczykowski 				fprintf(stdout, "Transmit-only\n");
792*1b481fc3SMaciej Żenczykowski 			else
793*1b481fc3SMaciej Żenczykowski 				fprintf(stdout, "No\n");
794*1b481fc3SMaciej Żenczykowski 		}
795*1b481fc3SMaciej Żenczykowski 
796*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "	%s auto-negotiation: ", an_prefix);
797*1b481fc3SMaciej Żenczykowski 		if (ethtool_link_mode_test_bit(
798*1b481fc3SMaciej Żenczykowski 			    ETHTOOL_LINK_MODE_Autoneg_BIT, mask))
799*1b481fc3SMaciej Żenczykowski 			fprintf(stdout, "Yes\n");
800*1b481fc3SMaciej Żenczykowski 		else
801*1b481fc3SMaciej Żenczykowski 			fprintf(stdout, "No\n");
802*1b481fc3SMaciej Żenczykowski 
803*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "	%s FEC modes:", prefix);
804*1b481fc3SMaciej Żenczykowski 		if (ethtool_link_mode_test_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT,
805*1b481fc3SMaciej Żenczykowski 					       mask)) {
806*1b481fc3SMaciej Żenczykowski 			fprintf(stdout, " None");
807*1b481fc3SMaciej Żenczykowski 			fecreported = 1;
808*1b481fc3SMaciej Żenczykowski 		}
809*1b481fc3SMaciej Żenczykowski 		if (ethtool_link_mode_test_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT,
810*1b481fc3SMaciej Żenczykowski 					       mask)) {
811*1b481fc3SMaciej Żenczykowski 			fprintf(stdout, " BaseR");
812*1b481fc3SMaciej Żenczykowski 			fecreported = 1;
813*1b481fc3SMaciej Żenczykowski 		}
814*1b481fc3SMaciej Żenczykowski 		if (ethtool_link_mode_test_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT,
815*1b481fc3SMaciej Żenczykowski 					       mask)) {
816*1b481fc3SMaciej Żenczykowski 			fprintf(stdout, " RS");
817*1b481fc3SMaciej Żenczykowski 			fecreported = 1;
818*1b481fc3SMaciej Żenczykowski 		}
819*1b481fc3SMaciej Żenczykowski 		if (ethtool_link_mode_test_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT,
820*1b481fc3SMaciej Żenczykowski 					       mask)) {
821*1b481fc3SMaciej Żenczykowski 			fprintf(stdout, " LLRS");
822*1b481fc3SMaciej Żenczykowski 			fecreported = 1;
823*1b481fc3SMaciej Żenczykowski 		}
824*1b481fc3SMaciej Żenczykowski 
825*1b481fc3SMaciej Żenczykowski 		if (!fecreported)
826*1b481fc3SMaciej Żenczykowski 			fprintf(stdout, " Not reported");
827*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "\n");
828*1b481fc3SMaciej Żenczykowski 	}
829*1b481fc3SMaciej Żenczykowski }
830*1b481fc3SMaciej Żenczykowski 
831*1b481fc3SMaciej Żenczykowski static int
dump_link_usettings(const struct ethtool_link_usettings * link_usettings)832*1b481fc3SMaciej Żenczykowski dump_link_usettings(const struct ethtool_link_usettings *link_usettings)
833*1b481fc3SMaciej Żenczykowski {
834*1b481fc3SMaciej Żenczykowski 	dump_supported(link_usettings);
835*1b481fc3SMaciej Żenczykowski 	dump_link_caps("Advertised", "Advertised",
836*1b481fc3SMaciej Żenczykowski 		       link_usettings->link_modes.advertising, 0);
837*1b481fc3SMaciej Żenczykowski 	if (!ethtool_link_mode_is_empty(
838*1b481fc3SMaciej Żenczykowski 		    link_usettings->link_modes.lp_advertising))
839*1b481fc3SMaciej Żenczykowski 		dump_link_caps("Link partner advertised",
840*1b481fc3SMaciej Żenczykowski 			       "Link partner advertised",
841*1b481fc3SMaciej Żenczykowski 			       link_usettings->link_modes.lp_advertising, 0);
842*1b481fc3SMaciej Żenczykowski 
843*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "	Speed: ");
844*1b481fc3SMaciej Żenczykowski 	if (link_usettings->base.speed == 0
845*1b481fc3SMaciej Żenczykowski 	    || link_usettings->base.speed == (u16)(-1)
846*1b481fc3SMaciej Żenczykowski 	    || link_usettings->base.speed == (u32)(-1))
847*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "Unknown!\n");
848*1b481fc3SMaciej Żenczykowski 	else
849*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "%uMb/s\n", link_usettings->base.speed);
850*1b481fc3SMaciej Żenczykowski 
851*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "	Duplex: ");
852*1b481fc3SMaciej Żenczykowski 	switch (link_usettings->base.duplex) {
853*1b481fc3SMaciej Żenczykowski 	case DUPLEX_HALF:
854*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "Half\n");
855*1b481fc3SMaciej Żenczykowski 		break;
856*1b481fc3SMaciej Żenczykowski 	case DUPLEX_FULL:
857*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "Full\n");
858*1b481fc3SMaciej Żenczykowski 		break;
859*1b481fc3SMaciej Żenczykowski 	default:
860*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "Unknown! (%i)\n", link_usettings->base.duplex);
861*1b481fc3SMaciej Żenczykowski 		break;
862*1b481fc3SMaciej Żenczykowski 	};
863*1b481fc3SMaciej Żenczykowski 
864*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "	Port: ");
865*1b481fc3SMaciej Żenczykowski 	switch (link_usettings->base.port) {
866*1b481fc3SMaciej Żenczykowski 	case PORT_TP:
867*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "Twisted Pair\n");
868*1b481fc3SMaciej Żenczykowski 		break;
869*1b481fc3SMaciej Żenczykowski 	case PORT_AUI:
870*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "AUI\n");
871*1b481fc3SMaciej Żenczykowski 		break;
872*1b481fc3SMaciej Żenczykowski 	case PORT_BNC:
873*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "BNC\n");
874*1b481fc3SMaciej Żenczykowski 		break;
875*1b481fc3SMaciej Żenczykowski 	case PORT_MII:
876*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "MII\n");
877*1b481fc3SMaciej Żenczykowski 		break;
878*1b481fc3SMaciej Żenczykowski 	case PORT_FIBRE:
879*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "FIBRE\n");
880*1b481fc3SMaciej Żenczykowski 		break;
881*1b481fc3SMaciej Żenczykowski 	case PORT_DA:
882*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "Direct Attach Copper\n");
883*1b481fc3SMaciej Żenczykowski 		break;
884*1b481fc3SMaciej Żenczykowski 	case PORT_NONE:
885*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "None\n");
886*1b481fc3SMaciej Żenczykowski 		break;
887*1b481fc3SMaciej Żenczykowski 	case PORT_OTHER:
888*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "Other\n");
889*1b481fc3SMaciej Żenczykowski 		break;
890*1b481fc3SMaciej Żenczykowski 	default:
891*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "Unknown! (%i)\n", link_usettings->base.port);
892*1b481fc3SMaciej Żenczykowski 		break;
893*1b481fc3SMaciej Żenczykowski 	};
894*1b481fc3SMaciej Żenczykowski 
895*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "	PHYAD: %d\n", link_usettings->base.phy_address);
896*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "	Transceiver: ");
897*1b481fc3SMaciej Żenczykowski 	switch (link_usettings->deprecated.transceiver) {
898*1b481fc3SMaciej Żenczykowski 	case XCVR_INTERNAL:
899*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "internal\n");
900*1b481fc3SMaciej Żenczykowski 		break;
901*1b481fc3SMaciej Żenczykowski 	case XCVR_EXTERNAL:
902*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "external\n");
903*1b481fc3SMaciej Żenczykowski 		break;
904*1b481fc3SMaciej Żenczykowski 	default:
905*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "Unknown!\n");
906*1b481fc3SMaciej Żenczykowski 		break;
907*1b481fc3SMaciej Żenczykowski 	};
908*1b481fc3SMaciej Żenczykowski 
909*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "	Auto-negotiation: %s\n",
910*1b481fc3SMaciej Żenczykowski 		(link_usettings->base.autoneg == AUTONEG_DISABLE) ?
911*1b481fc3SMaciej Żenczykowski 		"off" : "on");
912*1b481fc3SMaciej Żenczykowski 
913*1b481fc3SMaciej Żenczykowski 	if (link_usettings->base.port == PORT_TP)
914*1b481fc3SMaciej Żenczykowski 		dump_mdix(link_usettings->base.eth_tp_mdix,
915*1b481fc3SMaciej Żenczykowski 			  link_usettings->base.eth_tp_mdix_ctrl);
916*1b481fc3SMaciej Żenczykowski 
917*1b481fc3SMaciej Żenczykowski 	return 0;
918*1b481fc3SMaciej Żenczykowski }
919*1b481fc3SMaciej Żenczykowski 
dump_drvinfo(struct ethtool_drvinfo * info)920*1b481fc3SMaciej Żenczykowski static int dump_drvinfo(struct ethtool_drvinfo *info)
921*1b481fc3SMaciej Żenczykowski {
922*1b481fc3SMaciej Żenczykowski 	fprintf(stdout,
923*1b481fc3SMaciej Żenczykowski 		"driver: %.*s\n"
924*1b481fc3SMaciej Żenczykowski 		"version: %.*s\n"
925*1b481fc3SMaciej Żenczykowski 		"firmware-version: %.*s\n"
926*1b481fc3SMaciej Żenczykowski 		"expansion-rom-version: %.*s\n"
927*1b481fc3SMaciej Żenczykowski 		"bus-info: %.*s\n"
928*1b481fc3SMaciej Żenczykowski 		"supports-statistics: %s\n"
929*1b481fc3SMaciej Żenczykowski 		"supports-test: %s\n"
930*1b481fc3SMaciej Żenczykowski 		"supports-eeprom-access: %s\n"
931*1b481fc3SMaciej Żenczykowski 		"supports-register-dump: %s\n"
932*1b481fc3SMaciej Żenczykowski 		"supports-priv-flags: %s\n",
933*1b481fc3SMaciej Żenczykowski 		(int)sizeof(info->driver), info->driver,
934*1b481fc3SMaciej Żenczykowski 		(int)sizeof(info->version), info->version,
935*1b481fc3SMaciej Żenczykowski 		(int)sizeof(info->fw_version), info->fw_version,
936*1b481fc3SMaciej Żenczykowski 		(int)sizeof(info->erom_version), info->erom_version,
937*1b481fc3SMaciej Żenczykowski 		(int)sizeof(info->bus_info), info->bus_info,
938*1b481fc3SMaciej Żenczykowski 		info->n_stats ? "yes" : "no",
939*1b481fc3SMaciej Żenczykowski 		info->testinfo_len ? "yes" : "no",
940*1b481fc3SMaciej Żenczykowski 		info->eedump_len ? "yes" : "no",
941*1b481fc3SMaciej Żenczykowski 		info->regdump_len ? "yes" : "no",
942*1b481fc3SMaciej Żenczykowski 		info->n_priv_flags ? "yes" : "no");
943*1b481fc3SMaciej Żenczykowski 
944*1b481fc3SMaciej Żenczykowski 	return 0;
945*1b481fc3SMaciej Żenczykowski }
946*1b481fc3SMaciej Żenczykowski 
parse_wolopts(char * optstr,u32 * data)947*1b481fc3SMaciej Żenczykowski static int parse_wolopts(char *optstr, u32 *data)
948*1b481fc3SMaciej Żenczykowski {
949*1b481fc3SMaciej Żenczykowski 	*data = 0;
950*1b481fc3SMaciej Żenczykowski 	while (*optstr) {
951*1b481fc3SMaciej Żenczykowski 		switch (*optstr) {
952*1b481fc3SMaciej Żenczykowski 		case 'p':
953*1b481fc3SMaciej Żenczykowski 			*data |= WAKE_PHY;
954*1b481fc3SMaciej Żenczykowski 			break;
955*1b481fc3SMaciej Żenczykowski 		case 'u':
956*1b481fc3SMaciej Żenczykowski 			*data |= WAKE_UCAST;
957*1b481fc3SMaciej Żenczykowski 			break;
958*1b481fc3SMaciej Żenczykowski 		case 'm':
959*1b481fc3SMaciej Żenczykowski 			*data |= WAKE_MCAST;
960*1b481fc3SMaciej Żenczykowski 			break;
961*1b481fc3SMaciej Żenczykowski 		case 'b':
962*1b481fc3SMaciej Żenczykowski 			*data |= WAKE_BCAST;
963*1b481fc3SMaciej Żenczykowski 			break;
964*1b481fc3SMaciej Żenczykowski 		case 'a':
965*1b481fc3SMaciej Żenczykowski 			*data |= WAKE_ARP;
966*1b481fc3SMaciej Żenczykowski 			break;
967*1b481fc3SMaciej Żenczykowski 		case 'g':
968*1b481fc3SMaciej Żenczykowski 			*data |= WAKE_MAGIC;
969*1b481fc3SMaciej Żenczykowski 			break;
970*1b481fc3SMaciej Żenczykowski 		case 's':
971*1b481fc3SMaciej Żenczykowski 			*data |= WAKE_MAGICSECURE;
972*1b481fc3SMaciej Żenczykowski 			break;
973*1b481fc3SMaciej Żenczykowski 		case 'f':
974*1b481fc3SMaciej Żenczykowski 			*data |= WAKE_FILTER;
975*1b481fc3SMaciej Żenczykowski 			break;
976*1b481fc3SMaciej Żenczykowski 		case 'd':
977*1b481fc3SMaciej Żenczykowski 			*data = 0;
978*1b481fc3SMaciej Żenczykowski 			break;
979*1b481fc3SMaciej Żenczykowski 		default:
980*1b481fc3SMaciej Żenczykowski 			return -1;
981*1b481fc3SMaciej Żenczykowski 		}
982*1b481fc3SMaciej Żenczykowski 		optstr++;
983*1b481fc3SMaciej Żenczykowski 	}
984*1b481fc3SMaciej Żenczykowski 	return 0;
985*1b481fc3SMaciej Żenczykowski }
986*1b481fc3SMaciej Żenczykowski 
parse_rxfhashopts(char * optstr,u32 * data)987*1b481fc3SMaciej Żenczykowski static int parse_rxfhashopts(char *optstr, u32 *data)
988*1b481fc3SMaciej Żenczykowski {
989*1b481fc3SMaciej Żenczykowski 	*data = 0;
990*1b481fc3SMaciej Żenczykowski 	while (*optstr) {
991*1b481fc3SMaciej Żenczykowski 		switch (*optstr) {
992*1b481fc3SMaciej Żenczykowski 		case 'm':
993*1b481fc3SMaciej Żenczykowski 			*data |= RXH_L2DA;
994*1b481fc3SMaciej Żenczykowski 			break;
995*1b481fc3SMaciej Żenczykowski 		case 'v':
996*1b481fc3SMaciej Żenczykowski 			*data |= RXH_VLAN;
997*1b481fc3SMaciej Żenczykowski 			break;
998*1b481fc3SMaciej Żenczykowski 		case 't':
999*1b481fc3SMaciej Żenczykowski 			*data |= RXH_L3_PROTO;
1000*1b481fc3SMaciej Żenczykowski 			break;
1001*1b481fc3SMaciej Żenczykowski 		case 's':
1002*1b481fc3SMaciej Żenczykowski 			*data |= RXH_IP_SRC;
1003*1b481fc3SMaciej Żenczykowski 			break;
1004*1b481fc3SMaciej Żenczykowski 		case 'd':
1005*1b481fc3SMaciej Żenczykowski 			*data |= RXH_IP_DST;
1006*1b481fc3SMaciej Żenczykowski 			break;
1007*1b481fc3SMaciej Żenczykowski 		case 'f':
1008*1b481fc3SMaciej Żenczykowski 			*data |= RXH_L4_B_0_1;
1009*1b481fc3SMaciej Żenczykowski 			break;
1010*1b481fc3SMaciej Żenczykowski 		case 'n':
1011*1b481fc3SMaciej Żenczykowski 			*data |= RXH_L4_B_2_3;
1012*1b481fc3SMaciej Żenczykowski 			break;
1013*1b481fc3SMaciej Żenczykowski 		case 'r':
1014*1b481fc3SMaciej Żenczykowski 			*data |= RXH_DISCARD;
1015*1b481fc3SMaciej Żenczykowski 			break;
1016*1b481fc3SMaciej Żenczykowski 		default:
1017*1b481fc3SMaciej Żenczykowski 			return -1;
1018*1b481fc3SMaciej Żenczykowski 		}
1019*1b481fc3SMaciej Żenczykowski 		optstr++;
1020*1b481fc3SMaciej Żenczykowski 	}
1021*1b481fc3SMaciej Żenczykowski 	return 0;
1022*1b481fc3SMaciej Żenczykowski }
1023*1b481fc3SMaciej Żenczykowski 
unparse_rxfhashopts(u64 opts)1024*1b481fc3SMaciej Żenczykowski static char *unparse_rxfhashopts(u64 opts)
1025*1b481fc3SMaciej Żenczykowski {
1026*1b481fc3SMaciej Żenczykowski 	static char buf[300];
1027*1b481fc3SMaciej Żenczykowski 
1028*1b481fc3SMaciej Żenczykowski 	memset(buf, 0, sizeof(buf));
1029*1b481fc3SMaciej Żenczykowski 
1030*1b481fc3SMaciej Żenczykowski 	if (opts) {
1031*1b481fc3SMaciej Żenczykowski 		if (opts & RXH_L2DA)
1032*1b481fc3SMaciej Żenczykowski 			strcat(buf, "L2DA\n");
1033*1b481fc3SMaciej Żenczykowski 		if (opts & RXH_VLAN)
1034*1b481fc3SMaciej Żenczykowski 			strcat(buf, "VLAN tag\n");
1035*1b481fc3SMaciej Żenczykowski 		if (opts & RXH_L3_PROTO)
1036*1b481fc3SMaciej Żenczykowski 			strcat(buf, "L3 proto\n");
1037*1b481fc3SMaciej Żenczykowski 		if (opts & RXH_IP_SRC)
1038*1b481fc3SMaciej Żenczykowski 			strcat(buf, "IP SA\n");
1039*1b481fc3SMaciej Żenczykowski 		if (opts & RXH_IP_DST)
1040*1b481fc3SMaciej Żenczykowski 			strcat(buf, "IP DA\n");
1041*1b481fc3SMaciej Żenczykowski 		if (opts & RXH_L4_B_0_1)
1042*1b481fc3SMaciej Żenczykowski 			strcat(buf, "L4 bytes 0 & 1 [TCP/UDP src port]\n");
1043*1b481fc3SMaciej Żenczykowski 		if (opts & RXH_L4_B_2_3)
1044*1b481fc3SMaciej Żenczykowski 			strcat(buf, "L4 bytes 2 & 3 [TCP/UDP dst port]\n");
1045*1b481fc3SMaciej Żenczykowski 	} else {
1046*1b481fc3SMaciej Żenczykowski 		sprintf(buf, "None");
1047*1b481fc3SMaciej Żenczykowski 	}
1048*1b481fc3SMaciej Żenczykowski 
1049*1b481fc3SMaciej Żenczykowski 	return buf;
1050*1b481fc3SMaciej Żenczykowski }
1051*1b481fc3SMaciej Żenczykowski 
convert_string_to_hashkey(char * rss_hkey,u32 key_size,const char * rss_hkey_string)1052*1b481fc3SMaciej Żenczykowski static int convert_string_to_hashkey(char *rss_hkey, u32 key_size,
1053*1b481fc3SMaciej Żenczykowski 				     const char *rss_hkey_string)
1054*1b481fc3SMaciej Żenczykowski {
1055*1b481fc3SMaciej Żenczykowski 	u32 i = 0;
1056*1b481fc3SMaciej Żenczykowski 	int hex_byte, len;
1057*1b481fc3SMaciej Żenczykowski 
1058*1b481fc3SMaciej Żenczykowski 	do {
1059*1b481fc3SMaciej Żenczykowski 		if (i > (key_size - 1)) {
1060*1b481fc3SMaciej Żenczykowski 			fprintf(stderr,
1061*1b481fc3SMaciej Żenczykowski 				"Key is too long for device (%u > %u)\n",
1062*1b481fc3SMaciej Żenczykowski 				i + 1, key_size);
1063*1b481fc3SMaciej Żenczykowski 			goto err;
1064*1b481fc3SMaciej Żenczykowski 		}
1065*1b481fc3SMaciej Żenczykowski 
1066*1b481fc3SMaciej Żenczykowski 		if (sscanf(rss_hkey_string, "%2x%n", &hex_byte, &len) < 1 ||
1067*1b481fc3SMaciej Żenczykowski 		    len != 2) {
1068*1b481fc3SMaciej Żenczykowski 			fprintf(stderr, "Invalid RSS hash key format\n");
1069*1b481fc3SMaciej Żenczykowski 			goto err;
1070*1b481fc3SMaciej Żenczykowski 		}
1071*1b481fc3SMaciej Żenczykowski 
1072*1b481fc3SMaciej Żenczykowski 		rss_hkey[i++] = hex_byte;
1073*1b481fc3SMaciej Żenczykowski 		rss_hkey_string += 2;
1074*1b481fc3SMaciej Żenczykowski 
1075*1b481fc3SMaciej Żenczykowski 		if (*rss_hkey_string == ':') {
1076*1b481fc3SMaciej Żenczykowski 			rss_hkey_string++;
1077*1b481fc3SMaciej Żenczykowski 		} else if (*rss_hkey_string != '\0') {
1078*1b481fc3SMaciej Żenczykowski 			fprintf(stderr, "Invalid RSS hash key format\n");
1079*1b481fc3SMaciej Żenczykowski 			goto err;
1080*1b481fc3SMaciej Żenczykowski 		}
1081*1b481fc3SMaciej Żenczykowski 
1082*1b481fc3SMaciej Żenczykowski 	} while (*rss_hkey_string);
1083*1b481fc3SMaciej Żenczykowski 
1084*1b481fc3SMaciej Żenczykowski 	if (i != key_size) {
1085*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "Key is too short for device (%u < %u)\n",
1086*1b481fc3SMaciej Żenczykowski 			i, key_size);
1087*1b481fc3SMaciej Żenczykowski 		goto err;
1088*1b481fc3SMaciej Żenczykowski 	}
1089*1b481fc3SMaciej Żenczykowski 
1090*1b481fc3SMaciej Żenczykowski 	return 0;
1091*1b481fc3SMaciej Żenczykowski err:
1092*1b481fc3SMaciej Żenczykowski 	return 2;
1093*1b481fc3SMaciej Żenczykowski }
1094*1b481fc3SMaciej Żenczykowski 
parse_hkey(char ** rss_hkey,u32 key_size,const char * rss_hkey_string)1095*1b481fc3SMaciej Żenczykowski static int parse_hkey(char **rss_hkey, u32 key_size,
1096*1b481fc3SMaciej Żenczykowski 		      const char *rss_hkey_string)
1097*1b481fc3SMaciej Żenczykowski {
1098*1b481fc3SMaciej Żenczykowski 	if (!key_size) {
1099*1b481fc3SMaciej Żenczykowski 		fprintf(stderr,
1100*1b481fc3SMaciej Żenczykowski 			"Cannot set RX flow hash configuration:\n"
1101*1b481fc3SMaciej Żenczykowski 			" Hash key setting not supported\n");
1102*1b481fc3SMaciej Żenczykowski 		return 1;
1103*1b481fc3SMaciej Żenczykowski 	}
1104*1b481fc3SMaciej Żenczykowski 
1105*1b481fc3SMaciej Żenczykowski 	*rss_hkey = malloc(key_size);
1106*1b481fc3SMaciej Żenczykowski 	if (!(*rss_hkey)) {
1107*1b481fc3SMaciej Żenczykowski 		perror("Cannot allocate memory for RSS hash key");
1108*1b481fc3SMaciej Żenczykowski 		return 1;
1109*1b481fc3SMaciej Żenczykowski 	}
1110*1b481fc3SMaciej Żenczykowski 
1111*1b481fc3SMaciej Żenczykowski 	if (convert_string_to_hashkey(*rss_hkey, key_size,
1112*1b481fc3SMaciej Żenczykowski 				      rss_hkey_string)) {
1113*1b481fc3SMaciej Żenczykowski 		free(*rss_hkey);
1114*1b481fc3SMaciej Żenczykowski 		*rss_hkey = NULL;
1115*1b481fc3SMaciej Żenczykowski 		return 2;
1116*1b481fc3SMaciej Żenczykowski 	}
1117*1b481fc3SMaciej Żenczykowski 	return 0;
1118*1b481fc3SMaciej Żenczykowski }
1119*1b481fc3SMaciej Żenczykowski 
1120*1b481fc3SMaciej Żenczykowski #ifdef ETHTOOL_ENABLE_PRETTY_DUMP
1121*1b481fc3SMaciej Żenczykowski static const struct {
1122*1b481fc3SMaciej Żenczykowski 	const char *name;
1123*1b481fc3SMaciej Żenczykowski 	int (*func)(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
1124*1b481fc3SMaciej Żenczykowski 
1125*1b481fc3SMaciej Żenczykowski } driver_list[] = {
1126*1b481fc3SMaciej Żenczykowski 	{ "8139cp", realtek_dump_regs },
1127*1b481fc3SMaciej Żenczykowski 	{ "8139too", realtek_dump_regs },
1128*1b481fc3SMaciej Żenczykowski 	{ "r8169", realtek_dump_regs },
1129*1b481fc3SMaciej Żenczykowski 	{ "de2104x", de2104x_dump_regs },
1130*1b481fc3SMaciej Żenczykowski 	{ "e1000", e1000_dump_regs },
1131*1b481fc3SMaciej Żenczykowski 	{ "e1000e", e1000_dump_regs },
1132*1b481fc3SMaciej Żenczykowski 	{ "igb", igb_dump_regs },
1133*1b481fc3SMaciej Żenczykowski 	{ "ixgb", ixgb_dump_regs },
1134*1b481fc3SMaciej Żenczykowski 	{ "ixgbe", ixgbe_dump_regs },
1135*1b481fc3SMaciej Żenczykowski 	{ "ixgbevf", ixgbevf_dump_regs },
1136*1b481fc3SMaciej Żenczykowski 	{ "natsemi", natsemi_dump_regs },
1137*1b481fc3SMaciej Żenczykowski 	{ "e100", e100_dump_regs },
1138*1b481fc3SMaciej Żenczykowski 	{ "amd8111e", amd8111e_dump_regs },
1139*1b481fc3SMaciej Żenczykowski 	{ "pcnet32", pcnet32_dump_regs },
1140*1b481fc3SMaciej Żenczykowski 	{ "fec_8xx", fec_8xx_dump_regs },
1141*1b481fc3SMaciej Żenczykowski 	{ "ibm_emac", ibm_emac_dump_regs },
1142*1b481fc3SMaciej Żenczykowski 	{ "tg3", tg3_dump_regs },
1143*1b481fc3SMaciej Żenczykowski 	{ "skge", skge_dump_regs },
1144*1b481fc3SMaciej Żenczykowski 	{ "sky2", sky2_dump_regs },
1145*1b481fc3SMaciej Żenczykowski 	{ "vioc", vioc_dump_regs },
1146*1b481fc3SMaciej Żenczykowski 	{ "smsc911x", smsc911x_dump_regs },
1147*1b481fc3SMaciej Żenczykowski 	{ "at76c50x-usb", at76c50x_usb_dump_regs },
1148*1b481fc3SMaciej Żenczykowski 	{ "sfc", sfc_dump_regs },
1149*1b481fc3SMaciej Żenczykowski 	{ "st_mac100", st_mac100_dump_regs },
1150*1b481fc3SMaciej Żenczykowski 	{ "st_gmac", st_gmac_dump_regs },
1151*1b481fc3SMaciej Żenczykowski 	{ "et131x", et131x_dump_regs },
1152*1b481fc3SMaciej Żenczykowski 	{ "altera_tse", altera_tse_dump_regs },
1153*1b481fc3SMaciej Żenczykowski 	{ "vmxnet3", vmxnet3_dump_regs },
1154*1b481fc3SMaciej Żenczykowski 	{ "fjes", fjes_dump_regs },
1155*1b481fc3SMaciej Żenczykowski 	{ "lan78xx", lan78xx_dump_regs },
1156*1b481fc3SMaciej Żenczykowski 	{ "dsa", dsa_dump_regs },
1157*1b481fc3SMaciej Żenczykowski 	{ "fec", fec_dump_regs },
1158*1b481fc3SMaciej Żenczykowski 	{ "igc", igc_dump_regs },
1159*1b481fc3SMaciej Żenczykowski 	{ "bnxt_en", bnxt_dump_regs },
1160*1b481fc3SMaciej Żenczykowski 	{ "cpsw-switch", cpsw_dump_regs },
1161*1b481fc3SMaciej Żenczykowski 	{ "lan743x", lan743x_dump_regs },
1162*1b481fc3SMaciej Żenczykowski 	{ "fsl_enetc", fsl_enetc_dump_regs },
1163*1b481fc3SMaciej Żenczykowski 	{ "fsl_enetc_vf", fsl_enetc_dump_regs },
1164*1b481fc3SMaciej Żenczykowski 	{ "hns3", hns3_dump_regs },
1165*1b481fc3SMaciej Żenczykowski };
1166*1b481fc3SMaciej Żenczykowski #endif
1167*1b481fc3SMaciej Żenczykowski 
dump_hex(FILE * file,const u8 * data,int len,int offset)1168*1b481fc3SMaciej Żenczykowski void dump_hex(FILE *file, const u8 *data, int len, int offset)
1169*1b481fc3SMaciej Żenczykowski {
1170*1b481fc3SMaciej Żenczykowski 	int i;
1171*1b481fc3SMaciej Żenczykowski 
1172*1b481fc3SMaciej Żenczykowski 	fprintf(file, "Offset\t\tValues\n");
1173*1b481fc3SMaciej Żenczykowski 	fprintf(file, "------\t\t------");
1174*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < len; i++) {
1175*1b481fc3SMaciej Żenczykowski 		if (i % 16 == 0)
1176*1b481fc3SMaciej Żenczykowski 			fprintf(file, "\n0x%04x:\t\t", i + offset);
1177*1b481fc3SMaciej Żenczykowski 		fprintf(file, "%02x ", data[i]);
1178*1b481fc3SMaciej Żenczykowski 	}
1179*1b481fc3SMaciej Żenczykowski 	fprintf(file, "\n");
1180*1b481fc3SMaciej Żenczykowski }
1181*1b481fc3SMaciej Żenczykowski 
dump_regs(int gregs_dump_raw,int gregs_dump_hex,struct ethtool_drvinfo * info,struct ethtool_regs * regs)1182*1b481fc3SMaciej Żenczykowski static int dump_regs(int gregs_dump_raw, int gregs_dump_hex,
1183*1b481fc3SMaciej Żenczykowski 		     struct ethtool_drvinfo *info, struct ethtool_regs *regs)
1184*1b481fc3SMaciej Żenczykowski {
1185*1b481fc3SMaciej Żenczykowski 	if (gregs_dump_raw) {
1186*1b481fc3SMaciej Żenczykowski 		fwrite(regs->data, regs->len, 1, stdout);
1187*1b481fc3SMaciej Żenczykowski 		goto nested;
1188*1b481fc3SMaciej Żenczykowski 	}
1189*1b481fc3SMaciej Żenczykowski 
1190*1b481fc3SMaciej Żenczykowski #ifdef ETHTOOL_ENABLE_PRETTY_DUMP
1191*1b481fc3SMaciej Żenczykowski 	if (!gregs_dump_hex) {
1192*1b481fc3SMaciej Żenczykowski 		unsigned int i;
1193*1b481fc3SMaciej Żenczykowski 
1194*1b481fc3SMaciej Żenczykowski 		for (i = 0; i < ARRAY_SIZE(driver_list); i++)
1195*1b481fc3SMaciej Żenczykowski 			if (!strncmp(driver_list[i].name, info->driver,
1196*1b481fc3SMaciej Żenczykowski 				     ETHTOOL_BUSINFO_LEN)) {
1197*1b481fc3SMaciej Żenczykowski 				if (driver_list[i].func(info, regs) == 0)
1198*1b481fc3SMaciej Żenczykowski 					goto nested;
1199*1b481fc3SMaciej Żenczykowski 				/* This version (or some other
1200*1b481fc3SMaciej Żenczykowski 				 * variation in the dump format) is
1201*1b481fc3SMaciej Żenczykowski 				 * not handled; fall back to hex
1202*1b481fc3SMaciej Żenczykowski 				 */
1203*1b481fc3SMaciej Żenczykowski 				break;
1204*1b481fc3SMaciej Żenczykowski 			}
1205*1b481fc3SMaciej Żenczykowski 	}
1206*1b481fc3SMaciej Żenczykowski #endif
1207*1b481fc3SMaciej Żenczykowski 
1208*1b481fc3SMaciej Żenczykowski 	dump_hex(stdout, regs->data, regs->len, 0);
1209*1b481fc3SMaciej Żenczykowski 
1210*1b481fc3SMaciej Żenczykowski nested:
1211*1b481fc3SMaciej Żenczykowski 	/* Recurse dump if some drvinfo and regs structures are nested */
1212*1b481fc3SMaciej Żenczykowski 	if (info->regdump_len > regs->len + sizeof(*info) + sizeof(*regs)) {
1213*1b481fc3SMaciej Żenczykowski 		info = (struct ethtool_drvinfo *)(&regs->data[0] + regs->len);
1214*1b481fc3SMaciej Żenczykowski 		regs = (struct ethtool_regs *)(&regs->data[0] + regs->len + sizeof(*info));
1215*1b481fc3SMaciej Żenczykowski 
1216*1b481fc3SMaciej Żenczykowski 		return dump_regs(gregs_dump_raw, gregs_dump_hex, info, regs);
1217*1b481fc3SMaciej Żenczykowski 	}
1218*1b481fc3SMaciej Żenczykowski 
1219*1b481fc3SMaciej Żenczykowski 	return 0;
1220*1b481fc3SMaciej Żenczykowski }
1221*1b481fc3SMaciej Żenczykowski 
dump_eeprom(int geeprom_dump_raw,struct ethtool_drvinfo * info __maybe_unused,struct ethtool_eeprom * ee)1222*1b481fc3SMaciej Żenczykowski static int dump_eeprom(int geeprom_dump_raw,
1223*1b481fc3SMaciej Żenczykowski 		       struct ethtool_drvinfo *info __maybe_unused,
1224*1b481fc3SMaciej Żenczykowski 		       struct ethtool_eeprom *ee)
1225*1b481fc3SMaciej Żenczykowski {
1226*1b481fc3SMaciej Żenczykowski 	if (geeprom_dump_raw) {
1227*1b481fc3SMaciej Żenczykowski 		fwrite(ee->data, 1, ee->len, stdout);
1228*1b481fc3SMaciej Żenczykowski 		return 0;
1229*1b481fc3SMaciej Żenczykowski 	}
1230*1b481fc3SMaciej Żenczykowski #ifdef ETHTOOL_ENABLE_PRETTY_DUMP
1231*1b481fc3SMaciej Żenczykowski 	if (!strncmp("natsemi", info->driver, ETHTOOL_BUSINFO_LEN)) {
1232*1b481fc3SMaciej Żenczykowski 		return natsemi_dump_eeprom(info, ee);
1233*1b481fc3SMaciej Żenczykowski 	} else if (!strncmp("tg3", info->driver, ETHTOOL_BUSINFO_LEN)) {
1234*1b481fc3SMaciej Żenczykowski 		return tg3_dump_eeprom(info, ee);
1235*1b481fc3SMaciej Żenczykowski 	}
1236*1b481fc3SMaciej Żenczykowski #endif
1237*1b481fc3SMaciej Żenczykowski 	dump_hex(stdout, ee->data, ee->len, ee->offset);
1238*1b481fc3SMaciej Żenczykowski 
1239*1b481fc3SMaciej Żenczykowski 	return 0;
1240*1b481fc3SMaciej Żenczykowski }
1241*1b481fc3SMaciej Żenczykowski 
dump_test(struct ethtool_test * test,struct ethtool_gstrings * strings)1242*1b481fc3SMaciej Żenczykowski static int dump_test(struct ethtool_test *test,
1243*1b481fc3SMaciej Żenczykowski 		     struct ethtool_gstrings *strings)
1244*1b481fc3SMaciej Żenczykowski {
1245*1b481fc3SMaciej Żenczykowski 	unsigned int i;
1246*1b481fc3SMaciej Żenczykowski 	int rc;
1247*1b481fc3SMaciej Żenczykowski 
1248*1b481fc3SMaciej Żenczykowski 	rc = test->flags & ETH_TEST_FL_FAILED;
1249*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "The test result is %s\n", rc ? "FAIL" : "PASS");
1250*1b481fc3SMaciej Żenczykowski 
1251*1b481fc3SMaciej Żenczykowski 	if (test->flags & ETH_TEST_FL_EXTERNAL_LB)
1252*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "External loopback test was %sexecuted\n",
1253*1b481fc3SMaciej Żenczykowski 			(test->flags & ETH_TEST_FL_EXTERNAL_LB_DONE) ?
1254*1b481fc3SMaciej Żenczykowski 			"" : "not ");
1255*1b481fc3SMaciej Żenczykowski 
1256*1b481fc3SMaciej Żenczykowski 	if (strings->len)
1257*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "The test extra info:\n");
1258*1b481fc3SMaciej Żenczykowski 
1259*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < strings->len; i++) {
1260*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "%s\t %d\n",
1261*1b481fc3SMaciej Żenczykowski 			(char *)(strings->data + i * ETH_GSTRING_LEN),
1262*1b481fc3SMaciej Żenczykowski 			(u32) test->data[i]);
1263*1b481fc3SMaciej Żenczykowski 	}
1264*1b481fc3SMaciej Żenczykowski 
1265*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "\n");
1266*1b481fc3SMaciej Żenczykowski 	return rc;
1267*1b481fc3SMaciej Żenczykowski }
1268*1b481fc3SMaciej Żenczykowski 
dump_pause(const struct ethtool_pauseparam * epause,u32 advertising,u32 lp_advertising)1269*1b481fc3SMaciej Żenczykowski static int dump_pause(const struct ethtool_pauseparam *epause,
1270*1b481fc3SMaciej Żenczykowski 		      u32 advertising, u32 lp_advertising)
1271*1b481fc3SMaciej Żenczykowski {
1272*1b481fc3SMaciej Żenczykowski 	fprintf(stdout,
1273*1b481fc3SMaciej Żenczykowski 		"Autonegotiate:	%s\n"
1274*1b481fc3SMaciej Żenczykowski 		"RX:		%s\n"
1275*1b481fc3SMaciej Żenczykowski 		"TX:		%s\n",
1276*1b481fc3SMaciej Żenczykowski 		epause->autoneg ? "on" : "off",
1277*1b481fc3SMaciej Żenczykowski 		epause->rx_pause ? "on" : "off",
1278*1b481fc3SMaciej Żenczykowski 		epause->tx_pause ? "on" : "off");
1279*1b481fc3SMaciej Żenczykowski 
1280*1b481fc3SMaciej Żenczykowski 	if (lp_advertising) {
1281*1b481fc3SMaciej Żenczykowski 		int an_rx = 0, an_tx = 0;
1282*1b481fc3SMaciej Żenczykowski 
1283*1b481fc3SMaciej Żenczykowski 		/* Work out negotiated pause frame usage per
1284*1b481fc3SMaciej Żenczykowski 		 * IEEE 802.3-2005 table 28B-3.
1285*1b481fc3SMaciej Żenczykowski 		 */
1286*1b481fc3SMaciej Żenczykowski 		if (advertising & lp_advertising & ADVERTISED_Pause) {
1287*1b481fc3SMaciej Żenczykowski 			an_tx = 1;
1288*1b481fc3SMaciej Żenczykowski 			an_rx = 1;
1289*1b481fc3SMaciej Żenczykowski 		} else if (advertising & lp_advertising &
1290*1b481fc3SMaciej Żenczykowski 			   ADVERTISED_Asym_Pause) {
1291*1b481fc3SMaciej Żenczykowski 			if (advertising & ADVERTISED_Pause)
1292*1b481fc3SMaciej Żenczykowski 				an_rx = 1;
1293*1b481fc3SMaciej Żenczykowski 			else if (lp_advertising & ADVERTISED_Pause)
1294*1b481fc3SMaciej Żenczykowski 				an_tx = 1;
1295*1b481fc3SMaciej Żenczykowski 		}
1296*1b481fc3SMaciej Żenczykowski 
1297*1b481fc3SMaciej Żenczykowski 		fprintf(stdout,
1298*1b481fc3SMaciej Żenczykowski 			"RX negotiated:	%s\n"
1299*1b481fc3SMaciej Żenczykowski 			"TX negotiated:	%s\n",
1300*1b481fc3SMaciej Żenczykowski 			an_rx ? "on" : "off",
1301*1b481fc3SMaciej Żenczykowski 			an_tx ? "on" : "off");
1302*1b481fc3SMaciej Żenczykowski 	}
1303*1b481fc3SMaciej Żenczykowski 
1304*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "\n");
1305*1b481fc3SMaciej Żenczykowski 	return 0;
1306*1b481fc3SMaciej Żenczykowski }
1307*1b481fc3SMaciej Żenczykowski 
dump_ring(const struct ethtool_ringparam * ering)1308*1b481fc3SMaciej Żenczykowski static int dump_ring(const struct ethtool_ringparam *ering)
1309*1b481fc3SMaciej Żenczykowski {
1310*1b481fc3SMaciej Żenczykowski 	fprintf(stdout,
1311*1b481fc3SMaciej Żenczykowski 		"Pre-set maximums:\n"
1312*1b481fc3SMaciej Żenczykowski 		"RX:		%u\n"
1313*1b481fc3SMaciej Żenczykowski 		"RX Mini:	%u\n"
1314*1b481fc3SMaciej Żenczykowski 		"RX Jumbo:	%u\n"
1315*1b481fc3SMaciej Żenczykowski 		"TX:		%u\n",
1316*1b481fc3SMaciej Żenczykowski 		ering->rx_max_pending,
1317*1b481fc3SMaciej Żenczykowski 		ering->rx_mini_max_pending,
1318*1b481fc3SMaciej Żenczykowski 		ering->rx_jumbo_max_pending,
1319*1b481fc3SMaciej Żenczykowski 		ering->tx_max_pending);
1320*1b481fc3SMaciej Żenczykowski 
1321*1b481fc3SMaciej Żenczykowski 	fprintf(stdout,
1322*1b481fc3SMaciej Żenczykowski 		"Current hardware settings:\n"
1323*1b481fc3SMaciej Żenczykowski 		"RX:		%u\n"
1324*1b481fc3SMaciej Żenczykowski 		"RX Mini:	%u\n"
1325*1b481fc3SMaciej Żenczykowski 		"RX Jumbo:	%u\n"
1326*1b481fc3SMaciej Żenczykowski 		"TX:		%u\n",
1327*1b481fc3SMaciej Żenczykowski 		ering->rx_pending,
1328*1b481fc3SMaciej Żenczykowski 		ering->rx_mini_pending,
1329*1b481fc3SMaciej Żenczykowski 		ering->rx_jumbo_pending,
1330*1b481fc3SMaciej Żenczykowski 		ering->tx_pending);
1331*1b481fc3SMaciej Żenczykowski 
1332*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "\n");
1333*1b481fc3SMaciej Żenczykowski 	return 0;
1334*1b481fc3SMaciej Żenczykowski }
1335*1b481fc3SMaciej Żenczykowski 
dump_channels(const struct ethtool_channels * echannels)1336*1b481fc3SMaciej Żenczykowski static int dump_channels(const struct ethtool_channels *echannels)
1337*1b481fc3SMaciej Żenczykowski {
1338*1b481fc3SMaciej Żenczykowski 	fprintf(stdout,
1339*1b481fc3SMaciej Żenczykowski 		"Pre-set maximums:\n"
1340*1b481fc3SMaciej Żenczykowski 		"RX:		%u\n"
1341*1b481fc3SMaciej Żenczykowski 		"TX:		%u\n"
1342*1b481fc3SMaciej Żenczykowski 		"Other:		%u\n"
1343*1b481fc3SMaciej Żenczykowski 		"Combined:	%u\n",
1344*1b481fc3SMaciej Żenczykowski 		echannels->max_rx, echannels->max_tx,
1345*1b481fc3SMaciej Żenczykowski 		echannels->max_other,
1346*1b481fc3SMaciej Żenczykowski 		echannels->max_combined);
1347*1b481fc3SMaciej Żenczykowski 
1348*1b481fc3SMaciej Żenczykowski 	fprintf(stdout,
1349*1b481fc3SMaciej Żenczykowski 		"Current hardware settings:\n"
1350*1b481fc3SMaciej Żenczykowski 		"RX:		%u\n"
1351*1b481fc3SMaciej Żenczykowski 		"TX:		%u\n"
1352*1b481fc3SMaciej Żenczykowski 		"Other:		%u\n"
1353*1b481fc3SMaciej Żenczykowski 		"Combined:	%u\n",
1354*1b481fc3SMaciej Żenczykowski 		echannels->rx_count, echannels->tx_count,
1355*1b481fc3SMaciej Żenczykowski 		echannels->other_count,
1356*1b481fc3SMaciej Żenczykowski 		echannels->combined_count);
1357*1b481fc3SMaciej Żenczykowski 
1358*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "\n");
1359*1b481fc3SMaciej Żenczykowski 	return 0;
1360*1b481fc3SMaciej Żenczykowski }
1361*1b481fc3SMaciej Żenczykowski 
dump_coalesce(const struct ethtool_coalesce * ecoal)1362*1b481fc3SMaciej Żenczykowski static int dump_coalesce(const struct ethtool_coalesce *ecoal)
1363*1b481fc3SMaciej Żenczykowski {
1364*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "Adaptive RX: %s  TX: %s\n",
1365*1b481fc3SMaciej Żenczykowski 		ecoal->use_adaptive_rx_coalesce ? "on" : "off",
1366*1b481fc3SMaciej Żenczykowski 		ecoal->use_adaptive_tx_coalesce ? "on" : "off");
1367*1b481fc3SMaciej Żenczykowski 
1368*1b481fc3SMaciej Żenczykowski 	fprintf(stdout,
1369*1b481fc3SMaciej Żenczykowski 		"stats-block-usecs: %u\n"
1370*1b481fc3SMaciej Żenczykowski 		"sample-interval: %u\n"
1371*1b481fc3SMaciej Żenczykowski 		"pkt-rate-low: %u\n"
1372*1b481fc3SMaciej Żenczykowski 		"pkt-rate-high: %u\n"
1373*1b481fc3SMaciej Żenczykowski 		"\n"
1374*1b481fc3SMaciej Żenczykowski 		"rx-usecs: %u\n"
1375*1b481fc3SMaciej Żenczykowski 		"rx-frames: %u\n"
1376*1b481fc3SMaciej Żenczykowski 		"rx-usecs-irq: %u\n"
1377*1b481fc3SMaciej Żenczykowski 		"rx-frames-irq: %u\n"
1378*1b481fc3SMaciej Żenczykowski 		"\n"
1379*1b481fc3SMaciej Żenczykowski 		"tx-usecs: %u\n"
1380*1b481fc3SMaciej Żenczykowski 		"tx-frames: %u\n"
1381*1b481fc3SMaciej Żenczykowski 		"tx-usecs-irq: %u\n"
1382*1b481fc3SMaciej Żenczykowski 		"tx-frames-irq: %u\n"
1383*1b481fc3SMaciej Żenczykowski 		"\n"
1384*1b481fc3SMaciej Żenczykowski 		"rx-usecs-low: %u\n"
1385*1b481fc3SMaciej Żenczykowski 		"rx-frames-low: %u\n"
1386*1b481fc3SMaciej Żenczykowski 		"tx-usecs-low: %u\n"
1387*1b481fc3SMaciej Żenczykowski 		"tx-frames-low: %u\n"
1388*1b481fc3SMaciej Żenczykowski 		"\n"
1389*1b481fc3SMaciej Żenczykowski 		"rx-usecs-high: %u\n"
1390*1b481fc3SMaciej Żenczykowski 		"rx-frames-high: %u\n"
1391*1b481fc3SMaciej Żenczykowski 		"tx-usecs-high: %u\n"
1392*1b481fc3SMaciej Żenczykowski 		"tx-frames-high: %u\n"
1393*1b481fc3SMaciej Żenczykowski 		"\n",
1394*1b481fc3SMaciej Żenczykowski 		ecoal->stats_block_coalesce_usecs,
1395*1b481fc3SMaciej Żenczykowski 		ecoal->rate_sample_interval,
1396*1b481fc3SMaciej Żenczykowski 		ecoal->pkt_rate_low,
1397*1b481fc3SMaciej Żenczykowski 		ecoal->pkt_rate_high,
1398*1b481fc3SMaciej Żenczykowski 
1399*1b481fc3SMaciej Żenczykowski 		ecoal->rx_coalesce_usecs,
1400*1b481fc3SMaciej Żenczykowski 		ecoal->rx_max_coalesced_frames,
1401*1b481fc3SMaciej Żenczykowski 		ecoal->rx_coalesce_usecs_irq,
1402*1b481fc3SMaciej Żenczykowski 		ecoal->rx_max_coalesced_frames_irq,
1403*1b481fc3SMaciej Żenczykowski 
1404*1b481fc3SMaciej Żenczykowski 		ecoal->tx_coalesce_usecs,
1405*1b481fc3SMaciej Żenczykowski 		ecoal->tx_max_coalesced_frames,
1406*1b481fc3SMaciej Żenczykowski 		ecoal->tx_coalesce_usecs_irq,
1407*1b481fc3SMaciej Żenczykowski 		ecoal->tx_max_coalesced_frames_irq,
1408*1b481fc3SMaciej Żenczykowski 
1409*1b481fc3SMaciej Żenczykowski 		ecoal->rx_coalesce_usecs_low,
1410*1b481fc3SMaciej Żenczykowski 		ecoal->rx_max_coalesced_frames_low,
1411*1b481fc3SMaciej Żenczykowski 		ecoal->tx_coalesce_usecs_low,
1412*1b481fc3SMaciej Żenczykowski 		ecoal->tx_max_coalesced_frames_low,
1413*1b481fc3SMaciej Żenczykowski 
1414*1b481fc3SMaciej Żenczykowski 		ecoal->rx_coalesce_usecs_high,
1415*1b481fc3SMaciej Żenczykowski 		ecoal->rx_max_coalesced_frames_high,
1416*1b481fc3SMaciej Żenczykowski 		ecoal->tx_coalesce_usecs_high,
1417*1b481fc3SMaciej Żenczykowski 		ecoal->tx_max_coalesced_frames_high);
1418*1b481fc3SMaciej Żenczykowski 
1419*1b481fc3SMaciej Żenczykowski 	return 0;
1420*1b481fc3SMaciej Żenczykowski }
1421*1b481fc3SMaciej Żenczykowski 
dump_per_queue_coalesce(struct ethtool_per_queue_op * per_queue_opt,__u32 * queue_mask,int n_queues)1422*1b481fc3SMaciej Żenczykowski void dump_per_queue_coalesce(struct ethtool_per_queue_op *per_queue_opt,
1423*1b481fc3SMaciej Żenczykowski 			     __u32 *queue_mask, int n_queues)
1424*1b481fc3SMaciej Żenczykowski {
1425*1b481fc3SMaciej Żenczykowski 	struct ethtool_coalesce *ecoal;
1426*1b481fc3SMaciej Żenczykowski 	int i, idx = 0;
1427*1b481fc3SMaciej Żenczykowski 
1428*1b481fc3SMaciej Żenczykowski 	ecoal = (struct ethtool_coalesce *)(per_queue_opt + 1);
1429*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < __KERNEL_DIV_ROUND_UP(MAX_NUM_QUEUE, 32); i++) {
1430*1b481fc3SMaciej Żenczykowski 		int queue = i * 32;
1431*1b481fc3SMaciej Żenczykowski 		__u32 mask = queue_mask[i];
1432*1b481fc3SMaciej Żenczykowski 
1433*1b481fc3SMaciej Żenczykowski 		while (mask > 0) {
1434*1b481fc3SMaciej Żenczykowski 			if (mask & 0x1) {
1435*1b481fc3SMaciej Żenczykowski 				fprintf(stdout, "Queue: %d\n", queue);
1436*1b481fc3SMaciej Żenczykowski 				dump_coalesce(ecoal + idx);
1437*1b481fc3SMaciej Żenczykowski 				idx++;
1438*1b481fc3SMaciej Żenczykowski 			}
1439*1b481fc3SMaciej Żenczykowski 			mask = mask >> 1;
1440*1b481fc3SMaciej Żenczykowski 			queue++;
1441*1b481fc3SMaciej Żenczykowski 		}
1442*1b481fc3SMaciej Żenczykowski 		if (idx == n_queues)
1443*1b481fc3SMaciej Żenczykowski 			break;
1444*1b481fc3SMaciej Żenczykowski 	}
1445*1b481fc3SMaciej Żenczykowski }
1446*1b481fc3SMaciej Żenczykowski 
1447*1b481fc3SMaciej Żenczykowski struct feature_state {
1448*1b481fc3SMaciej Żenczykowski 	u32 off_flags;
1449*1b481fc3SMaciej Żenczykowski 	struct ethtool_gfeatures features;
1450*1b481fc3SMaciej Żenczykowski };
1451*1b481fc3SMaciej Żenczykowski 
dump_one_feature(const char * indent,const char * name,const struct feature_state * state,const struct feature_state * ref_state,u32 index)1452*1b481fc3SMaciej Żenczykowski static void dump_one_feature(const char *indent, const char *name,
1453*1b481fc3SMaciej Żenczykowski 			     const struct feature_state *state,
1454*1b481fc3SMaciej Żenczykowski 			     const struct feature_state *ref_state,
1455*1b481fc3SMaciej Żenczykowski 			     u32 index)
1456*1b481fc3SMaciej Żenczykowski {
1457*1b481fc3SMaciej Żenczykowski 	if (ref_state &&
1458*1b481fc3SMaciej Żenczykowski 	    !(FEATURE_BIT_IS_SET(state->features.features, index, active) ^
1459*1b481fc3SMaciej Żenczykowski 	      FEATURE_BIT_IS_SET(ref_state->features.features, index, active)))
1460*1b481fc3SMaciej Żenczykowski 		return;
1461*1b481fc3SMaciej Żenczykowski 
1462*1b481fc3SMaciej Żenczykowski 	printf("%s%s: %s%s\n",
1463*1b481fc3SMaciej Żenczykowski 	       indent, name,
1464*1b481fc3SMaciej Żenczykowski 	       FEATURE_BIT_IS_SET(state->features.features, index, active) ?
1465*1b481fc3SMaciej Żenczykowski 	       "on" : "off",
1466*1b481fc3SMaciej Żenczykowski 	       (!FEATURE_BIT_IS_SET(state->features.features, index, available)
1467*1b481fc3SMaciej Żenczykowski 		|| FEATURE_BIT_IS_SET(state->features.features, index,
1468*1b481fc3SMaciej Żenczykowski 				      never_changed))
1469*1b481fc3SMaciej Żenczykowski 	       ? " [fixed]"
1470*1b481fc3SMaciej Żenczykowski 	       : (FEATURE_BIT_IS_SET(state->features.features, index, requested)
1471*1b481fc3SMaciej Żenczykowski 		  ^ FEATURE_BIT_IS_SET(state->features.features, index, active))
1472*1b481fc3SMaciej Żenczykowski 	       ? (FEATURE_BIT_IS_SET(state->features.features, index, requested)
1473*1b481fc3SMaciej Żenczykowski 		  ? " [requested on]" : " [requested off]")
1474*1b481fc3SMaciej Żenczykowski 	       : "");
1475*1b481fc3SMaciej Żenczykowski }
1476*1b481fc3SMaciej Żenczykowski 
linux_version_code(void)1477*1b481fc3SMaciej Żenczykowski static unsigned int linux_version_code(void)
1478*1b481fc3SMaciej Żenczykowski {
1479*1b481fc3SMaciej Żenczykowski 	struct utsname utsname;
1480*1b481fc3SMaciej Żenczykowski 	unsigned version, patchlevel, sublevel = 0;
1481*1b481fc3SMaciej Żenczykowski 
1482*1b481fc3SMaciej Żenczykowski 	if (uname(&utsname))
1483*1b481fc3SMaciej Żenczykowski 		return -1;
1484*1b481fc3SMaciej Żenczykowski 	if (sscanf(utsname.release, "%u.%u.%u", &version, &patchlevel, &sublevel) < 2)
1485*1b481fc3SMaciej Żenczykowski 		return -1;
1486*1b481fc3SMaciej Żenczykowski 	return KERNEL_VERSION(version, patchlevel, sublevel);
1487*1b481fc3SMaciej Żenczykowski }
1488*1b481fc3SMaciej Żenczykowski 
dump_features(const struct feature_defs * defs,const struct feature_state * state,const struct feature_state * ref_state)1489*1b481fc3SMaciej Żenczykowski static void dump_features(const struct feature_defs *defs,
1490*1b481fc3SMaciej Żenczykowski 			  const struct feature_state *state,
1491*1b481fc3SMaciej Żenczykowski 			  const struct feature_state *ref_state)
1492*1b481fc3SMaciej Żenczykowski {
1493*1b481fc3SMaciej Żenczykowski 	unsigned int kernel_ver = linux_version_code();
1494*1b481fc3SMaciej Żenczykowski 	unsigned int i, j;
1495*1b481fc3SMaciej Żenczykowski 	int indent;
1496*1b481fc3SMaciej Żenczykowski 	u32 value;
1497*1b481fc3SMaciej Żenczykowski 
1498*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < OFF_FLAG_DEF_SIZE; i++) {
1499*1b481fc3SMaciej Żenczykowski 		/* Don't show features whose state is unknown on this
1500*1b481fc3SMaciej Żenczykowski 		 * kernel version
1501*1b481fc3SMaciej Żenczykowski 		 */
1502*1b481fc3SMaciej Żenczykowski 		if (defs->off_flag_matched[i] == 0 &&
1503*1b481fc3SMaciej Żenczykowski 		    ((off_flag_def[i].get_cmd == 0 &&
1504*1b481fc3SMaciej Żenczykowski 		      kernel_ver < off_flag_def[i].min_kernel_ver) ||
1505*1b481fc3SMaciej Żenczykowski 		     (off_flag_def[i].get_cmd == ETHTOOL_GUFO &&
1506*1b481fc3SMaciej Żenczykowski 		      kernel_ver >= KERNEL_VERSION(4, 14, 0))))
1507*1b481fc3SMaciej Żenczykowski 			continue;
1508*1b481fc3SMaciej Żenczykowski 
1509*1b481fc3SMaciej Żenczykowski 		value = off_flag_def[i].value;
1510*1b481fc3SMaciej Żenczykowski 
1511*1b481fc3SMaciej Żenczykowski 		/* If this offload flag matches exactly one generic
1512*1b481fc3SMaciej Żenczykowski 		 * feature then it's redundant to show the flag and
1513*1b481fc3SMaciej Żenczykowski 		 * feature states separately.  Otherwise, show the
1514*1b481fc3SMaciej Żenczykowski 		 * flag state first.
1515*1b481fc3SMaciej Żenczykowski 		 */
1516*1b481fc3SMaciej Żenczykowski 		if (defs->off_flag_matched[i] != 1 &&
1517*1b481fc3SMaciej Żenczykowski 		    (!ref_state ||
1518*1b481fc3SMaciej Żenczykowski 		     (state->off_flags ^ ref_state->off_flags) & value)) {
1519*1b481fc3SMaciej Żenczykowski 			printf("%s: %s\n",
1520*1b481fc3SMaciej Żenczykowski 			       off_flag_def[i].long_name,
1521*1b481fc3SMaciej Żenczykowski 			       (state->off_flags & value) ? "on" : "off");
1522*1b481fc3SMaciej Żenczykowski 			indent = 1;
1523*1b481fc3SMaciej Żenczykowski 		} else {
1524*1b481fc3SMaciej Żenczykowski 			indent = 0;
1525*1b481fc3SMaciej Żenczykowski 		}
1526*1b481fc3SMaciej Żenczykowski 
1527*1b481fc3SMaciej Żenczykowski 		/* Show matching features */
1528*1b481fc3SMaciej Żenczykowski 		for (j = 0; j < defs->n_features; j++) {
1529*1b481fc3SMaciej Żenczykowski 			if (defs->def[j].off_flag_index != (int)i)
1530*1b481fc3SMaciej Żenczykowski 				continue;
1531*1b481fc3SMaciej Żenczykowski 			if (defs->off_flag_matched[i] != 1)
1532*1b481fc3SMaciej Żenczykowski 				/* Show all matching feature states */
1533*1b481fc3SMaciej Żenczykowski 				dump_one_feature(indent ? "\t" : "",
1534*1b481fc3SMaciej Żenczykowski 						 defs->def[j].name,
1535*1b481fc3SMaciej Żenczykowski 						 state, ref_state, j);
1536*1b481fc3SMaciej Żenczykowski 			else
1537*1b481fc3SMaciej Żenczykowski 				/* Show full state with the old flag name */
1538*1b481fc3SMaciej Żenczykowski 				dump_one_feature("", off_flag_def[i].long_name,
1539*1b481fc3SMaciej Żenczykowski 						 state, ref_state, j);
1540*1b481fc3SMaciej Żenczykowski 		}
1541*1b481fc3SMaciej Żenczykowski 	}
1542*1b481fc3SMaciej Żenczykowski 
1543*1b481fc3SMaciej Żenczykowski 	/* Show all unmatched features that have non-null names */
1544*1b481fc3SMaciej Żenczykowski 	for (j = 0; j < defs->n_features; j++)
1545*1b481fc3SMaciej Żenczykowski 		if (defs->def[j].off_flag_index < 0 && defs->def[j].name[0])
1546*1b481fc3SMaciej Żenczykowski 			dump_one_feature("", defs->def[j].name,
1547*1b481fc3SMaciej Żenczykowski 					 state, ref_state, j);
1548*1b481fc3SMaciej Żenczykowski }
1549*1b481fc3SMaciej Żenczykowski 
dump_rxfhash(int fhash,u64 val)1550*1b481fc3SMaciej Żenczykowski static int dump_rxfhash(int fhash, u64 val)
1551*1b481fc3SMaciej Żenczykowski {
1552*1b481fc3SMaciej Żenczykowski 	switch (fhash & ~FLOW_RSS) {
1553*1b481fc3SMaciej Żenczykowski 	case TCP_V4_FLOW:
1554*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "TCP over IPV4 flows");
1555*1b481fc3SMaciej Żenczykowski 		break;
1556*1b481fc3SMaciej Żenczykowski 	case UDP_V4_FLOW:
1557*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "UDP over IPV4 flows");
1558*1b481fc3SMaciej Żenczykowski 		break;
1559*1b481fc3SMaciej Żenczykowski 	case SCTP_V4_FLOW:
1560*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "SCTP over IPV4 flows");
1561*1b481fc3SMaciej Żenczykowski 		break;
1562*1b481fc3SMaciej Żenczykowski 	case AH_ESP_V4_FLOW:
1563*1b481fc3SMaciej Żenczykowski 	case AH_V4_FLOW:
1564*1b481fc3SMaciej Żenczykowski 	case ESP_V4_FLOW:
1565*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "IPSEC AH/ESP over IPV4 flows");
1566*1b481fc3SMaciej Żenczykowski 		break;
1567*1b481fc3SMaciej Żenczykowski 	case TCP_V6_FLOW:
1568*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "TCP over IPV6 flows");
1569*1b481fc3SMaciej Żenczykowski 		break;
1570*1b481fc3SMaciej Żenczykowski 	case UDP_V6_FLOW:
1571*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "UDP over IPV6 flows");
1572*1b481fc3SMaciej Żenczykowski 		break;
1573*1b481fc3SMaciej Żenczykowski 	case SCTP_V6_FLOW:
1574*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "SCTP over IPV6 flows");
1575*1b481fc3SMaciej Żenczykowski 		break;
1576*1b481fc3SMaciej Żenczykowski 	case AH_ESP_V6_FLOW:
1577*1b481fc3SMaciej Żenczykowski 	case AH_V6_FLOW:
1578*1b481fc3SMaciej Żenczykowski 	case ESP_V6_FLOW:
1579*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "IPSEC AH/ESP over IPV6 flows");
1580*1b481fc3SMaciej Żenczykowski 		break;
1581*1b481fc3SMaciej Żenczykowski 	default:
1582*1b481fc3SMaciej Żenczykowski 		break;
1583*1b481fc3SMaciej Żenczykowski 	}
1584*1b481fc3SMaciej Żenczykowski 
1585*1b481fc3SMaciej Żenczykowski 	if (val & RXH_DISCARD) {
1586*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, " - All matching flows discarded on RX\n");
1587*1b481fc3SMaciej Żenczykowski 		return 0;
1588*1b481fc3SMaciej Żenczykowski 	}
1589*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, " use these fields for computing Hash flow key:\n");
1590*1b481fc3SMaciej Żenczykowski 
1591*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "%s\n", unparse_rxfhashopts(val));
1592*1b481fc3SMaciej Żenczykowski 
1593*1b481fc3SMaciej Żenczykowski 	return 0;
1594*1b481fc3SMaciej Żenczykowski }
1595*1b481fc3SMaciej Żenczykowski 
dump_eeecmd(struct ethtool_eee * ep)1596*1b481fc3SMaciej Żenczykowski static void dump_eeecmd(struct ethtool_eee *ep)
1597*1b481fc3SMaciej Żenczykowski {
1598*1b481fc3SMaciej Żenczykowski 	ETHTOOL_DECLARE_LINK_MODE_MASK(link_mode);
1599*1b481fc3SMaciej Żenczykowski 
1600*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "	EEE status: ");
1601*1b481fc3SMaciej Żenczykowski 	if (!ep->supported) {
1602*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "not supported\n");
1603*1b481fc3SMaciej Żenczykowski 		return;
1604*1b481fc3SMaciej Żenczykowski 	} else if (!ep->eee_enabled) {
1605*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "disabled\n");
1606*1b481fc3SMaciej Żenczykowski 	} else {
1607*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "enabled - ");
1608*1b481fc3SMaciej Żenczykowski 		if (ep->eee_active)
1609*1b481fc3SMaciej Żenczykowski 			fprintf(stdout, "active\n");
1610*1b481fc3SMaciej Żenczykowski 		else
1611*1b481fc3SMaciej Żenczykowski 			fprintf(stdout, "inactive\n");
1612*1b481fc3SMaciej Żenczykowski 	}
1613*1b481fc3SMaciej Żenczykowski 
1614*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "	Tx LPI:");
1615*1b481fc3SMaciej Żenczykowski 	if (ep->tx_lpi_enabled)
1616*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, " %d (us)\n", ep->tx_lpi_timer);
1617*1b481fc3SMaciej Żenczykowski 	else
1618*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, " disabled\n");
1619*1b481fc3SMaciej Żenczykowski 
1620*1b481fc3SMaciej Żenczykowski 	ethtool_link_mode_zero(link_mode);
1621*1b481fc3SMaciej Żenczykowski 
1622*1b481fc3SMaciej Żenczykowski 	link_mode[0] = ep->supported;
1623*1b481fc3SMaciej Żenczykowski 	dump_link_caps("Supported EEE", "", link_mode, 1);
1624*1b481fc3SMaciej Żenczykowski 
1625*1b481fc3SMaciej Żenczykowski 	link_mode[0] = ep->advertised;
1626*1b481fc3SMaciej Żenczykowski 	dump_link_caps("Advertised EEE", "", link_mode, 1);
1627*1b481fc3SMaciej Żenczykowski 
1628*1b481fc3SMaciej Żenczykowski 	link_mode[0] = ep->lp_advertised;
1629*1b481fc3SMaciej Żenczykowski 	dump_link_caps("Link partner advertised EEE", "", link_mode, 1);
1630*1b481fc3SMaciej Żenczykowski }
1631*1b481fc3SMaciej Żenczykowski 
dump_fec(u32 fec)1632*1b481fc3SMaciej Żenczykowski static void dump_fec(u32 fec)
1633*1b481fc3SMaciej Żenczykowski {
1634*1b481fc3SMaciej Żenczykowski 	if (fec & ETHTOOL_FEC_NONE)
1635*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, " None");
1636*1b481fc3SMaciej Żenczykowski 	if (fec & ETHTOOL_FEC_AUTO)
1637*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, " Auto");
1638*1b481fc3SMaciej Żenczykowski 	if (fec & ETHTOOL_FEC_OFF)
1639*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, " Off");
1640*1b481fc3SMaciej Żenczykowski 	if (fec & ETHTOOL_FEC_BASER)
1641*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, " BaseR");
1642*1b481fc3SMaciej Żenczykowski 	if (fec & ETHTOOL_FEC_RS)
1643*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, " RS");
1644*1b481fc3SMaciej Żenczykowski 	if (fec & ETHTOOL_FEC_LLRS)
1645*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, " LLRS");
1646*1b481fc3SMaciej Żenczykowski }
1647*1b481fc3SMaciej Żenczykowski 
1648*1b481fc3SMaciej Żenczykowski #define N_SOTS 7
1649*1b481fc3SMaciej Żenczykowski 
1650*1b481fc3SMaciej Żenczykowski static char *so_timestamping_labels[N_SOTS] = {
1651*1b481fc3SMaciej Żenczykowski 	"hardware-transmit     (SOF_TIMESTAMPING_TX_HARDWARE)",
1652*1b481fc3SMaciej Żenczykowski 	"software-transmit     (SOF_TIMESTAMPING_TX_SOFTWARE)",
1653*1b481fc3SMaciej Żenczykowski 	"hardware-receive      (SOF_TIMESTAMPING_RX_HARDWARE)",
1654*1b481fc3SMaciej Żenczykowski 	"software-receive      (SOF_TIMESTAMPING_RX_SOFTWARE)",
1655*1b481fc3SMaciej Żenczykowski 	"software-system-clock (SOF_TIMESTAMPING_SOFTWARE)",
1656*1b481fc3SMaciej Żenczykowski 	"hardware-legacy-clock (SOF_TIMESTAMPING_SYS_HARDWARE)",
1657*1b481fc3SMaciej Żenczykowski 	"hardware-raw-clock    (SOF_TIMESTAMPING_RAW_HARDWARE)",
1658*1b481fc3SMaciej Żenczykowski };
1659*1b481fc3SMaciej Żenczykowski 
1660*1b481fc3SMaciej Żenczykowski #define N_TX_TYPES (HWTSTAMP_TX_ONESTEP_SYNC + 1)
1661*1b481fc3SMaciej Żenczykowski 
1662*1b481fc3SMaciej Żenczykowski static char *tx_type_labels[N_TX_TYPES] = {
1663*1b481fc3SMaciej Żenczykowski 	"off                   (HWTSTAMP_TX_OFF)",
1664*1b481fc3SMaciej Żenczykowski 	"on                    (HWTSTAMP_TX_ON)",
1665*1b481fc3SMaciej Żenczykowski 	"one-step-sync         (HWTSTAMP_TX_ONESTEP_SYNC)",
1666*1b481fc3SMaciej Żenczykowski };
1667*1b481fc3SMaciej Żenczykowski 
1668*1b481fc3SMaciej Żenczykowski #define N_RX_FILTERS (HWTSTAMP_FILTER_NTP_ALL + 1)
1669*1b481fc3SMaciej Żenczykowski 
1670*1b481fc3SMaciej Żenczykowski static char *rx_filter_labels[N_RX_FILTERS] = {
1671*1b481fc3SMaciej Żenczykowski 	"none                  (HWTSTAMP_FILTER_NONE)",
1672*1b481fc3SMaciej Żenczykowski 	"all                   (HWTSTAMP_FILTER_ALL)",
1673*1b481fc3SMaciej Żenczykowski 	"some                  (HWTSTAMP_FILTER_SOME)",
1674*1b481fc3SMaciej Żenczykowski 	"ptpv1-l4-event        (HWTSTAMP_FILTER_PTP_V1_L4_EVENT)",
1675*1b481fc3SMaciej Żenczykowski 	"ptpv1-l4-sync         (HWTSTAMP_FILTER_PTP_V1_L4_SYNC)",
1676*1b481fc3SMaciej Żenczykowski 	"ptpv1-l4-delay-req    (HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ)",
1677*1b481fc3SMaciej Żenczykowski 	"ptpv2-l4-event        (HWTSTAMP_FILTER_PTP_V2_L4_EVENT)",
1678*1b481fc3SMaciej Żenczykowski 	"ptpv2-l4-sync         (HWTSTAMP_FILTER_PTP_V2_L4_SYNC)",
1679*1b481fc3SMaciej Żenczykowski 	"ptpv2-l4-delay-req    (HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ)",
1680*1b481fc3SMaciej Żenczykowski 	"ptpv2-l2-event        (HWTSTAMP_FILTER_PTP_V2_L2_EVENT)",
1681*1b481fc3SMaciej Żenczykowski 	"ptpv2-l2-sync         (HWTSTAMP_FILTER_PTP_V2_L2_SYNC)",
1682*1b481fc3SMaciej Żenczykowski 	"ptpv2-l2-delay-req    (HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ)",
1683*1b481fc3SMaciej Żenczykowski 	"ptpv2-event           (HWTSTAMP_FILTER_PTP_V2_EVENT)",
1684*1b481fc3SMaciej Żenczykowski 	"ptpv2-sync            (HWTSTAMP_FILTER_PTP_V2_SYNC)",
1685*1b481fc3SMaciej Żenczykowski 	"ptpv2-delay-req       (HWTSTAMP_FILTER_PTP_V2_DELAY_REQ)",
1686*1b481fc3SMaciej Żenczykowski 	"ntp-all               (HWTSTAMP_FILTER_NTP_ALL)",
1687*1b481fc3SMaciej Żenczykowski };
1688*1b481fc3SMaciej Żenczykowski 
dump_tsinfo(const struct ethtool_ts_info * info)1689*1b481fc3SMaciej Żenczykowski static int dump_tsinfo(const struct ethtool_ts_info *info)
1690*1b481fc3SMaciej Żenczykowski {
1691*1b481fc3SMaciej Żenczykowski 	int i;
1692*1b481fc3SMaciej Żenczykowski 
1693*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "Capabilities:\n");
1694*1b481fc3SMaciej Żenczykowski 
1695*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < N_SOTS; i++) {
1696*1b481fc3SMaciej Żenczykowski 		if (info->so_timestamping & (1 << i))
1697*1b481fc3SMaciej Żenczykowski 			fprintf(stdout, "\t%s\n", so_timestamping_labels[i]);
1698*1b481fc3SMaciej Żenczykowski 	}
1699*1b481fc3SMaciej Żenczykowski 
1700*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "PTP Hardware Clock: ");
1701*1b481fc3SMaciej Żenczykowski 
1702*1b481fc3SMaciej Żenczykowski 	if (info->phc_index < 0)
1703*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "none\n");
1704*1b481fc3SMaciej Żenczykowski 	else
1705*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "%d\n", info->phc_index);
1706*1b481fc3SMaciej Żenczykowski 
1707*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "Hardware Transmit Timestamp Modes:");
1708*1b481fc3SMaciej Żenczykowski 
1709*1b481fc3SMaciej Żenczykowski 	if (!info->tx_types)
1710*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, " none\n");
1711*1b481fc3SMaciej Żenczykowski 	else
1712*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "\n");
1713*1b481fc3SMaciej Żenczykowski 
1714*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < N_TX_TYPES; i++) {
1715*1b481fc3SMaciej Żenczykowski 		if (info->tx_types & (1 << i))
1716*1b481fc3SMaciej Żenczykowski 			fprintf(stdout,	"\t%s\n", tx_type_labels[i]);
1717*1b481fc3SMaciej Żenczykowski 	}
1718*1b481fc3SMaciej Żenczykowski 
1719*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "Hardware Receive Filter Modes:");
1720*1b481fc3SMaciej Żenczykowski 
1721*1b481fc3SMaciej Żenczykowski 	if (!info->rx_filters)
1722*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, " none\n");
1723*1b481fc3SMaciej Żenczykowski 	else
1724*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "\n");
1725*1b481fc3SMaciej Żenczykowski 
1726*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < N_RX_FILTERS; i++) {
1727*1b481fc3SMaciej Żenczykowski 		if (info->rx_filters & (1 << i))
1728*1b481fc3SMaciej Żenczykowski 			fprintf(stdout, "\t%s\n", rx_filter_labels[i]);
1729*1b481fc3SMaciej Żenczykowski 	}
1730*1b481fc3SMaciej Żenczykowski 
1731*1b481fc3SMaciej Żenczykowski 	return 0;
1732*1b481fc3SMaciej Żenczykowski }
1733*1b481fc3SMaciej Żenczykowski 
1734*1b481fc3SMaciej Żenczykowski static struct ethtool_gstrings *
get_stringset(struct cmd_context * ctx,enum ethtool_stringset set_id,ptrdiff_t drvinfo_offset,int null_terminate)1735*1b481fc3SMaciej Żenczykowski get_stringset(struct cmd_context *ctx, enum ethtool_stringset set_id,
1736*1b481fc3SMaciej Żenczykowski 	      ptrdiff_t drvinfo_offset, int null_terminate)
1737*1b481fc3SMaciej Żenczykowski {
1738*1b481fc3SMaciej Żenczykowski 	struct {
1739*1b481fc3SMaciej Żenczykowski 		struct ethtool_sset_info hdr;
1740*1b481fc3SMaciej Żenczykowski 		u32 buf[1];
1741*1b481fc3SMaciej Żenczykowski 	} sset_info;
1742*1b481fc3SMaciej Żenczykowski 	struct ethtool_drvinfo drvinfo;
1743*1b481fc3SMaciej Żenczykowski 	u32 len, i;
1744*1b481fc3SMaciej Żenczykowski 	struct ethtool_gstrings *strings;
1745*1b481fc3SMaciej Żenczykowski 
1746*1b481fc3SMaciej Żenczykowski 	sset_info.hdr.cmd = ETHTOOL_GSSET_INFO;
1747*1b481fc3SMaciej Żenczykowski 	sset_info.hdr.reserved = 0;
1748*1b481fc3SMaciej Żenczykowski 	sset_info.hdr.sset_mask = 1ULL << set_id;
1749*1b481fc3SMaciej Żenczykowski 	if (send_ioctl(ctx, &sset_info) == 0) {
1750*1b481fc3SMaciej Żenczykowski 		const u32 *sset_lengths = sset_info.hdr.data;
1751*1b481fc3SMaciej Żenczykowski 
1752*1b481fc3SMaciej Żenczykowski 		len = sset_info.hdr.sset_mask ? sset_lengths[0] : 0;
1753*1b481fc3SMaciej Żenczykowski 	} else if (errno == EOPNOTSUPP && drvinfo_offset != 0) {
1754*1b481fc3SMaciej Żenczykowski 		/* Fallback for old kernel versions */
1755*1b481fc3SMaciej Żenczykowski 		drvinfo.cmd = ETHTOOL_GDRVINFO;
1756*1b481fc3SMaciej Żenczykowski 		if (send_ioctl(ctx, &drvinfo))
1757*1b481fc3SMaciej Żenczykowski 			return NULL;
1758*1b481fc3SMaciej Żenczykowski 		len = *(u32 *)((char *)&drvinfo + drvinfo_offset);
1759*1b481fc3SMaciej Żenczykowski 	} else {
1760*1b481fc3SMaciej Żenczykowski 		return NULL;
1761*1b481fc3SMaciej Żenczykowski 	}
1762*1b481fc3SMaciej Żenczykowski 
1763*1b481fc3SMaciej Żenczykowski 	strings = calloc(1, sizeof(*strings) + len * ETH_GSTRING_LEN);
1764*1b481fc3SMaciej Żenczykowski 	if (!strings)
1765*1b481fc3SMaciej Żenczykowski 		return NULL;
1766*1b481fc3SMaciej Żenczykowski 
1767*1b481fc3SMaciej Żenczykowski 	strings->cmd = ETHTOOL_GSTRINGS;
1768*1b481fc3SMaciej Żenczykowski 	strings->string_set = set_id;
1769*1b481fc3SMaciej Żenczykowski 	strings->len = len;
1770*1b481fc3SMaciej Żenczykowski 	if (len != 0 && send_ioctl(ctx, strings)) {
1771*1b481fc3SMaciej Żenczykowski 		free(strings);
1772*1b481fc3SMaciej Żenczykowski 		return NULL;
1773*1b481fc3SMaciej Żenczykowski 	}
1774*1b481fc3SMaciej Żenczykowski 
1775*1b481fc3SMaciej Żenczykowski 	if (null_terminate)
1776*1b481fc3SMaciej Żenczykowski 		for (i = 0; i < len; i++)
1777*1b481fc3SMaciej Żenczykowski 			strings->data[(i + 1) * ETH_GSTRING_LEN - 1] = 0;
1778*1b481fc3SMaciej Żenczykowski 
1779*1b481fc3SMaciej Żenczykowski 	return strings;
1780*1b481fc3SMaciej Żenczykowski }
1781*1b481fc3SMaciej Żenczykowski 
get_feature_defs(struct cmd_context * ctx)1782*1b481fc3SMaciej Żenczykowski static struct feature_defs *get_feature_defs(struct cmd_context *ctx)
1783*1b481fc3SMaciej Żenczykowski {
1784*1b481fc3SMaciej Żenczykowski 	struct ethtool_gstrings *names;
1785*1b481fc3SMaciej Żenczykowski 	struct feature_defs *defs;
1786*1b481fc3SMaciej Żenczykowski 	unsigned int i, j;
1787*1b481fc3SMaciej Żenczykowski 	u32 n_features;
1788*1b481fc3SMaciej Żenczykowski 
1789*1b481fc3SMaciej Żenczykowski 	names = get_stringset(ctx, ETH_SS_FEATURES, 0, 1);
1790*1b481fc3SMaciej Żenczykowski 	if (names) {
1791*1b481fc3SMaciej Żenczykowski 		n_features = names->len;
1792*1b481fc3SMaciej Żenczykowski 	} else if (errno == EOPNOTSUPP || errno == EINVAL) {
1793*1b481fc3SMaciej Żenczykowski 		/* Kernel doesn't support named features; not an error */
1794*1b481fc3SMaciej Żenczykowski 		n_features = 0;
1795*1b481fc3SMaciej Żenczykowski 	} else if (errno == EPERM) {
1796*1b481fc3SMaciej Żenczykowski 		/* Kernel bug: ETHTOOL_GSSET_INFO was privileged.
1797*1b481fc3SMaciej Żenczykowski 		 * Work around it. */
1798*1b481fc3SMaciej Żenczykowski 		n_features = 0;
1799*1b481fc3SMaciej Żenczykowski 	} else {
1800*1b481fc3SMaciej Żenczykowski 		return NULL;
1801*1b481fc3SMaciej Żenczykowski 	}
1802*1b481fc3SMaciej Żenczykowski 
1803*1b481fc3SMaciej Żenczykowski 	defs = malloc(sizeof(*defs) + sizeof(defs->def[0]) * n_features);
1804*1b481fc3SMaciej Żenczykowski 	if (!defs) {
1805*1b481fc3SMaciej Żenczykowski 		free(names);
1806*1b481fc3SMaciej Żenczykowski 		return NULL;
1807*1b481fc3SMaciej Żenczykowski 	}
1808*1b481fc3SMaciej Żenczykowski 
1809*1b481fc3SMaciej Żenczykowski 	defs->n_features = n_features;
1810*1b481fc3SMaciej Żenczykowski 	memset(defs->off_flag_matched, 0, sizeof(defs->off_flag_matched));
1811*1b481fc3SMaciej Żenczykowski 
1812*1b481fc3SMaciej Żenczykowski 	/* Copy out feature names and find those associated with legacy flags */
1813*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < defs->n_features; i++) {
1814*1b481fc3SMaciej Żenczykowski 		memcpy(defs->def[i].name, names->data + i * ETH_GSTRING_LEN,
1815*1b481fc3SMaciej Żenczykowski 		       ETH_GSTRING_LEN);
1816*1b481fc3SMaciej Żenczykowski 		defs->def[i].off_flag_index = -1;
1817*1b481fc3SMaciej Żenczykowski 
1818*1b481fc3SMaciej Żenczykowski 		for (j = 0;
1819*1b481fc3SMaciej Żenczykowski 		     j < OFF_FLAG_DEF_SIZE &&
1820*1b481fc3SMaciej Żenczykowski 			     defs->def[i].off_flag_index < 0;
1821*1b481fc3SMaciej Żenczykowski 		     j++) {
1822*1b481fc3SMaciej Żenczykowski 			const char *pattern =
1823*1b481fc3SMaciej Żenczykowski 				off_flag_def[j].kernel_name;
1824*1b481fc3SMaciej Żenczykowski 			const char *name = defs->def[i].name;
1825*1b481fc3SMaciej Żenczykowski 			for (;;) {
1826*1b481fc3SMaciej Żenczykowski 				if (*pattern == '*') {
1827*1b481fc3SMaciej Żenczykowski 					/* There is only one wildcard; so
1828*1b481fc3SMaciej Żenczykowski 					 * switch to a suffix comparison */
1829*1b481fc3SMaciej Żenczykowski 					size_t pattern_len =
1830*1b481fc3SMaciej Żenczykowski 						strlen(pattern + 1);
1831*1b481fc3SMaciej Żenczykowski 					size_t name_len = strlen(name);
1832*1b481fc3SMaciej Żenczykowski 					if (name_len < pattern_len)
1833*1b481fc3SMaciej Żenczykowski 						break; /* name is too short */
1834*1b481fc3SMaciej Żenczykowski 					name += name_len - pattern_len;
1835*1b481fc3SMaciej Żenczykowski 					++pattern;
1836*1b481fc3SMaciej Żenczykowski 				} else if (*pattern != *name) {
1837*1b481fc3SMaciej Żenczykowski 					break; /* mismatch */
1838*1b481fc3SMaciej Żenczykowski 				} else if (*pattern == 0) {
1839*1b481fc3SMaciej Żenczykowski 					defs->def[i].off_flag_index = j;
1840*1b481fc3SMaciej Żenczykowski 					defs->off_flag_matched[j]++;
1841*1b481fc3SMaciej Żenczykowski 					break;
1842*1b481fc3SMaciej Żenczykowski 				} else {
1843*1b481fc3SMaciej Żenczykowski 					++name;
1844*1b481fc3SMaciej Żenczykowski 					++pattern;
1845*1b481fc3SMaciej Żenczykowski 				}
1846*1b481fc3SMaciej Żenczykowski 			}
1847*1b481fc3SMaciej Żenczykowski 		}
1848*1b481fc3SMaciej Żenczykowski 	}
1849*1b481fc3SMaciej Żenczykowski 
1850*1b481fc3SMaciej Żenczykowski 	free(names);
1851*1b481fc3SMaciej Żenczykowski 	return defs;
1852*1b481fc3SMaciej Żenczykowski }
1853*1b481fc3SMaciej Żenczykowski 
do_gdrv(struct cmd_context * ctx)1854*1b481fc3SMaciej Żenczykowski static int do_gdrv(struct cmd_context *ctx)
1855*1b481fc3SMaciej Żenczykowski {
1856*1b481fc3SMaciej Żenczykowski 	int err;
1857*1b481fc3SMaciej Żenczykowski 	struct ethtool_drvinfo drvinfo;
1858*1b481fc3SMaciej Żenczykowski 
1859*1b481fc3SMaciej Żenczykowski 	if (ctx->argc != 0)
1860*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
1861*1b481fc3SMaciej Żenczykowski 
1862*1b481fc3SMaciej Żenczykowski 	drvinfo.cmd = ETHTOOL_GDRVINFO;
1863*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &drvinfo);
1864*1b481fc3SMaciej Żenczykowski 	if (err < 0) {
1865*1b481fc3SMaciej Żenczykowski 		perror("Cannot get driver information");
1866*1b481fc3SMaciej Żenczykowski 		return 71;
1867*1b481fc3SMaciej Żenczykowski 	}
1868*1b481fc3SMaciej Żenczykowski 	return dump_drvinfo(&drvinfo);
1869*1b481fc3SMaciej Żenczykowski }
1870*1b481fc3SMaciej Żenczykowski 
do_gpause(struct cmd_context * ctx)1871*1b481fc3SMaciej Żenczykowski static int do_gpause(struct cmd_context *ctx)
1872*1b481fc3SMaciej Żenczykowski {
1873*1b481fc3SMaciej Żenczykowski 	struct ethtool_pauseparam epause;
1874*1b481fc3SMaciej Żenczykowski 	struct ethtool_cmd ecmd;
1875*1b481fc3SMaciej Żenczykowski 	int err;
1876*1b481fc3SMaciej Żenczykowski 
1877*1b481fc3SMaciej Żenczykowski 	if (ctx->argc != 0)
1878*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
1879*1b481fc3SMaciej Żenczykowski 
1880*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "Pause parameters for %s:\n", ctx->devname);
1881*1b481fc3SMaciej Żenczykowski 
1882*1b481fc3SMaciej Żenczykowski 	epause.cmd = ETHTOOL_GPAUSEPARAM;
1883*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &epause);
1884*1b481fc3SMaciej Żenczykowski 	if (err) {
1885*1b481fc3SMaciej Żenczykowski 		perror("Cannot get device pause settings");
1886*1b481fc3SMaciej Żenczykowski 		return 76;
1887*1b481fc3SMaciej Żenczykowski 	}
1888*1b481fc3SMaciej Żenczykowski 
1889*1b481fc3SMaciej Żenczykowski 	if (epause.autoneg) {
1890*1b481fc3SMaciej Żenczykowski 		ecmd.cmd = ETHTOOL_GSET;
1891*1b481fc3SMaciej Żenczykowski 		err = send_ioctl(ctx, &ecmd);
1892*1b481fc3SMaciej Żenczykowski 		if (err) {
1893*1b481fc3SMaciej Żenczykowski 			perror("Cannot get device settings");
1894*1b481fc3SMaciej Żenczykowski 			return 1;
1895*1b481fc3SMaciej Żenczykowski 		}
1896*1b481fc3SMaciej Żenczykowski 		dump_pause(&epause, ecmd.advertising, ecmd.lp_advertising);
1897*1b481fc3SMaciej Żenczykowski 	} else {
1898*1b481fc3SMaciej Żenczykowski 		dump_pause(&epause, 0, 0);
1899*1b481fc3SMaciej Żenczykowski 	}
1900*1b481fc3SMaciej Żenczykowski 
1901*1b481fc3SMaciej Żenczykowski 	return 0;
1902*1b481fc3SMaciej Żenczykowski }
1903*1b481fc3SMaciej Żenczykowski 
do_generic_set1(struct cmdline_info * info,int * changed_out)1904*1b481fc3SMaciej Żenczykowski static void do_generic_set1(struct cmdline_info *info, int *changed_out)
1905*1b481fc3SMaciej Żenczykowski {
1906*1b481fc3SMaciej Żenczykowski 	int wanted, *v1, *v2;
1907*1b481fc3SMaciej Żenczykowski 
1908*1b481fc3SMaciej Żenczykowski 	v1 = info->wanted_val;
1909*1b481fc3SMaciej Żenczykowski 	wanted = *v1;
1910*1b481fc3SMaciej Żenczykowski 
1911*1b481fc3SMaciej Żenczykowski 	if (wanted < 0)
1912*1b481fc3SMaciej Żenczykowski 		return;
1913*1b481fc3SMaciej Żenczykowski 
1914*1b481fc3SMaciej Żenczykowski 	v2 = info->ioctl_val;
1915*1b481fc3SMaciej Żenczykowski 	if (wanted == *v2) {
1916*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "%s unmodified, ignoring\n", info->name);
1917*1b481fc3SMaciej Żenczykowski 	} else {
1918*1b481fc3SMaciej Żenczykowski 		*v2 = wanted;
1919*1b481fc3SMaciej Żenczykowski 		*changed_out = 1;
1920*1b481fc3SMaciej Żenczykowski 	}
1921*1b481fc3SMaciej Żenczykowski }
1922*1b481fc3SMaciej Żenczykowski 
do_generic_set(struct cmdline_info * info,unsigned int n_info,int * changed_out)1923*1b481fc3SMaciej Żenczykowski static void do_generic_set(struct cmdline_info *info,
1924*1b481fc3SMaciej Żenczykowski 			   unsigned int n_info,
1925*1b481fc3SMaciej Żenczykowski 			   int *changed_out)
1926*1b481fc3SMaciej Żenczykowski {
1927*1b481fc3SMaciej Żenczykowski 	unsigned int i;
1928*1b481fc3SMaciej Żenczykowski 
1929*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < n_info; i++)
1930*1b481fc3SMaciej Żenczykowski 		do_generic_set1(&info[i], changed_out);
1931*1b481fc3SMaciej Żenczykowski }
1932*1b481fc3SMaciej Żenczykowski 
do_spause(struct cmd_context * ctx)1933*1b481fc3SMaciej Żenczykowski static int do_spause(struct cmd_context *ctx)
1934*1b481fc3SMaciej Żenczykowski {
1935*1b481fc3SMaciej Żenczykowski 	struct ethtool_pauseparam epause;
1936*1b481fc3SMaciej Żenczykowski 	int gpause_changed = 0;
1937*1b481fc3SMaciej Żenczykowski 	int pause_autoneg_wanted = -1;
1938*1b481fc3SMaciej Żenczykowski 	int pause_rx_wanted = -1;
1939*1b481fc3SMaciej Żenczykowski 	int pause_tx_wanted = -1;
1940*1b481fc3SMaciej Żenczykowski 	struct cmdline_info cmdline_pause[] = {
1941*1b481fc3SMaciej Żenczykowski 		{
1942*1b481fc3SMaciej Żenczykowski 			.name		= "autoneg",
1943*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_BOOL,
1944*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &pause_autoneg_wanted,
1945*1b481fc3SMaciej Żenczykowski 			.ioctl_val	= &epause.autoneg,
1946*1b481fc3SMaciej Żenczykowski 		},
1947*1b481fc3SMaciej Żenczykowski 		{
1948*1b481fc3SMaciej Żenczykowski 			.name		= "rx",
1949*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_BOOL,
1950*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &pause_rx_wanted,
1951*1b481fc3SMaciej Żenczykowski 			.ioctl_val	= &epause.rx_pause,
1952*1b481fc3SMaciej Żenczykowski 		},
1953*1b481fc3SMaciej Żenczykowski 		{
1954*1b481fc3SMaciej Żenczykowski 			.name		= "tx",
1955*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_BOOL,
1956*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &pause_tx_wanted,
1957*1b481fc3SMaciej Żenczykowski 			.ioctl_val	= &epause.tx_pause,
1958*1b481fc3SMaciej Żenczykowski 		},
1959*1b481fc3SMaciej Żenczykowski 	};
1960*1b481fc3SMaciej Żenczykowski 	int err, changed = 0;
1961*1b481fc3SMaciej Żenczykowski 
1962*1b481fc3SMaciej Żenczykowski 	parse_generic_cmdline(ctx, &gpause_changed,
1963*1b481fc3SMaciej Żenczykowski 			      cmdline_pause, ARRAY_SIZE(cmdline_pause));
1964*1b481fc3SMaciej Żenczykowski 
1965*1b481fc3SMaciej Żenczykowski 	epause.cmd = ETHTOOL_GPAUSEPARAM;
1966*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &epause);
1967*1b481fc3SMaciej Żenczykowski 	if (err) {
1968*1b481fc3SMaciej Żenczykowski 		perror("Cannot get device pause settings");
1969*1b481fc3SMaciej Żenczykowski 		return 77;
1970*1b481fc3SMaciej Żenczykowski 	}
1971*1b481fc3SMaciej Żenczykowski 
1972*1b481fc3SMaciej Żenczykowski 	do_generic_set(cmdline_pause, ARRAY_SIZE(cmdline_pause), &changed);
1973*1b481fc3SMaciej Żenczykowski 
1974*1b481fc3SMaciej Żenczykowski 	if (!changed) {
1975*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "no pause parameters changed, aborting\n");
1976*1b481fc3SMaciej Żenczykowski 		return 78;
1977*1b481fc3SMaciej Żenczykowski 	}
1978*1b481fc3SMaciej Żenczykowski 
1979*1b481fc3SMaciej Żenczykowski 	epause.cmd = ETHTOOL_SPAUSEPARAM;
1980*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &epause);
1981*1b481fc3SMaciej Żenczykowski 	if (err) {
1982*1b481fc3SMaciej Żenczykowski 		perror("Cannot set device pause parameters");
1983*1b481fc3SMaciej Żenczykowski 		return 79;
1984*1b481fc3SMaciej Żenczykowski 	}
1985*1b481fc3SMaciej Żenczykowski 
1986*1b481fc3SMaciej Żenczykowski 	return 0;
1987*1b481fc3SMaciej Żenczykowski }
1988*1b481fc3SMaciej Żenczykowski 
do_sring(struct cmd_context * ctx)1989*1b481fc3SMaciej Żenczykowski static int do_sring(struct cmd_context *ctx)
1990*1b481fc3SMaciej Żenczykowski {
1991*1b481fc3SMaciej Żenczykowski 	struct ethtool_ringparam ering;
1992*1b481fc3SMaciej Żenczykowski 	int gring_changed = 0;
1993*1b481fc3SMaciej Żenczykowski 	s32 ring_rx_wanted = -1;
1994*1b481fc3SMaciej Żenczykowski 	s32 ring_rx_mini_wanted = -1;
1995*1b481fc3SMaciej Żenczykowski 	s32 ring_rx_jumbo_wanted = -1;
1996*1b481fc3SMaciej Żenczykowski 	s32 ring_tx_wanted = -1;
1997*1b481fc3SMaciej Żenczykowski 	struct cmdline_info cmdline_ring[] = {
1998*1b481fc3SMaciej Żenczykowski 		{
1999*1b481fc3SMaciej Żenczykowski 			.name		= "rx",
2000*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_S32,
2001*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &ring_rx_wanted,
2002*1b481fc3SMaciej Żenczykowski 			.ioctl_val	= &ering.rx_pending,
2003*1b481fc3SMaciej Żenczykowski 		},
2004*1b481fc3SMaciej Żenczykowski 		{
2005*1b481fc3SMaciej Żenczykowski 			.name		= "rx-mini",
2006*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_S32,
2007*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &ring_rx_mini_wanted,
2008*1b481fc3SMaciej Żenczykowski 			.ioctl_val	= &ering.rx_mini_pending,
2009*1b481fc3SMaciej Żenczykowski 		},
2010*1b481fc3SMaciej Żenczykowski 		{
2011*1b481fc3SMaciej Żenczykowski 			.name		= "rx-jumbo",
2012*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_S32,
2013*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &ring_rx_jumbo_wanted,
2014*1b481fc3SMaciej Żenczykowski 			.ioctl_val	= &ering.rx_jumbo_pending,
2015*1b481fc3SMaciej Żenczykowski 		},
2016*1b481fc3SMaciej Żenczykowski 		{
2017*1b481fc3SMaciej Żenczykowski 			.name		= "tx",
2018*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_S32,
2019*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &ring_tx_wanted,
2020*1b481fc3SMaciej Żenczykowski 			.ioctl_val	= &ering.tx_pending,
2021*1b481fc3SMaciej Żenczykowski 		},
2022*1b481fc3SMaciej Żenczykowski 	};
2023*1b481fc3SMaciej Żenczykowski 	int err, changed = 0;
2024*1b481fc3SMaciej Żenczykowski 
2025*1b481fc3SMaciej Żenczykowski 	parse_generic_cmdline(ctx, &gring_changed,
2026*1b481fc3SMaciej Żenczykowski 			      cmdline_ring, ARRAY_SIZE(cmdline_ring));
2027*1b481fc3SMaciej Żenczykowski 
2028*1b481fc3SMaciej Żenczykowski 	ering.cmd = ETHTOOL_GRINGPARAM;
2029*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &ering);
2030*1b481fc3SMaciej Żenczykowski 	if (err) {
2031*1b481fc3SMaciej Żenczykowski 		perror("Cannot get device ring settings");
2032*1b481fc3SMaciej Żenczykowski 		return 76;
2033*1b481fc3SMaciej Żenczykowski 	}
2034*1b481fc3SMaciej Żenczykowski 
2035*1b481fc3SMaciej Żenczykowski 	do_generic_set(cmdline_ring, ARRAY_SIZE(cmdline_ring), &changed);
2036*1b481fc3SMaciej Żenczykowski 
2037*1b481fc3SMaciej Żenczykowski 	if (!changed) {
2038*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "no ring parameters changed, aborting\n");
2039*1b481fc3SMaciej Żenczykowski 		return 80;
2040*1b481fc3SMaciej Żenczykowski 	}
2041*1b481fc3SMaciej Żenczykowski 
2042*1b481fc3SMaciej Żenczykowski 	ering.cmd = ETHTOOL_SRINGPARAM;
2043*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &ering);
2044*1b481fc3SMaciej Żenczykowski 	if (err) {
2045*1b481fc3SMaciej Żenczykowski 		perror("Cannot set device ring parameters");
2046*1b481fc3SMaciej Żenczykowski 		return 81;
2047*1b481fc3SMaciej Żenczykowski 	}
2048*1b481fc3SMaciej Żenczykowski 
2049*1b481fc3SMaciej Żenczykowski 	return 0;
2050*1b481fc3SMaciej Żenczykowski }
2051*1b481fc3SMaciej Żenczykowski 
do_gring(struct cmd_context * ctx)2052*1b481fc3SMaciej Żenczykowski static int do_gring(struct cmd_context *ctx)
2053*1b481fc3SMaciej Żenczykowski {
2054*1b481fc3SMaciej Żenczykowski 	struct ethtool_ringparam ering;
2055*1b481fc3SMaciej Żenczykowski 	int err;
2056*1b481fc3SMaciej Żenczykowski 
2057*1b481fc3SMaciej Żenczykowski 	if (ctx->argc != 0)
2058*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
2059*1b481fc3SMaciej Żenczykowski 
2060*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "Ring parameters for %s:\n", ctx->devname);
2061*1b481fc3SMaciej Żenczykowski 
2062*1b481fc3SMaciej Żenczykowski 	ering.cmd = ETHTOOL_GRINGPARAM;
2063*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &ering);
2064*1b481fc3SMaciej Żenczykowski 	if (err == 0) {
2065*1b481fc3SMaciej Żenczykowski 		err = dump_ring(&ering);
2066*1b481fc3SMaciej Żenczykowski 		if (err)
2067*1b481fc3SMaciej Żenczykowski 			return err;
2068*1b481fc3SMaciej Żenczykowski 	} else {
2069*1b481fc3SMaciej Żenczykowski 		perror("Cannot get device ring settings");
2070*1b481fc3SMaciej Żenczykowski 		return 76;
2071*1b481fc3SMaciej Żenczykowski 	}
2072*1b481fc3SMaciej Żenczykowski 
2073*1b481fc3SMaciej Żenczykowski 	return 0;
2074*1b481fc3SMaciej Żenczykowski }
2075*1b481fc3SMaciej Żenczykowski 
do_schannels(struct cmd_context * ctx)2076*1b481fc3SMaciej Żenczykowski static int do_schannels(struct cmd_context *ctx)
2077*1b481fc3SMaciej Żenczykowski {
2078*1b481fc3SMaciej Żenczykowski 	struct ethtool_channels echannels;
2079*1b481fc3SMaciej Żenczykowski 	int gchannels_changed;
2080*1b481fc3SMaciej Żenczykowski 	s32 channels_rx_wanted = -1;
2081*1b481fc3SMaciej Żenczykowski 	s32 channels_tx_wanted = -1;
2082*1b481fc3SMaciej Żenczykowski 	s32 channels_other_wanted = -1;
2083*1b481fc3SMaciej Żenczykowski 	s32 channels_combined_wanted = -1;
2084*1b481fc3SMaciej Żenczykowski 	struct cmdline_info cmdline_channels[] = {
2085*1b481fc3SMaciej Żenczykowski 		{
2086*1b481fc3SMaciej Żenczykowski 			.name		= "rx",
2087*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_S32,
2088*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &channels_rx_wanted,
2089*1b481fc3SMaciej Żenczykowski 			.ioctl_val	= &echannels.rx_count,
2090*1b481fc3SMaciej Żenczykowski 		},
2091*1b481fc3SMaciej Żenczykowski 		{
2092*1b481fc3SMaciej Żenczykowski 			.name		= "tx",
2093*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_S32,
2094*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &channels_tx_wanted,
2095*1b481fc3SMaciej Żenczykowski 			.ioctl_val	= &echannels.tx_count,
2096*1b481fc3SMaciej Żenczykowski 		},
2097*1b481fc3SMaciej Żenczykowski 		{
2098*1b481fc3SMaciej Żenczykowski 			.name		= "other",
2099*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_S32,
2100*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &channels_other_wanted,
2101*1b481fc3SMaciej Żenczykowski 			.ioctl_val	= &echannels.other_count,
2102*1b481fc3SMaciej Żenczykowski 		},
2103*1b481fc3SMaciej Żenczykowski 		{
2104*1b481fc3SMaciej Żenczykowski 			.name		= "combined",
2105*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_S32,
2106*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &channels_combined_wanted,
2107*1b481fc3SMaciej Żenczykowski 			.ioctl_val	= &echannels.combined_count,
2108*1b481fc3SMaciej Żenczykowski 		},
2109*1b481fc3SMaciej Żenczykowski 	};
2110*1b481fc3SMaciej Żenczykowski 	int err, changed = 0;
2111*1b481fc3SMaciej Żenczykowski 
2112*1b481fc3SMaciej Żenczykowski 	parse_generic_cmdline(ctx, &gchannels_changed,
2113*1b481fc3SMaciej Żenczykowski 			      cmdline_channels, ARRAY_SIZE(cmdline_channels));
2114*1b481fc3SMaciej Żenczykowski 
2115*1b481fc3SMaciej Żenczykowski 	echannels.cmd = ETHTOOL_GCHANNELS;
2116*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &echannels);
2117*1b481fc3SMaciej Żenczykowski 	if (err) {
2118*1b481fc3SMaciej Żenczykowski 		perror("Cannot get device channel parameters");
2119*1b481fc3SMaciej Żenczykowski 		return 1;
2120*1b481fc3SMaciej Żenczykowski 	}
2121*1b481fc3SMaciej Żenczykowski 
2122*1b481fc3SMaciej Żenczykowski 	do_generic_set(cmdline_channels, ARRAY_SIZE(cmdline_channels),
2123*1b481fc3SMaciej Żenczykowski 			&changed);
2124*1b481fc3SMaciej Żenczykowski 
2125*1b481fc3SMaciej Żenczykowski 	if (!changed) {
2126*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "no channel parameters changed.\n");
2127*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "current values: rx %u tx %u other %u"
2128*1b481fc3SMaciej Żenczykowski 			" combined %u\n", echannels.rx_count,
2129*1b481fc3SMaciej Żenczykowski 			echannels.tx_count, echannels.other_count,
2130*1b481fc3SMaciej Żenczykowski 			echannels.combined_count);
2131*1b481fc3SMaciej Żenczykowski 		return 0;
2132*1b481fc3SMaciej Żenczykowski 	}
2133*1b481fc3SMaciej Żenczykowski 
2134*1b481fc3SMaciej Żenczykowski 	echannels.cmd = ETHTOOL_SCHANNELS;
2135*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &echannels);
2136*1b481fc3SMaciej Żenczykowski 	if (err) {
2137*1b481fc3SMaciej Żenczykowski 		perror("Cannot set device channel parameters");
2138*1b481fc3SMaciej Żenczykowski 		return 1;
2139*1b481fc3SMaciej Żenczykowski 	}
2140*1b481fc3SMaciej Żenczykowski 
2141*1b481fc3SMaciej Żenczykowski 	return 0;
2142*1b481fc3SMaciej Żenczykowski }
2143*1b481fc3SMaciej Żenczykowski 
do_gchannels(struct cmd_context * ctx)2144*1b481fc3SMaciej Żenczykowski static int do_gchannels(struct cmd_context *ctx)
2145*1b481fc3SMaciej Żenczykowski {
2146*1b481fc3SMaciej Żenczykowski 	struct ethtool_channels echannels;
2147*1b481fc3SMaciej Żenczykowski 	int err;
2148*1b481fc3SMaciej Żenczykowski 
2149*1b481fc3SMaciej Żenczykowski 	if (ctx->argc != 0)
2150*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
2151*1b481fc3SMaciej Żenczykowski 
2152*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "Channel parameters for %s:\n", ctx->devname);
2153*1b481fc3SMaciej Żenczykowski 
2154*1b481fc3SMaciej Żenczykowski 	echannels.cmd = ETHTOOL_GCHANNELS;
2155*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &echannels);
2156*1b481fc3SMaciej Żenczykowski 	if (err == 0) {
2157*1b481fc3SMaciej Żenczykowski 		err = dump_channels(&echannels);
2158*1b481fc3SMaciej Żenczykowski 		if (err)
2159*1b481fc3SMaciej Żenczykowski 			return err;
2160*1b481fc3SMaciej Żenczykowski 	} else {
2161*1b481fc3SMaciej Żenczykowski 		perror("Cannot get device channel parameters");
2162*1b481fc3SMaciej Żenczykowski 		return 1;
2163*1b481fc3SMaciej Żenczykowski 	}
2164*1b481fc3SMaciej Żenczykowski 	return 0;
2165*1b481fc3SMaciej Żenczykowski 
2166*1b481fc3SMaciej Żenczykowski }
2167*1b481fc3SMaciej Żenczykowski 
do_gcoalesce(struct cmd_context * ctx)2168*1b481fc3SMaciej Żenczykowski static int do_gcoalesce(struct cmd_context *ctx)
2169*1b481fc3SMaciej Żenczykowski {
2170*1b481fc3SMaciej Żenczykowski 	struct ethtool_coalesce ecoal = {};
2171*1b481fc3SMaciej Żenczykowski 	int err;
2172*1b481fc3SMaciej Żenczykowski 
2173*1b481fc3SMaciej Żenczykowski 	if (ctx->argc != 0)
2174*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
2175*1b481fc3SMaciej Żenczykowski 
2176*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "Coalesce parameters for %s:\n", ctx->devname);
2177*1b481fc3SMaciej Żenczykowski 
2178*1b481fc3SMaciej Żenczykowski 	ecoal.cmd = ETHTOOL_GCOALESCE;
2179*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &ecoal);
2180*1b481fc3SMaciej Żenczykowski 	if (err == 0) {
2181*1b481fc3SMaciej Żenczykowski 		err = dump_coalesce(&ecoal);
2182*1b481fc3SMaciej Żenczykowski 		if (err)
2183*1b481fc3SMaciej Żenczykowski 			return err;
2184*1b481fc3SMaciej Żenczykowski 	} else {
2185*1b481fc3SMaciej Żenczykowski 		perror("Cannot get device coalesce settings");
2186*1b481fc3SMaciej Żenczykowski 		return 82;
2187*1b481fc3SMaciej Żenczykowski 	}
2188*1b481fc3SMaciej Żenczykowski 
2189*1b481fc3SMaciej Żenczykowski 	return 0;
2190*1b481fc3SMaciej Żenczykowski }
2191*1b481fc3SMaciej Żenczykowski 
2192*1b481fc3SMaciej Żenczykowski #define DECLARE_COALESCE_OPTION_VARS()		\
2193*1b481fc3SMaciej Żenczykowski 	s32 coal_stats_wanted = -1;		\
2194*1b481fc3SMaciej Żenczykowski 	int coal_adaptive_rx_wanted = -1;	\
2195*1b481fc3SMaciej Żenczykowski 	int coal_adaptive_tx_wanted = -1;	\
2196*1b481fc3SMaciej Żenczykowski 	s32 coal_sample_rate_wanted = -1;	\
2197*1b481fc3SMaciej Żenczykowski 	s32 coal_pkt_rate_low_wanted = -1;	\
2198*1b481fc3SMaciej Żenczykowski 	s32 coal_pkt_rate_high_wanted = -1;	\
2199*1b481fc3SMaciej Żenczykowski 	s32 coal_rx_usec_wanted = -1;		\
2200*1b481fc3SMaciej Żenczykowski 	s32 coal_rx_frames_wanted = -1;		\
2201*1b481fc3SMaciej Żenczykowski 	s32 coal_rx_usec_irq_wanted = -1;	\
2202*1b481fc3SMaciej Żenczykowski 	s32 coal_rx_frames_irq_wanted = -1;	\
2203*1b481fc3SMaciej Żenczykowski 	s32 coal_tx_usec_wanted = -1;		\
2204*1b481fc3SMaciej Żenczykowski 	s32 coal_tx_frames_wanted = -1;		\
2205*1b481fc3SMaciej Żenczykowski 	s32 coal_tx_usec_irq_wanted = -1;	\
2206*1b481fc3SMaciej Żenczykowski 	s32 coal_tx_frames_irq_wanted = -1;	\
2207*1b481fc3SMaciej Żenczykowski 	s32 coal_rx_usec_low_wanted = -1;	\
2208*1b481fc3SMaciej Żenczykowski 	s32 coal_rx_frames_low_wanted = -1;	\
2209*1b481fc3SMaciej Żenczykowski 	s32 coal_tx_usec_low_wanted = -1;	\
2210*1b481fc3SMaciej Żenczykowski 	s32 coal_tx_frames_low_wanted = -1;	\
2211*1b481fc3SMaciej Żenczykowski 	s32 coal_rx_usec_high_wanted = -1;	\
2212*1b481fc3SMaciej Żenczykowski 	s32 coal_rx_frames_high_wanted = -1;	\
2213*1b481fc3SMaciej Żenczykowski 	s32 coal_tx_usec_high_wanted = -1;	\
2214*1b481fc3SMaciej Żenczykowski 	s32 coal_tx_frames_high_wanted = -1
2215*1b481fc3SMaciej Żenczykowski 
2216*1b481fc3SMaciej Żenczykowski #define COALESCE_CMDLINE_INFO(__ecoal)					\
2217*1b481fc3SMaciej Żenczykowski {									\
2218*1b481fc3SMaciej Żenczykowski 	{								\
2219*1b481fc3SMaciej Żenczykowski 		.name		= "adaptive-rx",			\
2220*1b481fc3SMaciej Żenczykowski 		.type		= CMDL_BOOL,				\
2221*1b481fc3SMaciej Żenczykowski 		.wanted_val	= &coal_adaptive_rx_wanted,		\
2222*1b481fc3SMaciej Żenczykowski 		.ioctl_val	= &__ecoal.use_adaptive_rx_coalesce,	\
2223*1b481fc3SMaciej Żenczykowski 	},								\
2224*1b481fc3SMaciej Żenczykowski 	{								\
2225*1b481fc3SMaciej Żenczykowski 		.name		= "adaptive-tx",			\
2226*1b481fc3SMaciej Żenczykowski 		.type		= CMDL_BOOL,				\
2227*1b481fc3SMaciej Żenczykowski 		.wanted_val	= &coal_adaptive_tx_wanted,		\
2228*1b481fc3SMaciej Żenczykowski 		.ioctl_val	= &__ecoal.use_adaptive_tx_coalesce,	\
2229*1b481fc3SMaciej Żenczykowski 	},								\
2230*1b481fc3SMaciej Żenczykowski 	{								\
2231*1b481fc3SMaciej Żenczykowski 		.name		= "sample-interval",			\
2232*1b481fc3SMaciej Żenczykowski 		.type		= CMDL_S32,				\
2233*1b481fc3SMaciej Żenczykowski 		.wanted_val	= &coal_sample_rate_wanted,		\
2234*1b481fc3SMaciej Żenczykowski 		.ioctl_val	= &__ecoal.rate_sample_interval,	\
2235*1b481fc3SMaciej Żenczykowski 	},								\
2236*1b481fc3SMaciej Żenczykowski 	{								\
2237*1b481fc3SMaciej Żenczykowski 		.name		= "stats-block-usecs",			\
2238*1b481fc3SMaciej Żenczykowski 		.type		= CMDL_S32,				\
2239*1b481fc3SMaciej Żenczykowski 		.wanted_val	= &coal_stats_wanted,			\
2240*1b481fc3SMaciej Żenczykowski 		.ioctl_val	= &__ecoal.stats_block_coalesce_usecs,	\
2241*1b481fc3SMaciej Żenczykowski 	},								\
2242*1b481fc3SMaciej Żenczykowski 	{								\
2243*1b481fc3SMaciej Żenczykowski 		.name		= "pkt-rate-low",			\
2244*1b481fc3SMaciej Żenczykowski 		.type		= CMDL_S32,				\
2245*1b481fc3SMaciej Żenczykowski 		.wanted_val	= &coal_pkt_rate_low_wanted,		\
2246*1b481fc3SMaciej Żenczykowski 		.ioctl_val	= &__ecoal.pkt_rate_low,		\
2247*1b481fc3SMaciej Żenczykowski 	},								\
2248*1b481fc3SMaciej Żenczykowski 	{								\
2249*1b481fc3SMaciej Żenczykowski 		.name		= "pkt-rate-high",			\
2250*1b481fc3SMaciej Żenczykowski 		.type		= CMDL_S32,				\
2251*1b481fc3SMaciej Żenczykowski 		.wanted_val	= &coal_pkt_rate_high_wanted,		\
2252*1b481fc3SMaciej Żenczykowski 		.ioctl_val	= &__ecoal.pkt_rate_high,		\
2253*1b481fc3SMaciej Żenczykowski 	},								\
2254*1b481fc3SMaciej Żenczykowski 	{								\
2255*1b481fc3SMaciej Żenczykowski 		.name		= "rx-usecs",				\
2256*1b481fc3SMaciej Żenczykowski 		.type		= CMDL_S32,				\
2257*1b481fc3SMaciej Żenczykowski 		.wanted_val	= &coal_rx_usec_wanted,			\
2258*1b481fc3SMaciej Żenczykowski 		.ioctl_val	= &__ecoal.rx_coalesce_usecs,		\
2259*1b481fc3SMaciej Żenczykowski 	},								\
2260*1b481fc3SMaciej Żenczykowski 	{								\
2261*1b481fc3SMaciej Żenczykowski 		.name		= "rx-frames",				\
2262*1b481fc3SMaciej Żenczykowski 		.type		= CMDL_S32,				\
2263*1b481fc3SMaciej Żenczykowski 		.wanted_val	= &coal_rx_frames_wanted,		\
2264*1b481fc3SMaciej Żenczykowski 		.ioctl_val	= &__ecoal.rx_max_coalesced_frames,	\
2265*1b481fc3SMaciej Żenczykowski 	},								\
2266*1b481fc3SMaciej Żenczykowski 	{								\
2267*1b481fc3SMaciej Żenczykowski 		.name		= "rx-usecs-irq",			\
2268*1b481fc3SMaciej Żenczykowski 		.type		= CMDL_S32,				\
2269*1b481fc3SMaciej Żenczykowski 		.wanted_val	= &coal_rx_usec_irq_wanted,		\
2270*1b481fc3SMaciej Żenczykowski 		.ioctl_val	= &__ecoal.rx_coalesce_usecs_irq,	\
2271*1b481fc3SMaciej Żenczykowski 	},								\
2272*1b481fc3SMaciej Żenczykowski 	{								\
2273*1b481fc3SMaciej Żenczykowski 		.name		= "rx-frames-irq",			\
2274*1b481fc3SMaciej Żenczykowski 		.type		= CMDL_S32,				\
2275*1b481fc3SMaciej Żenczykowski 		.wanted_val	= &coal_rx_frames_irq_wanted,		\
2276*1b481fc3SMaciej Żenczykowski 		.ioctl_val	= &__ecoal.rx_max_coalesced_frames_irq,	\
2277*1b481fc3SMaciej Żenczykowski 	},								\
2278*1b481fc3SMaciej Żenczykowski 	{								\
2279*1b481fc3SMaciej Żenczykowski 		.name		= "tx-usecs",				\
2280*1b481fc3SMaciej Żenczykowski 		.type		= CMDL_S32,				\
2281*1b481fc3SMaciej Żenczykowski 		.wanted_val	= &coal_tx_usec_wanted,			\
2282*1b481fc3SMaciej Żenczykowski 		.ioctl_val	= &__ecoal.tx_coalesce_usecs,		\
2283*1b481fc3SMaciej Żenczykowski 	},								\
2284*1b481fc3SMaciej Żenczykowski 	{								\
2285*1b481fc3SMaciej Żenczykowski 		.name		= "tx-frames",				\
2286*1b481fc3SMaciej Żenczykowski 		.type		= CMDL_S32,				\
2287*1b481fc3SMaciej Żenczykowski 		.wanted_val	= &coal_tx_frames_wanted,		\
2288*1b481fc3SMaciej Żenczykowski 		.ioctl_val	= &__ecoal.tx_max_coalesced_frames,	\
2289*1b481fc3SMaciej Żenczykowski 	},								\
2290*1b481fc3SMaciej Żenczykowski 	{								\
2291*1b481fc3SMaciej Żenczykowski 		.name		= "tx-usecs-irq",			\
2292*1b481fc3SMaciej Żenczykowski 		.type		= CMDL_S32,				\
2293*1b481fc3SMaciej Żenczykowski 		.wanted_val	= &coal_tx_usec_irq_wanted,		\
2294*1b481fc3SMaciej Żenczykowski 		.ioctl_val	= &__ecoal.tx_coalesce_usecs_irq,	\
2295*1b481fc3SMaciej Żenczykowski 	},								\
2296*1b481fc3SMaciej Żenczykowski 	{								\
2297*1b481fc3SMaciej Żenczykowski 		.name		= "tx-frames-irq",			\
2298*1b481fc3SMaciej Żenczykowski 		.type		= CMDL_S32,				\
2299*1b481fc3SMaciej Żenczykowski 		.wanted_val	= &coal_tx_frames_irq_wanted,		\
2300*1b481fc3SMaciej Żenczykowski 		.ioctl_val	= &__ecoal.tx_max_coalesced_frames_irq,	\
2301*1b481fc3SMaciej Żenczykowski 	},								\
2302*1b481fc3SMaciej Żenczykowski 	{								\
2303*1b481fc3SMaciej Żenczykowski 		.name		= "rx-usecs-low",			\
2304*1b481fc3SMaciej Żenczykowski 		.type		= CMDL_S32,				\
2305*1b481fc3SMaciej Żenczykowski 		.wanted_val	= &coal_rx_usec_low_wanted,		\
2306*1b481fc3SMaciej Żenczykowski 		.ioctl_val	= &__ecoal.rx_coalesce_usecs_low,	\
2307*1b481fc3SMaciej Żenczykowski 	},								\
2308*1b481fc3SMaciej Żenczykowski 	{								\
2309*1b481fc3SMaciej Żenczykowski 		.name		= "rx-frames-low",			\
2310*1b481fc3SMaciej Żenczykowski 		.type		= CMDL_S32,				\
2311*1b481fc3SMaciej Żenczykowski 		.wanted_val	= &coal_rx_frames_low_wanted,		\
2312*1b481fc3SMaciej Żenczykowski 		.ioctl_val	= &__ecoal.rx_max_coalesced_frames_low,	\
2313*1b481fc3SMaciej Żenczykowski 	},								\
2314*1b481fc3SMaciej Żenczykowski 	{								\
2315*1b481fc3SMaciej Żenczykowski 		.name		= "tx-usecs-low",			\
2316*1b481fc3SMaciej Żenczykowski 		.type		= CMDL_S32,				\
2317*1b481fc3SMaciej Żenczykowski 		.wanted_val	= &coal_tx_usec_low_wanted,		\
2318*1b481fc3SMaciej Żenczykowski 		.ioctl_val	= &__ecoal.tx_coalesce_usecs_low,	\
2319*1b481fc3SMaciej Żenczykowski 	},								\
2320*1b481fc3SMaciej Żenczykowski 	{								\
2321*1b481fc3SMaciej Żenczykowski 		.name		= "tx-frames-low",			\
2322*1b481fc3SMaciej Żenczykowski 		.type		= CMDL_S32,				\
2323*1b481fc3SMaciej Żenczykowski 		.wanted_val	= &coal_tx_frames_low_wanted,		\
2324*1b481fc3SMaciej Żenczykowski 		.ioctl_val	= &__ecoal.tx_max_coalesced_frames_low,	\
2325*1b481fc3SMaciej Żenczykowski 	},								\
2326*1b481fc3SMaciej Żenczykowski 	{								\
2327*1b481fc3SMaciej Żenczykowski 		.name		= "rx-usecs-high",			\
2328*1b481fc3SMaciej Żenczykowski 		.type		= CMDL_S32,				\
2329*1b481fc3SMaciej Żenczykowski 		.wanted_val	= &coal_rx_usec_high_wanted,		\
2330*1b481fc3SMaciej Żenczykowski 		.ioctl_val	= &__ecoal.rx_coalesce_usecs_high,	\
2331*1b481fc3SMaciej Żenczykowski 	},								\
2332*1b481fc3SMaciej Żenczykowski 	{								\
2333*1b481fc3SMaciej Żenczykowski 		.name		= "rx-frames-high",			\
2334*1b481fc3SMaciej Żenczykowski 		.type		= CMDL_S32,				\
2335*1b481fc3SMaciej Żenczykowski 		.wanted_val	= &coal_rx_frames_high_wanted,		\
2336*1b481fc3SMaciej Żenczykowski 		.ioctl_val	= &__ecoal.rx_max_coalesced_frames_high,\
2337*1b481fc3SMaciej Żenczykowski 	},								\
2338*1b481fc3SMaciej Żenczykowski 	{								\
2339*1b481fc3SMaciej Żenczykowski 		.name		= "tx-usecs-high",			\
2340*1b481fc3SMaciej Żenczykowski 		.type		= CMDL_S32,				\
2341*1b481fc3SMaciej Żenczykowski 		.wanted_val	= &coal_tx_usec_high_wanted,		\
2342*1b481fc3SMaciej Żenczykowski 		.ioctl_val	= &__ecoal.tx_coalesce_usecs_high,	\
2343*1b481fc3SMaciej Żenczykowski 	},								\
2344*1b481fc3SMaciej Żenczykowski 	{								\
2345*1b481fc3SMaciej Żenczykowski 		.name		= "tx-frames-high",			\
2346*1b481fc3SMaciej Żenczykowski 		.type		= CMDL_S32,				\
2347*1b481fc3SMaciej Żenczykowski 		.wanted_val	= &coal_tx_frames_high_wanted,		\
2348*1b481fc3SMaciej Żenczykowski 		.ioctl_val	= &__ecoal.tx_max_coalesced_frames_high,\
2349*1b481fc3SMaciej Żenczykowski 	},								\
2350*1b481fc3SMaciej Żenczykowski }
2351*1b481fc3SMaciej Żenczykowski 
do_scoalesce(struct cmd_context * ctx)2352*1b481fc3SMaciej Żenczykowski static int do_scoalesce(struct cmd_context *ctx)
2353*1b481fc3SMaciej Żenczykowski {
2354*1b481fc3SMaciej Żenczykowski 	struct ethtool_coalesce ecoal;
2355*1b481fc3SMaciej Żenczykowski 	int gcoalesce_changed = 0;
2356*1b481fc3SMaciej Żenczykowski 	DECLARE_COALESCE_OPTION_VARS();
2357*1b481fc3SMaciej Żenczykowski 	struct cmdline_info cmdline_coalesce[] = COALESCE_CMDLINE_INFO(ecoal);
2358*1b481fc3SMaciej Żenczykowski 	int err, changed = 0;
2359*1b481fc3SMaciej Żenczykowski 
2360*1b481fc3SMaciej Żenczykowski 	parse_generic_cmdline(ctx, &gcoalesce_changed,
2361*1b481fc3SMaciej Żenczykowski 			      cmdline_coalesce, ARRAY_SIZE(cmdline_coalesce));
2362*1b481fc3SMaciej Żenczykowski 
2363*1b481fc3SMaciej Żenczykowski 	ecoal.cmd = ETHTOOL_GCOALESCE;
2364*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &ecoal);
2365*1b481fc3SMaciej Żenczykowski 	if (err) {
2366*1b481fc3SMaciej Żenczykowski 		perror("Cannot get device coalesce settings");
2367*1b481fc3SMaciej Żenczykowski 		return 76;
2368*1b481fc3SMaciej Żenczykowski 	}
2369*1b481fc3SMaciej Żenczykowski 
2370*1b481fc3SMaciej Żenczykowski 	do_generic_set(cmdline_coalesce, ARRAY_SIZE(cmdline_coalesce),
2371*1b481fc3SMaciej Żenczykowski 		       &changed);
2372*1b481fc3SMaciej Żenczykowski 
2373*1b481fc3SMaciej Żenczykowski 	if (!changed) {
2374*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "no coalesce parameters changed, aborting\n");
2375*1b481fc3SMaciej Żenczykowski 		return 80;
2376*1b481fc3SMaciej Żenczykowski 	}
2377*1b481fc3SMaciej Żenczykowski 
2378*1b481fc3SMaciej Żenczykowski 	ecoal.cmd = ETHTOOL_SCOALESCE;
2379*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &ecoal);
2380*1b481fc3SMaciej Żenczykowski 	if (err) {
2381*1b481fc3SMaciej Żenczykowski 		perror("Cannot set device coalesce parameters");
2382*1b481fc3SMaciej Żenczykowski 		return 81;
2383*1b481fc3SMaciej Żenczykowski 	}
2384*1b481fc3SMaciej Żenczykowski 
2385*1b481fc3SMaciej Żenczykowski 	return 0;
2386*1b481fc3SMaciej Żenczykowski }
2387*1b481fc3SMaciej Żenczykowski 
2388*1b481fc3SMaciej Żenczykowski static struct feature_state *
get_features(struct cmd_context * ctx,const struct feature_defs * defs)2389*1b481fc3SMaciej Żenczykowski get_features(struct cmd_context *ctx, const struct feature_defs *defs)
2390*1b481fc3SMaciej Żenczykowski {
2391*1b481fc3SMaciej Żenczykowski 	struct feature_state *state;
2392*1b481fc3SMaciej Żenczykowski 	struct ethtool_value eval;
2393*1b481fc3SMaciej Żenczykowski 	int err, allfail = 1;
2394*1b481fc3SMaciej Żenczykowski 	u32 value;
2395*1b481fc3SMaciej Żenczykowski 	int i;
2396*1b481fc3SMaciej Żenczykowski 
2397*1b481fc3SMaciej Żenczykowski 	state = malloc(sizeof(*state) +
2398*1b481fc3SMaciej Żenczykowski 		       FEATURE_BITS_TO_BLOCKS(defs->n_features) *
2399*1b481fc3SMaciej Żenczykowski 		       sizeof(state->features.features[0]));
2400*1b481fc3SMaciej Żenczykowski 	if (!state)
2401*1b481fc3SMaciej Żenczykowski 		return NULL;
2402*1b481fc3SMaciej Żenczykowski 
2403*1b481fc3SMaciej Żenczykowski 	state->off_flags = 0;
2404*1b481fc3SMaciej Żenczykowski 
2405*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < OFF_FLAG_DEF_SIZE; i++) {
2406*1b481fc3SMaciej Żenczykowski 		value = off_flag_def[i].value;
2407*1b481fc3SMaciej Żenczykowski 		if (!off_flag_def[i].get_cmd)
2408*1b481fc3SMaciej Żenczykowski 			continue;
2409*1b481fc3SMaciej Żenczykowski 		eval.cmd = off_flag_def[i].get_cmd;
2410*1b481fc3SMaciej Żenczykowski 		err = send_ioctl(ctx, &eval);
2411*1b481fc3SMaciej Żenczykowski 		if (err) {
2412*1b481fc3SMaciej Żenczykowski 			if (errno == EOPNOTSUPP &&
2413*1b481fc3SMaciej Żenczykowski 			    off_flag_def[i].get_cmd == ETHTOOL_GUFO)
2414*1b481fc3SMaciej Żenczykowski 				continue;
2415*1b481fc3SMaciej Żenczykowski 
2416*1b481fc3SMaciej Żenczykowski 			fprintf(stderr,
2417*1b481fc3SMaciej Żenczykowski 				"Cannot get device %s settings: %m\n",
2418*1b481fc3SMaciej Żenczykowski 				off_flag_def[i].long_name);
2419*1b481fc3SMaciej Żenczykowski 		} else {
2420*1b481fc3SMaciej Żenczykowski 			if (eval.data)
2421*1b481fc3SMaciej Żenczykowski 				state->off_flags |= value;
2422*1b481fc3SMaciej Żenczykowski 			allfail = 0;
2423*1b481fc3SMaciej Żenczykowski 		}
2424*1b481fc3SMaciej Żenczykowski 	}
2425*1b481fc3SMaciej Żenczykowski 
2426*1b481fc3SMaciej Żenczykowski 	eval.cmd = ETHTOOL_GFLAGS;
2427*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &eval);
2428*1b481fc3SMaciej Żenczykowski 	if (err) {
2429*1b481fc3SMaciej Żenczykowski 		perror("Cannot get device flags");
2430*1b481fc3SMaciej Żenczykowski 	} else {
2431*1b481fc3SMaciej Żenczykowski 		state->off_flags |= eval.data & ETH_FLAG_EXT_MASK;
2432*1b481fc3SMaciej Żenczykowski 		allfail = 0;
2433*1b481fc3SMaciej Żenczykowski 	}
2434*1b481fc3SMaciej Żenczykowski 
2435*1b481fc3SMaciej Żenczykowski 	if (defs->n_features) {
2436*1b481fc3SMaciej Żenczykowski 		state->features.cmd = ETHTOOL_GFEATURES;
2437*1b481fc3SMaciej Żenczykowski 		state->features.size = FEATURE_BITS_TO_BLOCKS(defs->n_features);
2438*1b481fc3SMaciej Żenczykowski 		err = send_ioctl(ctx, &state->features);
2439*1b481fc3SMaciej Żenczykowski 		if (err)
2440*1b481fc3SMaciej Żenczykowski 			perror("Cannot get device generic features");
2441*1b481fc3SMaciej Żenczykowski 		else
2442*1b481fc3SMaciej Żenczykowski 			allfail = 0;
2443*1b481fc3SMaciej Żenczykowski 	}
2444*1b481fc3SMaciej Żenczykowski 
2445*1b481fc3SMaciej Żenczykowski 	if (allfail) {
2446*1b481fc3SMaciej Żenczykowski 		free(state);
2447*1b481fc3SMaciej Żenczykowski 		return NULL;
2448*1b481fc3SMaciej Żenczykowski 	}
2449*1b481fc3SMaciej Żenczykowski 
2450*1b481fc3SMaciej Żenczykowski 	return state;
2451*1b481fc3SMaciej Żenczykowski }
2452*1b481fc3SMaciej Żenczykowski 
do_gfeatures(struct cmd_context * ctx)2453*1b481fc3SMaciej Żenczykowski static int do_gfeatures(struct cmd_context *ctx)
2454*1b481fc3SMaciej Żenczykowski {
2455*1b481fc3SMaciej Żenczykowski 	struct feature_defs *defs;
2456*1b481fc3SMaciej Żenczykowski 	struct feature_state *features;
2457*1b481fc3SMaciej Żenczykowski 
2458*1b481fc3SMaciej Żenczykowski 	if (ctx->argc != 0)
2459*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
2460*1b481fc3SMaciej Żenczykowski 
2461*1b481fc3SMaciej Żenczykowski 	defs = get_feature_defs(ctx);
2462*1b481fc3SMaciej Żenczykowski 	if (!defs) {
2463*1b481fc3SMaciej Żenczykowski 		perror("Cannot get device feature names");
2464*1b481fc3SMaciej Żenczykowski 		return 1;
2465*1b481fc3SMaciej Żenczykowski 	}
2466*1b481fc3SMaciej Żenczykowski 
2467*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "Features for %s:\n", ctx->devname);
2468*1b481fc3SMaciej Żenczykowski 
2469*1b481fc3SMaciej Żenczykowski 	features = get_features(ctx, defs);
2470*1b481fc3SMaciej Żenczykowski 	if (!features) {
2471*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "no feature info available\n");
2472*1b481fc3SMaciej Żenczykowski 		free(defs);
2473*1b481fc3SMaciej Żenczykowski 		return 1;
2474*1b481fc3SMaciej Żenczykowski 	}
2475*1b481fc3SMaciej Żenczykowski 
2476*1b481fc3SMaciej Żenczykowski 	dump_features(defs, features, NULL);
2477*1b481fc3SMaciej Żenczykowski 	free(features);
2478*1b481fc3SMaciej Żenczykowski 	free(defs);
2479*1b481fc3SMaciej Żenczykowski 	return 0;
2480*1b481fc3SMaciej Żenczykowski }
2481*1b481fc3SMaciej Żenczykowski 
do_sfeatures(struct cmd_context * ctx)2482*1b481fc3SMaciej Żenczykowski static int do_sfeatures(struct cmd_context *ctx)
2483*1b481fc3SMaciej Żenczykowski {
2484*1b481fc3SMaciej Żenczykowski 	struct feature_defs *defs;
2485*1b481fc3SMaciej Żenczykowski 	int any_changed = 0, any_mismatch = 0;
2486*1b481fc3SMaciej Żenczykowski 	u32 off_flags_wanted = 0;
2487*1b481fc3SMaciej Żenczykowski 	u32 off_flags_mask = 0;
2488*1b481fc3SMaciej Żenczykowski 	struct ethtool_sfeatures *efeatures = NULL;
2489*1b481fc3SMaciej Żenczykowski 	struct feature_state *old_state = NULL;
2490*1b481fc3SMaciej Żenczykowski 	struct feature_state *new_state = NULL;
2491*1b481fc3SMaciej Żenczykowski 	struct cmdline_info *cmdline_features;
2492*1b481fc3SMaciej Żenczykowski 	struct ethtool_value eval;
2493*1b481fc3SMaciej Żenczykowski 	unsigned int i, j;
2494*1b481fc3SMaciej Żenczykowski 	int err, rc;
2495*1b481fc3SMaciej Żenczykowski 
2496*1b481fc3SMaciej Żenczykowski 	defs = get_feature_defs(ctx);
2497*1b481fc3SMaciej Żenczykowski 	if (!defs) {
2498*1b481fc3SMaciej Żenczykowski 		perror("Cannot get device feature names");
2499*1b481fc3SMaciej Żenczykowski 		return 1;
2500*1b481fc3SMaciej Żenczykowski 	}
2501*1b481fc3SMaciej Żenczykowski 	if (defs->n_features) {
2502*1b481fc3SMaciej Żenczykowski 		efeatures = malloc(sizeof(*efeatures) +
2503*1b481fc3SMaciej Żenczykowski 				   FEATURE_BITS_TO_BLOCKS(defs->n_features) *
2504*1b481fc3SMaciej Żenczykowski 				   sizeof(efeatures->features[0]));
2505*1b481fc3SMaciej Żenczykowski 		if (!efeatures) {
2506*1b481fc3SMaciej Żenczykowski 			perror("Cannot parse arguments");
2507*1b481fc3SMaciej Żenczykowski 			rc = 1;
2508*1b481fc3SMaciej Żenczykowski 			goto err;
2509*1b481fc3SMaciej Żenczykowski 		}
2510*1b481fc3SMaciej Żenczykowski 		efeatures->cmd = ETHTOOL_SFEATURES;
2511*1b481fc3SMaciej Żenczykowski 		efeatures->size = FEATURE_BITS_TO_BLOCKS(defs->n_features);
2512*1b481fc3SMaciej Żenczykowski 		memset(efeatures->features, 0,
2513*1b481fc3SMaciej Żenczykowski 		       FEATURE_BITS_TO_BLOCKS(defs->n_features) *
2514*1b481fc3SMaciej Żenczykowski 		       sizeof(efeatures->features[0]));
2515*1b481fc3SMaciej Żenczykowski 	}
2516*1b481fc3SMaciej Żenczykowski 
2517*1b481fc3SMaciej Żenczykowski 	/* Generate cmdline_info for legacy flags and kernel-named
2518*1b481fc3SMaciej Żenczykowski 	 * features, and parse our arguments.
2519*1b481fc3SMaciej Żenczykowski 	 */
2520*1b481fc3SMaciej Żenczykowski 	cmdline_features = calloc(2 * OFF_FLAG_DEF_SIZE + defs->n_features,
2521*1b481fc3SMaciej Żenczykowski 				  sizeof(cmdline_features[0]));
2522*1b481fc3SMaciej Żenczykowski 	if (!cmdline_features) {
2523*1b481fc3SMaciej Żenczykowski 		perror("Cannot parse arguments");
2524*1b481fc3SMaciej Żenczykowski 		rc = 1;
2525*1b481fc3SMaciej Żenczykowski 		goto err;
2526*1b481fc3SMaciej Żenczykowski 	}
2527*1b481fc3SMaciej Żenczykowski 	j = 0;
2528*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < OFF_FLAG_DEF_SIZE; i++) {
2529*1b481fc3SMaciej Żenczykowski 		flag_to_cmdline_info(off_flag_def[i].short_name,
2530*1b481fc3SMaciej Żenczykowski 				     off_flag_def[i].value,
2531*1b481fc3SMaciej Żenczykowski 				     &off_flags_wanted, &off_flags_mask,
2532*1b481fc3SMaciej Żenczykowski 				     &cmdline_features[j++]);
2533*1b481fc3SMaciej Żenczykowski 		flag_to_cmdline_info(off_flag_def[i].long_name,
2534*1b481fc3SMaciej Żenczykowski 				     off_flag_def[i].value,
2535*1b481fc3SMaciej Żenczykowski 				     &off_flags_wanted, &off_flags_mask,
2536*1b481fc3SMaciej Żenczykowski 				     &cmdline_features[j++]);
2537*1b481fc3SMaciej Żenczykowski 	}
2538*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < defs->n_features; i++)
2539*1b481fc3SMaciej Żenczykowski 		flag_to_cmdline_info(
2540*1b481fc3SMaciej Żenczykowski 			defs->def[i].name, FEATURE_FIELD_FLAG(i),
2541*1b481fc3SMaciej Żenczykowski 			&FEATURE_WORD(efeatures->features, i, requested),
2542*1b481fc3SMaciej Żenczykowski 			&FEATURE_WORD(efeatures->features, i, valid),
2543*1b481fc3SMaciej Żenczykowski 			&cmdline_features[j++]);
2544*1b481fc3SMaciej Żenczykowski 	parse_generic_cmdline(ctx, &any_changed, cmdline_features,
2545*1b481fc3SMaciej Żenczykowski 			      2 * OFF_FLAG_DEF_SIZE + defs->n_features);
2546*1b481fc3SMaciej Żenczykowski 	free(cmdline_features);
2547*1b481fc3SMaciej Żenczykowski 
2548*1b481fc3SMaciej Żenczykowski 	if (!any_changed) {
2549*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "no features changed\n");
2550*1b481fc3SMaciej Żenczykowski 		rc = 0;
2551*1b481fc3SMaciej Żenczykowski 		goto err;
2552*1b481fc3SMaciej Żenczykowski 	}
2553*1b481fc3SMaciej Żenczykowski 
2554*1b481fc3SMaciej Żenczykowski 	old_state = get_features(ctx, defs);
2555*1b481fc3SMaciej Żenczykowski 	if (!old_state) {
2556*1b481fc3SMaciej Żenczykowski 		rc = 1;
2557*1b481fc3SMaciej Żenczykowski 		goto err;
2558*1b481fc3SMaciej Żenczykowski 	}
2559*1b481fc3SMaciej Żenczykowski 
2560*1b481fc3SMaciej Żenczykowski 	if (efeatures) {
2561*1b481fc3SMaciej Żenczykowski 		/* For each offload that the user specified, update any
2562*1b481fc3SMaciej Żenczykowski 		 * related features that the user did not specify and that
2563*1b481fc3SMaciej Żenczykowski 		 * are not fixed.  Warn if all related features are fixed.
2564*1b481fc3SMaciej Żenczykowski 		 */
2565*1b481fc3SMaciej Żenczykowski 		for (i = 0; i < OFF_FLAG_DEF_SIZE; i++) {
2566*1b481fc3SMaciej Żenczykowski 			int fixed = 1;
2567*1b481fc3SMaciej Żenczykowski 
2568*1b481fc3SMaciej Żenczykowski 			if (!(off_flags_mask & off_flag_def[i].value))
2569*1b481fc3SMaciej Żenczykowski 				continue;
2570*1b481fc3SMaciej Żenczykowski 
2571*1b481fc3SMaciej Żenczykowski 			for (j = 0; j < defs->n_features; j++) {
2572*1b481fc3SMaciej Żenczykowski 				if (defs->def[j].off_flag_index != (int)i ||
2573*1b481fc3SMaciej Żenczykowski 				    !FEATURE_BIT_IS_SET(
2574*1b481fc3SMaciej Żenczykowski 					    old_state->features.features,
2575*1b481fc3SMaciej Żenczykowski 					    j, available) ||
2576*1b481fc3SMaciej Żenczykowski 				    FEATURE_BIT_IS_SET(
2577*1b481fc3SMaciej Żenczykowski 					    old_state->features.features,
2578*1b481fc3SMaciej Żenczykowski 					    j, never_changed))
2579*1b481fc3SMaciej Żenczykowski 					continue;
2580*1b481fc3SMaciej Żenczykowski 
2581*1b481fc3SMaciej Żenczykowski 				fixed = 0;
2582*1b481fc3SMaciej Żenczykowski 				if (!FEATURE_BIT_IS_SET(efeatures->features,
2583*1b481fc3SMaciej Żenczykowski 							j, valid)) {
2584*1b481fc3SMaciej Żenczykowski 					FEATURE_BIT_SET(efeatures->features,
2585*1b481fc3SMaciej Żenczykowski 							j, valid);
2586*1b481fc3SMaciej Żenczykowski 					if (off_flags_wanted &
2587*1b481fc3SMaciej Żenczykowski 					    off_flag_def[i].value)
2588*1b481fc3SMaciej Żenczykowski 						FEATURE_BIT_SET(
2589*1b481fc3SMaciej Żenczykowski 							efeatures->features,
2590*1b481fc3SMaciej Żenczykowski 							j, requested);
2591*1b481fc3SMaciej Żenczykowski 				}
2592*1b481fc3SMaciej Żenczykowski 			}
2593*1b481fc3SMaciej Żenczykowski 
2594*1b481fc3SMaciej Żenczykowski 			if (fixed)
2595*1b481fc3SMaciej Żenczykowski 				fprintf(stderr, "Cannot change %s\n",
2596*1b481fc3SMaciej Żenczykowski 					off_flag_def[i].long_name);
2597*1b481fc3SMaciej Żenczykowski 		}
2598*1b481fc3SMaciej Żenczykowski 
2599*1b481fc3SMaciej Żenczykowski 		err = send_ioctl(ctx, efeatures);
2600*1b481fc3SMaciej Żenczykowski 		if (err < 0) {
2601*1b481fc3SMaciej Żenczykowski 			perror("Cannot set device feature settings");
2602*1b481fc3SMaciej Żenczykowski 			rc = 1;
2603*1b481fc3SMaciej Żenczykowski 			goto err;
2604*1b481fc3SMaciej Żenczykowski 		}
2605*1b481fc3SMaciej Żenczykowski 	} else {
2606*1b481fc3SMaciej Żenczykowski 		for (i = 0; i < OFF_FLAG_DEF_SIZE; i++) {
2607*1b481fc3SMaciej Żenczykowski 			if (!off_flag_def[i].set_cmd)
2608*1b481fc3SMaciej Żenczykowski 				continue;
2609*1b481fc3SMaciej Żenczykowski 			if (off_flags_mask & off_flag_def[i].value) {
2610*1b481fc3SMaciej Żenczykowski 				eval.cmd = off_flag_def[i].set_cmd;
2611*1b481fc3SMaciej Żenczykowski 				eval.data = !!(off_flags_wanted &
2612*1b481fc3SMaciej Żenczykowski 					       off_flag_def[i].value);
2613*1b481fc3SMaciej Żenczykowski 				err = send_ioctl(ctx, &eval);
2614*1b481fc3SMaciej Żenczykowski 				if (err) {
2615*1b481fc3SMaciej Żenczykowski 					fprintf(stderr,
2616*1b481fc3SMaciej Żenczykowski 						"Cannot set device %s settings: %m\n",
2617*1b481fc3SMaciej Żenczykowski 						off_flag_def[i].long_name);
2618*1b481fc3SMaciej Żenczykowski 					rc = 1;
2619*1b481fc3SMaciej Żenczykowski 					goto err;
2620*1b481fc3SMaciej Żenczykowski 				}
2621*1b481fc3SMaciej Żenczykowski 			}
2622*1b481fc3SMaciej Żenczykowski 		}
2623*1b481fc3SMaciej Żenczykowski 
2624*1b481fc3SMaciej Żenczykowski 		if (off_flags_mask & ETH_FLAG_EXT_MASK) {
2625*1b481fc3SMaciej Żenczykowski 			eval.cmd = ETHTOOL_SFLAGS;
2626*1b481fc3SMaciej Żenczykowski 			eval.data = (old_state->off_flags & ~off_flags_mask &
2627*1b481fc3SMaciej Żenczykowski 				     ETH_FLAG_EXT_MASK);
2628*1b481fc3SMaciej Żenczykowski 			eval.data |= off_flags_wanted & ETH_FLAG_EXT_MASK;
2629*1b481fc3SMaciej Żenczykowski 
2630*1b481fc3SMaciej Żenczykowski 			err = send_ioctl(ctx, &eval);
2631*1b481fc3SMaciej Żenczykowski 			if (err) {
2632*1b481fc3SMaciej Żenczykowski 				perror("Cannot set device flag settings");
2633*1b481fc3SMaciej Żenczykowski 				rc = 92;
2634*1b481fc3SMaciej Żenczykowski 				goto err;
2635*1b481fc3SMaciej Żenczykowski 			}
2636*1b481fc3SMaciej Żenczykowski 		}
2637*1b481fc3SMaciej Żenczykowski 	}
2638*1b481fc3SMaciej Żenczykowski 
2639*1b481fc3SMaciej Żenczykowski 	/* Compare new state with requested state */
2640*1b481fc3SMaciej Żenczykowski 	new_state = get_features(ctx, defs);
2641*1b481fc3SMaciej Żenczykowski 	if (!new_state) {
2642*1b481fc3SMaciej Żenczykowski 		rc = 1;
2643*1b481fc3SMaciej Żenczykowski 		goto err;
2644*1b481fc3SMaciej Żenczykowski 	}
2645*1b481fc3SMaciej Żenczykowski 	any_changed = new_state->off_flags != old_state->off_flags;
2646*1b481fc3SMaciej Żenczykowski 	any_mismatch = (new_state->off_flags !=
2647*1b481fc3SMaciej Żenczykowski 			((old_state->off_flags & ~off_flags_mask) |
2648*1b481fc3SMaciej Żenczykowski 			 off_flags_wanted));
2649*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < FEATURE_BITS_TO_BLOCKS(defs->n_features); i++) {
2650*1b481fc3SMaciej Żenczykowski 		if (new_state->features.features[i].active !=
2651*1b481fc3SMaciej Żenczykowski 		    old_state->features.features[i].active)
2652*1b481fc3SMaciej Żenczykowski 			any_changed = 1;
2653*1b481fc3SMaciej Żenczykowski 		if (new_state->features.features[i].active !=
2654*1b481fc3SMaciej Żenczykowski 		    ((old_state->features.features[i].active &
2655*1b481fc3SMaciej Żenczykowski 		      ~efeatures->features[i].valid) |
2656*1b481fc3SMaciej Żenczykowski 		     efeatures->features[i].requested))
2657*1b481fc3SMaciej Żenczykowski 			any_mismatch = 1;
2658*1b481fc3SMaciej Żenczykowski 	}
2659*1b481fc3SMaciej Żenczykowski 	if (any_mismatch) {
2660*1b481fc3SMaciej Żenczykowski 		if (!any_changed) {
2661*1b481fc3SMaciej Żenczykowski 			fprintf(stderr,
2662*1b481fc3SMaciej Żenczykowski 				"Could not change any device features\n");
2663*1b481fc3SMaciej Żenczykowski 			rc = 1;
2664*1b481fc3SMaciej Żenczykowski 			goto err;
2665*1b481fc3SMaciej Żenczykowski 		}
2666*1b481fc3SMaciej Żenczykowski 		printf("Actual changes:\n");
2667*1b481fc3SMaciej Żenczykowski 		dump_features(defs, new_state, old_state);
2668*1b481fc3SMaciej Żenczykowski 	}
2669*1b481fc3SMaciej Żenczykowski 
2670*1b481fc3SMaciej Żenczykowski 	rc = 0;
2671*1b481fc3SMaciej Żenczykowski 
2672*1b481fc3SMaciej Żenczykowski err:
2673*1b481fc3SMaciej Żenczykowski 	free(new_state);
2674*1b481fc3SMaciej Żenczykowski 	free(old_state);
2675*1b481fc3SMaciej Żenczykowski 	free(defs);
2676*1b481fc3SMaciej Żenczykowski 	free(efeatures);
2677*1b481fc3SMaciej Żenczykowski 
2678*1b481fc3SMaciej Żenczykowski 	return rc;
2679*1b481fc3SMaciej Żenczykowski }
2680*1b481fc3SMaciej Żenczykowski 
2681*1b481fc3SMaciej Żenczykowski static struct ethtool_link_usettings *
do_ioctl_glinksettings(struct cmd_context * ctx)2682*1b481fc3SMaciej Żenczykowski do_ioctl_glinksettings(struct cmd_context *ctx)
2683*1b481fc3SMaciej Żenczykowski {
2684*1b481fc3SMaciej Żenczykowski 	int err;
2685*1b481fc3SMaciej Żenczykowski 	struct {
2686*1b481fc3SMaciej Żenczykowski 		struct ethtool_link_settings req;
2687*1b481fc3SMaciej Żenczykowski 		__u32 link_mode_data[3 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32];
2688*1b481fc3SMaciej Żenczykowski 	} ecmd;
2689*1b481fc3SMaciej Żenczykowski 	struct ethtool_link_usettings *link_usettings;
2690*1b481fc3SMaciej Żenczykowski 	unsigned int u32_offs;
2691*1b481fc3SMaciej Żenczykowski 
2692*1b481fc3SMaciej Żenczykowski 	/* Handshake with kernel to determine number of words for link
2693*1b481fc3SMaciej Żenczykowski 	 * mode bitmaps. When requested number of bitmap words is not
2694*1b481fc3SMaciej Żenczykowski 	 * the one expected by kernel, the latter returns the integer
2695*1b481fc3SMaciej Żenczykowski 	 * opposite of what it is expecting. We request length 0 below
2696*1b481fc3SMaciej Żenczykowski 	 * (aka. invalid bitmap length) to get this info.
2697*1b481fc3SMaciej Żenczykowski 	 */
2698*1b481fc3SMaciej Żenczykowski 	memset(&ecmd, 0, sizeof(ecmd));
2699*1b481fc3SMaciej Żenczykowski 	ecmd.req.cmd = ETHTOOL_GLINKSETTINGS;
2700*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &ecmd);
2701*1b481fc3SMaciej Żenczykowski 	if (err < 0)
2702*1b481fc3SMaciej Żenczykowski 		return NULL;
2703*1b481fc3SMaciej Żenczykowski 
2704*1b481fc3SMaciej Żenczykowski 	/* see above: we expect a strictly negative value from kernel.
2705*1b481fc3SMaciej Żenczykowski 	 */
2706*1b481fc3SMaciej Żenczykowski 	if (ecmd.req.link_mode_masks_nwords >= 0
2707*1b481fc3SMaciej Żenczykowski 	    || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS)
2708*1b481fc3SMaciej Żenczykowski 		return NULL;
2709*1b481fc3SMaciej Żenczykowski 
2710*1b481fc3SMaciej Żenczykowski 	/* got the real ecmd.req.link_mode_masks_nwords,
2711*1b481fc3SMaciej Żenczykowski 	 * now send the real request
2712*1b481fc3SMaciej Żenczykowski 	 */
2713*1b481fc3SMaciej Żenczykowski 	ecmd.req.cmd = ETHTOOL_GLINKSETTINGS;
2714*1b481fc3SMaciej Żenczykowski 	ecmd.req.link_mode_masks_nwords = -ecmd.req.link_mode_masks_nwords;
2715*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &ecmd);
2716*1b481fc3SMaciej Żenczykowski 	if (err < 0)
2717*1b481fc3SMaciej Żenczykowski 		return NULL;
2718*1b481fc3SMaciej Żenczykowski 
2719*1b481fc3SMaciej Żenczykowski 	if (ecmd.req.link_mode_masks_nwords <= 0
2720*1b481fc3SMaciej Żenczykowski 	    || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS)
2721*1b481fc3SMaciej Żenczykowski 		return NULL;
2722*1b481fc3SMaciej Żenczykowski 
2723*1b481fc3SMaciej Żenczykowski 	/* Convert to usettings struct */
2724*1b481fc3SMaciej Żenczykowski 	link_usettings = calloc(1, sizeof(*link_usettings));
2725*1b481fc3SMaciej Żenczykowski 	if (link_usettings == NULL)
2726*1b481fc3SMaciej Żenczykowski 		return NULL;
2727*1b481fc3SMaciej Żenczykowski 
2728*1b481fc3SMaciej Żenczykowski 	memcpy(&link_usettings->base, &ecmd.req, sizeof(link_usettings->base));
2729*1b481fc3SMaciej Żenczykowski 	link_usettings->deprecated.transceiver = ecmd.req.transceiver;
2730*1b481fc3SMaciej Żenczykowski 
2731*1b481fc3SMaciej Żenczykowski 	/* copy link mode bitmaps */
2732*1b481fc3SMaciej Żenczykowski 	u32_offs = 0;
2733*1b481fc3SMaciej Żenczykowski 	memcpy(link_usettings->link_modes.supported,
2734*1b481fc3SMaciej Żenczykowski 	       &ecmd.link_mode_data[u32_offs],
2735*1b481fc3SMaciej Żenczykowski 	       4 * ecmd.req.link_mode_masks_nwords);
2736*1b481fc3SMaciej Żenczykowski 
2737*1b481fc3SMaciej Żenczykowski 	u32_offs += ecmd.req.link_mode_masks_nwords;
2738*1b481fc3SMaciej Żenczykowski 	memcpy(link_usettings->link_modes.advertising,
2739*1b481fc3SMaciej Żenczykowski 	       &ecmd.link_mode_data[u32_offs],
2740*1b481fc3SMaciej Żenczykowski 	       4 * ecmd.req.link_mode_masks_nwords);
2741*1b481fc3SMaciej Żenczykowski 
2742*1b481fc3SMaciej Żenczykowski 	u32_offs += ecmd.req.link_mode_masks_nwords;
2743*1b481fc3SMaciej Żenczykowski 	memcpy(link_usettings->link_modes.lp_advertising,
2744*1b481fc3SMaciej Żenczykowski 	       &ecmd.link_mode_data[u32_offs],
2745*1b481fc3SMaciej Żenczykowski 	       4 * ecmd.req.link_mode_masks_nwords);
2746*1b481fc3SMaciej Żenczykowski 
2747*1b481fc3SMaciej Żenczykowski 	return link_usettings;
2748*1b481fc3SMaciej Żenczykowski }
2749*1b481fc3SMaciej Żenczykowski 
2750*1b481fc3SMaciej Żenczykowski static int
do_ioctl_slinksettings(struct cmd_context * ctx,const struct ethtool_link_usettings * link_usettings)2751*1b481fc3SMaciej Żenczykowski do_ioctl_slinksettings(struct cmd_context *ctx,
2752*1b481fc3SMaciej Żenczykowski 		       const struct ethtool_link_usettings *link_usettings)
2753*1b481fc3SMaciej Żenczykowski {
2754*1b481fc3SMaciej Żenczykowski 	struct {
2755*1b481fc3SMaciej Żenczykowski 		struct ethtool_link_settings req;
2756*1b481fc3SMaciej Żenczykowski 		__u32 link_mode_data[3 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32];
2757*1b481fc3SMaciej Żenczykowski 	} ecmd;
2758*1b481fc3SMaciej Żenczykowski 	unsigned int u32_offs;
2759*1b481fc3SMaciej Żenczykowski 
2760*1b481fc3SMaciej Żenczykowski 	/* refuse to send ETHTOOL_SLINKSETTINGS ioctl if
2761*1b481fc3SMaciej Żenczykowski 	 * link_usettings was retrieved with ETHTOOL_GSET
2762*1b481fc3SMaciej Żenczykowski 	 */
2763*1b481fc3SMaciej Żenczykowski 	if (link_usettings->base.cmd != ETHTOOL_GLINKSETTINGS)
2764*1b481fc3SMaciej Żenczykowski 		return -1;
2765*1b481fc3SMaciej Żenczykowski 
2766*1b481fc3SMaciej Żenczykowski 	/* refuse to send ETHTOOL_SLINKSETTINGS ioctl if deprecated fields
2767*1b481fc3SMaciej Żenczykowski 	 * were set
2768*1b481fc3SMaciej Żenczykowski 	 */
2769*1b481fc3SMaciej Żenczykowski 	if (link_usettings->deprecated.transceiver)
2770*1b481fc3SMaciej Żenczykowski 		return -1;
2771*1b481fc3SMaciej Żenczykowski 
2772*1b481fc3SMaciej Żenczykowski 	if (link_usettings->base.link_mode_masks_nwords <= 0)
2773*1b481fc3SMaciej Żenczykowski 		return -1;
2774*1b481fc3SMaciej Żenczykowski 
2775*1b481fc3SMaciej Żenczykowski 	memcpy(&ecmd.req, &link_usettings->base, sizeof(ecmd.req));
2776*1b481fc3SMaciej Żenczykowski 	ecmd.req.cmd = ETHTOOL_SLINKSETTINGS;
2777*1b481fc3SMaciej Żenczykowski 
2778*1b481fc3SMaciej Żenczykowski 	/* copy link mode bitmaps */
2779*1b481fc3SMaciej Żenczykowski 	u32_offs = 0;
2780*1b481fc3SMaciej Żenczykowski 	memcpy(&ecmd.link_mode_data[u32_offs],
2781*1b481fc3SMaciej Żenczykowski 	       link_usettings->link_modes.supported,
2782*1b481fc3SMaciej Żenczykowski 	       4 * ecmd.req.link_mode_masks_nwords);
2783*1b481fc3SMaciej Żenczykowski 
2784*1b481fc3SMaciej Żenczykowski 	u32_offs += ecmd.req.link_mode_masks_nwords;
2785*1b481fc3SMaciej Żenczykowski 	memcpy(&ecmd.link_mode_data[u32_offs],
2786*1b481fc3SMaciej Żenczykowski 	       link_usettings->link_modes.advertising,
2787*1b481fc3SMaciej Żenczykowski 	       4 * ecmd.req.link_mode_masks_nwords);
2788*1b481fc3SMaciej Żenczykowski 
2789*1b481fc3SMaciej Żenczykowski 	u32_offs += ecmd.req.link_mode_masks_nwords;
2790*1b481fc3SMaciej Żenczykowski 	memcpy(&ecmd.link_mode_data[u32_offs],
2791*1b481fc3SMaciej Żenczykowski 	       link_usettings->link_modes.lp_advertising,
2792*1b481fc3SMaciej Żenczykowski 	       4 * ecmd.req.link_mode_masks_nwords);
2793*1b481fc3SMaciej Żenczykowski 
2794*1b481fc3SMaciej Żenczykowski 	return send_ioctl(ctx, &ecmd);
2795*1b481fc3SMaciej Żenczykowski }
2796*1b481fc3SMaciej Żenczykowski 
2797*1b481fc3SMaciej Żenczykowski static struct ethtool_link_usettings *
do_ioctl_gset(struct cmd_context * ctx)2798*1b481fc3SMaciej Żenczykowski do_ioctl_gset(struct cmd_context *ctx)
2799*1b481fc3SMaciej Żenczykowski {
2800*1b481fc3SMaciej Żenczykowski 	int err;
2801*1b481fc3SMaciej Żenczykowski 	struct ethtool_cmd ecmd;
2802*1b481fc3SMaciej Żenczykowski 	struct ethtool_link_usettings *link_usettings;
2803*1b481fc3SMaciej Żenczykowski 
2804*1b481fc3SMaciej Żenczykowski 	memset(&ecmd, 0, sizeof(ecmd));
2805*1b481fc3SMaciej Żenczykowski 	ecmd.cmd = ETHTOOL_GSET;
2806*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &ecmd);
2807*1b481fc3SMaciej Żenczykowski 	if (err < 0)
2808*1b481fc3SMaciej Żenczykowski 		return NULL;
2809*1b481fc3SMaciej Żenczykowski 
2810*1b481fc3SMaciej Żenczykowski 	link_usettings = calloc(1, sizeof(*link_usettings));
2811*1b481fc3SMaciej Żenczykowski 	if (link_usettings == NULL)
2812*1b481fc3SMaciej Żenczykowski 		return NULL;
2813*1b481fc3SMaciej Żenczykowski 
2814*1b481fc3SMaciej Żenczykowski 	/* remember that ETHTOOL_GSET was used */
2815*1b481fc3SMaciej Żenczykowski 	link_usettings->base.cmd = ETHTOOL_GSET;
2816*1b481fc3SMaciej Żenczykowski 
2817*1b481fc3SMaciej Żenczykowski 	link_usettings->base.link_mode_masks_nwords = 1;
2818*1b481fc3SMaciej Żenczykowski 	link_usettings->link_modes.supported[0] = ecmd.supported;
2819*1b481fc3SMaciej Żenczykowski 	link_usettings->link_modes.advertising[0] = ecmd.advertising;
2820*1b481fc3SMaciej Żenczykowski 	link_usettings->link_modes.lp_advertising[0] = ecmd.lp_advertising;
2821*1b481fc3SMaciej Żenczykowski 	link_usettings->base.speed = ethtool_cmd_speed(&ecmd);
2822*1b481fc3SMaciej Żenczykowski 	link_usettings->base.duplex = ecmd.duplex;
2823*1b481fc3SMaciej Żenczykowski 	link_usettings->base.port = ecmd.port;
2824*1b481fc3SMaciej Żenczykowski 	link_usettings->base.phy_address = ecmd.phy_address;
2825*1b481fc3SMaciej Żenczykowski 	link_usettings->deprecated.transceiver = ecmd.transceiver;
2826*1b481fc3SMaciej Żenczykowski 	link_usettings->base.autoneg = ecmd.autoneg;
2827*1b481fc3SMaciej Żenczykowski 	link_usettings->base.mdio_support = ecmd.mdio_support;
2828*1b481fc3SMaciej Żenczykowski 	/* ignored (fully deprecated): maxrxpkt, maxtxpkt */
2829*1b481fc3SMaciej Żenczykowski 	link_usettings->base.eth_tp_mdix = ecmd.eth_tp_mdix;
2830*1b481fc3SMaciej Żenczykowski 	link_usettings->base.eth_tp_mdix_ctrl = ecmd.eth_tp_mdix_ctrl;
2831*1b481fc3SMaciej Żenczykowski 
2832*1b481fc3SMaciej Żenczykowski 	return link_usettings;
2833*1b481fc3SMaciej Żenczykowski }
2834*1b481fc3SMaciej Żenczykowski 
ethtool_link_mode_is_backward_compatible(const u32 * mask)2835*1b481fc3SMaciej Żenczykowski static bool ethtool_link_mode_is_backward_compatible(const u32 *mask)
2836*1b481fc3SMaciej Żenczykowski {
2837*1b481fc3SMaciej Żenczykowski 	unsigned int i;
2838*1b481fc3SMaciej Żenczykowski 
2839*1b481fc3SMaciej Żenczykowski 	for (i = 1; i < ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32; ++i)
2840*1b481fc3SMaciej Żenczykowski 		if (mask[i])
2841*1b481fc3SMaciej Żenczykowski 			return false;
2842*1b481fc3SMaciej Żenczykowski 
2843*1b481fc3SMaciej Żenczykowski 	return true;
2844*1b481fc3SMaciej Żenczykowski }
2845*1b481fc3SMaciej Żenczykowski 
2846*1b481fc3SMaciej Żenczykowski static int
do_ioctl_sset(struct cmd_context * ctx,const struct ethtool_link_usettings * link_usettings)2847*1b481fc3SMaciej Żenczykowski do_ioctl_sset(struct cmd_context *ctx,
2848*1b481fc3SMaciej Żenczykowski 	      const struct ethtool_link_usettings *link_usettings)
2849*1b481fc3SMaciej Żenczykowski {
2850*1b481fc3SMaciej Żenczykowski 	struct ethtool_cmd ecmd;
2851*1b481fc3SMaciej Żenczykowski 
2852*1b481fc3SMaciej Żenczykowski 	/* refuse to send ETHTOOL_SSET ioctl if link_usettings was
2853*1b481fc3SMaciej Żenczykowski 	 * retrieved with ETHTOOL_GLINKSETTINGS
2854*1b481fc3SMaciej Żenczykowski 	 */
2855*1b481fc3SMaciej Żenczykowski 	if (link_usettings->base.cmd != ETHTOOL_GSET)
2856*1b481fc3SMaciej Żenczykowski 		return -1;
2857*1b481fc3SMaciej Żenczykowski 
2858*1b481fc3SMaciej Żenczykowski 	if (link_usettings->base.link_mode_masks_nwords <= 0)
2859*1b481fc3SMaciej Żenczykowski 		return -1;
2860*1b481fc3SMaciej Żenczykowski 
2861*1b481fc3SMaciej Żenczykowski 	/* refuse to sset if any bit > 31 is set */
2862*1b481fc3SMaciej Żenczykowski 	if (!ethtool_link_mode_is_backward_compatible(
2863*1b481fc3SMaciej Żenczykowski 		    link_usettings->link_modes.supported))
2864*1b481fc3SMaciej Żenczykowski 		return -1;
2865*1b481fc3SMaciej Żenczykowski 	if (!ethtool_link_mode_is_backward_compatible(
2866*1b481fc3SMaciej Żenczykowski 		    link_usettings->link_modes.advertising))
2867*1b481fc3SMaciej Żenczykowski 		return -1;
2868*1b481fc3SMaciej Żenczykowski 	if (!ethtool_link_mode_is_backward_compatible(
2869*1b481fc3SMaciej Żenczykowski 		    link_usettings->link_modes.lp_advertising))
2870*1b481fc3SMaciej Żenczykowski 		return -1;
2871*1b481fc3SMaciej Żenczykowski 
2872*1b481fc3SMaciej Żenczykowski 	memset(&ecmd, 0, sizeof(ecmd));
2873*1b481fc3SMaciej Żenczykowski 	ecmd.cmd = ETHTOOL_SSET;
2874*1b481fc3SMaciej Żenczykowski 
2875*1b481fc3SMaciej Żenczykowski 	ecmd.supported = link_usettings->link_modes.supported[0];
2876*1b481fc3SMaciej Żenczykowski 	ecmd.advertising = link_usettings->link_modes.advertising[0];
2877*1b481fc3SMaciej Żenczykowski 	ecmd.lp_advertising = link_usettings->link_modes.lp_advertising[0];
2878*1b481fc3SMaciej Żenczykowski 	ethtool_cmd_speed_set(&ecmd, link_usettings->base.speed);
2879*1b481fc3SMaciej Żenczykowski 	ecmd.duplex = link_usettings->base.duplex;
2880*1b481fc3SMaciej Żenczykowski 	ecmd.port = link_usettings->base.port;
2881*1b481fc3SMaciej Żenczykowski 	ecmd.phy_address = link_usettings->base.phy_address;
2882*1b481fc3SMaciej Żenczykowski 	ecmd.transceiver = link_usettings->deprecated.transceiver;
2883*1b481fc3SMaciej Żenczykowski 	ecmd.autoneg = link_usettings->base.autoneg;
2884*1b481fc3SMaciej Żenczykowski 	ecmd.mdio_support = link_usettings->base.mdio_support;
2885*1b481fc3SMaciej Żenczykowski 	/* ignored (fully deprecated): maxrxpkt, maxtxpkt */
2886*1b481fc3SMaciej Żenczykowski 	ecmd.eth_tp_mdix = link_usettings->base.eth_tp_mdix;
2887*1b481fc3SMaciej Żenczykowski 	ecmd.eth_tp_mdix_ctrl = link_usettings->base.eth_tp_mdix_ctrl;
2888*1b481fc3SMaciej Żenczykowski 	return send_ioctl(ctx, &ecmd);
2889*1b481fc3SMaciej Żenczykowski }
2890*1b481fc3SMaciej Żenczykowski 
do_gset(struct cmd_context * ctx)2891*1b481fc3SMaciej Żenczykowski static int do_gset(struct cmd_context *ctx)
2892*1b481fc3SMaciej Żenczykowski {
2893*1b481fc3SMaciej Żenczykowski 	int err;
2894*1b481fc3SMaciej Żenczykowski 	struct ethtool_link_usettings *link_usettings;
2895*1b481fc3SMaciej Żenczykowski 	struct ethtool_wolinfo wolinfo;
2896*1b481fc3SMaciej Żenczykowski 	struct ethtool_value edata;
2897*1b481fc3SMaciej Żenczykowski 	int allfail = 1;
2898*1b481fc3SMaciej Żenczykowski 
2899*1b481fc3SMaciej Żenczykowski 	if (ctx->argc != 0)
2900*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
2901*1b481fc3SMaciej Żenczykowski 
2902*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "Settings for %s:\n", ctx->devname);
2903*1b481fc3SMaciej Żenczykowski 
2904*1b481fc3SMaciej Żenczykowski 	link_usettings = do_ioctl_glinksettings(ctx);
2905*1b481fc3SMaciej Żenczykowski 	if (link_usettings == NULL)
2906*1b481fc3SMaciej Żenczykowski 		link_usettings = do_ioctl_gset(ctx);
2907*1b481fc3SMaciej Żenczykowski 	if (link_usettings != NULL) {
2908*1b481fc3SMaciej Żenczykowski 		err = dump_link_usettings(link_usettings);
2909*1b481fc3SMaciej Żenczykowski 		free(link_usettings);
2910*1b481fc3SMaciej Żenczykowski 		if (err)
2911*1b481fc3SMaciej Żenczykowski 			return err;
2912*1b481fc3SMaciej Żenczykowski 		allfail = 0;
2913*1b481fc3SMaciej Żenczykowski 	} else if (errno != EOPNOTSUPP) {
2914*1b481fc3SMaciej Żenczykowski 		perror("Cannot get device settings");
2915*1b481fc3SMaciej Żenczykowski 	}
2916*1b481fc3SMaciej Żenczykowski 
2917*1b481fc3SMaciej Żenczykowski 	wolinfo.cmd = ETHTOOL_GWOL;
2918*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &wolinfo);
2919*1b481fc3SMaciej Żenczykowski 	if (err == 0) {
2920*1b481fc3SMaciej Żenczykowski 		err = dump_wol(&wolinfo);
2921*1b481fc3SMaciej Żenczykowski 		if (err)
2922*1b481fc3SMaciej Żenczykowski 			return err;
2923*1b481fc3SMaciej Żenczykowski 		allfail = 0;
2924*1b481fc3SMaciej Żenczykowski 	} else if (errno != EOPNOTSUPP) {
2925*1b481fc3SMaciej Żenczykowski 		perror("Cannot get wake-on-lan settings");
2926*1b481fc3SMaciej Żenczykowski 	}
2927*1b481fc3SMaciej Żenczykowski 
2928*1b481fc3SMaciej Żenczykowski 	edata.cmd = ETHTOOL_GMSGLVL;
2929*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &edata);
2930*1b481fc3SMaciej Żenczykowski 	if (err == 0) {
2931*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "	Current message level: 0x%08x (%d)\n"
2932*1b481fc3SMaciej Żenczykowski 			"			       ",
2933*1b481fc3SMaciej Żenczykowski 			edata.data, edata.data);
2934*1b481fc3SMaciej Żenczykowski 		print_flags(flags_msglvl, n_flags_msglvl, edata.data);
2935*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "\n");
2936*1b481fc3SMaciej Żenczykowski 		allfail = 0;
2937*1b481fc3SMaciej Żenczykowski 	} else if (errno != EOPNOTSUPP) {
2938*1b481fc3SMaciej Żenczykowski 		perror("Cannot get message level");
2939*1b481fc3SMaciej Żenczykowski 	}
2940*1b481fc3SMaciej Żenczykowski 
2941*1b481fc3SMaciej Żenczykowski 	edata.cmd = ETHTOOL_GLINK;
2942*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &edata);
2943*1b481fc3SMaciej Żenczykowski 	if (err == 0) {
2944*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "	Link detected: %s\n",
2945*1b481fc3SMaciej Żenczykowski 			edata.data ? "yes":"no");
2946*1b481fc3SMaciej Żenczykowski 		allfail = 0;
2947*1b481fc3SMaciej Żenczykowski 	} else if (errno != EOPNOTSUPP) {
2948*1b481fc3SMaciej Żenczykowski 		perror("Cannot get link status");
2949*1b481fc3SMaciej Żenczykowski 	}
2950*1b481fc3SMaciej Żenczykowski 
2951*1b481fc3SMaciej Żenczykowski 	if (allfail) {
2952*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "No data available\n");
2953*1b481fc3SMaciej Żenczykowski 		return 75;
2954*1b481fc3SMaciej Żenczykowski 	}
2955*1b481fc3SMaciej Żenczykowski 	return 0;
2956*1b481fc3SMaciej Żenczykowski }
2957*1b481fc3SMaciej Żenczykowski 
do_sset(struct cmd_context * ctx)2958*1b481fc3SMaciej Żenczykowski static int do_sset(struct cmd_context *ctx)
2959*1b481fc3SMaciej Żenczykowski {
2960*1b481fc3SMaciej Żenczykowski 	int speed_wanted = -1;
2961*1b481fc3SMaciej Żenczykowski 	int duplex_wanted = -1;
2962*1b481fc3SMaciej Żenczykowski 	int port_wanted = -1;
2963*1b481fc3SMaciej Żenczykowski 	int mdix_wanted = -1;
2964*1b481fc3SMaciej Żenczykowski 	int autoneg_wanted = -1;
2965*1b481fc3SMaciej Żenczykowski 	int phyad_wanted = -1;
2966*1b481fc3SMaciej Żenczykowski 	int xcvr_wanted = -1;
2967*1b481fc3SMaciej Żenczykowski 	u32 *full_advertising_wanted = NULL;
2968*1b481fc3SMaciej Żenczykowski 	u32 *advertising_wanted = NULL;
2969*1b481fc3SMaciej Żenczykowski 	ETHTOOL_DECLARE_LINK_MODE_MASK(mask_full_advertising_wanted);
2970*1b481fc3SMaciej Żenczykowski 	ETHTOOL_DECLARE_LINK_MODE_MASK(mask_advertising_wanted);
2971*1b481fc3SMaciej Żenczykowski 	int gset_changed = 0; /* did anything in GSET change? */
2972*1b481fc3SMaciej Żenczykowski 	u32 wol_wanted = 0;
2973*1b481fc3SMaciej Żenczykowski 	int wol_change = 0;
2974*1b481fc3SMaciej Żenczykowski 	u8 sopass_wanted[SOPASS_MAX];
2975*1b481fc3SMaciej Żenczykowski 	int sopass_change = 0;
2976*1b481fc3SMaciej Żenczykowski 	int gwol_changed = 0; /* did anything in GWOL change? */
2977*1b481fc3SMaciej Żenczykowski 	int msglvl_changed = 0;
2978*1b481fc3SMaciej Żenczykowski 	u32 msglvl_wanted = 0;
2979*1b481fc3SMaciej Żenczykowski 	u32 msglvl_mask = 0;
2980*1b481fc3SMaciej Żenczykowski 	struct cmdline_info cmdline_msglvl[n_flags_msglvl];
2981*1b481fc3SMaciej Żenczykowski 	unsigned int argc = ctx->argc;
2982*1b481fc3SMaciej Żenczykowski 	char **argp = ctx->argp;
2983*1b481fc3SMaciej Żenczykowski 	unsigned int i;
2984*1b481fc3SMaciej Żenczykowski 	int err = 0;
2985*1b481fc3SMaciej Żenczykowski 
2986*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < n_flags_msglvl; i++)
2987*1b481fc3SMaciej Żenczykowski 		flag_to_cmdline_info(flags_msglvl[i].name,
2988*1b481fc3SMaciej Żenczykowski 				     flags_msglvl[i].value,
2989*1b481fc3SMaciej Żenczykowski 				     &msglvl_wanted, &msglvl_mask,
2990*1b481fc3SMaciej Żenczykowski 				     &cmdline_msglvl[i]);
2991*1b481fc3SMaciej Żenczykowski 
2992*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < argc; i++) {
2993*1b481fc3SMaciej Żenczykowski 		if (!strcmp(argp[i], "speed")) {
2994*1b481fc3SMaciej Żenczykowski 			gset_changed = 1;
2995*1b481fc3SMaciej Żenczykowski 			i += 1;
2996*1b481fc3SMaciej Żenczykowski 			if (i >= argc)
2997*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
2998*1b481fc3SMaciej Żenczykowski 			speed_wanted = get_int(argp[i], 10);
2999*1b481fc3SMaciej Żenczykowski 		} else if (!strcmp(argp[i], "duplex")) {
3000*1b481fc3SMaciej Żenczykowski 			gset_changed = 1;
3001*1b481fc3SMaciej Żenczykowski 			i += 1;
3002*1b481fc3SMaciej Żenczykowski 			if (i >= argc)
3003*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
3004*1b481fc3SMaciej Żenczykowski 			if (!strcmp(argp[i], "half"))
3005*1b481fc3SMaciej Żenczykowski 				duplex_wanted = DUPLEX_HALF;
3006*1b481fc3SMaciej Żenczykowski 			else if (!strcmp(argp[i], "full"))
3007*1b481fc3SMaciej Żenczykowski 				duplex_wanted = DUPLEX_FULL;
3008*1b481fc3SMaciej Żenczykowski 			else
3009*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
3010*1b481fc3SMaciej Żenczykowski 		} else if (!strcmp(argp[i], "port")) {
3011*1b481fc3SMaciej Żenczykowski 			gset_changed = 1;
3012*1b481fc3SMaciej Żenczykowski 			i += 1;
3013*1b481fc3SMaciej Żenczykowski 			if (i >= argc)
3014*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
3015*1b481fc3SMaciej Żenczykowski 			if (!strcmp(argp[i], "tp"))
3016*1b481fc3SMaciej Żenczykowski 				port_wanted = PORT_TP;
3017*1b481fc3SMaciej Żenczykowski 			else if (!strcmp(argp[i], "aui"))
3018*1b481fc3SMaciej Żenczykowski 				port_wanted = PORT_AUI;
3019*1b481fc3SMaciej Żenczykowski 			else if (!strcmp(argp[i], "bnc"))
3020*1b481fc3SMaciej Żenczykowski 				port_wanted = PORT_BNC;
3021*1b481fc3SMaciej Żenczykowski 			else if (!strcmp(argp[i], "mii"))
3022*1b481fc3SMaciej Żenczykowski 				port_wanted = PORT_MII;
3023*1b481fc3SMaciej Żenczykowski 			else if (!strcmp(argp[i], "fibre"))
3024*1b481fc3SMaciej Żenczykowski 				port_wanted = PORT_FIBRE;
3025*1b481fc3SMaciej Żenczykowski 			else
3026*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
3027*1b481fc3SMaciej Żenczykowski 		} else if (!strcmp(argp[i], "mdix")) {
3028*1b481fc3SMaciej Żenczykowski 			gset_changed = 1;
3029*1b481fc3SMaciej Żenczykowski 			i += 1;
3030*1b481fc3SMaciej Żenczykowski 			if (i >= argc)
3031*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
3032*1b481fc3SMaciej Żenczykowski 			if (!strcmp(argp[i], "auto"))
3033*1b481fc3SMaciej Żenczykowski 				mdix_wanted = ETH_TP_MDI_AUTO;
3034*1b481fc3SMaciej Żenczykowski 			else if (!strcmp(argp[i], "on"))
3035*1b481fc3SMaciej Żenczykowski 				mdix_wanted = ETH_TP_MDI_X;
3036*1b481fc3SMaciej Żenczykowski 			else if (!strcmp(argp[i], "off"))
3037*1b481fc3SMaciej Żenczykowski 				mdix_wanted = ETH_TP_MDI;
3038*1b481fc3SMaciej Żenczykowski 			else
3039*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
3040*1b481fc3SMaciej Żenczykowski 		} else if (!strcmp(argp[i], "autoneg")) {
3041*1b481fc3SMaciej Żenczykowski 			i += 1;
3042*1b481fc3SMaciej Żenczykowski 			if (i >= argc)
3043*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
3044*1b481fc3SMaciej Żenczykowski 			if (!strcmp(argp[i], "on")) {
3045*1b481fc3SMaciej Żenczykowski 				gset_changed = 1;
3046*1b481fc3SMaciej Żenczykowski 				autoneg_wanted = AUTONEG_ENABLE;
3047*1b481fc3SMaciej Żenczykowski 			} else if (!strcmp(argp[i], "off")) {
3048*1b481fc3SMaciej Żenczykowski 				gset_changed = 1;
3049*1b481fc3SMaciej Żenczykowski 				autoneg_wanted = AUTONEG_DISABLE;
3050*1b481fc3SMaciej Żenczykowski 			} else {
3051*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
3052*1b481fc3SMaciej Żenczykowski 			}
3053*1b481fc3SMaciej Żenczykowski 		} else if (!strcmp(argp[i], "advertise")) {
3054*1b481fc3SMaciej Żenczykowski 			gset_changed = 1;
3055*1b481fc3SMaciej Żenczykowski 			i += 1;
3056*1b481fc3SMaciej Żenczykowski 			if (i >= argc)
3057*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
3058*1b481fc3SMaciej Żenczykowski 			if (parse_hex_u32_bitmap(
3059*1b481fc3SMaciej Żenczykowski 				    argp[i],
3060*1b481fc3SMaciej Żenczykowski 				    ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBITS,
3061*1b481fc3SMaciej Żenczykowski 				    mask_full_advertising_wanted))
3062*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
3063*1b481fc3SMaciej Żenczykowski 			full_advertising_wanted = mask_full_advertising_wanted;
3064*1b481fc3SMaciej Żenczykowski 		} else if (!strcmp(argp[i], "phyad")) {
3065*1b481fc3SMaciej Żenczykowski 			gset_changed = 1;
3066*1b481fc3SMaciej Żenczykowski 			i += 1;
3067*1b481fc3SMaciej Żenczykowski 			if (i >= argc)
3068*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
3069*1b481fc3SMaciej Żenczykowski 			phyad_wanted = get_int(argp[i], 0);
3070*1b481fc3SMaciej Żenczykowski 		} else if (!strcmp(argp[i], "xcvr")) {
3071*1b481fc3SMaciej Żenczykowski 			gset_changed = 1;
3072*1b481fc3SMaciej Żenczykowski 			i += 1;
3073*1b481fc3SMaciej Żenczykowski 			if (i >= argc)
3074*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
3075*1b481fc3SMaciej Żenczykowski 			if (!strcmp(argp[i], "internal"))
3076*1b481fc3SMaciej Żenczykowski 				xcvr_wanted = XCVR_INTERNAL;
3077*1b481fc3SMaciej Żenczykowski 			else if (!strcmp(argp[i], "external"))
3078*1b481fc3SMaciej Żenczykowski 				xcvr_wanted = XCVR_EXTERNAL;
3079*1b481fc3SMaciej Żenczykowski 			else
3080*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
3081*1b481fc3SMaciej Żenczykowski 		} else if (!strcmp(argp[i], "wol")) {
3082*1b481fc3SMaciej Żenczykowski 			gwol_changed = 1;
3083*1b481fc3SMaciej Żenczykowski 			i++;
3084*1b481fc3SMaciej Żenczykowski 			if (i >= argc)
3085*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
3086*1b481fc3SMaciej Żenczykowski 			if (parse_wolopts(argp[i], &wol_wanted) < 0)
3087*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
3088*1b481fc3SMaciej Żenczykowski 			wol_change = 1;
3089*1b481fc3SMaciej Żenczykowski 		} else if (!strcmp(argp[i], "sopass")) {
3090*1b481fc3SMaciej Żenczykowski 			gwol_changed = 1;
3091*1b481fc3SMaciej Żenczykowski 			i++;
3092*1b481fc3SMaciej Żenczykowski 			if (i >= argc)
3093*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
3094*1b481fc3SMaciej Żenczykowski 			get_mac_addr(argp[i], sopass_wanted);
3095*1b481fc3SMaciej Żenczykowski 			sopass_change = 1;
3096*1b481fc3SMaciej Żenczykowski 		} else if (!strcmp(argp[i], "msglvl")) {
3097*1b481fc3SMaciej Żenczykowski 			i++;
3098*1b481fc3SMaciej Żenczykowski 			if (i >= argc)
3099*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
3100*1b481fc3SMaciej Żenczykowski 			if (isdigit((unsigned char)argp[i][0])) {
3101*1b481fc3SMaciej Żenczykowski 				msglvl_changed = 1;
3102*1b481fc3SMaciej Żenczykowski 				msglvl_mask = ~0;
3103*1b481fc3SMaciej Żenczykowski 				msglvl_wanted =
3104*1b481fc3SMaciej Żenczykowski 					get_uint_range(argp[i], 0,
3105*1b481fc3SMaciej Żenczykowski 						       0xffffffff);
3106*1b481fc3SMaciej Żenczykowski 			} else {
3107*1b481fc3SMaciej Żenczykowski 				ctx->argc -= i;
3108*1b481fc3SMaciej Żenczykowski 				ctx->argp += i;
3109*1b481fc3SMaciej Żenczykowski 				parse_generic_cmdline(
3110*1b481fc3SMaciej Żenczykowski 					ctx, &msglvl_changed,
3111*1b481fc3SMaciej Żenczykowski 					cmdline_msglvl,
3112*1b481fc3SMaciej Żenczykowski 					ARRAY_SIZE(cmdline_msglvl));
3113*1b481fc3SMaciej Żenczykowski 				break;
3114*1b481fc3SMaciej Żenczykowski 			}
3115*1b481fc3SMaciej Żenczykowski 		} else if (!strcmp(argp[i], "master-slave")) {
3116*1b481fc3SMaciej Żenczykowski 			exit_nlonly_param(argp[i]);
3117*1b481fc3SMaciej Żenczykowski 		} else {
3118*1b481fc3SMaciej Żenczykowski 			exit_bad_args();
3119*1b481fc3SMaciej Żenczykowski 		}
3120*1b481fc3SMaciej Żenczykowski 	}
3121*1b481fc3SMaciej Żenczykowski 
3122*1b481fc3SMaciej Żenczykowski 	if (full_advertising_wanted == NULL) {
3123*1b481fc3SMaciej Żenczykowski 		/* User didn't supply a full advertisement bitfield:
3124*1b481fc3SMaciej Żenczykowski 		 * construct one from the specified speed and duplex.
3125*1b481fc3SMaciej Żenczykowski 		 */
3126*1b481fc3SMaciej Żenczykowski 		int adv_bit = -1;
3127*1b481fc3SMaciej Żenczykowski 
3128*1b481fc3SMaciej Żenczykowski 		if (speed_wanted == SPEED_10 && duplex_wanted == DUPLEX_HALF)
3129*1b481fc3SMaciej Żenczykowski 			adv_bit = ETHTOOL_LINK_MODE_10baseT_Half_BIT;
3130*1b481fc3SMaciej Żenczykowski 		else if (speed_wanted == SPEED_10 &&
3131*1b481fc3SMaciej Żenczykowski 			 duplex_wanted == DUPLEX_FULL)
3132*1b481fc3SMaciej Żenczykowski 			adv_bit = ETHTOOL_LINK_MODE_10baseT_Full_BIT;
3133*1b481fc3SMaciej Żenczykowski 		else if (speed_wanted == SPEED_100 &&
3134*1b481fc3SMaciej Żenczykowski 			 duplex_wanted == DUPLEX_HALF)
3135*1b481fc3SMaciej Żenczykowski 			adv_bit = ETHTOOL_LINK_MODE_100baseT_Half_BIT;
3136*1b481fc3SMaciej Żenczykowski 		else if (speed_wanted == SPEED_100 &&
3137*1b481fc3SMaciej Żenczykowski 			 duplex_wanted == DUPLEX_FULL)
3138*1b481fc3SMaciej Żenczykowski 			adv_bit = ETHTOOL_LINK_MODE_100baseT_Full_BIT;
3139*1b481fc3SMaciej Żenczykowski 		else if (speed_wanted == SPEED_1000 &&
3140*1b481fc3SMaciej Żenczykowski 			 duplex_wanted == DUPLEX_HALF)
3141*1b481fc3SMaciej Żenczykowski 			adv_bit = ETHTOOL_LINK_MODE_1000baseT_Half_BIT;
3142*1b481fc3SMaciej Żenczykowski 		else if (speed_wanted == SPEED_1000 &&
3143*1b481fc3SMaciej Żenczykowski 			 duplex_wanted == DUPLEX_FULL)
3144*1b481fc3SMaciej Żenczykowski 			adv_bit = ETHTOOL_LINK_MODE_1000baseT_Full_BIT;
3145*1b481fc3SMaciej Żenczykowski 		else if (speed_wanted == SPEED_2500 &&
3146*1b481fc3SMaciej Żenczykowski 			 duplex_wanted == DUPLEX_FULL)
3147*1b481fc3SMaciej Żenczykowski 			adv_bit = ETHTOOL_LINK_MODE_2500baseX_Full_BIT;
3148*1b481fc3SMaciej Żenczykowski 		else if (speed_wanted == SPEED_10000 &&
3149*1b481fc3SMaciej Żenczykowski 			 duplex_wanted == DUPLEX_FULL)
3150*1b481fc3SMaciej Żenczykowski 			adv_bit = ETHTOOL_LINK_MODE_10000baseT_Full_BIT;
3151*1b481fc3SMaciej Żenczykowski 
3152*1b481fc3SMaciej Żenczykowski 		if (adv_bit >= 0) {
3153*1b481fc3SMaciej Żenczykowski 			advertising_wanted = mask_advertising_wanted;
3154*1b481fc3SMaciej Żenczykowski 			ethtool_link_mode_zero(advertising_wanted);
3155*1b481fc3SMaciej Żenczykowski 			ethtool_link_mode_set_bit(
3156*1b481fc3SMaciej Żenczykowski 				adv_bit, advertising_wanted);
3157*1b481fc3SMaciej Żenczykowski 		}
3158*1b481fc3SMaciej Żenczykowski 		/* otherwise: auto negotiate without forcing,
3159*1b481fc3SMaciej Żenczykowski 		 * all supported speed will be assigned below
3160*1b481fc3SMaciej Żenczykowski 		 */
3161*1b481fc3SMaciej Żenczykowski 	}
3162*1b481fc3SMaciej Żenczykowski 
3163*1b481fc3SMaciej Żenczykowski 	if (gset_changed) {
3164*1b481fc3SMaciej Żenczykowski 		struct ethtool_link_usettings *link_usettings;
3165*1b481fc3SMaciej Żenczykowski 
3166*1b481fc3SMaciej Żenczykowski 		link_usettings = do_ioctl_glinksettings(ctx);
3167*1b481fc3SMaciej Żenczykowski 		if (link_usettings == NULL)
3168*1b481fc3SMaciej Żenczykowski 			link_usettings = do_ioctl_gset(ctx);
3169*1b481fc3SMaciej Żenczykowski 		else
3170*1b481fc3SMaciej Żenczykowski 			memset(&link_usettings->deprecated, 0,
3171*1b481fc3SMaciej Żenczykowski 			       sizeof(link_usettings->deprecated));
3172*1b481fc3SMaciej Żenczykowski 		if (link_usettings == NULL) {
3173*1b481fc3SMaciej Żenczykowski 			perror("Cannot get current device settings");
3174*1b481fc3SMaciej Żenczykowski 			err = -1;
3175*1b481fc3SMaciej Żenczykowski 		} else {
3176*1b481fc3SMaciej Żenczykowski 			/* Change everything the user specified. */
3177*1b481fc3SMaciej Żenczykowski 			if (speed_wanted != -1)
3178*1b481fc3SMaciej Żenczykowski 				link_usettings->base.speed = speed_wanted;
3179*1b481fc3SMaciej Żenczykowski 			if (duplex_wanted != -1)
3180*1b481fc3SMaciej Żenczykowski 				link_usettings->base.duplex = duplex_wanted;
3181*1b481fc3SMaciej Żenczykowski 			if (port_wanted != -1)
3182*1b481fc3SMaciej Żenczykowski 				link_usettings->base.port = port_wanted;
3183*1b481fc3SMaciej Żenczykowski 			if (mdix_wanted != -1) {
3184*1b481fc3SMaciej Żenczykowski 				/* check driver supports MDI-X */
3185*1b481fc3SMaciej Żenczykowski 				if (link_usettings->base.eth_tp_mdix_ctrl
3186*1b481fc3SMaciej Żenczykowski 				    != ETH_TP_MDI_INVALID)
3187*1b481fc3SMaciej Żenczykowski 					link_usettings->base.eth_tp_mdix_ctrl
3188*1b481fc3SMaciej Żenczykowski 						= mdix_wanted;
3189*1b481fc3SMaciej Żenczykowski 				else
3190*1b481fc3SMaciej Żenczykowski 					fprintf(stderr,
3191*1b481fc3SMaciej Żenczykowski 						"setting MDI not supported\n");
3192*1b481fc3SMaciej Żenczykowski 			}
3193*1b481fc3SMaciej Żenczykowski 			if (autoneg_wanted != -1)
3194*1b481fc3SMaciej Żenczykowski 				link_usettings->base.autoneg = autoneg_wanted;
3195*1b481fc3SMaciej Żenczykowski 			if (phyad_wanted != -1)
3196*1b481fc3SMaciej Żenczykowski 				link_usettings->base.phy_address = phyad_wanted;
3197*1b481fc3SMaciej Żenczykowski 			if (xcvr_wanted != -1)
3198*1b481fc3SMaciej Żenczykowski 				link_usettings->deprecated.transceiver
3199*1b481fc3SMaciej Żenczykowski 					= xcvr_wanted;
3200*1b481fc3SMaciej Żenczykowski 			/* XXX If the user specified speed or duplex
3201*1b481fc3SMaciej Żenczykowski 			 * then we should mask the advertised modes
3202*1b481fc3SMaciej Żenczykowski 			 * accordingly.  For now, warn that we aren't
3203*1b481fc3SMaciej Żenczykowski 			 * doing that.
3204*1b481fc3SMaciej Żenczykowski 			 */
3205*1b481fc3SMaciej Żenczykowski 			if ((speed_wanted != -1 || duplex_wanted != -1) &&
3206*1b481fc3SMaciej Żenczykowski 			    link_usettings->base.autoneg &&
3207*1b481fc3SMaciej Żenczykowski 			    advertising_wanted == NULL) {
3208*1b481fc3SMaciej Żenczykowski 				fprintf(stderr, "Cannot advertise");
3209*1b481fc3SMaciej Żenczykowski 				if (speed_wanted >= 0)
3210*1b481fc3SMaciej Żenczykowski 					fprintf(stderr, " speed %d",
3211*1b481fc3SMaciej Żenczykowski 						speed_wanted);
3212*1b481fc3SMaciej Żenczykowski 				if (duplex_wanted >= 0)
3213*1b481fc3SMaciej Żenczykowski 					fprintf(stderr, " duplex %s",
3214*1b481fc3SMaciej Żenczykowski 						duplex_wanted ?
3215*1b481fc3SMaciej Żenczykowski 						"full" : "half");
3216*1b481fc3SMaciej Żenczykowski 				fprintf(stderr,	"\n");
3217*1b481fc3SMaciej Żenczykowski 			}
3218*1b481fc3SMaciej Żenczykowski 			if (autoneg_wanted == AUTONEG_ENABLE &&
3219*1b481fc3SMaciej Żenczykowski 			    advertising_wanted == NULL &&
3220*1b481fc3SMaciej Żenczykowski 			    full_advertising_wanted == NULL) {
3221*1b481fc3SMaciej Żenczykowski 				unsigned int i;
3222*1b481fc3SMaciej Żenczykowski 
3223*1b481fc3SMaciej Żenczykowski 				/* Auto negotiation enabled, but with
3224*1b481fc3SMaciej Żenczykowski 				 * unspecified speed and duplex: enable all
3225*1b481fc3SMaciej Żenczykowski 				 * supported speeds and duplexes.
3226*1b481fc3SMaciej Żenczykowski 				 */
3227*1b481fc3SMaciej Żenczykowski 				ethtool_link_mode_for_each_u32(i) {
3228*1b481fc3SMaciej Żenczykowski 					u32 sup = link_usettings->link_modes.supported[i];
3229*1b481fc3SMaciej Żenczykowski 					u32 *adv = link_usettings->link_modes.advertising + i;
3230*1b481fc3SMaciej Żenczykowski 
3231*1b481fc3SMaciej Żenczykowski 					*adv = ((*adv & ~all_advertised_modes[i])
3232*1b481fc3SMaciej Żenczykowski 						| (sup & all_advertised_modes[i]));
3233*1b481fc3SMaciej Żenczykowski 				}
3234*1b481fc3SMaciej Żenczykowski 
3235*1b481fc3SMaciej Żenczykowski 				/* If driver supports unknown flags, we cannot
3236*1b481fc3SMaciej Żenczykowski 				 * be sure that we enable all link modes.
3237*1b481fc3SMaciej Żenczykowski 				 */
3238*1b481fc3SMaciej Żenczykowski 				ethtool_link_mode_for_each_u32(i) {
3239*1b481fc3SMaciej Żenczykowski 					u32 sup = link_usettings->link_modes.supported[i];
3240*1b481fc3SMaciej Żenczykowski 
3241*1b481fc3SMaciej Żenczykowski 					if ((sup & all_advertised_flags[i]) != sup) {
3242*1b481fc3SMaciej Żenczykowski 						fprintf(stderr, "Driver supports one or more unknown flags\n");
3243*1b481fc3SMaciej Żenczykowski 						break;
3244*1b481fc3SMaciej Żenczykowski 					}
3245*1b481fc3SMaciej Żenczykowski 				}
3246*1b481fc3SMaciej Żenczykowski 			} else if (advertising_wanted != NULL) {
3247*1b481fc3SMaciej Żenczykowski 				unsigned int i;
3248*1b481fc3SMaciej Żenczykowski 
3249*1b481fc3SMaciej Żenczykowski 				/* Enable all requested modes */
3250*1b481fc3SMaciej Żenczykowski 				ethtool_link_mode_for_each_u32(i) {
3251*1b481fc3SMaciej Żenczykowski 					u32 *adv = link_usettings->link_modes.advertising + i;
3252*1b481fc3SMaciej Żenczykowski 
3253*1b481fc3SMaciej Żenczykowski 					*adv = ((*adv & ~all_advertised_modes[i])
3254*1b481fc3SMaciej Żenczykowski 						| advertising_wanted[i]);
3255*1b481fc3SMaciej Żenczykowski 				}
3256*1b481fc3SMaciej Żenczykowski 			} else if (full_advertising_wanted != NULL) {
3257*1b481fc3SMaciej Żenczykowski 				ethtool_link_mode_copy(
3258*1b481fc3SMaciej Żenczykowski 					link_usettings->link_modes.advertising,
3259*1b481fc3SMaciej Żenczykowski 					full_advertising_wanted);
3260*1b481fc3SMaciej Żenczykowski 			}
3261*1b481fc3SMaciej Żenczykowski 
3262*1b481fc3SMaciej Żenczykowski 			/* Try to perform the update. */
3263*1b481fc3SMaciej Żenczykowski 			if (link_usettings->base.cmd == ETHTOOL_GLINKSETTINGS)
3264*1b481fc3SMaciej Żenczykowski 				err = do_ioctl_slinksettings(ctx,
3265*1b481fc3SMaciej Żenczykowski 							     link_usettings);
3266*1b481fc3SMaciej Żenczykowski 			else
3267*1b481fc3SMaciej Żenczykowski 				err = do_ioctl_sset(ctx, link_usettings);
3268*1b481fc3SMaciej Żenczykowski 			free(link_usettings);
3269*1b481fc3SMaciej Żenczykowski 			if (err < 0)
3270*1b481fc3SMaciej Żenczykowski 				perror("Cannot set new settings");
3271*1b481fc3SMaciej Żenczykowski 		}
3272*1b481fc3SMaciej Żenczykowski 		if (err < 0) {
3273*1b481fc3SMaciej Żenczykowski 			if (speed_wanted != -1)
3274*1b481fc3SMaciej Żenczykowski 				fprintf(stderr, "  not setting speed\n");
3275*1b481fc3SMaciej Żenczykowski 			if (duplex_wanted != -1)
3276*1b481fc3SMaciej Żenczykowski 				fprintf(stderr, "  not setting duplex\n");
3277*1b481fc3SMaciej Żenczykowski 			if (port_wanted != -1)
3278*1b481fc3SMaciej Żenczykowski 				fprintf(stderr, "  not setting port\n");
3279*1b481fc3SMaciej Żenczykowski 			if (autoneg_wanted != -1)
3280*1b481fc3SMaciej Żenczykowski 				fprintf(stderr, "  not setting autoneg\n");
3281*1b481fc3SMaciej Żenczykowski 			if (phyad_wanted != -1)
3282*1b481fc3SMaciej Żenczykowski 				fprintf(stderr, "  not setting phy_address\n");
3283*1b481fc3SMaciej Żenczykowski 			if (xcvr_wanted != -1)
3284*1b481fc3SMaciej Żenczykowski 				fprintf(stderr, "  not setting transceiver\n");
3285*1b481fc3SMaciej Żenczykowski 			if (mdix_wanted != -1)
3286*1b481fc3SMaciej Żenczykowski 				fprintf(stderr, "  not setting mdix\n");
3287*1b481fc3SMaciej Żenczykowski 		}
3288*1b481fc3SMaciej Żenczykowski 	}
3289*1b481fc3SMaciej Żenczykowski 
3290*1b481fc3SMaciej Żenczykowski 	if (gwol_changed) {
3291*1b481fc3SMaciej Żenczykowski 		struct ethtool_wolinfo wol;
3292*1b481fc3SMaciej Żenczykowski 
3293*1b481fc3SMaciej Żenczykowski 		wol.cmd = ETHTOOL_GWOL;
3294*1b481fc3SMaciej Żenczykowski 		err = send_ioctl(ctx, &wol);
3295*1b481fc3SMaciej Żenczykowski 		if (err < 0) {
3296*1b481fc3SMaciej Żenczykowski 			perror("Cannot get current wake-on-lan settings");
3297*1b481fc3SMaciej Żenczykowski 		} else {
3298*1b481fc3SMaciej Żenczykowski 			/* Change everything the user specified. */
3299*1b481fc3SMaciej Żenczykowski 			if (wol_change)
3300*1b481fc3SMaciej Żenczykowski 				wol.wolopts = wol_wanted;
3301*1b481fc3SMaciej Żenczykowski 			if (sopass_change) {
3302*1b481fc3SMaciej Żenczykowski 				int i;
3303*1b481fc3SMaciej Żenczykowski 				for (i = 0; i < SOPASS_MAX; i++)
3304*1b481fc3SMaciej Żenczykowski 					wol.sopass[i] = sopass_wanted[i];
3305*1b481fc3SMaciej Żenczykowski 			}
3306*1b481fc3SMaciej Żenczykowski 
3307*1b481fc3SMaciej Żenczykowski 			/* Try to perform the update. */
3308*1b481fc3SMaciej Żenczykowski 			wol.cmd = ETHTOOL_SWOL;
3309*1b481fc3SMaciej Żenczykowski 			err = send_ioctl(ctx, &wol);
3310*1b481fc3SMaciej Żenczykowski 			if (err < 0)
3311*1b481fc3SMaciej Żenczykowski 				perror("Cannot set new wake-on-lan settings");
3312*1b481fc3SMaciej Żenczykowski 		}
3313*1b481fc3SMaciej Żenczykowski 		if (err < 0) {
3314*1b481fc3SMaciej Żenczykowski 			if (wol_change)
3315*1b481fc3SMaciej Żenczykowski 				fprintf(stderr, "  not setting wol\n");
3316*1b481fc3SMaciej Żenczykowski 			if (sopass_change)
3317*1b481fc3SMaciej Żenczykowski 				fprintf(stderr, "  not setting sopass\n");
3318*1b481fc3SMaciej Żenczykowski 		}
3319*1b481fc3SMaciej Żenczykowski 	}
3320*1b481fc3SMaciej Żenczykowski 
3321*1b481fc3SMaciej Żenczykowski 	if (msglvl_changed) {
3322*1b481fc3SMaciej Żenczykowski 		struct ethtool_value edata;
3323*1b481fc3SMaciej Żenczykowski 
3324*1b481fc3SMaciej Żenczykowski 		edata.cmd = ETHTOOL_GMSGLVL;
3325*1b481fc3SMaciej Żenczykowski 		err = send_ioctl(ctx, &edata);
3326*1b481fc3SMaciej Żenczykowski 		if (err < 0) {
3327*1b481fc3SMaciej Żenczykowski 			perror("Cannot get msglvl");
3328*1b481fc3SMaciej Żenczykowski 		} else {
3329*1b481fc3SMaciej Żenczykowski 			edata.cmd = ETHTOOL_SMSGLVL;
3330*1b481fc3SMaciej Żenczykowski 			edata.data = ((edata.data & ~msglvl_mask) |
3331*1b481fc3SMaciej Żenczykowski 				      msglvl_wanted);
3332*1b481fc3SMaciej Żenczykowski 			err = send_ioctl(ctx, &edata);
3333*1b481fc3SMaciej Żenczykowski 			if (err < 0)
3334*1b481fc3SMaciej Żenczykowski 				perror("Cannot set new msglvl");
3335*1b481fc3SMaciej Żenczykowski 		}
3336*1b481fc3SMaciej Żenczykowski 	}
3337*1b481fc3SMaciej Żenczykowski 
3338*1b481fc3SMaciej Żenczykowski 	return 0;
3339*1b481fc3SMaciej Żenczykowski }
3340*1b481fc3SMaciej Żenczykowski 
do_gregs(struct cmd_context * ctx)3341*1b481fc3SMaciej Żenczykowski static int do_gregs(struct cmd_context *ctx)
3342*1b481fc3SMaciej Żenczykowski {
3343*1b481fc3SMaciej Żenczykowski 	int gregs_changed = 0;
3344*1b481fc3SMaciej Żenczykowski 	int gregs_dump_raw = 0;
3345*1b481fc3SMaciej Żenczykowski 	int gregs_dump_hex = 0;
3346*1b481fc3SMaciej Żenczykowski 	char *gregs_dump_file = NULL;
3347*1b481fc3SMaciej Żenczykowski 	struct cmdline_info cmdline_gregs[] = {
3348*1b481fc3SMaciej Żenczykowski 		{
3349*1b481fc3SMaciej Żenczykowski 			.name		= "raw",
3350*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_BOOL,
3351*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &gregs_dump_raw,
3352*1b481fc3SMaciej Żenczykowski 		},
3353*1b481fc3SMaciej Żenczykowski 		{
3354*1b481fc3SMaciej Żenczykowski 			.name		= "hex",
3355*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_BOOL,
3356*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &gregs_dump_hex,
3357*1b481fc3SMaciej Żenczykowski 		},
3358*1b481fc3SMaciej Żenczykowski 		{
3359*1b481fc3SMaciej Żenczykowski 			.name		= "file",
3360*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_STR,
3361*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &gregs_dump_file,
3362*1b481fc3SMaciej Żenczykowski 		},
3363*1b481fc3SMaciej Żenczykowski 	};
3364*1b481fc3SMaciej Żenczykowski 	int err;
3365*1b481fc3SMaciej Żenczykowski 	struct ethtool_drvinfo drvinfo;
3366*1b481fc3SMaciej Żenczykowski 	struct ethtool_regs *regs;
3367*1b481fc3SMaciej Żenczykowski 
3368*1b481fc3SMaciej Żenczykowski 	parse_generic_cmdline(ctx, &gregs_changed,
3369*1b481fc3SMaciej Żenczykowski 			      cmdline_gregs, ARRAY_SIZE(cmdline_gregs));
3370*1b481fc3SMaciej Żenczykowski 
3371*1b481fc3SMaciej Żenczykowski 	drvinfo.cmd = ETHTOOL_GDRVINFO;
3372*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &drvinfo);
3373*1b481fc3SMaciej Żenczykowski 	if (err < 0) {
3374*1b481fc3SMaciej Żenczykowski 		perror("Cannot get driver information");
3375*1b481fc3SMaciej Żenczykowski 		return 72;
3376*1b481fc3SMaciej Żenczykowski 	}
3377*1b481fc3SMaciej Żenczykowski 
3378*1b481fc3SMaciej Żenczykowski 	regs = calloc(1, sizeof(*regs)+drvinfo.regdump_len);
3379*1b481fc3SMaciej Żenczykowski 	if (!regs) {
3380*1b481fc3SMaciej Żenczykowski 		perror("Cannot allocate memory for register dump");
3381*1b481fc3SMaciej Żenczykowski 		return 73;
3382*1b481fc3SMaciej Żenczykowski 	}
3383*1b481fc3SMaciej Żenczykowski 	regs->cmd = ETHTOOL_GREGS;
3384*1b481fc3SMaciej Żenczykowski 	regs->len = drvinfo.regdump_len;
3385*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, regs);
3386*1b481fc3SMaciej Żenczykowski 	if (err < 0) {
3387*1b481fc3SMaciej Żenczykowski 		perror("Cannot get register dump");
3388*1b481fc3SMaciej Żenczykowski 		free(regs);
3389*1b481fc3SMaciej Żenczykowski 		return 74;
3390*1b481fc3SMaciej Żenczykowski 	}
3391*1b481fc3SMaciej Żenczykowski 
3392*1b481fc3SMaciej Żenczykowski 	if (!gregs_dump_raw && gregs_dump_file != NULL) {
3393*1b481fc3SMaciej Żenczykowski 		/* overwrite reg values from file dump */
3394*1b481fc3SMaciej Żenczykowski 		FILE *f = fopen(gregs_dump_file, "r");
3395*1b481fc3SMaciej Żenczykowski 		struct ethtool_regs *nregs;
3396*1b481fc3SMaciej Żenczykowski 		struct stat st;
3397*1b481fc3SMaciej Żenczykowski 		size_t nread;
3398*1b481fc3SMaciej Żenczykowski 
3399*1b481fc3SMaciej Żenczykowski 		if (!f || fstat(fileno(f), &st) < 0) {
3400*1b481fc3SMaciej Żenczykowski 			fprintf(stderr, "Can't open '%s': %s\n",
3401*1b481fc3SMaciej Żenczykowski 				gregs_dump_file, strerror(errno));
3402*1b481fc3SMaciej Żenczykowski 			if (f)
3403*1b481fc3SMaciej Żenczykowski 				fclose(f);
3404*1b481fc3SMaciej Żenczykowski 			free(regs);
3405*1b481fc3SMaciej Żenczykowski 			return 75;
3406*1b481fc3SMaciej Żenczykowski 		}
3407*1b481fc3SMaciej Żenczykowski 
3408*1b481fc3SMaciej Żenczykowski 		nregs = realloc(regs, sizeof(*regs) + st.st_size);
3409*1b481fc3SMaciej Żenczykowski 		if (!nregs) {
3410*1b481fc3SMaciej Żenczykowski 			perror("Cannot allocate memory for register dump");
3411*1b481fc3SMaciej Żenczykowski 			free(regs); /* was not freed by realloc */
3412*1b481fc3SMaciej Żenczykowski 			return 73;
3413*1b481fc3SMaciej Żenczykowski 		}
3414*1b481fc3SMaciej Żenczykowski 		regs = nregs;
3415*1b481fc3SMaciej Żenczykowski 		regs->len = st.st_size;
3416*1b481fc3SMaciej Żenczykowski 		nread = fread(regs->data, regs->len, 1, f);
3417*1b481fc3SMaciej Żenczykowski 		fclose(f);
3418*1b481fc3SMaciej Żenczykowski 		if (nread != 1) {
3419*1b481fc3SMaciej Żenczykowski 			free(regs);
3420*1b481fc3SMaciej Żenczykowski 			return 75;
3421*1b481fc3SMaciej Żenczykowski 		}
3422*1b481fc3SMaciej Żenczykowski 	}
3423*1b481fc3SMaciej Żenczykowski 
3424*1b481fc3SMaciej Żenczykowski 	if (dump_regs(gregs_dump_raw, gregs_dump_hex,
3425*1b481fc3SMaciej Żenczykowski 		      &drvinfo, regs) < 0) {
3426*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "Cannot dump registers\n");
3427*1b481fc3SMaciej Żenczykowski 		free(regs);
3428*1b481fc3SMaciej Żenczykowski 		return 75;
3429*1b481fc3SMaciej Żenczykowski 	}
3430*1b481fc3SMaciej Żenczykowski 	free(regs);
3431*1b481fc3SMaciej Żenczykowski 
3432*1b481fc3SMaciej Żenczykowski 	return 0;
3433*1b481fc3SMaciej Żenczykowski }
3434*1b481fc3SMaciej Żenczykowski 
do_nway_rst(struct cmd_context * ctx)3435*1b481fc3SMaciej Żenczykowski static int do_nway_rst(struct cmd_context *ctx)
3436*1b481fc3SMaciej Żenczykowski {
3437*1b481fc3SMaciej Żenczykowski 	struct ethtool_value edata;
3438*1b481fc3SMaciej Żenczykowski 	int err;
3439*1b481fc3SMaciej Żenczykowski 
3440*1b481fc3SMaciej Żenczykowski 	if (ctx->argc != 0)
3441*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
3442*1b481fc3SMaciej Żenczykowski 
3443*1b481fc3SMaciej Żenczykowski 	edata.cmd = ETHTOOL_NWAY_RST;
3444*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &edata);
3445*1b481fc3SMaciej Żenczykowski 	if (err < 0)
3446*1b481fc3SMaciej Żenczykowski 		perror("Cannot restart autonegotiation");
3447*1b481fc3SMaciej Żenczykowski 
3448*1b481fc3SMaciej Żenczykowski 	return err;
3449*1b481fc3SMaciej Żenczykowski }
3450*1b481fc3SMaciej Żenczykowski 
do_geeprom(struct cmd_context * ctx)3451*1b481fc3SMaciej Żenczykowski static int do_geeprom(struct cmd_context *ctx)
3452*1b481fc3SMaciej Żenczykowski {
3453*1b481fc3SMaciej Żenczykowski 	int geeprom_changed = 0;
3454*1b481fc3SMaciej Żenczykowski 	int geeprom_dump_raw = 0;
3455*1b481fc3SMaciej Żenczykowski 	u32 geeprom_offset = 0;
3456*1b481fc3SMaciej Żenczykowski 	u32 geeprom_length = 0;
3457*1b481fc3SMaciej Żenczykowski 	int geeprom_length_seen = 0;
3458*1b481fc3SMaciej Żenczykowski 	struct cmdline_info cmdline_geeprom[] = {
3459*1b481fc3SMaciej Żenczykowski 		{
3460*1b481fc3SMaciej Żenczykowski 			.name		= "offset",
3461*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_U32,
3462*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &geeprom_offset,
3463*1b481fc3SMaciej Żenczykowski 		},
3464*1b481fc3SMaciej Żenczykowski 		{
3465*1b481fc3SMaciej Żenczykowski 			.name		= "length",
3466*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_U32,
3467*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &geeprom_length,
3468*1b481fc3SMaciej Żenczykowski 			.seen_val	= &geeprom_length_seen,
3469*1b481fc3SMaciej Żenczykowski 		},
3470*1b481fc3SMaciej Żenczykowski 		{
3471*1b481fc3SMaciej Żenczykowski 			.name		= "raw",
3472*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_BOOL,
3473*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &geeprom_dump_raw,
3474*1b481fc3SMaciej Żenczykowski 		},
3475*1b481fc3SMaciej Żenczykowski 	};
3476*1b481fc3SMaciej Żenczykowski 	int err;
3477*1b481fc3SMaciej Żenczykowski 	struct ethtool_drvinfo drvinfo;
3478*1b481fc3SMaciej Żenczykowski 	struct ethtool_eeprom *eeprom;
3479*1b481fc3SMaciej Żenczykowski 
3480*1b481fc3SMaciej Żenczykowski 	parse_generic_cmdline(ctx, &geeprom_changed,
3481*1b481fc3SMaciej Żenczykowski 			      cmdline_geeprom, ARRAY_SIZE(cmdline_geeprom));
3482*1b481fc3SMaciej Żenczykowski 
3483*1b481fc3SMaciej Żenczykowski 	drvinfo.cmd = ETHTOOL_GDRVINFO;
3484*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &drvinfo);
3485*1b481fc3SMaciej Żenczykowski 	if (err < 0) {
3486*1b481fc3SMaciej Żenczykowski 		perror("Cannot get driver information");
3487*1b481fc3SMaciej Żenczykowski 		return 74;
3488*1b481fc3SMaciej Żenczykowski 	}
3489*1b481fc3SMaciej Żenczykowski 
3490*1b481fc3SMaciej Żenczykowski 	if (!geeprom_length_seen)
3491*1b481fc3SMaciej Żenczykowski 		geeprom_length = drvinfo.eedump_len;
3492*1b481fc3SMaciej Żenczykowski 
3493*1b481fc3SMaciej Żenczykowski 	if (drvinfo.eedump_len < geeprom_offset + geeprom_length)
3494*1b481fc3SMaciej Żenczykowski 		geeprom_length = drvinfo.eedump_len - geeprom_offset;
3495*1b481fc3SMaciej Żenczykowski 
3496*1b481fc3SMaciej Żenczykowski 	eeprom = calloc(1, sizeof(*eeprom)+geeprom_length);
3497*1b481fc3SMaciej Żenczykowski 	if (!eeprom) {
3498*1b481fc3SMaciej Żenczykowski 		perror("Cannot allocate memory for EEPROM data");
3499*1b481fc3SMaciej Żenczykowski 		return 75;
3500*1b481fc3SMaciej Żenczykowski 	}
3501*1b481fc3SMaciej Żenczykowski 	eeprom->cmd = ETHTOOL_GEEPROM;
3502*1b481fc3SMaciej Żenczykowski 	eeprom->len = geeprom_length;
3503*1b481fc3SMaciej Żenczykowski 	eeprom->offset = geeprom_offset;
3504*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, eeprom);
3505*1b481fc3SMaciej Żenczykowski 	if (err < 0) {
3506*1b481fc3SMaciej Żenczykowski 		perror("Cannot get EEPROM data");
3507*1b481fc3SMaciej Żenczykowski 		free(eeprom);
3508*1b481fc3SMaciej Żenczykowski 		return 74;
3509*1b481fc3SMaciej Żenczykowski 	}
3510*1b481fc3SMaciej Żenczykowski 	err = dump_eeprom(geeprom_dump_raw, &drvinfo, eeprom);
3511*1b481fc3SMaciej Żenczykowski 	free(eeprom);
3512*1b481fc3SMaciej Żenczykowski 
3513*1b481fc3SMaciej Żenczykowski 	return err;
3514*1b481fc3SMaciej Żenczykowski }
3515*1b481fc3SMaciej Żenczykowski 
do_seeprom(struct cmd_context * ctx)3516*1b481fc3SMaciej Żenczykowski static int do_seeprom(struct cmd_context *ctx)
3517*1b481fc3SMaciej Żenczykowski {
3518*1b481fc3SMaciej Żenczykowski 	int seeprom_changed = 0;
3519*1b481fc3SMaciej Żenczykowski 	u32 seeprom_magic = 0;
3520*1b481fc3SMaciej Żenczykowski 	u32 seeprom_length = 0;
3521*1b481fc3SMaciej Żenczykowski 	u32 seeprom_offset = 0;
3522*1b481fc3SMaciej Żenczykowski 	u8 seeprom_value = 0;
3523*1b481fc3SMaciej Żenczykowski 	int seeprom_length_seen = 0;
3524*1b481fc3SMaciej Żenczykowski 	int seeprom_value_seen = 0;
3525*1b481fc3SMaciej Żenczykowski 	struct cmdline_info cmdline_seeprom[] = {
3526*1b481fc3SMaciej Żenczykowski 		{
3527*1b481fc3SMaciej Żenczykowski 			.name		= "magic",
3528*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_U32,
3529*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &seeprom_magic,
3530*1b481fc3SMaciej Żenczykowski 		},
3531*1b481fc3SMaciej Żenczykowski 		{
3532*1b481fc3SMaciej Żenczykowski 			.name		= "offset",
3533*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_U32,
3534*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &seeprom_offset,
3535*1b481fc3SMaciej Żenczykowski 		},
3536*1b481fc3SMaciej Żenczykowski 		{
3537*1b481fc3SMaciej Żenczykowski 			.name		= "length",
3538*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_U32,
3539*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &seeprom_length,
3540*1b481fc3SMaciej Żenczykowski 			.seen_val	= &seeprom_length_seen,
3541*1b481fc3SMaciej Żenczykowski 		},
3542*1b481fc3SMaciej Żenczykowski 		{
3543*1b481fc3SMaciej Żenczykowski 			.name		= "value",
3544*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_U8,
3545*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &seeprom_value,
3546*1b481fc3SMaciej Żenczykowski 			.seen_val	= &seeprom_value_seen,
3547*1b481fc3SMaciej Żenczykowski 		},
3548*1b481fc3SMaciej Żenczykowski 	};
3549*1b481fc3SMaciej Żenczykowski 	int err;
3550*1b481fc3SMaciej Żenczykowski 	struct ethtool_drvinfo drvinfo;
3551*1b481fc3SMaciej Żenczykowski 	struct ethtool_eeprom *eeprom;
3552*1b481fc3SMaciej Żenczykowski 
3553*1b481fc3SMaciej Żenczykowski 	parse_generic_cmdline(ctx, &seeprom_changed,
3554*1b481fc3SMaciej Żenczykowski 			      cmdline_seeprom, ARRAY_SIZE(cmdline_seeprom));
3555*1b481fc3SMaciej Żenczykowski 
3556*1b481fc3SMaciej Żenczykowski 	drvinfo.cmd = ETHTOOL_GDRVINFO;
3557*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &drvinfo);
3558*1b481fc3SMaciej Żenczykowski 	if (err < 0) {
3559*1b481fc3SMaciej Żenczykowski 		perror("Cannot get driver information");
3560*1b481fc3SMaciej Żenczykowski 		return 74;
3561*1b481fc3SMaciej Żenczykowski 	}
3562*1b481fc3SMaciej Żenczykowski 
3563*1b481fc3SMaciej Żenczykowski 	if (seeprom_value_seen && !seeprom_length_seen)
3564*1b481fc3SMaciej Żenczykowski 		seeprom_length = 1;
3565*1b481fc3SMaciej Żenczykowski 	else if (!seeprom_length_seen)
3566*1b481fc3SMaciej Żenczykowski 		seeprom_length = drvinfo.eedump_len;
3567*1b481fc3SMaciej Żenczykowski 
3568*1b481fc3SMaciej Żenczykowski 	if (seeprom_value_seen && (seeprom_length != 1)) {
3569*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "value requires length 1\n");
3570*1b481fc3SMaciej Żenczykowski 		return 1;
3571*1b481fc3SMaciej Żenczykowski 	}
3572*1b481fc3SMaciej Żenczykowski 
3573*1b481fc3SMaciej Żenczykowski 	if (drvinfo.eedump_len < seeprom_offset + seeprom_length) {
3574*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "offset & length out of bounds\n");
3575*1b481fc3SMaciej Żenczykowski 		return 1;
3576*1b481fc3SMaciej Żenczykowski 	}
3577*1b481fc3SMaciej Żenczykowski 
3578*1b481fc3SMaciej Żenczykowski 	eeprom = calloc(1, sizeof(*eeprom)+seeprom_length);
3579*1b481fc3SMaciej Żenczykowski 	if (!eeprom) {
3580*1b481fc3SMaciej Żenczykowski 		perror("Cannot allocate memory for EEPROM data");
3581*1b481fc3SMaciej Żenczykowski 		return 75;
3582*1b481fc3SMaciej Żenczykowski 	}
3583*1b481fc3SMaciej Żenczykowski 
3584*1b481fc3SMaciej Żenczykowski 	eeprom->cmd = ETHTOOL_SEEPROM;
3585*1b481fc3SMaciej Żenczykowski 	eeprom->len = seeprom_length;
3586*1b481fc3SMaciej Żenczykowski 	eeprom->offset = seeprom_offset;
3587*1b481fc3SMaciej Żenczykowski 	eeprom->magic = seeprom_magic;
3588*1b481fc3SMaciej Żenczykowski 	eeprom->data[0] = seeprom_value;
3589*1b481fc3SMaciej Żenczykowski 
3590*1b481fc3SMaciej Żenczykowski 	/* Multi-byte write: read input from stdin */
3591*1b481fc3SMaciej Żenczykowski 	if (!seeprom_value_seen) {
3592*1b481fc3SMaciej Żenczykowski 		if (fread(eeprom->data, eeprom->len, 1, stdin) != 1) {
3593*1b481fc3SMaciej Żenczykowski 			fprintf(stderr, "not enough data from stdin\n");
3594*1b481fc3SMaciej Żenczykowski 			free(eeprom);
3595*1b481fc3SMaciej Żenczykowski 			return 75;
3596*1b481fc3SMaciej Żenczykowski 		}
3597*1b481fc3SMaciej Żenczykowski 		if ((fgetc(stdin) != EOF) || !feof(stdin)) {
3598*1b481fc3SMaciej Żenczykowski 			fprintf(stderr, "too much data from stdin\n");
3599*1b481fc3SMaciej Żenczykowski 			free(eeprom);
3600*1b481fc3SMaciej Żenczykowski 			return 75;
3601*1b481fc3SMaciej Żenczykowski 		}
3602*1b481fc3SMaciej Żenczykowski 	}
3603*1b481fc3SMaciej Żenczykowski 
3604*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, eeprom);
3605*1b481fc3SMaciej Żenczykowski 	if (err < 0) {
3606*1b481fc3SMaciej Żenczykowski 		perror("Cannot set EEPROM data");
3607*1b481fc3SMaciej Żenczykowski 		err = 87;
3608*1b481fc3SMaciej Żenczykowski 	}
3609*1b481fc3SMaciej Żenczykowski 	free(eeprom);
3610*1b481fc3SMaciej Żenczykowski 
3611*1b481fc3SMaciej Żenczykowski 	return err;
3612*1b481fc3SMaciej Żenczykowski }
3613*1b481fc3SMaciej Żenczykowski 
do_test(struct cmd_context * ctx)3614*1b481fc3SMaciej Żenczykowski static int do_test(struct cmd_context *ctx)
3615*1b481fc3SMaciej Żenczykowski {
3616*1b481fc3SMaciej Żenczykowski 	enum {
3617*1b481fc3SMaciej Żenczykowski 		ONLINE = 0,
3618*1b481fc3SMaciej Żenczykowski 		OFFLINE,
3619*1b481fc3SMaciej Żenczykowski 		EXTERNAL_LB,
3620*1b481fc3SMaciej Żenczykowski 	} test_type;
3621*1b481fc3SMaciej Żenczykowski 	int err;
3622*1b481fc3SMaciej Żenczykowski 	struct ethtool_test *test;
3623*1b481fc3SMaciej Żenczykowski 	struct ethtool_gstrings *strings;
3624*1b481fc3SMaciej Żenczykowski 
3625*1b481fc3SMaciej Żenczykowski 	if (ctx->argc > 1)
3626*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
3627*1b481fc3SMaciej Żenczykowski 	if (ctx->argc == 1) {
3628*1b481fc3SMaciej Żenczykowski 		if (!strcmp(ctx->argp[0], "online"))
3629*1b481fc3SMaciej Żenczykowski 			test_type = ONLINE;
3630*1b481fc3SMaciej Żenczykowski 		else if (!strcmp(*ctx->argp, "offline"))
3631*1b481fc3SMaciej Żenczykowski 			test_type = OFFLINE;
3632*1b481fc3SMaciej Żenczykowski 		else if (!strcmp(*ctx->argp, "external_lb"))
3633*1b481fc3SMaciej Żenczykowski 			test_type = EXTERNAL_LB;
3634*1b481fc3SMaciej Żenczykowski 		else
3635*1b481fc3SMaciej Żenczykowski 			exit_bad_args();
3636*1b481fc3SMaciej Żenczykowski 	} else {
3637*1b481fc3SMaciej Żenczykowski 		test_type = OFFLINE;
3638*1b481fc3SMaciej Żenczykowski 	}
3639*1b481fc3SMaciej Żenczykowski 
3640*1b481fc3SMaciej Żenczykowski 	strings = get_stringset(ctx, ETH_SS_TEST,
3641*1b481fc3SMaciej Żenczykowski 				offsetof(struct ethtool_drvinfo, testinfo_len),
3642*1b481fc3SMaciej Żenczykowski 				1);
3643*1b481fc3SMaciej Żenczykowski 	if (!strings) {
3644*1b481fc3SMaciej Żenczykowski 		perror("Cannot get strings");
3645*1b481fc3SMaciej Żenczykowski 		return 74;
3646*1b481fc3SMaciej Żenczykowski 	}
3647*1b481fc3SMaciej Żenczykowski 
3648*1b481fc3SMaciej Żenczykowski 	test = calloc(1, sizeof(*test) + strings->len * sizeof(u64));
3649*1b481fc3SMaciej Żenczykowski 	if (!test) {
3650*1b481fc3SMaciej Żenczykowski 		perror("Cannot allocate memory for test info");
3651*1b481fc3SMaciej Żenczykowski 		free(strings);
3652*1b481fc3SMaciej Żenczykowski 		return 73;
3653*1b481fc3SMaciej Żenczykowski 	}
3654*1b481fc3SMaciej Żenczykowski 	memset(test->data, 0, strings->len * sizeof(u64));
3655*1b481fc3SMaciej Żenczykowski 	test->cmd = ETHTOOL_TEST;
3656*1b481fc3SMaciej Żenczykowski 	test->len = strings->len;
3657*1b481fc3SMaciej Żenczykowski 	if (test_type == EXTERNAL_LB)
3658*1b481fc3SMaciej Żenczykowski 		test->flags = (ETH_TEST_FL_OFFLINE | ETH_TEST_FL_EXTERNAL_LB);
3659*1b481fc3SMaciej Żenczykowski 	else if (test_type == OFFLINE)
3660*1b481fc3SMaciej Żenczykowski 		test->flags = ETH_TEST_FL_OFFLINE;
3661*1b481fc3SMaciej Żenczykowski 	else
3662*1b481fc3SMaciej Żenczykowski 		test->flags = 0;
3663*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, test);
3664*1b481fc3SMaciej Żenczykowski 	if (err < 0) {
3665*1b481fc3SMaciej Żenczykowski 		perror("Cannot test");
3666*1b481fc3SMaciej Żenczykowski 		free(test);
3667*1b481fc3SMaciej Żenczykowski 		free(strings);
3668*1b481fc3SMaciej Żenczykowski 		return 74;
3669*1b481fc3SMaciej Żenczykowski 	}
3670*1b481fc3SMaciej Żenczykowski 
3671*1b481fc3SMaciej Żenczykowski 	err = dump_test(test, strings);
3672*1b481fc3SMaciej Żenczykowski 	free(test);
3673*1b481fc3SMaciej Żenczykowski 	free(strings);
3674*1b481fc3SMaciej Żenczykowski 
3675*1b481fc3SMaciej Żenczykowski 	return err;
3676*1b481fc3SMaciej Żenczykowski }
3677*1b481fc3SMaciej Żenczykowski 
do_phys_id(struct cmd_context * ctx)3678*1b481fc3SMaciej Żenczykowski static int do_phys_id(struct cmd_context *ctx)
3679*1b481fc3SMaciej Żenczykowski {
3680*1b481fc3SMaciej Żenczykowski 	int err;
3681*1b481fc3SMaciej Żenczykowski 	struct ethtool_value edata;
3682*1b481fc3SMaciej Żenczykowski 	int phys_id_time;
3683*1b481fc3SMaciej Żenczykowski 
3684*1b481fc3SMaciej Żenczykowski 	if (ctx->argc > 1)
3685*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
3686*1b481fc3SMaciej Żenczykowski 	if (ctx->argc == 1)
3687*1b481fc3SMaciej Żenczykowski 		phys_id_time = get_int(*ctx->argp, 0);
3688*1b481fc3SMaciej Żenczykowski 	else
3689*1b481fc3SMaciej Żenczykowski 		phys_id_time = 0;
3690*1b481fc3SMaciej Żenczykowski 
3691*1b481fc3SMaciej Żenczykowski 	edata.cmd = ETHTOOL_PHYS_ID;
3692*1b481fc3SMaciej Żenczykowski 	edata.data = phys_id_time;
3693*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &edata);
3694*1b481fc3SMaciej Żenczykowski 	if (err < 0)
3695*1b481fc3SMaciej Żenczykowski 		perror("Cannot identify NIC");
3696*1b481fc3SMaciej Żenczykowski 
3697*1b481fc3SMaciej Żenczykowski 	return err;
3698*1b481fc3SMaciej Żenczykowski }
3699*1b481fc3SMaciej Żenczykowski 
do_gstats(struct cmd_context * ctx,int cmd,int stringset,const char * name)3700*1b481fc3SMaciej Żenczykowski static int do_gstats(struct cmd_context *ctx, int cmd, int stringset,
3701*1b481fc3SMaciej Żenczykowski 		    const char *name)
3702*1b481fc3SMaciej Żenczykowski {
3703*1b481fc3SMaciej Żenczykowski 	struct ethtool_gstrings *strings;
3704*1b481fc3SMaciej Żenczykowski 	struct ethtool_stats *stats;
3705*1b481fc3SMaciej Żenczykowski 	unsigned int n_stats, sz_stats, i;
3706*1b481fc3SMaciej Żenczykowski 	int err;
3707*1b481fc3SMaciej Żenczykowski 
3708*1b481fc3SMaciej Żenczykowski 	if (ctx->argc != 0)
3709*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
3710*1b481fc3SMaciej Żenczykowski 
3711*1b481fc3SMaciej Żenczykowski 	strings = get_stringset(ctx, stringset,
3712*1b481fc3SMaciej Żenczykowski 				offsetof(struct ethtool_drvinfo, n_stats),
3713*1b481fc3SMaciej Żenczykowski 				0);
3714*1b481fc3SMaciej Żenczykowski 	if (!strings) {
3715*1b481fc3SMaciej Żenczykowski 		perror("Cannot get stats strings information");
3716*1b481fc3SMaciej Żenczykowski 		return 96;
3717*1b481fc3SMaciej Żenczykowski 	}
3718*1b481fc3SMaciej Żenczykowski 
3719*1b481fc3SMaciej Żenczykowski 	n_stats = strings->len;
3720*1b481fc3SMaciej Żenczykowski 	if (n_stats < 1) {
3721*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "no stats available\n");
3722*1b481fc3SMaciej Żenczykowski 		free(strings);
3723*1b481fc3SMaciej Żenczykowski 		return 94;
3724*1b481fc3SMaciej Żenczykowski 	}
3725*1b481fc3SMaciej Żenczykowski 
3726*1b481fc3SMaciej Żenczykowski 	sz_stats = n_stats * sizeof(u64);
3727*1b481fc3SMaciej Żenczykowski 
3728*1b481fc3SMaciej Żenczykowski 	stats = calloc(1, sz_stats + sizeof(struct ethtool_stats));
3729*1b481fc3SMaciej Żenczykowski 	if (!stats) {
3730*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "no memory available\n");
3731*1b481fc3SMaciej Żenczykowski 		free(strings);
3732*1b481fc3SMaciej Żenczykowski 		return 95;
3733*1b481fc3SMaciej Żenczykowski 	}
3734*1b481fc3SMaciej Żenczykowski 
3735*1b481fc3SMaciej Żenczykowski 	stats->cmd = cmd;
3736*1b481fc3SMaciej Żenczykowski 	stats->n_stats = n_stats;
3737*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, stats);
3738*1b481fc3SMaciej Żenczykowski 	if (err < 0) {
3739*1b481fc3SMaciej Żenczykowski 		perror("Cannot get stats information");
3740*1b481fc3SMaciej Żenczykowski 		free(strings);
3741*1b481fc3SMaciej Żenczykowski 		free(stats);
3742*1b481fc3SMaciej Żenczykowski 		return 97;
3743*1b481fc3SMaciej Żenczykowski 	}
3744*1b481fc3SMaciej Żenczykowski 
3745*1b481fc3SMaciej Żenczykowski 	/* todo - pretty-print the strings per-driver */
3746*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "%s statistics:\n", name);
3747*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < n_stats; i++) {
3748*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "     %.*s: %llu\n",
3749*1b481fc3SMaciej Żenczykowski 			ETH_GSTRING_LEN,
3750*1b481fc3SMaciej Żenczykowski 			&strings->data[i * ETH_GSTRING_LEN],
3751*1b481fc3SMaciej Żenczykowski 			stats->data[i]);
3752*1b481fc3SMaciej Żenczykowski 	}
3753*1b481fc3SMaciej Żenczykowski 	free(strings);
3754*1b481fc3SMaciej Żenczykowski 	free(stats);
3755*1b481fc3SMaciej Żenczykowski 
3756*1b481fc3SMaciej Żenczykowski 	return 0;
3757*1b481fc3SMaciej Żenczykowski }
3758*1b481fc3SMaciej Żenczykowski 
do_gnicstats(struct cmd_context * ctx)3759*1b481fc3SMaciej Żenczykowski static int do_gnicstats(struct cmd_context *ctx)
3760*1b481fc3SMaciej Żenczykowski {
3761*1b481fc3SMaciej Żenczykowski 	return do_gstats(ctx, ETHTOOL_GSTATS, ETH_SS_STATS, "NIC");
3762*1b481fc3SMaciej Żenczykowski }
3763*1b481fc3SMaciej Żenczykowski 
do_gphystats(struct cmd_context * ctx)3764*1b481fc3SMaciej Żenczykowski static int do_gphystats(struct cmd_context *ctx)
3765*1b481fc3SMaciej Żenczykowski {
3766*1b481fc3SMaciej Żenczykowski 	return do_gstats(ctx, ETHTOOL_GPHYSTATS, ETH_SS_PHY_STATS, "PHY");
3767*1b481fc3SMaciej Żenczykowski }
3768*1b481fc3SMaciej Żenczykowski 
3769*1b481fc3SMaciej Żenczykowski static int do_srxntuple(struct cmd_context *ctx,
3770*1b481fc3SMaciej Żenczykowski 			struct ethtool_rx_flow_spec *rx_rule_fs);
3771*1b481fc3SMaciej Żenczykowski 
do_srxclass(struct cmd_context * ctx)3772*1b481fc3SMaciej Żenczykowski static int do_srxclass(struct cmd_context *ctx)
3773*1b481fc3SMaciej Żenczykowski {
3774*1b481fc3SMaciej Żenczykowski 	int err;
3775*1b481fc3SMaciej Żenczykowski 
3776*1b481fc3SMaciej Żenczykowski 	if (ctx->argc < 2)
3777*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
3778*1b481fc3SMaciej Żenczykowski 
3779*1b481fc3SMaciej Żenczykowski 	if (!strcmp(ctx->argp[0], "rx-flow-hash")) {
3780*1b481fc3SMaciej Żenczykowski 		int rx_fhash_set;
3781*1b481fc3SMaciej Żenczykowski 		u32 rx_fhash_val;
3782*1b481fc3SMaciej Żenczykowski 		struct ethtool_rxnfc nfccmd;
3783*1b481fc3SMaciej Żenczykowski 		bool flow_rss = false;
3784*1b481fc3SMaciej Żenczykowski 
3785*1b481fc3SMaciej Żenczykowski 		if (ctx->argc == 5) {
3786*1b481fc3SMaciej Żenczykowski 			if (strcmp(ctx->argp[3], "context"))
3787*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
3788*1b481fc3SMaciej Żenczykowski 			flow_rss = true;
3789*1b481fc3SMaciej Żenczykowski 			nfccmd.rss_context = get_u32(ctx->argp[4], 0);
3790*1b481fc3SMaciej Żenczykowski 		} else if (ctx->argc != 3) {
3791*1b481fc3SMaciej Żenczykowski 			exit_bad_args();
3792*1b481fc3SMaciej Żenczykowski 		}
3793*1b481fc3SMaciej Żenczykowski 		rx_fhash_set = rxflow_str_to_type(ctx->argp[1]);
3794*1b481fc3SMaciej Żenczykowski 		if (!rx_fhash_set)
3795*1b481fc3SMaciej Żenczykowski 			exit_bad_args();
3796*1b481fc3SMaciej Żenczykowski 		if (parse_rxfhashopts(ctx->argp[2], &rx_fhash_val) < 0)
3797*1b481fc3SMaciej Żenczykowski 			exit_bad_args();
3798*1b481fc3SMaciej Żenczykowski 
3799*1b481fc3SMaciej Żenczykowski 		nfccmd.cmd = ETHTOOL_SRXFH;
3800*1b481fc3SMaciej Żenczykowski 		nfccmd.flow_type = rx_fhash_set;
3801*1b481fc3SMaciej Żenczykowski 		nfccmd.data = rx_fhash_val;
3802*1b481fc3SMaciej Żenczykowski 		if (flow_rss)
3803*1b481fc3SMaciej Żenczykowski 			nfccmd.flow_type |= FLOW_RSS;
3804*1b481fc3SMaciej Żenczykowski 
3805*1b481fc3SMaciej Żenczykowski 		err = send_ioctl(ctx, &nfccmd);
3806*1b481fc3SMaciej Żenczykowski 		if (err < 0)
3807*1b481fc3SMaciej Żenczykowski 			perror("Cannot change RX network flow hashing options");
3808*1b481fc3SMaciej Żenczykowski 	} else if (!strcmp(ctx->argp[0], "flow-type")) {
3809*1b481fc3SMaciej Żenczykowski 		struct ethtool_rx_flow_spec rx_rule_fs;
3810*1b481fc3SMaciej Żenczykowski 		__u32 rss_context = 0;
3811*1b481fc3SMaciej Żenczykowski 
3812*1b481fc3SMaciej Żenczykowski 		ctx->argc--;
3813*1b481fc3SMaciej Żenczykowski 		ctx->argp++;
3814*1b481fc3SMaciej Żenczykowski 		if (rxclass_parse_ruleopts(ctx, &rx_rule_fs, &rss_context) < 0)
3815*1b481fc3SMaciej Żenczykowski 			exit_bad_args();
3816*1b481fc3SMaciej Żenczykowski 
3817*1b481fc3SMaciej Żenczykowski 		/* attempt to add rule via N-tuple specifier */
3818*1b481fc3SMaciej Żenczykowski 		err = do_srxntuple(ctx, &rx_rule_fs);
3819*1b481fc3SMaciej Żenczykowski 		if (!err)
3820*1b481fc3SMaciej Żenczykowski 			return 0;
3821*1b481fc3SMaciej Żenczykowski 
3822*1b481fc3SMaciej Żenczykowski 		/* attempt to add rule via network flow classifier */
3823*1b481fc3SMaciej Żenczykowski 		err = rxclass_rule_ins(ctx, &rx_rule_fs, rss_context);
3824*1b481fc3SMaciej Żenczykowski 		if (err < 0) {
3825*1b481fc3SMaciej Żenczykowski 			fprintf(stderr, "Cannot insert"
3826*1b481fc3SMaciej Żenczykowski 				" classification rule\n");
3827*1b481fc3SMaciej Żenczykowski 			return 1;
3828*1b481fc3SMaciej Żenczykowski 		}
3829*1b481fc3SMaciej Żenczykowski 	} else if (!strcmp(ctx->argp[0], "delete")) {
3830*1b481fc3SMaciej Żenczykowski 		int rx_class_rule_del =
3831*1b481fc3SMaciej Żenczykowski 			get_uint_range(ctx->argp[1], 0, INT_MAX);
3832*1b481fc3SMaciej Żenczykowski 
3833*1b481fc3SMaciej Żenczykowski 		err = rxclass_rule_del(ctx, rx_class_rule_del);
3834*1b481fc3SMaciej Żenczykowski 
3835*1b481fc3SMaciej Żenczykowski 		if (err < 0) {
3836*1b481fc3SMaciej Żenczykowski 			fprintf(stderr, "Cannot delete"
3837*1b481fc3SMaciej Żenczykowski 				" classification rule\n");
3838*1b481fc3SMaciej Żenczykowski 			return 1;
3839*1b481fc3SMaciej Żenczykowski 		}
3840*1b481fc3SMaciej Żenczykowski 	} else {
3841*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
3842*1b481fc3SMaciej Żenczykowski 	}
3843*1b481fc3SMaciej Żenczykowski 
3844*1b481fc3SMaciej Żenczykowski 	return 0;
3845*1b481fc3SMaciej Żenczykowski }
3846*1b481fc3SMaciej Żenczykowski 
do_grxclass(struct cmd_context * ctx)3847*1b481fc3SMaciej Żenczykowski static int do_grxclass(struct cmd_context *ctx)
3848*1b481fc3SMaciej Żenczykowski {
3849*1b481fc3SMaciej Żenczykowski 	struct ethtool_rxnfc nfccmd;
3850*1b481fc3SMaciej Żenczykowski 	int err;
3851*1b481fc3SMaciej Żenczykowski 
3852*1b481fc3SMaciej Żenczykowski 	if (ctx->argc > 0 && !strcmp(ctx->argp[0], "rx-flow-hash")) {
3853*1b481fc3SMaciej Żenczykowski 		int rx_fhash_get;
3854*1b481fc3SMaciej Żenczykowski 		bool flow_rss = false;
3855*1b481fc3SMaciej Żenczykowski 
3856*1b481fc3SMaciej Żenczykowski 		if (ctx->argc == 4) {
3857*1b481fc3SMaciej Żenczykowski 			if (strcmp(ctx->argp[2], "context"))
3858*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
3859*1b481fc3SMaciej Żenczykowski 			flow_rss = true;
3860*1b481fc3SMaciej Żenczykowski 			nfccmd.rss_context = get_u32(ctx->argp[3], 0);
3861*1b481fc3SMaciej Żenczykowski 		} else if (ctx->argc != 2) {
3862*1b481fc3SMaciej Żenczykowski 			exit_bad_args();
3863*1b481fc3SMaciej Żenczykowski 		}
3864*1b481fc3SMaciej Żenczykowski 
3865*1b481fc3SMaciej Żenczykowski 		rx_fhash_get = rxflow_str_to_type(ctx->argp[1]);
3866*1b481fc3SMaciej Żenczykowski 		if (!rx_fhash_get)
3867*1b481fc3SMaciej Żenczykowski 			exit_bad_args();
3868*1b481fc3SMaciej Żenczykowski 
3869*1b481fc3SMaciej Żenczykowski 		nfccmd.cmd = ETHTOOL_GRXFH;
3870*1b481fc3SMaciej Żenczykowski 		nfccmd.flow_type = rx_fhash_get;
3871*1b481fc3SMaciej Żenczykowski 		if (flow_rss)
3872*1b481fc3SMaciej Żenczykowski 			nfccmd.flow_type |= FLOW_RSS;
3873*1b481fc3SMaciej Żenczykowski 		err = send_ioctl(ctx, &nfccmd);
3874*1b481fc3SMaciej Żenczykowski 		if (err < 0) {
3875*1b481fc3SMaciej Żenczykowski 			perror("Cannot get RX network flow hashing options");
3876*1b481fc3SMaciej Żenczykowski 		} else {
3877*1b481fc3SMaciej Żenczykowski 			if (flow_rss)
3878*1b481fc3SMaciej Żenczykowski 				fprintf(stdout, "For RSS context %u:\n",
3879*1b481fc3SMaciej Żenczykowski 					nfccmd.rss_context);
3880*1b481fc3SMaciej Żenczykowski 			dump_rxfhash(rx_fhash_get, nfccmd.data);
3881*1b481fc3SMaciej Żenczykowski 		}
3882*1b481fc3SMaciej Żenczykowski 	} else if (ctx->argc == 2 && !strcmp(ctx->argp[0], "rule")) {
3883*1b481fc3SMaciej Żenczykowski 		int rx_class_rule_get =
3884*1b481fc3SMaciej Żenczykowski 			get_uint_range(ctx->argp[1], 0, INT_MAX);
3885*1b481fc3SMaciej Żenczykowski 
3886*1b481fc3SMaciej Żenczykowski 		err = rxclass_rule_get(ctx, rx_class_rule_get);
3887*1b481fc3SMaciej Żenczykowski 		if (err < 0)
3888*1b481fc3SMaciej Żenczykowski 			fprintf(stderr, "Cannot get RX classification rule\n");
3889*1b481fc3SMaciej Żenczykowski 	} else if (ctx->argc == 0) {
3890*1b481fc3SMaciej Żenczykowski 		nfccmd.cmd = ETHTOOL_GRXRINGS;
3891*1b481fc3SMaciej Żenczykowski 		err = send_ioctl(ctx, &nfccmd);
3892*1b481fc3SMaciej Żenczykowski 		if (err < 0)
3893*1b481fc3SMaciej Żenczykowski 			perror("Cannot get RX rings");
3894*1b481fc3SMaciej Żenczykowski 		else
3895*1b481fc3SMaciej Żenczykowski 			fprintf(stdout, "%d RX rings available\n",
3896*1b481fc3SMaciej Żenczykowski 				(int)nfccmd.data);
3897*1b481fc3SMaciej Żenczykowski 
3898*1b481fc3SMaciej Żenczykowski 		err = rxclass_rule_getall(ctx);
3899*1b481fc3SMaciej Żenczykowski 		if (err < 0)
3900*1b481fc3SMaciej Żenczykowski 			fprintf(stderr, "RX classification rule retrieval failed\n");
3901*1b481fc3SMaciej Żenczykowski 
3902*1b481fc3SMaciej Żenczykowski 	} else {
3903*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
3904*1b481fc3SMaciej Żenczykowski 	}
3905*1b481fc3SMaciej Żenczykowski 
3906*1b481fc3SMaciej Żenczykowski 	return err ? 1 : 0;
3907*1b481fc3SMaciej Żenczykowski }
3908*1b481fc3SMaciej Żenczykowski 
do_grxfhindir(struct cmd_context * ctx,struct ethtool_rxnfc * ring_count)3909*1b481fc3SMaciej Żenczykowski static int do_grxfhindir(struct cmd_context *ctx,
3910*1b481fc3SMaciej Żenczykowski 			 struct ethtool_rxnfc *ring_count)
3911*1b481fc3SMaciej Żenczykowski {
3912*1b481fc3SMaciej Żenczykowski 	struct ethtool_rxfh_indir indir_head;
3913*1b481fc3SMaciej Żenczykowski 	struct ethtool_rxfh_indir *indir;
3914*1b481fc3SMaciej Żenczykowski 	int err;
3915*1b481fc3SMaciej Żenczykowski 
3916*1b481fc3SMaciej Żenczykowski 	indir_head.cmd = ETHTOOL_GRXFHINDIR;
3917*1b481fc3SMaciej Żenczykowski 	indir_head.size = 0;
3918*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &indir_head);
3919*1b481fc3SMaciej Żenczykowski 	if (err < 0) {
3920*1b481fc3SMaciej Żenczykowski 		perror("Cannot get RX flow hash indirection table size");
3921*1b481fc3SMaciej Żenczykowski 		return 1;
3922*1b481fc3SMaciej Żenczykowski 	}
3923*1b481fc3SMaciej Żenczykowski 
3924*1b481fc3SMaciej Żenczykowski 	indir = malloc(sizeof(*indir) +
3925*1b481fc3SMaciej Żenczykowski 		       indir_head.size * sizeof(*indir->ring_index));
3926*1b481fc3SMaciej Żenczykowski 	if (!indir) {
3927*1b481fc3SMaciej Żenczykowski 		perror("Cannot allocate memory for indirection table");
3928*1b481fc3SMaciej Żenczykowski 		return 1;
3929*1b481fc3SMaciej Żenczykowski 	}
3930*1b481fc3SMaciej Żenczykowski 
3931*1b481fc3SMaciej Żenczykowski 	indir->cmd = ETHTOOL_GRXFHINDIR;
3932*1b481fc3SMaciej Żenczykowski 	indir->size = indir_head.size;
3933*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, indir);
3934*1b481fc3SMaciej Żenczykowski 	if (err < 0) {
3935*1b481fc3SMaciej Żenczykowski 		perror("Cannot get RX flow hash indirection table");
3936*1b481fc3SMaciej Żenczykowski 		free(indir);
3937*1b481fc3SMaciej Żenczykowski 		return 1;
3938*1b481fc3SMaciej Żenczykowski 	}
3939*1b481fc3SMaciej Żenczykowski 
3940*1b481fc3SMaciej Żenczykowski 	print_indir_table(ctx, ring_count->data, indir->size,
3941*1b481fc3SMaciej Żenczykowski 			  indir->ring_index);
3942*1b481fc3SMaciej Żenczykowski 
3943*1b481fc3SMaciej Żenczykowski 	free(indir);
3944*1b481fc3SMaciej Żenczykowski 	return 0;
3945*1b481fc3SMaciej Żenczykowski }
3946*1b481fc3SMaciej Żenczykowski 
do_grxfh(struct cmd_context * ctx)3947*1b481fc3SMaciej Żenczykowski static int do_grxfh(struct cmd_context *ctx)
3948*1b481fc3SMaciej Żenczykowski {
3949*1b481fc3SMaciej Żenczykowski 	struct ethtool_gstrings *hfuncs = NULL;
3950*1b481fc3SMaciej Żenczykowski 	struct ethtool_rxfh rss_head = {0};
3951*1b481fc3SMaciej Żenczykowski 	struct ethtool_rxnfc ring_count;
3952*1b481fc3SMaciej Żenczykowski 	struct ethtool_rxfh *rss;
3953*1b481fc3SMaciej Żenczykowski 	u32 rss_context = 0;
3954*1b481fc3SMaciej Żenczykowski 	u32 i, indir_bytes;
3955*1b481fc3SMaciej Żenczykowski 	unsigned int arg_num = 0;
3956*1b481fc3SMaciej Żenczykowski 	u8 *hkey;
3957*1b481fc3SMaciej Żenczykowski 	int err;
3958*1b481fc3SMaciej Żenczykowski 
3959*1b481fc3SMaciej Żenczykowski 	while (arg_num < ctx->argc) {
3960*1b481fc3SMaciej Żenczykowski 		if (!strcmp(ctx->argp[arg_num], "context")) {
3961*1b481fc3SMaciej Żenczykowski 			++arg_num;
3962*1b481fc3SMaciej Żenczykowski 			rss_context = get_int_range(ctx->argp[arg_num], 0, 1,
3963*1b481fc3SMaciej Żenczykowski 						    ETH_RXFH_CONTEXT_ALLOC - 1);
3964*1b481fc3SMaciej Żenczykowski 			++arg_num;
3965*1b481fc3SMaciej Żenczykowski 		} else {
3966*1b481fc3SMaciej Żenczykowski 			exit_bad_args();
3967*1b481fc3SMaciej Żenczykowski 		}
3968*1b481fc3SMaciej Żenczykowski 	}
3969*1b481fc3SMaciej Żenczykowski 
3970*1b481fc3SMaciej Żenczykowski 	ring_count.cmd = ETHTOOL_GRXRINGS;
3971*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &ring_count);
3972*1b481fc3SMaciej Żenczykowski 	if (err < 0) {
3973*1b481fc3SMaciej Żenczykowski 		perror("Cannot get RX ring count");
3974*1b481fc3SMaciej Żenczykowski 		return 1;
3975*1b481fc3SMaciej Żenczykowski 	}
3976*1b481fc3SMaciej Żenczykowski 
3977*1b481fc3SMaciej Żenczykowski 	rss_head.cmd = ETHTOOL_GRSSH;
3978*1b481fc3SMaciej Żenczykowski 	rss_head.rss_context = rss_context;
3979*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &rss_head);
3980*1b481fc3SMaciej Żenczykowski 	if (err < 0 && errno == EOPNOTSUPP && !rss_context) {
3981*1b481fc3SMaciej Żenczykowski 		return do_grxfhindir(ctx, &ring_count);
3982*1b481fc3SMaciej Żenczykowski 	} else if (err < 0) {
3983*1b481fc3SMaciej Żenczykowski 		perror("Cannot get RX flow hash indir size and/or key size");
3984*1b481fc3SMaciej Żenczykowski 		return 1;
3985*1b481fc3SMaciej Żenczykowski 	}
3986*1b481fc3SMaciej Żenczykowski 
3987*1b481fc3SMaciej Żenczykowski 	rss = calloc(1, sizeof(*rss) +
3988*1b481fc3SMaciej Żenczykowski 			rss_head.indir_size * sizeof(rss_head.rss_config[0]) +
3989*1b481fc3SMaciej Żenczykowski 			rss_head.key_size);
3990*1b481fc3SMaciej Żenczykowski 	if (!rss) {
3991*1b481fc3SMaciej Żenczykowski 		perror("Cannot allocate memory for RX flow hash config");
3992*1b481fc3SMaciej Żenczykowski 		return 1;
3993*1b481fc3SMaciej Żenczykowski 	}
3994*1b481fc3SMaciej Żenczykowski 
3995*1b481fc3SMaciej Żenczykowski 	rss->cmd = ETHTOOL_GRSSH;
3996*1b481fc3SMaciej Żenczykowski 	rss->rss_context = rss_context;
3997*1b481fc3SMaciej Żenczykowski 	rss->indir_size = rss_head.indir_size;
3998*1b481fc3SMaciej Żenczykowski 	rss->key_size = rss_head.key_size;
3999*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, rss);
4000*1b481fc3SMaciej Żenczykowski 	if (err < 0) {
4001*1b481fc3SMaciej Żenczykowski 		perror("Cannot get RX flow hash configuration");
4002*1b481fc3SMaciej Żenczykowski 		free(rss);
4003*1b481fc3SMaciej Żenczykowski 		return 1;
4004*1b481fc3SMaciej Żenczykowski 	}
4005*1b481fc3SMaciej Żenczykowski 
4006*1b481fc3SMaciej Żenczykowski 	print_indir_table(ctx, ring_count.data, rss->indir_size,
4007*1b481fc3SMaciej Żenczykowski 			  rss->rss_config);
4008*1b481fc3SMaciej Żenczykowski 
4009*1b481fc3SMaciej Żenczykowski 	indir_bytes = rss->indir_size * sizeof(rss->rss_config[0]);
4010*1b481fc3SMaciej Żenczykowski 	hkey = ((u8 *)rss->rss_config + indir_bytes);
4011*1b481fc3SMaciej Żenczykowski 
4012*1b481fc3SMaciej Żenczykowski 	print_rss_hkey(hkey, rss->key_size);
4013*1b481fc3SMaciej Żenczykowski 
4014*1b481fc3SMaciej Żenczykowski 	printf("RSS hash function:\n");
4015*1b481fc3SMaciej Żenczykowski 	if (!rss->hfunc) {
4016*1b481fc3SMaciej Żenczykowski 		printf("    Operation not supported\n");
4017*1b481fc3SMaciej Żenczykowski 		goto out;
4018*1b481fc3SMaciej Żenczykowski 	}
4019*1b481fc3SMaciej Żenczykowski 
4020*1b481fc3SMaciej Żenczykowski 	hfuncs = get_stringset(ctx, ETH_SS_RSS_HASH_FUNCS, 0, 1);
4021*1b481fc3SMaciej Żenczykowski 	if (!hfuncs) {
4022*1b481fc3SMaciej Żenczykowski 		perror("Cannot get hash functions names");
4023*1b481fc3SMaciej Żenczykowski 		free(rss);
4024*1b481fc3SMaciej Żenczykowski 		return 1;
4025*1b481fc3SMaciej Żenczykowski 	}
4026*1b481fc3SMaciej Żenczykowski 
4027*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < hfuncs->len; i++)
4028*1b481fc3SMaciej Żenczykowski 		printf("    %s: %s\n",
4029*1b481fc3SMaciej Żenczykowski 		       (const char *)hfuncs->data + i * ETH_GSTRING_LEN,
4030*1b481fc3SMaciej Żenczykowski 		       (rss->hfunc & (1 << i)) ? "on" : "off");
4031*1b481fc3SMaciej Żenczykowski 
4032*1b481fc3SMaciej Żenczykowski out:
4033*1b481fc3SMaciej Żenczykowski 	free(hfuncs);
4034*1b481fc3SMaciej Żenczykowski 	free(rss);
4035*1b481fc3SMaciej Żenczykowski 	return 0;
4036*1b481fc3SMaciej Żenczykowski }
4037*1b481fc3SMaciej Żenczykowski 
fill_indir_table(u32 * indir_size,u32 * indir,int rxfhindir_default,int rxfhindir_start,int rxfhindir_equal,char ** rxfhindir_weight,u32 num_weights)4038*1b481fc3SMaciej Żenczykowski static int fill_indir_table(u32 *indir_size, u32 *indir, int rxfhindir_default,
4039*1b481fc3SMaciej Żenczykowski 			    int rxfhindir_start, int rxfhindir_equal,
4040*1b481fc3SMaciej Żenczykowski 			    char **rxfhindir_weight, u32 num_weights)
4041*1b481fc3SMaciej Żenczykowski {
4042*1b481fc3SMaciej Żenczykowski 	u32 i;
4043*1b481fc3SMaciej Żenczykowski 
4044*1b481fc3SMaciej Żenczykowski 	if (rxfhindir_equal) {
4045*1b481fc3SMaciej Żenczykowski 		for (i = 0; i < *indir_size; i++)
4046*1b481fc3SMaciej Żenczykowski 			indir[i] = rxfhindir_start + (i % rxfhindir_equal);
4047*1b481fc3SMaciej Żenczykowski 	} else if (rxfhindir_weight) {
4048*1b481fc3SMaciej Żenczykowski 		u32 j, weight, sum = 0, partial = 0;
4049*1b481fc3SMaciej Żenczykowski 
4050*1b481fc3SMaciej Żenczykowski 		for (j = 0; j < num_weights; j++) {
4051*1b481fc3SMaciej Żenczykowski 			weight = get_u32(rxfhindir_weight[j], 0);
4052*1b481fc3SMaciej Żenczykowski 			sum += weight;
4053*1b481fc3SMaciej Żenczykowski 		}
4054*1b481fc3SMaciej Żenczykowski 
4055*1b481fc3SMaciej Żenczykowski 		if (sum == 0) {
4056*1b481fc3SMaciej Żenczykowski 			fprintf(stderr,
4057*1b481fc3SMaciej Żenczykowski 				"At least one weight must be non-zero\n");
4058*1b481fc3SMaciej Żenczykowski 			return 2;
4059*1b481fc3SMaciej Żenczykowski 		}
4060*1b481fc3SMaciej Żenczykowski 
4061*1b481fc3SMaciej Żenczykowski 		if (sum > *indir_size) {
4062*1b481fc3SMaciej Żenczykowski 			fprintf(stderr,
4063*1b481fc3SMaciej Żenczykowski 				"Total weight exceeds the size of the "
4064*1b481fc3SMaciej Żenczykowski 				"indirection table\n");
4065*1b481fc3SMaciej Żenczykowski 			return 2;
4066*1b481fc3SMaciej Żenczykowski 		}
4067*1b481fc3SMaciej Żenczykowski 
4068*1b481fc3SMaciej Żenczykowski 		j = -1;
4069*1b481fc3SMaciej Żenczykowski 		for (i = 0; i < *indir_size; i++) {
4070*1b481fc3SMaciej Żenczykowski 			while (i >= (*indir_size) * partial / sum) {
4071*1b481fc3SMaciej Żenczykowski 				j += 1;
4072*1b481fc3SMaciej Żenczykowski 				weight = get_u32(rxfhindir_weight[j], 0);
4073*1b481fc3SMaciej Żenczykowski 				partial += weight;
4074*1b481fc3SMaciej Żenczykowski 			}
4075*1b481fc3SMaciej Żenczykowski 			indir[i] = rxfhindir_start + j;
4076*1b481fc3SMaciej Żenczykowski 		}
4077*1b481fc3SMaciej Żenczykowski 	} else if (rxfhindir_default) {
4078*1b481fc3SMaciej Żenczykowski 		/* "*indir_size == 0" ==> reset indir to default */
4079*1b481fc3SMaciej Żenczykowski 		*indir_size = 0;
4080*1b481fc3SMaciej Żenczykowski 	} else {
4081*1b481fc3SMaciej Żenczykowski 		*indir_size = ETH_RXFH_INDIR_NO_CHANGE;
4082*1b481fc3SMaciej Żenczykowski 	}
4083*1b481fc3SMaciej Żenczykowski 
4084*1b481fc3SMaciej Żenczykowski 	return 0;
4085*1b481fc3SMaciej Żenczykowski }
4086*1b481fc3SMaciej Żenczykowski 
do_srxfhindir(struct cmd_context * ctx,int rxfhindir_default,int rxfhindir_start,int rxfhindir_equal,char ** rxfhindir_weight,u32 num_weights)4087*1b481fc3SMaciej Żenczykowski static int do_srxfhindir(struct cmd_context *ctx, int rxfhindir_default,
4088*1b481fc3SMaciej Żenczykowski 			 int rxfhindir_start, int rxfhindir_equal,
4089*1b481fc3SMaciej Żenczykowski 			 char **rxfhindir_weight, u32 num_weights)
4090*1b481fc3SMaciej Żenczykowski {
4091*1b481fc3SMaciej Żenczykowski 	struct ethtool_rxfh_indir indir_head;
4092*1b481fc3SMaciej Żenczykowski 	struct ethtool_rxfh_indir *indir;
4093*1b481fc3SMaciej Żenczykowski 	int err;
4094*1b481fc3SMaciej Żenczykowski 
4095*1b481fc3SMaciej Żenczykowski 	indir_head.cmd = ETHTOOL_GRXFHINDIR;
4096*1b481fc3SMaciej Żenczykowski 	indir_head.size = 0;
4097*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &indir_head);
4098*1b481fc3SMaciej Żenczykowski 	if (err < 0) {
4099*1b481fc3SMaciej Żenczykowski 		perror("Cannot get RX flow hash indirection table size");
4100*1b481fc3SMaciej Żenczykowski 		return 1;
4101*1b481fc3SMaciej Żenczykowski 	}
4102*1b481fc3SMaciej Żenczykowski 
4103*1b481fc3SMaciej Żenczykowski 	indir = malloc(sizeof(*indir) +
4104*1b481fc3SMaciej Żenczykowski 		       indir_head.size * sizeof(*indir->ring_index));
4105*1b481fc3SMaciej Żenczykowski 
4106*1b481fc3SMaciej Żenczykowski 	if (!indir) {
4107*1b481fc3SMaciej Żenczykowski 		perror("Cannot allocate memory for indirection table");
4108*1b481fc3SMaciej Żenczykowski 		return 1;
4109*1b481fc3SMaciej Żenczykowski 	}
4110*1b481fc3SMaciej Żenczykowski 
4111*1b481fc3SMaciej Żenczykowski 	indir->cmd = ETHTOOL_SRXFHINDIR;
4112*1b481fc3SMaciej Żenczykowski 	indir->size = indir_head.size;
4113*1b481fc3SMaciej Żenczykowski 
4114*1b481fc3SMaciej Żenczykowski 	if (fill_indir_table(&indir->size, indir->ring_index,
4115*1b481fc3SMaciej Żenczykowski 			     rxfhindir_default, rxfhindir_start,
4116*1b481fc3SMaciej Żenczykowski 			     rxfhindir_equal, rxfhindir_weight, num_weights)) {
4117*1b481fc3SMaciej Żenczykowski 		free(indir);
4118*1b481fc3SMaciej Żenczykowski 		return 1;
4119*1b481fc3SMaciej Żenczykowski 	}
4120*1b481fc3SMaciej Żenczykowski 
4121*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, indir);
4122*1b481fc3SMaciej Żenczykowski 	if (err < 0) {
4123*1b481fc3SMaciej Żenczykowski 		perror("Cannot set RX flow hash indirection table");
4124*1b481fc3SMaciej Żenczykowski 		free(indir);
4125*1b481fc3SMaciej Żenczykowski 		return 1;
4126*1b481fc3SMaciej Żenczykowski 	}
4127*1b481fc3SMaciej Żenczykowski 
4128*1b481fc3SMaciej Żenczykowski 	free(indir);
4129*1b481fc3SMaciej Żenczykowski 	return 0;
4130*1b481fc3SMaciej Żenczykowski }
4131*1b481fc3SMaciej Żenczykowski 
do_srxfh(struct cmd_context * ctx)4132*1b481fc3SMaciej Żenczykowski static int do_srxfh(struct cmd_context *ctx)
4133*1b481fc3SMaciej Żenczykowski {
4134*1b481fc3SMaciej Żenczykowski 	struct ethtool_rxfh rss_head = {0};
4135*1b481fc3SMaciej Żenczykowski 	struct ethtool_rxfh *rss = NULL;
4136*1b481fc3SMaciej Żenczykowski 	struct ethtool_rxnfc ring_count;
4137*1b481fc3SMaciej Żenczykowski 	int rxfhindir_equal = 0, rxfhindir_default = 0, rxfhindir_start = 0;
4138*1b481fc3SMaciej Żenczykowski 	struct ethtool_gstrings *hfuncs = NULL;
4139*1b481fc3SMaciej Żenczykowski 	char **rxfhindir_weight = NULL;
4140*1b481fc3SMaciej Żenczykowski 	char *rxfhindir_key = NULL;
4141*1b481fc3SMaciej Żenczykowski 	char *req_hfunc_name = NULL;
4142*1b481fc3SMaciej Żenczykowski 	char *hfunc_name = NULL;
4143*1b481fc3SMaciej Żenczykowski 	char *hkey = NULL;
4144*1b481fc3SMaciej Żenczykowski 	int err = 0;
4145*1b481fc3SMaciej Żenczykowski 	unsigned int i;
4146*1b481fc3SMaciej Żenczykowski 	u32 arg_num = 0, indir_bytes = 0;
4147*1b481fc3SMaciej Żenczykowski 	u32 req_hfunc = 0;
4148*1b481fc3SMaciej Żenczykowski 	u32 entry_size = sizeof(rss_head.rss_config[0]);
4149*1b481fc3SMaciej Żenczykowski 	u32 num_weights = 0;
4150*1b481fc3SMaciej Żenczykowski 	u32 rss_context = 0;
4151*1b481fc3SMaciej Żenczykowski 	int delete = 0;
4152*1b481fc3SMaciej Żenczykowski 
4153*1b481fc3SMaciej Żenczykowski 	if (ctx->argc < 1)
4154*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
4155*1b481fc3SMaciej Żenczykowski 
4156*1b481fc3SMaciej Żenczykowski 	while (arg_num < ctx->argc) {
4157*1b481fc3SMaciej Żenczykowski 		if (!strcmp(ctx->argp[arg_num], "equal")) {
4158*1b481fc3SMaciej Żenczykowski 			++arg_num;
4159*1b481fc3SMaciej Żenczykowski 			rxfhindir_equal = get_int_range(ctx->argp[arg_num],
4160*1b481fc3SMaciej Żenczykowski 							0, 1, INT_MAX);
4161*1b481fc3SMaciej Żenczykowski 			++arg_num;
4162*1b481fc3SMaciej Żenczykowski 		} else if (!strcmp(ctx->argp[arg_num], "start")) {
4163*1b481fc3SMaciej Żenczykowski 			++arg_num;
4164*1b481fc3SMaciej Żenczykowski 			rxfhindir_start = get_int_range(ctx->argp[arg_num],
4165*1b481fc3SMaciej Żenczykowski 							0, 0, INT_MAX);
4166*1b481fc3SMaciej Żenczykowski 			++arg_num;
4167*1b481fc3SMaciej Żenczykowski 		} else if (!strcmp(ctx->argp[arg_num], "weight")) {
4168*1b481fc3SMaciej Żenczykowski 			++arg_num;
4169*1b481fc3SMaciej Żenczykowski 			rxfhindir_weight = ctx->argp + arg_num;
4170*1b481fc3SMaciej Żenczykowski 			while (arg_num < ctx->argc &&
4171*1b481fc3SMaciej Żenczykowski 			       isdigit((unsigned char)ctx->argp[arg_num][0])) {
4172*1b481fc3SMaciej Żenczykowski 				++arg_num;
4173*1b481fc3SMaciej Żenczykowski 				++num_weights;
4174*1b481fc3SMaciej Żenczykowski 			}
4175*1b481fc3SMaciej Żenczykowski 			if (!num_weights)
4176*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
4177*1b481fc3SMaciej Żenczykowski 		} else if (!strcmp(ctx->argp[arg_num], "hkey")) {
4178*1b481fc3SMaciej Żenczykowski 			++arg_num;
4179*1b481fc3SMaciej Żenczykowski 			rxfhindir_key = ctx->argp[arg_num];
4180*1b481fc3SMaciej Żenczykowski 			if (!rxfhindir_key)
4181*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
4182*1b481fc3SMaciej Żenczykowski 			++arg_num;
4183*1b481fc3SMaciej Żenczykowski 		} else if (!strcmp(ctx->argp[arg_num], "default")) {
4184*1b481fc3SMaciej Żenczykowski 			++arg_num;
4185*1b481fc3SMaciej Żenczykowski 			rxfhindir_default = 1;
4186*1b481fc3SMaciej Żenczykowski 		} else if (!strcmp(ctx->argp[arg_num], "hfunc")) {
4187*1b481fc3SMaciej Żenczykowski 			++arg_num;
4188*1b481fc3SMaciej Żenczykowski 			req_hfunc_name = ctx->argp[arg_num];
4189*1b481fc3SMaciej Żenczykowski 			if (!req_hfunc_name)
4190*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
4191*1b481fc3SMaciej Żenczykowski 			++arg_num;
4192*1b481fc3SMaciej Żenczykowski 		} else if (!strcmp(ctx->argp[arg_num], "context")) {
4193*1b481fc3SMaciej Żenczykowski 			++arg_num;
4194*1b481fc3SMaciej Żenczykowski 			if(!strcmp(ctx->argp[arg_num], "new"))
4195*1b481fc3SMaciej Żenczykowski 				rss_context = ETH_RXFH_CONTEXT_ALLOC;
4196*1b481fc3SMaciej Żenczykowski 			else
4197*1b481fc3SMaciej Żenczykowski 				rss_context = get_int_range(
4198*1b481fc3SMaciej Żenczykowski 						ctx->argp[arg_num], 0, 1,
4199*1b481fc3SMaciej Żenczykowski 						ETH_RXFH_CONTEXT_ALLOC - 1);
4200*1b481fc3SMaciej Żenczykowski 			++arg_num;
4201*1b481fc3SMaciej Żenczykowski 		} else if (!strcmp(ctx->argp[arg_num], "delete")) {
4202*1b481fc3SMaciej Żenczykowski 			++arg_num;
4203*1b481fc3SMaciej Żenczykowski 			delete = 1;
4204*1b481fc3SMaciej Żenczykowski 		} else {
4205*1b481fc3SMaciej Żenczykowski 			exit_bad_args();
4206*1b481fc3SMaciej Żenczykowski 		}
4207*1b481fc3SMaciej Żenczykowski 	}
4208*1b481fc3SMaciej Żenczykowski 
4209*1b481fc3SMaciej Żenczykowski 	if (rxfhindir_equal && rxfhindir_weight) {
4210*1b481fc3SMaciej Żenczykowski 		fprintf(stderr,
4211*1b481fc3SMaciej Żenczykowski 			"Equal and weight options are mutually exclusive\n");
4212*1b481fc3SMaciej Żenczykowski 		return 1;
4213*1b481fc3SMaciej Żenczykowski 	}
4214*1b481fc3SMaciej Żenczykowski 
4215*1b481fc3SMaciej Żenczykowski 	if (rxfhindir_equal && rxfhindir_default) {
4216*1b481fc3SMaciej Żenczykowski 		fprintf(stderr,
4217*1b481fc3SMaciej Żenczykowski 			"Equal and default options are mutually exclusive\n");
4218*1b481fc3SMaciej Żenczykowski 		return 1;
4219*1b481fc3SMaciej Żenczykowski 	}
4220*1b481fc3SMaciej Żenczykowski 
4221*1b481fc3SMaciej Żenczykowski 	if (rxfhindir_weight && rxfhindir_default) {
4222*1b481fc3SMaciej Żenczykowski 		fprintf(stderr,
4223*1b481fc3SMaciej Żenczykowski 			"Weight and default options are mutually exclusive\n");
4224*1b481fc3SMaciej Żenczykowski 		return 1;
4225*1b481fc3SMaciej Żenczykowski 	}
4226*1b481fc3SMaciej Żenczykowski 
4227*1b481fc3SMaciej Żenczykowski 	if (rxfhindir_start && rxfhindir_default) {
4228*1b481fc3SMaciej Żenczykowski 		fprintf(stderr,
4229*1b481fc3SMaciej Żenczykowski 			"Start and default options are mutually exclusive\n");
4230*1b481fc3SMaciej Żenczykowski 		return 1;
4231*1b481fc3SMaciej Żenczykowski 	}
4232*1b481fc3SMaciej Żenczykowski 
4233*1b481fc3SMaciej Żenczykowski 	if (rxfhindir_start && !(rxfhindir_equal || rxfhindir_weight)) {
4234*1b481fc3SMaciej Żenczykowski 		fprintf(stderr,
4235*1b481fc3SMaciej Żenczykowski 			"Start must be used with equal or weight options\n");
4236*1b481fc3SMaciej Żenczykowski 		return 1;
4237*1b481fc3SMaciej Żenczykowski 	}
4238*1b481fc3SMaciej Żenczykowski 
4239*1b481fc3SMaciej Żenczykowski 	if (rxfhindir_default && rss_context) {
4240*1b481fc3SMaciej Żenczykowski 		fprintf(stderr,
4241*1b481fc3SMaciej Żenczykowski 			"Default and context options are mutually exclusive\n");
4242*1b481fc3SMaciej Żenczykowski 		return 1;
4243*1b481fc3SMaciej Żenczykowski 	}
4244*1b481fc3SMaciej Żenczykowski 
4245*1b481fc3SMaciej Żenczykowski 	if (delete && !rss_context) {
4246*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "Delete option requires context option\n");
4247*1b481fc3SMaciej Żenczykowski 		return 1;
4248*1b481fc3SMaciej Żenczykowski 	}
4249*1b481fc3SMaciej Żenczykowski 
4250*1b481fc3SMaciej Żenczykowski 	if (delete && rxfhindir_weight) {
4251*1b481fc3SMaciej Żenczykowski 		fprintf(stderr,
4252*1b481fc3SMaciej Żenczykowski 			"Delete and weight options are mutually exclusive\n");
4253*1b481fc3SMaciej Żenczykowski 		return 1;
4254*1b481fc3SMaciej Żenczykowski 	}
4255*1b481fc3SMaciej Żenczykowski 
4256*1b481fc3SMaciej Żenczykowski 	if (delete && rxfhindir_equal) {
4257*1b481fc3SMaciej Żenczykowski 		fprintf(stderr,
4258*1b481fc3SMaciej Żenczykowski 			"Delete and equal options are mutually exclusive\n");
4259*1b481fc3SMaciej Żenczykowski 		return 1;
4260*1b481fc3SMaciej Żenczykowski 	}
4261*1b481fc3SMaciej Żenczykowski 
4262*1b481fc3SMaciej Żenczykowski 	if (delete && rxfhindir_default) {
4263*1b481fc3SMaciej Żenczykowski 		fprintf(stderr,
4264*1b481fc3SMaciej Żenczykowski 			"Delete and default options are mutually exclusive\n");
4265*1b481fc3SMaciej Żenczykowski 		return 1;
4266*1b481fc3SMaciej Żenczykowski 	}
4267*1b481fc3SMaciej Żenczykowski 
4268*1b481fc3SMaciej Żenczykowski 	if (delete && rxfhindir_key) {
4269*1b481fc3SMaciej Żenczykowski 		fprintf(stderr,
4270*1b481fc3SMaciej Żenczykowski 			"Delete and hkey options are mutually exclusive\n");
4271*1b481fc3SMaciej Żenczykowski 		return 1;
4272*1b481fc3SMaciej Żenczykowski 	}
4273*1b481fc3SMaciej Żenczykowski 
4274*1b481fc3SMaciej Żenczykowski 	ring_count.cmd = ETHTOOL_GRXRINGS;
4275*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &ring_count);
4276*1b481fc3SMaciej Żenczykowski 	if (err < 0) {
4277*1b481fc3SMaciej Żenczykowski 		perror("Cannot get RX ring count");
4278*1b481fc3SMaciej Żenczykowski 		return 1;
4279*1b481fc3SMaciej Żenczykowski 	}
4280*1b481fc3SMaciej Żenczykowski 
4281*1b481fc3SMaciej Żenczykowski 	rss_head.cmd = ETHTOOL_GRSSH;
4282*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &rss_head);
4283*1b481fc3SMaciej Żenczykowski 	if (err < 0 && errno == EOPNOTSUPP && !rxfhindir_key &&
4284*1b481fc3SMaciej Żenczykowski 	    !req_hfunc_name && !rss_context) {
4285*1b481fc3SMaciej Żenczykowski 		return do_srxfhindir(ctx, rxfhindir_default, rxfhindir_start,
4286*1b481fc3SMaciej Żenczykowski 				     rxfhindir_equal, rxfhindir_weight,
4287*1b481fc3SMaciej Żenczykowski 				     num_weights);
4288*1b481fc3SMaciej Żenczykowski 	} else if (err < 0) {
4289*1b481fc3SMaciej Żenczykowski 		perror("Cannot get RX flow hash indir size and key size");
4290*1b481fc3SMaciej Żenczykowski 		return 1;
4291*1b481fc3SMaciej Żenczykowski 	}
4292*1b481fc3SMaciej Żenczykowski 
4293*1b481fc3SMaciej Żenczykowski 	if (rxfhindir_key) {
4294*1b481fc3SMaciej Żenczykowski 		err = parse_hkey(&hkey, rss_head.key_size,
4295*1b481fc3SMaciej Żenczykowski 				 rxfhindir_key);
4296*1b481fc3SMaciej Żenczykowski 		if (err)
4297*1b481fc3SMaciej Żenczykowski 			return err;
4298*1b481fc3SMaciej Żenczykowski 	}
4299*1b481fc3SMaciej Żenczykowski 
4300*1b481fc3SMaciej Żenczykowski 	if (rxfhindir_equal || rxfhindir_weight)
4301*1b481fc3SMaciej Żenczykowski 		indir_bytes = rss_head.indir_size * entry_size;
4302*1b481fc3SMaciej Żenczykowski 
4303*1b481fc3SMaciej Żenczykowski 	if (rss_head.hfunc && req_hfunc_name) {
4304*1b481fc3SMaciej Żenczykowski 		hfuncs = get_stringset(ctx, ETH_SS_RSS_HASH_FUNCS, 0, 1);
4305*1b481fc3SMaciej Żenczykowski 		if (!hfuncs) {
4306*1b481fc3SMaciej Żenczykowski 			perror("Cannot get hash functions names");
4307*1b481fc3SMaciej Żenczykowski 			err = 1;
4308*1b481fc3SMaciej Żenczykowski 			goto free;
4309*1b481fc3SMaciej Żenczykowski 		}
4310*1b481fc3SMaciej Żenczykowski 
4311*1b481fc3SMaciej Żenczykowski 		for (i = 0; i < hfuncs->len && !req_hfunc ; i++) {
4312*1b481fc3SMaciej Żenczykowski 			hfunc_name = (char *)(hfuncs->data +
4313*1b481fc3SMaciej Żenczykowski 					      i * ETH_GSTRING_LEN);
4314*1b481fc3SMaciej Żenczykowski 			if (!strncmp(hfunc_name, req_hfunc_name,
4315*1b481fc3SMaciej Żenczykowski 				     ETH_GSTRING_LEN))
4316*1b481fc3SMaciej Żenczykowski 				req_hfunc = (u32)1 << i;
4317*1b481fc3SMaciej Żenczykowski 		}
4318*1b481fc3SMaciej Żenczykowski 
4319*1b481fc3SMaciej Żenczykowski 		if (!req_hfunc) {
4320*1b481fc3SMaciej Żenczykowski 			fprintf(stderr,
4321*1b481fc3SMaciej Żenczykowski 				"Unknown hash function: %s\n", req_hfunc_name);
4322*1b481fc3SMaciej Żenczykowski 			err = 1;
4323*1b481fc3SMaciej Żenczykowski 			goto free;
4324*1b481fc3SMaciej Żenczykowski 		}
4325*1b481fc3SMaciej Żenczykowski 	}
4326*1b481fc3SMaciej Żenczykowski 
4327*1b481fc3SMaciej Żenczykowski 	rss = calloc(1, sizeof(*rss) + indir_bytes + rss_head.key_size);
4328*1b481fc3SMaciej Żenczykowski 	if (!rss) {
4329*1b481fc3SMaciej Żenczykowski 		perror("Cannot allocate memory for RX flow hash config");
4330*1b481fc3SMaciej Żenczykowski 		err = 1;
4331*1b481fc3SMaciej Żenczykowski 		goto free;
4332*1b481fc3SMaciej Żenczykowski 	}
4333*1b481fc3SMaciej Żenczykowski 	rss->cmd = ETHTOOL_SRSSH;
4334*1b481fc3SMaciej Żenczykowski 	rss->rss_context = rss_context;
4335*1b481fc3SMaciej Żenczykowski 	rss->hfunc = req_hfunc;
4336*1b481fc3SMaciej Żenczykowski 	if (delete) {
4337*1b481fc3SMaciej Żenczykowski 		rss->indir_size = rss->key_size = 0;
4338*1b481fc3SMaciej Żenczykowski 	} else {
4339*1b481fc3SMaciej Żenczykowski 		rss->indir_size = rss_head.indir_size;
4340*1b481fc3SMaciej Żenczykowski 		rss->key_size = rss_head.key_size;
4341*1b481fc3SMaciej Żenczykowski 		if (fill_indir_table(&rss->indir_size, rss->rss_config,
4342*1b481fc3SMaciej Żenczykowski 				     rxfhindir_default, rxfhindir_start,
4343*1b481fc3SMaciej Żenczykowski 				     rxfhindir_equal, rxfhindir_weight,
4344*1b481fc3SMaciej Żenczykowski 				     num_weights)) {
4345*1b481fc3SMaciej Żenczykowski 			err = 1;
4346*1b481fc3SMaciej Żenczykowski 			goto free;
4347*1b481fc3SMaciej Żenczykowski 		}
4348*1b481fc3SMaciej Żenczykowski 	}
4349*1b481fc3SMaciej Żenczykowski 
4350*1b481fc3SMaciej Żenczykowski 	if (hkey)
4351*1b481fc3SMaciej Żenczykowski 		memcpy((char *)rss->rss_config + indir_bytes,
4352*1b481fc3SMaciej Żenczykowski 		       hkey, rss->key_size);
4353*1b481fc3SMaciej Żenczykowski 	else
4354*1b481fc3SMaciej Żenczykowski 		rss->key_size = 0;
4355*1b481fc3SMaciej Żenczykowski 
4356*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, rss);
4357*1b481fc3SMaciej Żenczykowski 	if (err < 0) {
4358*1b481fc3SMaciej Żenczykowski 		perror("Cannot set RX flow hash configuration");
4359*1b481fc3SMaciej Żenczykowski 		err = 1;
4360*1b481fc3SMaciej Żenczykowski 	} else if (rss_context == ETH_RXFH_CONTEXT_ALLOC) {
4361*1b481fc3SMaciej Żenczykowski 		printf("New RSS context is %d\n", rss->rss_context);
4362*1b481fc3SMaciej Żenczykowski 	}
4363*1b481fc3SMaciej Żenczykowski 
4364*1b481fc3SMaciej Żenczykowski free:
4365*1b481fc3SMaciej Żenczykowski 	free(hkey);
4366*1b481fc3SMaciej Żenczykowski 	free(rss);
4367*1b481fc3SMaciej Żenczykowski 	free(hfuncs);
4368*1b481fc3SMaciej Żenczykowski 	return err;
4369*1b481fc3SMaciej Żenczykowski }
4370*1b481fc3SMaciej Żenczykowski 
do_flash(struct cmd_context * ctx)4371*1b481fc3SMaciej Żenczykowski static int do_flash(struct cmd_context *ctx)
4372*1b481fc3SMaciej Żenczykowski {
4373*1b481fc3SMaciej Żenczykowski 	char *flash_file;
4374*1b481fc3SMaciej Żenczykowski 	int flash_region;
4375*1b481fc3SMaciej Żenczykowski 	struct ethtool_flash efl;
4376*1b481fc3SMaciej Żenczykowski 	int err;
4377*1b481fc3SMaciej Żenczykowski 
4378*1b481fc3SMaciej Żenczykowski 	if (ctx->argc < 1 || ctx->argc > 2)
4379*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
4380*1b481fc3SMaciej Żenczykowski 	flash_file = ctx->argp[0];
4381*1b481fc3SMaciej Żenczykowski 	if (ctx->argc == 2) {
4382*1b481fc3SMaciej Żenczykowski 		flash_region = strtol(ctx->argp[1], NULL, 0);
4383*1b481fc3SMaciej Żenczykowski 		if (flash_region < 0)
4384*1b481fc3SMaciej Żenczykowski 			exit_bad_args();
4385*1b481fc3SMaciej Żenczykowski 	} else {
4386*1b481fc3SMaciej Żenczykowski 		flash_region = -1;
4387*1b481fc3SMaciej Żenczykowski 	}
4388*1b481fc3SMaciej Żenczykowski 
4389*1b481fc3SMaciej Żenczykowski 	if (strlen(flash_file) > ETHTOOL_FLASH_MAX_FILENAME - 1) {
4390*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "Filename too long\n");
4391*1b481fc3SMaciej Żenczykowski 		return 99;
4392*1b481fc3SMaciej Żenczykowski 	}
4393*1b481fc3SMaciej Żenczykowski 
4394*1b481fc3SMaciej Żenczykowski 	efl.cmd = ETHTOOL_FLASHDEV;
4395*1b481fc3SMaciej Żenczykowski 	strcpy(efl.data, flash_file);
4396*1b481fc3SMaciej Żenczykowski 
4397*1b481fc3SMaciej Żenczykowski 	if (flash_region < 0)
4398*1b481fc3SMaciej Żenczykowski 		efl.region = ETHTOOL_FLASH_ALL_REGIONS;
4399*1b481fc3SMaciej Żenczykowski 	else
4400*1b481fc3SMaciej Żenczykowski 		efl.region = flash_region;
4401*1b481fc3SMaciej Żenczykowski 
4402*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &efl);
4403*1b481fc3SMaciej Żenczykowski 	if (err < 0)
4404*1b481fc3SMaciej Żenczykowski 		perror("Flashing failed");
4405*1b481fc3SMaciej Żenczykowski 
4406*1b481fc3SMaciej Żenczykowski 	return err;
4407*1b481fc3SMaciej Żenczykowski }
4408*1b481fc3SMaciej Żenczykowski 
do_permaddr(struct cmd_context * ctx)4409*1b481fc3SMaciej Żenczykowski static int do_permaddr(struct cmd_context *ctx)
4410*1b481fc3SMaciej Żenczykowski {
4411*1b481fc3SMaciej Żenczykowski 	unsigned int i;
4412*1b481fc3SMaciej Żenczykowski 	int err;
4413*1b481fc3SMaciej Żenczykowski 	struct ethtool_perm_addr *epaddr;
4414*1b481fc3SMaciej Żenczykowski 
4415*1b481fc3SMaciej Żenczykowski 	epaddr = malloc(sizeof(struct ethtool_perm_addr) + MAX_ADDR_LEN);
4416*1b481fc3SMaciej Żenczykowski 	if (!epaddr) {
4417*1b481fc3SMaciej Żenczykowski 		perror("Cannot allocate memory for operation");
4418*1b481fc3SMaciej Żenczykowski 		return 1;
4419*1b481fc3SMaciej Żenczykowski 	}
4420*1b481fc3SMaciej Żenczykowski 
4421*1b481fc3SMaciej Żenczykowski 	epaddr->cmd = ETHTOOL_GPERMADDR;
4422*1b481fc3SMaciej Żenczykowski 	epaddr->size = MAX_ADDR_LEN;
4423*1b481fc3SMaciej Żenczykowski 
4424*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, epaddr);
4425*1b481fc3SMaciej Żenczykowski 	if (err < 0)
4426*1b481fc3SMaciej Żenczykowski 		perror("Cannot read permanent address");
4427*1b481fc3SMaciej Żenczykowski 	else {
4428*1b481fc3SMaciej Żenczykowski 		printf("Permanent address:");
4429*1b481fc3SMaciej Żenczykowski 		for (i = 0; i < epaddr->size; i++)
4430*1b481fc3SMaciej Żenczykowski 			printf("%c%02x", (i == 0) ? ' ' : ':',
4431*1b481fc3SMaciej Żenczykowski 			       epaddr->data[i]);
4432*1b481fc3SMaciej Żenczykowski 		printf("\n");
4433*1b481fc3SMaciej Żenczykowski 	}
4434*1b481fc3SMaciej Żenczykowski 	free(epaddr);
4435*1b481fc3SMaciej Żenczykowski 
4436*1b481fc3SMaciej Żenczykowski 	return err;
4437*1b481fc3SMaciej Żenczykowski }
4438*1b481fc3SMaciej Żenczykowski 
flow_type_is_ntuple_supported(__u32 flow_type)4439*1b481fc3SMaciej Żenczykowski static bool flow_type_is_ntuple_supported(__u32 flow_type)
4440*1b481fc3SMaciej Żenczykowski {
4441*1b481fc3SMaciej Żenczykowski 	switch (flow_type) {
4442*1b481fc3SMaciej Żenczykowski 	case TCP_V4_FLOW:
4443*1b481fc3SMaciej Żenczykowski 	case UDP_V4_FLOW:
4444*1b481fc3SMaciej Żenczykowski 	case SCTP_V4_FLOW:
4445*1b481fc3SMaciej Żenczykowski 	case AH_V4_FLOW:
4446*1b481fc3SMaciej Żenczykowski 	case ESP_V4_FLOW:
4447*1b481fc3SMaciej Żenczykowski 	case IPV4_USER_FLOW:
4448*1b481fc3SMaciej Żenczykowski 	case ETHER_FLOW:
4449*1b481fc3SMaciej Żenczykowski 		return true;
4450*1b481fc3SMaciej Żenczykowski 	default:
4451*1b481fc3SMaciej Żenczykowski 		return false;
4452*1b481fc3SMaciej Żenczykowski 	}
4453*1b481fc3SMaciej Żenczykowski }
4454*1b481fc3SMaciej Żenczykowski 
flow_spec_to_ntuple(struct ethtool_rx_flow_spec * fsp,struct ethtool_rx_ntuple_flow_spec * ntuple)4455*1b481fc3SMaciej Żenczykowski static int flow_spec_to_ntuple(struct ethtool_rx_flow_spec *fsp,
4456*1b481fc3SMaciej Żenczykowski 			       struct ethtool_rx_ntuple_flow_spec *ntuple)
4457*1b481fc3SMaciej Żenczykowski {
4458*1b481fc3SMaciej Żenczykowski 	size_t i;
4459*1b481fc3SMaciej Żenczykowski 
4460*1b481fc3SMaciej Żenczykowski 	/* verify location is not specified */
4461*1b481fc3SMaciej Żenczykowski 	if (fsp->location != RX_CLS_LOC_ANY)
4462*1b481fc3SMaciej Żenczykowski 		return -1;
4463*1b481fc3SMaciej Żenczykowski 
4464*1b481fc3SMaciej Żenczykowski 	/* destination MAC address in L3/L4 rules is not supported by ntuple */
4465*1b481fc3SMaciej Żenczykowski 	if (fsp->flow_type & FLOW_MAC_EXT)
4466*1b481fc3SMaciej Żenczykowski 		return -1;
4467*1b481fc3SMaciej Żenczykowski 
4468*1b481fc3SMaciej Żenczykowski 	/* verify ring cookie can transfer to action */
4469*1b481fc3SMaciej Żenczykowski 	if (fsp->ring_cookie > INT_MAX && fsp->ring_cookie < (u64)(-2))
4470*1b481fc3SMaciej Żenczykowski 		return -1;
4471*1b481fc3SMaciej Żenczykowski 
4472*1b481fc3SMaciej Żenczykowski 	/* verify only one field is setting data field */
4473*1b481fc3SMaciej Żenczykowski 	if ((fsp->flow_type & FLOW_EXT) &&
4474*1b481fc3SMaciej Żenczykowski 	    (fsp->m_ext.data[0] || fsp->m_ext.data[1]) &&
4475*1b481fc3SMaciej Żenczykowski 	    fsp->m_ext.vlan_etype)
4476*1b481fc3SMaciej Żenczykowski 		return -1;
4477*1b481fc3SMaciej Żenczykowski 
4478*1b481fc3SMaciej Żenczykowski 	/* IPv6 flow types are not supported by ntuple */
4479*1b481fc3SMaciej Żenczykowski 	if (!flow_type_is_ntuple_supported(fsp->flow_type & ~FLOW_EXT))
4480*1b481fc3SMaciej Żenczykowski 		return -1;
4481*1b481fc3SMaciej Żenczykowski 
4482*1b481fc3SMaciej Żenczykowski 	/* Set entire ntuple to ~0 to guarantee all masks are set */
4483*1b481fc3SMaciej Żenczykowski 	memset(ntuple, ~0, sizeof(*ntuple));
4484*1b481fc3SMaciej Żenczykowski 
4485*1b481fc3SMaciej Żenczykowski 	/* set non-filter values */
4486*1b481fc3SMaciej Żenczykowski 	ntuple->flow_type = fsp->flow_type;
4487*1b481fc3SMaciej Żenczykowski 	ntuple->action = fsp->ring_cookie;
4488*1b481fc3SMaciej Żenczykowski 
4489*1b481fc3SMaciej Żenczykowski 	/*
4490*1b481fc3SMaciej Żenczykowski 	 * Copy over header union, they are identical in layout however
4491*1b481fc3SMaciej Żenczykowski 	 * the ntuple union contains additional padding on the end
4492*1b481fc3SMaciej Żenczykowski 	 */
4493*1b481fc3SMaciej Żenczykowski 	memcpy(&ntuple->h_u, &fsp->h_u, sizeof(fsp->h_u));
4494*1b481fc3SMaciej Żenczykowski 
4495*1b481fc3SMaciej Żenczykowski 	/*
4496*1b481fc3SMaciej Żenczykowski 	 * The same rule mentioned above applies to the mask union.  However,
4497*1b481fc3SMaciej Żenczykowski 	 * in addition we need to invert the mask bits to match the ntuple
4498*1b481fc3SMaciej Żenczykowski 	 * mask which is 1 for masked, versus 0 for masked as seen in nfc.
4499*1b481fc3SMaciej Żenczykowski 	 */
4500*1b481fc3SMaciej Żenczykowski 	memcpy(&ntuple->m_u, &fsp->m_u, sizeof(fsp->m_u));
4501*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < sizeof(fsp->m_u); i++)
4502*1b481fc3SMaciej Żenczykowski 		ntuple->m_u.hdata[i] ^= 0xFF;
4503*1b481fc3SMaciej Żenczykowski 
4504*1b481fc3SMaciej Żenczykowski 	/* copy extended fields */
4505*1b481fc3SMaciej Żenczykowski 	if (fsp->flow_type & FLOW_EXT) {
4506*1b481fc3SMaciej Żenczykowski 		ntuple->vlan_tag =
4507*1b481fc3SMaciej Żenczykowski 			ntohs(fsp->h_ext.vlan_tci);
4508*1b481fc3SMaciej Żenczykowski 		ntuple->vlan_tag_mask =
4509*1b481fc3SMaciej Żenczykowski 			~ntohs(fsp->m_ext.vlan_tci);
4510*1b481fc3SMaciej Żenczykowski 		if (fsp->m_ext.vlan_etype) {
4511*1b481fc3SMaciej Żenczykowski 			/*
4512*1b481fc3SMaciej Żenczykowski 			 * vlan_etype and user data are mutually exclusive
4513*1b481fc3SMaciej Żenczykowski 			 * in ntuple configuration as they occupy the same
4514*1b481fc3SMaciej Żenczykowski 			 * space.
4515*1b481fc3SMaciej Żenczykowski 			 */
4516*1b481fc3SMaciej Żenczykowski 			if (fsp->m_ext.data[0] || fsp->m_ext.data[1])
4517*1b481fc3SMaciej Żenczykowski 				return -1;
4518*1b481fc3SMaciej Żenczykowski 			ntuple->data =
4519*1b481fc3SMaciej Żenczykowski 				ntohl(fsp->h_ext.vlan_etype);
4520*1b481fc3SMaciej Żenczykowski 			ntuple->data_mask =
4521*1b481fc3SMaciej Żenczykowski 				~(u64)ntohl(fsp->m_ext.vlan_etype);
4522*1b481fc3SMaciej Żenczykowski 		} else {
4523*1b481fc3SMaciej Żenczykowski 			ntuple->data =
4524*1b481fc3SMaciej Żenczykowski 				(u64)ntohl(fsp->h_ext.data[0]) << 32;
4525*1b481fc3SMaciej Żenczykowski 			ntuple->data |=
4526*1b481fc3SMaciej Żenczykowski 				(u64)ntohl(fsp->h_ext.data[1]);
4527*1b481fc3SMaciej Żenczykowski 			ntuple->data_mask =
4528*1b481fc3SMaciej Żenczykowski 				(u64)ntohl(~fsp->m_ext.data[0]) << 32;
4529*1b481fc3SMaciej Żenczykowski 			ntuple->data_mask |=
4530*1b481fc3SMaciej Żenczykowski 				(u64)ntohl(~fsp->m_ext.data[1]);
4531*1b481fc3SMaciej Żenczykowski 		}
4532*1b481fc3SMaciej Żenczykowski 	}
4533*1b481fc3SMaciej Żenczykowski 
4534*1b481fc3SMaciej Żenczykowski 	/* Mask out the extended bit, because ntuple does not know it! */
4535*1b481fc3SMaciej Żenczykowski 	ntuple->flow_type &= ~FLOW_EXT;
4536*1b481fc3SMaciej Żenczykowski 
4537*1b481fc3SMaciej Żenczykowski 	return 0;
4538*1b481fc3SMaciej Żenczykowski }
4539*1b481fc3SMaciej Żenczykowski 
do_srxntuple(struct cmd_context * ctx,struct ethtool_rx_flow_spec * rx_rule_fs)4540*1b481fc3SMaciej Żenczykowski static int do_srxntuple(struct cmd_context *ctx,
4541*1b481fc3SMaciej Żenczykowski 			struct ethtool_rx_flow_spec *rx_rule_fs)
4542*1b481fc3SMaciej Żenczykowski {
4543*1b481fc3SMaciej Żenczykowski 	struct ethtool_rx_ntuple ntuplecmd;
4544*1b481fc3SMaciej Żenczykowski 	struct ethtool_value eval;
4545*1b481fc3SMaciej Żenczykowski 	int err;
4546*1b481fc3SMaciej Żenczykowski 
4547*1b481fc3SMaciej Żenczykowski 	/* attempt to convert the flow classifier to an ntuple classifier */
4548*1b481fc3SMaciej Żenczykowski 	err = flow_spec_to_ntuple(rx_rule_fs, &ntuplecmd.fs);
4549*1b481fc3SMaciej Żenczykowski 	if (err)
4550*1b481fc3SMaciej Żenczykowski 		return -1;
4551*1b481fc3SMaciej Żenczykowski 
4552*1b481fc3SMaciej Żenczykowski 	/*
4553*1b481fc3SMaciej Żenczykowski 	 * Check to see if the flag is set for N-tuple, this allows
4554*1b481fc3SMaciej Żenczykowski 	 * us to avoid the possible EINVAL response for the N-tuple
4555*1b481fc3SMaciej Żenczykowski 	 * flag not being set on the device
4556*1b481fc3SMaciej Żenczykowski 	 */
4557*1b481fc3SMaciej Żenczykowski 	eval.cmd = ETHTOOL_GFLAGS;
4558*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &eval);
4559*1b481fc3SMaciej Żenczykowski 	if (err || !(eval.data & ETH_FLAG_NTUPLE))
4560*1b481fc3SMaciej Żenczykowski 		return -1;
4561*1b481fc3SMaciej Żenczykowski 
4562*1b481fc3SMaciej Żenczykowski 	/* send rule via N-tuple */
4563*1b481fc3SMaciej Żenczykowski 	ntuplecmd.cmd = ETHTOOL_SRXNTUPLE;
4564*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &ntuplecmd);
4565*1b481fc3SMaciej Żenczykowski 
4566*1b481fc3SMaciej Żenczykowski 	/*
4567*1b481fc3SMaciej Żenczykowski 	 * Display error only if response is something other than op not
4568*1b481fc3SMaciej Żenczykowski 	 * supported.  It is possible that the interface uses the network
4569*1b481fc3SMaciej Żenczykowski 	 * flow classifier interface instead of N-tuple.
4570*1b481fc3SMaciej Żenczykowski 	 */
4571*1b481fc3SMaciej Żenczykowski 	if (err < 0) {
4572*1b481fc3SMaciej Żenczykowski 		if (errno != EOPNOTSUPP)
4573*1b481fc3SMaciej Żenczykowski 			perror("Cannot add new rule via N-tuple");
4574*1b481fc3SMaciej Żenczykowski 		return -1;
4575*1b481fc3SMaciej Żenczykowski 	}
4576*1b481fc3SMaciej Żenczykowski 
4577*1b481fc3SMaciej Żenczykowski 	return 0;
4578*1b481fc3SMaciej Żenczykowski }
4579*1b481fc3SMaciej Żenczykowski 
do_writefwdump(struct ethtool_dump * dump,const char * dump_file)4580*1b481fc3SMaciej Żenczykowski static int do_writefwdump(struct ethtool_dump *dump, const char *dump_file)
4581*1b481fc3SMaciej Żenczykowski {
4582*1b481fc3SMaciej Żenczykowski 	int err = 0;
4583*1b481fc3SMaciej Żenczykowski 	FILE *f;
4584*1b481fc3SMaciej Żenczykowski 	size_t bytes;
4585*1b481fc3SMaciej Żenczykowski 
4586*1b481fc3SMaciej Żenczykowski 	f = fopen(dump_file, "wb+");
4587*1b481fc3SMaciej Żenczykowski 
4588*1b481fc3SMaciej Żenczykowski 	if (!f) {
4589*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "Can't open file %s: %s\n",
4590*1b481fc3SMaciej Żenczykowski 			dump_file, strerror(errno));
4591*1b481fc3SMaciej Żenczykowski 		return 1;
4592*1b481fc3SMaciej Żenczykowski 	}
4593*1b481fc3SMaciej Żenczykowski 	bytes = fwrite(dump->data, 1, dump->len, f);
4594*1b481fc3SMaciej Żenczykowski 	if (bytes != dump->len) {
4595*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "Can not write all of dump data\n");
4596*1b481fc3SMaciej Żenczykowski 		err = 1;
4597*1b481fc3SMaciej Żenczykowski 	}
4598*1b481fc3SMaciej Żenczykowski 	if (fclose(f)) {
4599*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "Can't close file %s: %s\n",
4600*1b481fc3SMaciej Żenczykowski 			dump_file, strerror(errno));
4601*1b481fc3SMaciej Żenczykowski 		err = 1;
4602*1b481fc3SMaciej Żenczykowski 	}
4603*1b481fc3SMaciej Żenczykowski 	return err;
4604*1b481fc3SMaciej Żenczykowski }
4605*1b481fc3SMaciej Żenczykowski 
do_getfwdump(struct cmd_context * ctx)4606*1b481fc3SMaciej Żenczykowski static int do_getfwdump(struct cmd_context *ctx)
4607*1b481fc3SMaciej Żenczykowski {
4608*1b481fc3SMaciej Żenczykowski 	u32 dump_flag;
4609*1b481fc3SMaciej Żenczykowski 	char *dump_file;
4610*1b481fc3SMaciej Żenczykowski 	int err;
4611*1b481fc3SMaciej Żenczykowski 	struct ethtool_dump edata;
4612*1b481fc3SMaciej Żenczykowski 	struct ethtool_dump *data;
4613*1b481fc3SMaciej Żenczykowski 
4614*1b481fc3SMaciej Żenczykowski 	if (ctx->argc == 2 && !strcmp(ctx->argp[0], "data")) {
4615*1b481fc3SMaciej Żenczykowski 		dump_flag = ETHTOOL_GET_DUMP_DATA;
4616*1b481fc3SMaciej Żenczykowski 		dump_file = ctx->argp[1];
4617*1b481fc3SMaciej Żenczykowski 	} else if (ctx->argc == 0) {
4618*1b481fc3SMaciej Żenczykowski 		dump_flag = 0;
4619*1b481fc3SMaciej Żenczykowski 		dump_file = NULL;
4620*1b481fc3SMaciej Żenczykowski 	} else {
4621*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
4622*1b481fc3SMaciej Żenczykowski 	}
4623*1b481fc3SMaciej Żenczykowski 
4624*1b481fc3SMaciej Żenczykowski 	edata.cmd = ETHTOOL_GET_DUMP_FLAG;
4625*1b481fc3SMaciej Żenczykowski 
4626*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &edata);
4627*1b481fc3SMaciej Żenczykowski 	if (err < 0) {
4628*1b481fc3SMaciej Żenczykowski 		perror("Can not get dump level");
4629*1b481fc3SMaciej Żenczykowski 		return 1;
4630*1b481fc3SMaciej Żenczykowski 	}
4631*1b481fc3SMaciej Żenczykowski 	if (dump_flag != ETHTOOL_GET_DUMP_DATA) {
4632*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "flag: %u, version: %u, length: %u\n",
4633*1b481fc3SMaciej Żenczykowski 			edata.flag, edata.version, edata.len);
4634*1b481fc3SMaciej Żenczykowski 		return 0;
4635*1b481fc3SMaciej Żenczykowski 	}
4636*1b481fc3SMaciej Żenczykowski 	data = calloc(1, offsetof(struct ethtool_dump, data) + edata.len);
4637*1b481fc3SMaciej Żenczykowski 	if (!data) {
4638*1b481fc3SMaciej Żenczykowski 		perror("Can not allocate enough memory");
4639*1b481fc3SMaciej Żenczykowski 		return 1;
4640*1b481fc3SMaciej Żenczykowski 	}
4641*1b481fc3SMaciej Żenczykowski 	data->cmd = ETHTOOL_GET_DUMP_DATA;
4642*1b481fc3SMaciej Żenczykowski 	data->len = edata.len;
4643*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, data);
4644*1b481fc3SMaciej Żenczykowski 	if (err < 0) {
4645*1b481fc3SMaciej Żenczykowski 		perror("Can not get dump data");
4646*1b481fc3SMaciej Żenczykowski 		err = 1;
4647*1b481fc3SMaciej Żenczykowski 		goto free;
4648*1b481fc3SMaciej Żenczykowski 	}
4649*1b481fc3SMaciej Żenczykowski 	err = do_writefwdump(data, dump_file);
4650*1b481fc3SMaciej Żenczykowski free:
4651*1b481fc3SMaciej Żenczykowski 	free(data);
4652*1b481fc3SMaciej Żenczykowski 	return err;
4653*1b481fc3SMaciej Żenczykowski }
4654*1b481fc3SMaciej Żenczykowski 
do_setfwdump(struct cmd_context * ctx)4655*1b481fc3SMaciej Żenczykowski static int do_setfwdump(struct cmd_context *ctx)
4656*1b481fc3SMaciej Żenczykowski {
4657*1b481fc3SMaciej Żenczykowski 	u32 dump_flag;
4658*1b481fc3SMaciej Żenczykowski 	int err;
4659*1b481fc3SMaciej Żenczykowski 	struct ethtool_dump dump;
4660*1b481fc3SMaciej Żenczykowski 
4661*1b481fc3SMaciej Żenczykowski 	if (ctx->argc != 1)
4662*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
4663*1b481fc3SMaciej Żenczykowski 	dump_flag = get_u32(ctx->argp[0], 0);
4664*1b481fc3SMaciej Żenczykowski 
4665*1b481fc3SMaciej Żenczykowski 	dump.cmd = ETHTOOL_SET_DUMP;
4666*1b481fc3SMaciej Żenczykowski 	dump.flag = dump_flag;
4667*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &dump);
4668*1b481fc3SMaciej Żenczykowski 	if (err < 0) {
4669*1b481fc3SMaciej Żenczykowski 		perror("Can not set dump level");
4670*1b481fc3SMaciej Żenczykowski 		return 1;
4671*1b481fc3SMaciej Żenczykowski 	}
4672*1b481fc3SMaciej Żenczykowski 	return 0;
4673*1b481fc3SMaciej Żenczykowski }
4674*1b481fc3SMaciej Żenczykowski 
do_gprivflags(struct cmd_context * ctx)4675*1b481fc3SMaciej Żenczykowski static int do_gprivflags(struct cmd_context *ctx)
4676*1b481fc3SMaciej Żenczykowski {
4677*1b481fc3SMaciej Żenczykowski 	struct ethtool_gstrings *strings;
4678*1b481fc3SMaciej Żenczykowski 	struct ethtool_value flags;
4679*1b481fc3SMaciej Żenczykowski 	unsigned int i;
4680*1b481fc3SMaciej Żenczykowski 	int max_len = 0, cur_len, rc;
4681*1b481fc3SMaciej Żenczykowski 
4682*1b481fc3SMaciej Żenczykowski 	if (ctx->argc != 0)
4683*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
4684*1b481fc3SMaciej Żenczykowski 
4685*1b481fc3SMaciej Żenczykowski 	strings = get_stringset(ctx, ETH_SS_PRIV_FLAGS,
4686*1b481fc3SMaciej Żenczykowski 				offsetof(struct ethtool_drvinfo, n_priv_flags),
4687*1b481fc3SMaciej Żenczykowski 				1);
4688*1b481fc3SMaciej Żenczykowski 	if (!strings) {
4689*1b481fc3SMaciej Żenczykowski 		perror("Cannot get private flag names");
4690*1b481fc3SMaciej Żenczykowski 		return 1;
4691*1b481fc3SMaciej Żenczykowski 	}
4692*1b481fc3SMaciej Żenczykowski 	if (strings->len == 0) {
4693*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "No private flags defined\n");
4694*1b481fc3SMaciej Żenczykowski 		rc = 1;
4695*1b481fc3SMaciej Żenczykowski 		goto err;
4696*1b481fc3SMaciej Żenczykowski 	}
4697*1b481fc3SMaciej Żenczykowski 	if (strings->len > 32) {
4698*1b481fc3SMaciej Żenczykowski 		/* ETHTOOL_GPFLAGS can only cover 32 flags */
4699*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "Only showing first 32 private flags\n");
4700*1b481fc3SMaciej Żenczykowski 		strings->len = 32;
4701*1b481fc3SMaciej Żenczykowski 	}
4702*1b481fc3SMaciej Żenczykowski 
4703*1b481fc3SMaciej Żenczykowski 	flags.cmd = ETHTOOL_GPFLAGS;
4704*1b481fc3SMaciej Żenczykowski 	if (send_ioctl(ctx, &flags)) {
4705*1b481fc3SMaciej Żenczykowski 		perror("Cannot get private flags");
4706*1b481fc3SMaciej Żenczykowski 		rc = 1;
4707*1b481fc3SMaciej Żenczykowski 		goto err;
4708*1b481fc3SMaciej Żenczykowski 	}
4709*1b481fc3SMaciej Żenczykowski 
4710*1b481fc3SMaciej Żenczykowski 	/* Find longest string and align all strings accordingly */
4711*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < strings->len; i++) {
4712*1b481fc3SMaciej Żenczykowski 		cur_len = strlen((const char *)strings->data +
4713*1b481fc3SMaciej Żenczykowski 				 i * ETH_GSTRING_LEN);
4714*1b481fc3SMaciej Żenczykowski 		if (cur_len > max_len)
4715*1b481fc3SMaciej Żenczykowski 			max_len = cur_len;
4716*1b481fc3SMaciej Żenczykowski 	}
4717*1b481fc3SMaciej Żenczykowski 
4718*1b481fc3SMaciej Żenczykowski 	printf("Private flags for %s:\n", ctx->devname);
4719*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < strings->len; i++)
4720*1b481fc3SMaciej Żenczykowski 		printf("%-*s: %s\n",
4721*1b481fc3SMaciej Żenczykowski 		       max_len,
4722*1b481fc3SMaciej Żenczykowski 		       (const char *)strings->data + i * ETH_GSTRING_LEN,
4723*1b481fc3SMaciej Żenczykowski 		       (flags.data & (1U << i)) ? "on" : "off");
4724*1b481fc3SMaciej Żenczykowski 
4725*1b481fc3SMaciej Żenczykowski 	rc = 0;
4726*1b481fc3SMaciej Żenczykowski 
4727*1b481fc3SMaciej Żenczykowski err:
4728*1b481fc3SMaciej Żenczykowski 	free(strings);
4729*1b481fc3SMaciej Żenczykowski 	return rc;
4730*1b481fc3SMaciej Żenczykowski }
4731*1b481fc3SMaciej Żenczykowski 
do_sprivflags(struct cmd_context * ctx)4732*1b481fc3SMaciej Żenczykowski static int do_sprivflags(struct cmd_context *ctx)
4733*1b481fc3SMaciej Żenczykowski {
4734*1b481fc3SMaciej Żenczykowski 	struct ethtool_gstrings *strings;
4735*1b481fc3SMaciej Żenczykowski 	struct cmdline_info *cmdline;
4736*1b481fc3SMaciej Żenczykowski 	struct ethtool_value flags;
4737*1b481fc3SMaciej Żenczykowski 	u32 wanted_flags = 0, seen_flags = 0;
4738*1b481fc3SMaciej Żenczykowski 	int any_changed, rc;
4739*1b481fc3SMaciej Żenczykowski 	unsigned int i;
4740*1b481fc3SMaciej Żenczykowski 
4741*1b481fc3SMaciej Żenczykowski 	strings = get_stringset(ctx, ETH_SS_PRIV_FLAGS,
4742*1b481fc3SMaciej Żenczykowski 				offsetof(struct ethtool_drvinfo, n_priv_flags),
4743*1b481fc3SMaciej Żenczykowski 				1);
4744*1b481fc3SMaciej Żenczykowski 	if (!strings) {
4745*1b481fc3SMaciej Żenczykowski 		perror("Cannot get private flag names");
4746*1b481fc3SMaciej Żenczykowski 		return 1;
4747*1b481fc3SMaciej Żenczykowski 	}
4748*1b481fc3SMaciej Żenczykowski 	if (strings->len == 0) {
4749*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "No private flags defined\n");
4750*1b481fc3SMaciej Żenczykowski 		rc = 1;
4751*1b481fc3SMaciej Żenczykowski 		goto err;
4752*1b481fc3SMaciej Żenczykowski 	}
4753*1b481fc3SMaciej Żenczykowski 	if (strings->len > 32) {
4754*1b481fc3SMaciej Żenczykowski 		/* ETHTOOL_{G,S}PFLAGS can only cover 32 flags */
4755*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "Only setting first 32 private flags\n");
4756*1b481fc3SMaciej Żenczykowski 		strings->len = 32;
4757*1b481fc3SMaciej Żenczykowski 	}
4758*1b481fc3SMaciej Żenczykowski 
4759*1b481fc3SMaciej Żenczykowski 	cmdline = calloc(strings->len, sizeof(*cmdline));
4760*1b481fc3SMaciej Żenczykowski 	if (!cmdline) {
4761*1b481fc3SMaciej Żenczykowski 		perror("Cannot parse arguments");
4762*1b481fc3SMaciej Żenczykowski 		rc = 1;
4763*1b481fc3SMaciej Żenczykowski 		goto err;
4764*1b481fc3SMaciej Żenczykowski 	}
4765*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < strings->len; i++) {
4766*1b481fc3SMaciej Żenczykowski 		cmdline[i].name = ((const char *)strings->data +
4767*1b481fc3SMaciej Żenczykowski 				   i * ETH_GSTRING_LEN);
4768*1b481fc3SMaciej Żenczykowski 		cmdline[i].type = CMDL_FLAG;
4769*1b481fc3SMaciej Żenczykowski 		cmdline[i].wanted_val = &wanted_flags;
4770*1b481fc3SMaciej Żenczykowski 		cmdline[i].flag_val = 1U << i;
4771*1b481fc3SMaciej Żenczykowski 		cmdline[i].seen_val = &seen_flags;
4772*1b481fc3SMaciej Żenczykowski 	}
4773*1b481fc3SMaciej Żenczykowski 	parse_generic_cmdline(ctx, &any_changed, cmdline, strings->len);
4774*1b481fc3SMaciej Żenczykowski 	free(cmdline);
4775*1b481fc3SMaciej Żenczykowski 
4776*1b481fc3SMaciej Żenczykowski 	flags.cmd = ETHTOOL_GPFLAGS;
4777*1b481fc3SMaciej Żenczykowski 	if (send_ioctl(ctx, &flags)) {
4778*1b481fc3SMaciej Żenczykowski 		perror("Cannot get private flags");
4779*1b481fc3SMaciej Żenczykowski 		rc = 1;
4780*1b481fc3SMaciej Żenczykowski 		goto err;
4781*1b481fc3SMaciej Żenczykowski 	}
4782*1b481fc3SMaciej Żenczykowski 
4783*1b481fc3SMaciej Żenczykowski 	flags.cmd = ETHTOOL_SPFLAGS;
4784*1b481fc3SMaciej Żenczykowski 	flags.data = (flags.data & ~seen_flags) | wanted_flags;
4785*1b481fc3SMaciej Żenczykowski 	if (send_ioctl(ctx, &flags)) {
4786*1b481fc3SMaciej Żenczykowski 		perror("Cannot set private flags");
4787*1b481fc3SMaciej Żenczykowski 		rc = 1;
4788*1b481fc3SMaciej Żenczykowski 		goto err;
4789*1b481fc3SMaciej Żenczykowski 	}
4790*1b481fc3SMaciej Żenczykowski 
4791*1b481fc3SMaciej Żenczykowski 	rc = 0;
4792*1b481fc3SMaciej Żenczykowski err:
4793*1b481fc3SMaciej Żenczykowski 	free(strings);
4794*1b481fc3SMaciej Żenczykowski 	return rc;
4795*1b481fc3SMaciej Żenczykowski }
4796*1b481fc3SMaciej Żenczykowski 
do_tsinfo(struct cmd_context * ctx)4797*1b481fc3SMaciej Żenczykowski static int do_tsinfo(struct cmd_context *ctx)
4798*1b481fc3SMaciej Żenczykowski {
4799*1b481fc3SMaciej Żenczykowski 	struct ethtool_ts_info info;
4800*1b481fc3SMaciej Żenczykowski 
4801*1b481fc3SMaciej Żenczykowski 	if (ctx->argc != 0)
4802*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
4803*1b481fc3SMaciej Żenczykowski 
4804*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "Time stamping parameters for %s:\n", ctx->devname);
4805*1b481fc3SMaciej Żenczykowski 	info.cmd = ETHTOOL_GET_TS_INFO;
4806*1b481fc3SMaciej Żenczykowski 	if (send_ioctl(ctx, &info)) {
4807*1b481fc3SMaciej Żenczykowski 		perror("Cannot get device time stamping settings");
4808*1b481fc3SMaciej Żenczykowski 		return -1;
4809*1b481fc3SMaciej Żenczykowski 	}
4810*1b481fc3SMaciej Żenczykowski 	dump_tsinfo(&info);
4811*1b481fc3SMaciej Żenczykowski 	return 0;
4812*1b481fc3SMaciej Żenczykowski }
4813*1b481fc3SMaciej Żenczykowski 
do_getmodule(struct cmd_context * ctx)4814*1b481fc3SMaciej Żenczykowski static int do_getmodule(struct cmd_context *ctx)
4815*1b481fc3SMaciej Żenczykowski {
4816*1b481fc3SMaciej Żenczykowski 	struct ethtool_modinfo modinfo;
4817*1b481fc3SMaciej Żenczykowski 	struct ethtool_eeprom *eeprom;
4818*1b481fc3SMaciej Żenczykowski 	u32 geeprom_offset = 0;
4819*1b481fc3SMaciej Żenczykowski 	u32 geeprom_length = 0;
4820*1b481fc3SMaciej Żenczykowski 	int geeprom_changed = 0;
4821*1b481fc3SMaciej Żenczykowski 	int geeprom_dump_raw = 0;
4822*1b481fc3SMaciej Żenczykowski 	int geeprom_dump_hex = 0;
4823*1b481fc3SMaciej Żenczykowski 	int geeprom_length_seen = 0;
4824*1b481fc3SMaciej Żenczykowski 	int err;
4825*1b481fc3SMaciej Żenczykowski 
4826*1b481fc3SMaciej Żenczykowski 	struct cmdline_info cmdline_geeprom[] = {
4827*1b481fc3SMaciej Żenczykowski 		{
4828*1b481fc3SMaciej Żenczykowski 			.name		= "offset",
4829*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_U32,
4830*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &geeprom_offset,
4831*1b481fc3SMaciej Żenczykowski 		},
4832*1b481fc3SMaciej Żenczykowski 		{
4833*1b481fc3SMaciej Żenczykowski 			.name		= "length",
4834*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_U32,
4835*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &geeprom_length,
4836*1b481fc3SMaciej Żenczykowski 			.seen_val	= &geeprom_length_seen,
4837*1b481fc3SMaciej Żenczykowski 		},
4838*1b481fc3SMaciej Żenczykowski 		{
4839*1b481fc3SMaciej Żenczykowski 			.name		= "raw",
4840*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_BOOL,
4841*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &geeprom_dump_raw,
4842*1b481fc3SMaciej Żenczykowski 		},
4843*1b481fc3SMaciej Żenczykowski 		{
4844*1b481fc3SMaciej Żenczykowski 			.name		= "hex",
4845*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_BOOL,
4846*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &geeprom_dump_hex,
4847*1b481fc3SMaciej Żenczykowski 		},
4848*1b481fc3SMaciej Żenczykowski 	};
4849*1b481fc3SMaciej Żenczykowski 
4850*1b481fc3SMaciej Żenczykowski 	parse_generic_cmdline(ctx, &geeprom_changed,
4851*1b481fc3SMaciej Żenczykowski 			      cmdline_geeprom, ARRAY_SIZE(cmdline_geeprom));
4852*1b481fc3SMaciej Żenczykowski 
4853*1b481fc3SMaciej Żenczykowski 	if (geeprom_dump_raw && geeprom_dump_hex) {
4854*1b481fc3SMaciej Żenczykowski 		printf("Hex and raw dump cannot be specified together\n");
4855*1b481fc3SMaciej Żenczykowski 		return 1;
4856*1b481fc3SMaciej Żenczykowski 	}
4857*1b481fc3SMaciej Żenczykowski 
4858*1b481fc3SMaciej Żenczykowski 	modinfo.cmd = ETHTOOL_GMODULEINFO;
4859*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, &modinfo);
4860*1b481fc3SMaciej Żenczykowski 	if (err < 0) {
4861*1b481fc3SMaciej Żenczykowski 		perror("Cannot get module EEPROM information");
4862*1b481fc3SMaciej Żenczykowski 		return 1;
4863*1b481fc3SMaciej Żenczykowski 	}
4864*1b481fc3SMaciej Żenczykowski 
4865*1b481fc3SMaciej Żenczykowski 	if (!geeprom_length_seen)
4866*1b481fc3SMaciej Żenczykowski 		geeprom_length = modinfo.eeprom_len;
4867*1b481fc3SMaciej Żenczykowski 
4868*1b481fc3SMaciej Żenczykowski 	if (modinfo.eeprom_len < geeprom_offset + geeprom_length)
4869*1b481fc3SMaciej Żenczykowski 		geeprom_length = modinfo.eeprom_len - geeprom_offset;
4870*1b481fc3SMaciej Żenczykowski 
4871*1b481fc3SMaciej Żenczykowski 	eeprom = calloc(1, sizeof(*eeprom)+geeprom_length);
4872*1b481fc3SMaciej Żenczykowski 	if (!eeprom) {
4873*1b481fc3SMaciej Żenczykowski 		perror("Cannot allocate memory for Module EEPROM data");
4874*1b481fc3SMaciej Żenczykowski 		return 1;
4875*1b481fc3SMaciej Żenczykowski 	}
4876*1b481fc3SMaciej Żenczykowski 
4877*1b481fc3SMaciej Żenczykowski 	eeprom->cmd = ETHTOOL_GMODULEEEPROM;
4878*1b481fc3SMaciej Żenczykowski 	eeprom->len = geeprom_length;
4879*1b481fc3SMaciej Żenczykowski 	eeprom->offset = geeprom_offset;
4880*1b481fc3SMaciej Żenczykowski 	err = send_ioctl(ctx, eeprom);
4881*1b481fc3SMaciej Żenczykowski 	if (err < 0) {
4882*1b481fc3SMaciej Żenczykowski 		int saved_errno = errno;
4883*1b481fc3SMaciej Żenczykowski 
4884*1b481fc3SMaciej Żenczykowski 		perror("Cannot get Module EEPROM data");
4885*1b481fc3SMaciej Żenczykowski 		if (saved_errno == ENODEV || saved_errno == EIO ||
4886*1b481fc3SMaciej Żenczykowski 		    saved_errno == ENXIO)
4887*1b481fc3SMaciej Żenczykowski 			fprintf(stderr, "SFP module not in cage?\n");
4888*1b481fc3SMaciej Żenczykowski 		free(eeprom);
4889*1b481fc3SMaciej Żenczykowski 		return 1;
4890*1b481fc3SMaciej Żenczykowski 	}
4891*1b481fc3SMaciej Żenczykowski 
4892*1b481fc3SMaciej Żenczykowski 	/*
4893*1b481fc3SMaciej Żenczykowski 	 * SFF-8079 EEPROM layout contains the memory available at A0 address on
4894*1b481fc3SMaciej Żenczykowski 	 * the PHY EEPROM.
4895*1b481fc3SMaciej Żenczykowski 	 * SFF-8472 defines a virtual extension of the EEPROM, where the
4896*1b481fc3SMaciej Żenczykowski 	 * microcontroller on the SFP/SFP+ generates a page at the A2 address,
4897*1b481fc3SMaciej Żenczykowski 	 * which contains data relative to optical diagnostics.
4898*1b481fc3SMaciej Żenczykowski 	 * The current kernel implementation returns a blob, which contains:
4899*1b481fc3SMaciej Żenczykowski 	 *  - ETH_MODULE_SFF_8079 => The A0 page only.
4900*1b481fc3SMaciej Żenczykowski 	 *  - ETH_MODULE_SFF_8472 => The A0 and A2 page concatenated.
4901*1b481fc3SMaciej Żenczykowski 	 */
4902*1b481fc3SMaciej Żenczykowski 	if (geeprom_dump_raw) {
4903*1b481fc3SMaciej Żenczykowski 		fwrite(eeprom->data, 1, eeprom->len, stdout);
4904*1b481fc3SMaciej Żenczykowski 	} else {
4905*1b481fc3SMaciej Żenczykowski 		if (eeprom->offset != 0  ||
4906*1b481fc3SMaciej Żenczykowski 		    (eeprom->len != modinfo.eeprom_len)) {
4907*1b481fc3SMaciej Żenczykowski 			geeprom_dump_hex = 1;
4908*1b481fc3SMaciej Żenczykowski 		} else if (!geeprom_dump_hex) {
4909*1b481fc3SMaciej Żenczykowski 			switch (modinfo.type) {
4910*1b481fc3SMaciej Żenczykowski #ifdef ETHTOOL_ENABLE_PRETTY_DUMP
4911*1b481fc3SMaciej Żenczykowski 			case ETH_MODULE_SFF_8079:
4912*1b481fc3SMaciej Żenczykowski 				sff8079_show_all_ioctl(eeprom->data);
4913*1b481fc3SMaciej Żenczykowski 				break;
4914*1b481fc3SMaciej Żenczykowski 			case ETH_MODULE_SFF_8472:
4915*1b481fc3SMaciej Żenczykowski 				sff8079_show_all_ioctl(eeprom->data);
4916*1b481fc3SMaciej Żenczykowski 				sff8472_show_all(eeprom->data);
4917*1b481fc3SMaciej Żenczykowski 				break;
4918*1b481fc3SMaciej Żenczykowski 			case ETH_MODULE_SFF_8436:
4919*1b481fc3SMaciej Żenczykowski 			case ETH_MODULE_SFF_8636:
4920*1b481fc3SMaciej Żenczykowski 				sff8636_show_all_ioctl(eeprom->data,
4921*1b481fc3SMaciej Żenczykowski 						       modinfo.eeprom_len);
4922*1b481fc3SMaciej Żenczykowski 				break;
4923*1b481fc3SMaciej Żenczykowski #endif
4924*1b481fc3SMaciej Żenczykowski 			default:
4925*1b481fc3SMaciej Żenczykowski 				geeprom_dump_hex = 1;
4926*1b481fc3SMaciej Żenczykowski 				break;
4927*1b481fc3SMaciej Żenczykowski 			}
4928*1b481fc3SMaciej Żenczykowski 		}
4929*1b481fc3SMaciej Żenczykowski 		if (geeprom_dump_hex)
4930*1b481fc3SMaciej Żenczykowski 			dump_hex(stdout, eeprom->data,
4931*1b481fc3SMaciej Żenczykowski 				 eeprom->len, eeprom->offset);
4932*1b481fc3SMaciej Żenczykowski 	}
4933*1b481fc3SMaciej Żenczykowski 
4934*1b481fc3SMaciej Żenczykowski 	free(eeprom);
4935*1b481fc3SMaciej Żenczykowski 
4936*1b481fc3SMaciej Żenczykowski 	return 0;
4937*1b481fc3SMaciej Żenczykowski }
4938*1b481fc3SMaciej Żenczykowski 
do_geee(struct cmd_context * ctx)4939*1b481fc3SMaciej Żenczykowski static int do_geee(struct cmd_context *ctx)
4940*1b481fc3SMaciej Żenczykowski {
4941*1b481fc3SMaciej Żenczykowski 	struct ethtool_eee eeecmd;
4942*1b481fc3SMaciej Żenczykowski 
4943*1b481fc3SMaciej Żenczykowski 	if (ctx->argc != 0)
4944*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
4945*1b481fc3SMaciej Żenczykowski 
4946*1b481fc3SMaciej Żenczykowski 	eeecmd.cmd = ETHTOOL_GEEE;
4947*1b481fc3SMaciej Żenczykowski 	if (send_ioctl(ctx, &eeecmd)) {
4948*1b481fc3SMaciej Żenczykowski 		perror("Cannot get EEE settings");
4949*1b481fc3SMaciej Żenczykowski 		return 1;
4950*1b481fc3SMaciej Żenczykowski 	}
4951*1b481fc3SMaciej Żenczykowski 
4952*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "EEE Settings for %s:\n", ctx->devname);
4953*1b481fc3SMaciej Żenczykowski 	dump_eeecmd(&eeecmd);
4954*1b481fc3SMaciej Żenczykowski 
4955*1b481fc3SMaciej Żenczykowski 	return 0;
4956*1b481fc3SMaciej Żenczykowski }
4957*1b481fc3SMaciej Żenczykowski 
do_seee(struct cmd_context * ctx)4958*1b481fc3SMaciej Żenczykowski static int do_seee(struct cmd_context *ctx)
4959*1b481fc3SMaciej Żenczykowski {
4960*1b481fc3SMaciej Żenczykowski 	int adv_c = -1, lpi_c = -1, lpi_time_c = -1, eee_c = -1;
4961*1b481fc3SMaciej Żenczykowski 	int change = -1, change2 = 0;
4962*1b481fc3SMaciej Żenczykowski 	struct ethtool_eee eeecmd;
4963*1b481fc3SMaciej Żenczykowski 	struct cmdline_info cmdline_eee[] = {
4964*1b481fc3SMaciej Żenczykowski 		{
4965*1b481fc3SMaciej Żenczykowski 			.name		= "advertise",
4966*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_U32,
4967*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &adv_c,
4968*1b481fc3SMaciej Żenczykowski 			.ioctl_val	= &eeecmd.advertised,
4969*1b481fc3SMaciej Żenczykowski 		},
4970*1b481fc3SMaciej Żenczykowski 		{
4971*1b481fc3SMaciej Żenczykowski 			.name		= "tx-lpi",
4972*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_BOOL,
4973*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &lpi_c,
4974*1b481fc3SMaciej Żenczykowski 			.ioctl_val	= &eeecmd.tx_lpi_enabled,
4975*1b481fc3SMaciej Żenczykowski 		},
4976*1b481fc3SMaciej Żenczykowski 		{
4977*1b481fc3SMaciej Żenczykowski 			.name		= "tx-timer",
4978*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_U32,
4979*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &lpi_time_c,
4980*1b481fc3SMaciej Żenczykowski 			.ioctl_val	= &eeecmd.tx_lpi_timer,
4981*1b481fc3SMaciej Żenczykowski 		},
4982*1b481fc3SMaciej Żenczykowski 		{
4983*1b481fc3SMaciej Żenczykowski 			.name		= "eee",
4984*1b481fc3SMaciej Żenczykowski 			.type		= CMDL_BOOL,
4985*1b481fc3SMaciej Żenczykowski 			.wanted_val	= &eee_c,
4986*1b481fc3SMaciej Żenczykowski 			.ioctl_val	= &eeecmd.eee_enabled,
4987*1b481fc3SMaciej Żenczykowski 		},
4988*1b481fc3SMaciej Żenczykowski 	};
4989*1b481fc3SMaciej Żenczykowski 
4990*1b481fc3SMaciej Żenczykowski 	if (ctx->argc == 0)
4991*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
4992*1b481fc3SMaciej Żenczykowski 
4993*1b481fc3SMaciej Żenczykowski 	parse_generic_cmdline(ctx, &change, cmdline_eee,
4994*1b481fc3SMaciej Żenczykowski 			      ARRAY_SIZE(cmdline_eee));
4995*1b481fc3SMaciej Żenczykowski 
4996*1b481fc3SMaciej Żenczykowski 	eeecmd.cmd = ETHTOOL_GEEE;
4997*1b481fc3SMaciej Żenczykowski 	if (send_ioctl(ctx, &eeecmd)) {
4998*1b481fc3SMaciej Żenczykowski 		perror("Cannot get EEE settings");
4999*1b481fc3SMaciej Żenczykowski 		return 1;
5000*1b481fc3SMaciej Żenczykowski 	}
5001*1b481fc3SMaciej Żenczykowski 
5002*1b481fc3SMaciej Żenczykowski 	do_generic_set(cmdline_eee, ARRAY_SIZE(cmdline_eee), &change2);
5003*1b481fc3SMaciej Żenczykowski 
5004*1b481fc3SMaciej Żenczykowski 	if (change2) {
5005*1b481fc3SMaciej Żenczykowski 		eeecmd.cmd = ETHTOOL_SEEE;
5006*1b481fc3SMaciej Żenczykowski 		if (send_ioctl(ctx, &eeecmd)) {
5007*1b481fc3SMaciej Żenczykowski 			perror("Cannot set EEE settings");
5008*1b481fc3SMaciej Żenczykowski 			return 1;
5009*1b481fc3SMaciej Żenczykowski 		}
5010*1b481fc3SMaciej Żenczykowski 	}
5011*1b481fc3SMaciej Żenczykowski 
5012*1b481fc3SMaciej Żenczykowski 	return 0;
5013*1b481fc3SMaciej Żenczykowski }
5014*1b481fc3SMaciej Żenczykowski 
5015*1b481fc3SMaciej Żenczykowski /* copy of net/ethtool/common.c */
5016*1b481fc3SMaciej Żenczykowski char
5017*1b481fc3SMaciej Żenczykowski tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN] = {
5018*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_ID_UNSPEC]		= "Unspec",
5019*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_RX_COPYBREAK]		= "rx-copybreak",
5020*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_TX_COPYBREAK]		= "tx-copybreak",
5021*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_TX_COPYBREAK_BUF_SIZE] = "tx-buf-size",
5022*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_PFC_PREVENTION_TOUT]	= "pfc-prevention-tout",
5023*1b481fc3SMaciej Żenczykowski };
5024*1b481fc3SMaciej Żenczykowski 
5025*1b481fc3SMaciej Żenczykowski union ethtool_tunable_info_val {
5026*1b481fc3SMaciej Żenczykowski 	uint8_t u8;
5027*1b481fc3SMaciej Żenczykowski 	uint16_t u16;
5028*1b481fc3SMaciej Żenczykowski 	uint32_t u32;
5029*1b481fc3SMaciej Żenczykowski 	uint64_t u64;
5030*1b481fc3SMaciej Żenczykowski 	int8_t s8;
5031*1b481fc3SMaciej Żenczykowski 	int16_t s16;
5032*1b481fc3SMaciej Żenczykowski 	int32_t s32;
5033*1b481fc3SMaciej Żenczykowski 	int64_t s64;
5034*1b481fc3SMaciej Żenczykowski };
5035*1b481fc3SMaciej Żenczykowski 
5036*1b481fc3SMaciej Żenczykowski struct ethtool_tunable_info {
5037*1b481fc3SMaciej Żenczykowski 	enum tunable_id t_id;
5038*1b481fc3SMaciej Żenczykowski 	enum tunable_type_id t_type_id;
5039*1b481fc3SMaciej Żenczykowski 	size_t size;
5040*1b481fc3SMaciej Żenczykowski 	cmdline_type_t type;
5041*1b481fc3SMaciej Żenczykowski 	union ethtool_tunable_info_val wanted;
5042*1b481fc3SMaciej Żenczykowski 	int seen;
5043*1b481fc3SMaciej Żenczykowski };
5044*1b481fc3SMaciej Żenczykowski 
5045*1b481fc3SMaciej Żenczykowski static struct ethtool_tunable_info tunables_info[] = {
5046*1b481fc3SMaciej Żenczykowski 	{ .t_id		= ETHTOOL_RX_COPYBREAK,
5047*1b481fc3SMaciej Żenczykowski 	  .t_type_id	= ETHTOOL_TUNABLE_U32,
5048*1b481fc3SMaciej Żenczykowski 	  .size		= sizeof(u32),
5049*1b481fc3SMaciej Żenczykowski 	  .type		= CMDL_U32,
5050*1b481fc3SMaciej Żenczykowski 	},
5051*1b481fc3SMaciej Żenczykowski 	{ .t_id		= ETHTOOL_TX_COPYBREAK,
5052*1b481fc3SMaciej Żenczykowski 	  .t_type_id	= ETHTOOL_TUNABLE_U32,
5053*1b481fc3SMaciej Żenczykowski 	  .size		= sizeof(u32),
5054*1b481fc3SMaciej Żenczykowski 	  .type		= CMDL_U32,
5055*1b481fc3SMaciej Żenczykowski 	},
5056*1b481fc3SMaciej Żenczykowski 	{ .t_id		= ETHTOOL_PFC_PREVENTION_TOUT,
5057*1b481fc3SMaciej Żenczykowski 	  .t_type_id	= ETHTOOL_TUNABLE_U16,
5058*1b481fc3SMaciej Żenczykowski 	  .size		= sizeof(u16),
5059*1b481fc3SMaciej Żenczykowski 	  .type		= CMDL_U16,
5060*1b481fc3SMaciej Żenczykowski 	},
5061*1b481fc3SMaciej Żenczykowski 	{ .t_id         = ETHTOOL_TX_COPYBREAK_BUF_SIZE,
5062*1b481fc3SMaciej Żenczykowski 	  .t_type_id    = ETHTOOL_TUNABLE_U32,
5063*1b481fc3SMaciej Żenczykowski 	  .size         = sizeof(u32),
5064*1b481fc3SMaciej Żenczykowski 	  .type         = CMDL_U32,
5065*1b481fc3SMaciej Żenczykowski 	},
5066*1b481fc3SMaciej Żenczykowski };
5067*1b481fc3SMaciej Żenczykowski #define TUNABLES_INFO_SIZE	ARRAY_SIZE(tunables_info)
5068*1b481fc3SMaciej Żenczykowski 
do_stunable(struct cmd_context * ctx)5069*1b481fc3SMaciej Żenczykowski static int do_stunable(struct cmd_context *ctx)
5070*1b481fc3SMaciej Żenczykowski {
5071*1b481fc3SMaciej Żenczykowski 	struct cmdline_info cmdline_tunable[TUNABLES_INFO_SIZE];
5072*1b481fc3SMaciej Żenczykowski 	struct ethtool_tunable_info *tinfo = tunables_info;
5073*1b481fc3SMaciej Żenczykowski 	int changed = 0;
5074*1b481fc3SMaciej Żenczykowski 	unsigned int i;
5075*1b481fc3SMaciej Żenczykowski 
5076*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < TUNABLES_INFO_SIZE; i++) {
5077*1b481fc3SMaciej Żenczykowski 		cmdline_tunable[i].name = tunable_strings[tinfo[i].t_id];
5078*1b481fc3SMaciej Żenczykowski 		cmdline_tunable[i].type = tinfo[i].type;
5079*1b481fc3SMaciej Żenczykowski 		cmdline_tunable[i].wanted_val = &tinfo[i].wanted;
5080*1b481fc3SMaciej Żenczykowski 		cmdline_tunable[i].seen_val = &tinfo[i].seen;
5081*1b481fc3SMaciej Żenczykowski 	}
5082*1b481fc3SMaciej Żenczykowski 
5083*1b481fc3SMaciej Żenczykowski 	parse_generic_cmdline(ctx, &changed, cmdline_tunable, TUNABLES_INFO_SIZE);
5084*1b481fc3SMaciej Żenczykowski 	if (!changed)
5085*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
5086*1b481fc3SMaciej Żenczykowski 
5087*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < TUNABLES_INFO_SIZE; i++) {
5088*1b481fc3SMaciej Żenczykowski 		struct ethtool_tunable *tuna;
5089*1b481fc3SMaciej Żenczykowski 		size_t size;
5090*1b481fc3SMaciej Żenczykowski 		int ret;
5091*1b481fc3SMaciej Żenczykowski 
5092*1b481fc3SMaciej Żenczykowski 		if (!tinfo[i].seen)
5093*1b481fc3SMaciej Żenczykowski 			continue;
5094*1b481fc3SMaciej Żenczykowski 
5095*1b481fc3SMaciej Żenczykowski 		size = sizeof(*tuna) + tinfo[i].size;
5096*1b481fc3SMaciej Żenczykowski 		tuna = calloc(1, size);
5097*1b481fc3SMaciej Żenczykowski 		if (!tuna) {
5098*1b481fc3SMaciej Żenczykowski 			perror(tunable_strings[tinfo[i].t_id]);
5099*1b481fc3SMaciej Żenczykowski 			return 1;
5100*1b481fc3SMaciej Żenczykowski 		}
5101*1b481fc3SMaciej Żenczykowski 		tuna->cmd = ETHTOOL_STUNABLE;
5102*1b481fc3SMaciej Żenczykowski 		tuna->id = tinfo[i].t_id;
5103*1b481fc3SMaciej Żenczykowski 		tuna->type_id = tinfo[i].t_type_id;
5104*1b481fc3SMaciej Żenczykowski 		tuna->len = tinfo[i].size;
5105*1b481fc3SMaciej Żenczykowski 		memcpy(tuna->data, &tinfo[i].wanted, tuna->len);
5106*1b481fc3SMaciej Żenczykowski 		ret = send_ioctl(ctx, tuna);
5107*1b481fc3SMaciej Żenczykowski 		if (ret) {
5108*1b481fc3SMaciej Żenczykowski 			perror(tunable_strings[tuna->id]);
5109*1b481fc3SMaciej Żenczykowski 			free(tuna);
5110*1b481fc3SMaciej Żenczykowski 			return ret;
5111*1b481fc3SMaciej Żenczykowski 		}
5112*1b481fc3SMaciej Żenczykowski 		free(tuna);
5113*1b481fc3SMaciej Żenczykowski 	}
5114*1b481fc3SMaciej Żenczykowski 	return 0;
5115*1b481fc3SMaciej Żenczykowski }
5116*1b481fc3SMaciej Żenczykowski 
print_tunable(struct ethtool_tunable * tuna)5117*1b481fc3SMaciej Żenczykowski static void print_tunable(struct ethtool_tunable *tuna)
5118*1b481fc3SMaciej Żenczykowski {
5119*1b481fc3SMaciej Żenczykowski 	char *name = tunable_strings[tuna->id];
5120*1b481fc3SMaciej Żenczykowski 	union ethtool_tunable_info_val *val;
5121*1b481fc3SMaciej Żenczykowski 
5122*1b481fc3SMaciej Żenczykowski 	val = (union ethtool_tunable_info_val *)tuna->data;
5123*1b481fc3SMaciej Żenczykowski 	switch (tuna->type_id) {
5124*1b481fc3SMaciej Żenczykowski 	case ETHTOOL_TUNABLE_U8:
5125*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "%s: %" PRIu8 "\n", name, val->u8);
5126*1b481fc3SMaciej Żenczykowski 		break;
5127*1b481fc3SMaciej Żenczykowski 	case ETHTOOL_TUNABLE_U16:
5128*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "%s: %" PRIu16 "\n", name, val->u16);
5129*1b481fc3SMaciej Żenczykowski 		break;
5130*1b481fc3SMaciej Żenczykowski 	case ETHTOOL_TUNABLE_U32:
5131*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "%s: %" PRIu32 "\n", name, val->u32);
5132*1b481fc3SMaciej Żenczykowski 		break;
5133*1b481fc3SMaciej Żenczykowski 	case ETHTOOL_TUNABLE_U64:
5134*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "%s: %" PRIu64 "\n", name, val->u64);
5135*1b481fc3SMaciej Żenczykowski 		break;
5136*1b481fc3SMaciej Żenczykowski 	case ETHTOOL_TUNABLE_S8:
5137*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "%s: %" PRId8 "\n", name, val->s8);
5138*1b481fc3SMaciej Żenczykowski 		break;
5139*1b481fc3SMaciej Żenczykowski 	case ETHTOOL_TUNABLE_S16:
5140*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "%s: %" PRId16 "\n", name, val->s16);
5141*1b481fc3SMaciej Żenczykowski 		break;
5142*1b481fc3SMaciej Żenczykowski 	case ETHTOOL_TUNABLE_S32:
5143*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "%s: %" PRId32 "\n", name, val->s32);
5144*1b481fc3SMaciej Żenczykowski 		break;
5145*1b481fc3SMaciej Żenczykowski 	case ETHTOOL_TUNABLE_S64:
5146*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "%s: %" PRId64 "\n", name, val->s64);
5147*1b481fc3SMaciej Żenczykowski 		break;
5148*1b481fc3SMaciej Żenczykowski 	default:
5149*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "%s: Unknown format\n", name);
5150*1b481fc3SMaciej Żenczykowski 	}
5151*1b481fc3SMaciej Żenczykowski }
5152*1b481fc3SMaciej Żenczykowski 
do_gtunable(struct cmd_context * ctx)5153*1b481fc3SMaciej Żenczykowski static int do_gtunable(struct cmd_context *ctx)
5154*1b481fc3SMaciej Żenczykowski {
5155*1b481fc3SMaciej Żenczykowski 	struct ethtool_tunable_info *tinfo = tunables_info;
5156*1b481fc3SMaciej Żenczykowski 	char **argp = ctx->argp;
5157*1b481fc3SMaciej Żenczykowski 	unsigned int argc = ctx->argc;
5158*1b481fc3SMaciej Żenczykowski 	unsigned int i, j;
5159*1b481fc3SMaciej Żenczykowski 
5160*1b481fc3SMaciej Żenczykowski 	if (argc < 1)
5161*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
5162*1b481fc3SMaciej Żenczykowski 
5163*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < argc; i++) {
5164*1b481fc3SMaciej Żenczykowski 		int valid = 0;
5165*1b481fc3SMaciej Żenczykowski 
5166*1b481fc3SMaciej Żenczykowski 		for (j = 0; j < TUNABLES_INFO_SIZE; j++) {
5167*1b481fc3SMaciej Żenczykowski 			char *ts = tunable_strings[tinfo[j].t_id];
5168*1b481fc3SMaciej Żenczykowski 			struct ethtool_tunable *tuna;
5169*1b481fc3SMaciej Żenczykowski 			int ret;
5170*1b481fc3SMaciej Żenczykowski 
5171*1b481fc3SMaciej Żenczykowski 			if (strcmp(argp[i], ts))
5172*1b481fc3SMaciej Żenczykowski 				continue;
5173*1b481fc3SMaciej Żenczykowski 			valid = 1;
5174*1b481fc3SMaciej Żenczykowski 
5175*1b481fc3SMaciej Żenczykowski 			tuna = calloc(1, sizeof(*tuna) + tinfo[j].size);
5176*1b481fc3SMaciej Żenczykowski 			if (!tuna) {
5177*1b481fc3SMaciej Żenczykowski 				perror(ts);
5178*1b481fc3SMaciej Żenczykowski 				return 1;
5179*1b481fc3SMaciej Żenczykowski 			}
5180*1b481fc3SMaciej Żenczykowski 			tuna->cmd = ETHTOOL_GTUNABLE;
5181*1b481fc3SMaciej Żenczykowski 			tuna->id = tinfo[j].t_id;
5182*1b481fc3SMaciej Żenczykowski 			tuna->type_id = tinfo[j].t_type_id;
5183*1b481fc3SMaciej Żenczykowski 			tuna->len = tinfo[j].size;
5184*1b481fc3SMaciej Żenczykowski 			ret = send_ioctl(ctx, tuna);
5185*1b481fc3SMaciej Żenczykowski 			if (ret) {
5186*1b481fc3SMaciej Żenczykowski 				fprintf(stderr, "%s: Cannot get tunable\n", ts);
5187*1b481fc3SMaciej Żenczykowski 				free(tuna);
5188*1b481fc3SMaciej Żenczykowski 				return ret;
5189*1b481fc3SMaciej Żenczykowski 			}
5190*1b481fc3SMaciej Żenczykowski 			print_tunable(tuna);
5191*1b481fc3SMaciej Żenczykowski 			free(tuna);
5192*1b481fc3SMaciej Żenczykowski 		}
5193*1b481fc3SMaciej Żenczykowski 		if (!valid)
5194*1b481fc3SMaciej Żenczykowski 			exit_bad_args();
5195*1b481fc3SMaciej Żenczykowski 	}
5196*1b481fc3SMaciej Żenczykowski 	return 0;
5197*1b481fc3SMaciej Żenczykowski }
5198*1b481fc3SMaciej Żenczykowski 
do_get_phy_tunable(struct cmd_context * ctx)5199*1b481fc3SMaciej Żenczykowski static int do_get_phy_tunable(struct cmd_context *ctx)
5200*1b481fc3SMaciej Żenczykowski {
5201*1b481fc3SMaciej Żenczykowski 	unsigned int argc = ctx->argc;
5202*1b481fc3SMaciej Żenczykowski 	char **argp = ctx->argp;
5203*1b481fc3SMaciej Żenczykowski 
5204*1b481fc3SMaciej Żenczykowski 	if (argc < 1)
5205*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
5206*1b481fc3SMaciej Żenczykowski 
5207*1b481fc3SMaciej Żenczykowski 	if (!strcmp(argp[0], "downshift")) {
5208*1b481fc3SMaciej Żenczykowski 		struct {
5209*1b481fc3SMaciej Żenczykowski 			struct ethtool_tunable ds;
5210*1b481fc3SMaciej Żenczykowski 			u8 count;
5211*1b481fc3SMaciej Żenczykowski 		} cont;
5212*1b481fc3SMaciej Żenczykowski 
5213*1b481fc3SMaciej Żenczykowski 		cont.ds.cmd = ETHTOOL_PHY_GTUNABLE;
5214*1b481fc3SMaciej Żenczykowski 		cont.ds.id = ETHTOOL_PHY_DOWNSHIFT;
5215*1b481fc3SMaciej Żenczykowski 		cont.ds.type_id = ETHTOOL_TUNABLE_U8;
5216*1b481fc3SMaciej Żenczykowski 		cont.ds.len = 1;
5217*1b481fc3SMaciej Żenczykowski 		if (send_ioctl(ctx, &cont.ds) < 0) {
5218*1b481fc3SMaciej Żenczykowski 			perror("Cannot Get PHY downshift count");
5219*1b481fc3SMaciej Żenczykowski 			return 87;
5220*1b481fc3SMaciej Żenczykowski 		}
5221*1b481fc3SMaciej Żenczykowski 		if (cont.count)
5222*1b481fc3SMaciej Żenczykowski 			fprintf(stdout, "Downshift count: %d\n", cont.count);
5223*1b481fc3SMaciej Żenczykowski 		else
5224*1b481fc3SMaciej Żenczykowski 			fprintf(stdout, "Downshift disabled\n");
5225*1b481fc3SMaciej Żenczykowski 	} else if (!strcmp(argp[0], "fast-link-down")) {
5226*1b481fc3SMaciej Żenczykowski 		struct {
5227*1b481fc3SMaciej Żenczykowski 			struct ethtool_tunable fld;
5228*1b481fc3SMaciej Żenczykowski 			u8 msecs;
5229*1b481fc3SMaciej Żenczykowski 		} cont;
5230*1b481fc3SMaciej Żenczykowski 
5231*1b481fc3SMaciej Żenczykowski 		cont.fld.cmd = ETHTOOL_PHY_GTUNABLE;
5232*1b481fc3SMaciej Żenczykowski 		cont.fld.id = ETHTOOL_PHY_FAST_LINK_DOWN;
5233*1b481fc3SMaciej Żenczykowski 		cont.fld.type_id = ETHTOOL_TUNABLE_U8;
5234*1b481fc3SMaciej Żenczykowski 		cont.fld.len = 1;
5235*1b481fc3SMaciej Żenczykowski 		if (send_ioctl(ctx, &cont.fld) < 0) {
5236*1b481fc3SMaciej Żenczykowski 			perror("Cannot Get PHY Fast Link Down value");
5237*1b481fc3SMaciej Żenczykowski 			return 87;
5238*1b481fc3SMaciej Żenczykowski 		}
5239*1b481fc3SMaciej Żenczykowski 
5240*1b481fc3SMaciej Żenczykowski 		if (cont.msecs == ETHTOOL_PHY_FAST_LINK_DOWN_ON)
5241*1b481fc3SMaciej Żenczykowski 			fprintf(stdout, "Fast Link Down enabled\n");
5242*1b481fc3SMaciej Żenczykowski 		else if (cont.msecs == ETHTOOL_PHY_FAST_LINK_DOWN_OFF)
5243*1b481fc3SMaciej Żenczykowski 			fprintf(stdout, "Fast Link Down disabled\n");
5244*1b481fc3SMaciej Żenczykowski 		else
5245*1b481fc3SMaciej Żenczykowski 			fprintf(stdout, "Fast Link Down enabled, %d msecs\n",
5246*1b481fc3SMaciej Żenczykowski 				cont.msecs);
5247*1b481fc3SMaciej Żenczykowski 	} else if (!strcmp(argp[0], "energy-detect-power-down")) {
5248*1b481fc3SMaciej Żenczykowski 		struct {
5249*1b481fc3SMaciej Żenczykowski 			struct ethtool_tunable ds;
5250*1b481fc3SMaciej Żenczykowski 			u16 msecs;
5251*1b481fc3SMaciej Żenczykowski 		} cont;
5252*1b481fc3SMaciej Żenczykowski 
5253*1b481fc3SMaciej Żenczykowski 		cont.ds.cmd = ETHTOOL_PHY_GTUNABLE;
5254*1b481fc3SMaciej Żenczykowski 		cont.ds.id = ETHTOOL_PHY_EDPD;
5255*1b481fc3SMaciej Żenczykowski 		cont.ds.type_id = ETHTOOL_TUNABLE_U16;
5256*1b481fc3SMaciej Żenczykowski 		cont.ds.len = 2;
5257*1b481fc3SMaciej Żenczykowski 		if (send_ioctl(ctx, &cont.ds) < 0) {
5258*1b481fc3SMaciej Żenczykowski 			perror("Cannot Get PHY Energy Detect Power Down value");
5259*1b481fc3SMaciej Żenczykowski 			return 87;
5260*1b481fc3SMaciej Żenczykowski 		}
5261*1b481fc3SMaciej Żenczykowski 
5262*1b481fc3SMaciej Żenczykowski 		if (cont.msecs == ETHTOOL_PHY_EDPD_DISABLE)
5263*1b481fc3SMaciej Żenczykowski 			fprintf(stdout, "Energy Detect Power Down: disabled\n");
5264*1b481fc3SMaciej Żenczykowski 		else if (cont.msecs == ETHTOOL_PHY_EDPD_NO_TX)
5265*1b481fc3SMaciej Żenczykowski 			fprintf(stdout,
5266*1b481fc3SMaciej Żenczykowski 				"Energy Detect Power Down: enabled, TX disabled\n");
5267*1b481fc3SMaciej Żenczykowski 		else
5268*1b481fc3SMaciej Żenczykowski 			fprintf(stdout,
5269*1b481fc3SMaciej Żenczykowski 				"Energy Detect Power Down: enabled, TX %u msecs\n",
5270*1b481fc3SMaciej Żenczykowski 				cont.msecs);
5271*1b481fc3SMaciej Żenczykowski 	} else {
5272*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
5273*1b481fc3SMaciej Żenczykowski 	}
5274*1b481fc3SMaciej Żenczykowski 
5275*1b481fc3SMaciej Żenczykowski 	return 0;
5276*1b481fc3SMaciej Żenczykowski }
5277*1b481fc3SMaciej Żenczykowski 
parse_reset(char * val,__u32 bitset,char * arg,__u32 * data)5278*1b481fc3SMaciej Żenczykowski static __u32 parse_reset(char *val, __u32 bitset, char *arg, __u32 *data)
5279*1b481fc3SMaciej Żenczykowski {
5280*1b481fc3SMaciej Żenczykowski 	__u32 bitval = 0;
5281*1b481fc3SMaciej Żenczykowski 	int i;
5282*1b481fc3SMaciej Żenczykowski 
5283*1b481fc3SMaciej Żenczykowski 	/* Check for component match */
5284*1b481fc3SMaciej Żenczykowski 	for (i = 0; val[i] != '\0'; i++)
5285*1b481fc3SMaciej Żenczykowski 		if (arg[i] != val[i])
5286*1b481fc3SMaciej Żenczykowski 			return 0;
5287*1b481fc3SMaciej Żenczykowski 
5288*1b481fc3SMaciej Żenczykowski 	/* Check if component has -shared specified or not */
5289*1b481fc3SMaciej Żenczykowski 	if (arg[i] == '\0')
5290*1b481fc3SMaciej Żenczykowski 		bitval = bitset;
5291*1b481fc3SMaciej Żenczykowski 	else if (!strcmp(arg+i, "-shared"))
5292*1b481fc3SMaciej Żenczykowski 		bitval = bitset << ETH_RESET_SHARED_SHIFT;
5293*1b481fc3SMaciej Żenczykowski 
5294*1b481fc3SMaciej Żenczykowski 	if (bitval) {
5295*1b481fc3SMaciej Żenczykowski 		*data |= bitval;
5296*1b481fc3SMaciej Żenczykowski 		return 1;
5297*1b481fc3SMaciej Żenczykowski 	}
5298*1b481fc3SMaciej Żenczykowski 	return 0;
5299*1b481fc3SMaciej Żenczykowski }
5300*1b481fc3SMaciej Żenczykowski 
do_reset(struct cmd_context * ctx)5301*1b481fc3SMaciej Żenczykowski static int do_reset(struct cmd_context *ctx)
5302*1b481fc3SMaciej Żenczykowski {
5303*1b481fc3SMaciej Żenczykowski 	struct ethtool_value resetinfo;
5304*1b481fc3SMaciej Żenczykowski 	__u32 data;
5305*1b481fc3SMaciej Żenczykowski 	unsigned int argc = ctx->argc;
5306*1b481fc3SMaciej Żenczykowski 	char **argp = ctx->argp;
5307*1b481fc3SMaciej Żenczykowski 	unsigned int i;
5308*1b481fc3SMaciej Żenczykowski 
5309*1b481fc3SMaciej Żenczykowski 	if (argc == 0)
5310*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
5311*1b481fc3SMaciej Żenczykowski 
5312*1b481fc3SMaciej Żenczykowski 	data = 0;
5313*1b481fc3SMaciej Żenczykowski 
5314*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < argc; i++) {
5315*1b481fc3SMaciej Żenczykowski 		if (!strcmp(argp[i], "flags")) {
5316*1b481fc3SMaciej Żenczykowski 			__u32 flags;
5317*1b481fc3SMaciej Żenczykowski 
5318*1b481fc3SMaciej Żenczykowski 			i++;
5319*1b481fc3SMaciej Żenczykowski 			if (i >= argc)
5320*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
5321*1b481fc3SMaciej Żenczykowski 			flags = strtoul(argp[i], NULL, 0);
5322*1b481fc3SMaciej Żenczykowski 			if (flags == 0)
5323*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
5324*1b481fc3SMaciej Żenczykowski 			else
5325*1b481fc3SMaciej Żenczykowski 				data |= flags;
5326*1b481fc3SMaciej Żenczykowski 		} else if (parse_reset("mgmt", ETH_RESET_MGMT,
5327*1b481fc3SMaciej Żenczykowski 				      argp[i], &data)) {
5328*1b481fc3SMaciej Żenczykowski 		} else if (parse_reset("irq",  ETH_RESET_IRQ,
5329*1b481fc3SMaciej Żenczykowski 				    argp[i], &data)) {
5330*1b481fc3SMaciej Żenczykowski 		} else if (parse_reset("dma", ETH_RESET_DMA,
5331*1b481fc3SMaciej Żenczykowski 				    argp[i], &data)) {
5332*1b481fc3SMaciej Żenczykowski 		} else if (parse_reset("filter", ETH_RESET_FILTER,
5333*1b481fc3SMaciej Żenczykowski 				    argp[i], &data)) {
5334*1b481fc3SMaciej Żenczykowski 		} else if (parse_reset("offload", ETH_RESET_OFFLOAD,
5335*1b481fc3SMaciej Żenczykowski 				    argp[i], &data)) {
5336*1b481fc3SMaciej Żenczykowski 		} else if (parse_reset("mac", ETH_RESET_MAC,
5337*1b481fc3SMaciej Żenczykowski 				    argp[i], &data)) {
5338*1b481fc3SMaciej Żenczykowski 		} else if (parse_reset("phy", ETH_RESET_PHY,
5339*1b481fc3SMaciej Żenczykowski 				    argp[i], &data)) {
5340*1b481fc3SMaciej Żenczykowski 		} else if (parse_reset("ram", ETH_RESET_RAM,
5341*1b481fc3SMaciej Żenczykowski 				    argp[i], &data)) {
5342*1b481fc3SMaciej Żenczykowski 		} else if (parse_reset("ap", ETH_RESET_AP,
5343*1b481fc3SMaciej Żenczykowski 				    argp[i], &data)) {
5344*1b481fc3SMaciej Żenczykowski 		} else if (!strcmp(argp[i], "dedicated")) {
5345*1b481fc3SMaciej Żenczykowski 			data |= ETH_RESET_DEDICATED;
5346*1b481fc3SMaciej Żenczykowski 		} else if (!strcmp(argp[i], "all")) {
5347*1b481fc3SMaciej Żenczykowski 			data |= ETH_RESET_ALL;
5348*1b481fc3SMaciej Żenczykowski 		} else {
5349*1b481fc3SMaciej Żenczykowski 			exit_bad_args();
5350*1b481fc3SMaciej Żenczykowski 		}
5351*1b481fc3SMaciej Żenczykowski 	}
5352*1b481fc3SMaciej Żenczykowski 
5353*1b481fc3SMaciej Żenczykowski 	resetinfo.cmd = ETHTOOL_RESET;
5354*1b481fc3SMaciej Żenczykowski 	resetinfo.data = data;
5355*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "ETHTOOL_RESET 0x%x\n", resetinfo.data);
5356*1b481fc3SMaciej Żenczykowski 
5357*1b481fc3SMaciej Żenczykowski 	if (send_ioctl(ctx, &resetinfo)) {
5358*1b481fc3SMaciej Żenczykowski 		perror("Cannot issue ETHTOOL_RESET");
5359*1b481fc3SMaciej Żenczykowski 		return 1;
5360*1b481fc3SMaciej Żenczykowski 	}
5361*1b481fc3SMaciej Żenczykowski 
5362*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "Components reset:     0x%x\n", data & ~resetinfo.data);
5363*1b481fc3SMaciej Żenczykowski 	if (resetinfo.data)
5364*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "Components not reset: 0x%x\n", resetinfo.data);
5365*1b481fc3SMaciej Żenczykowski 
5366*1b481fc3SMaciej Żenczykowski 	return 0;
5367*1b481fc3SMaciej Żenczykowski }
5368*1b481fc3SMaciej Żenczykowski 
parse_named_bool(struct cmd_context * ctx,const char * name,u8 * on)5369*1b481fc3SMaciej Żenczykowski static int parse_named_bool(struct cmd_context *ctx, const char *name, u8 *on)
5370*1b481fc3SMaciej Żenczykowski {
5371*1b481fc3SMaciej Żenczykowski 	if (ctx->argc < 2)
5372*1b481fc3SMaciej Żenczykowski 		return 0;
5373*1b481fc3SMaciej Żenczykowski 
5374*1b481fc3SMaciej Żenczykowski 	if (strcmp(*ctx->argp, name))
5375*1b481fc3SMaciej Żenczykowski 		return 0;
5376*1b481fc3SMaciej Żenczykowski 
5377*1b481fc3SMaciej Żenczykowski 	if (!strcmp(*(ctx->argp + 1), "on")) {
5378*1b481fc3SMaciej Żenczykowski 		*on = 1;
5379*1b481fc3SMaciej Żenczykowski 	} else if (!strcmp(*(ctx->argp + 1), "off")) {
5380*1b481fc3SMaciej Żenczykowski 		*on = 0;
5381*1b481fc3SMaciej Żenczykowski 	} else {
5382*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "Invalid boolean\n");
5383*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
5384*1b481fc3SMaciej Żenczykowski 	}
5385*1b481fc3SMaciej Żenczykowski 
5386*1b481fc3SMaciej Żenczykowski 	ctx->argc -= 2;
5387*1b481fc3SMaciej Żenczykowski 	ctx->argp += 2;
5388*1b481fc3SMaciej Żenczykowski 
5389*1b481fc3SMaciej Żenczykowski 	return 1;
5390*1b481fc3SMaciej Żenczykowski }
5391*1b481fc3SMaciej Żenczykowski 
parse_named_uint(struct cmd_context * ctx,const char * name,unsigned long long * val,unsigned long long max)5392*1b481fc3SMaciej Żenczykowski static int parse_named_uint(struct cmd_context *ctx,
5393*1b481fc3SMaciej Żenczykowski 			    const char *name,
5394*1b481fc3SMaciej Żenczykowski 			    unsigned long long *val,
5395*1b481fc3SMaciej Żenczykowski 			    unsigned long long max)
5396*1b481fc3SMaciej Żenczykowski {
5397*1b481fc3SMaciej Żenczykowski 	if (ctx->argc < 2)
5398*1b481fc3SMaciej Żenczykowski 		return 0;
5399*1b481fc3SMaciej Żenczykowski 
5400*1b481fc3SMaciej Żenczykowski 	if (strcmp(*ctx->argp, name))
5401*1b481fc3SMaciej Żenczykowski 		return 0;
5402*1b481fc3SMaciej Żenczykowski 
5403*1b481fc3SMaciej Żenczykowski 	*val = get_uint_range(*(ctx->argp + 1), 0, max);
5404*1b481fc3SMaciej Żenczykowski 
5405*1b481fc3SMaciej Żenczykowski 	ctx->argc -= 2;
5406*1b481fc3SMaciej Żenczykowski 	ctx->argp += 2;
5407*1b481fc3SMaciej Żenczykowski 
5408*1b481fc3SMaciej Żenczykowski 	return 1;
5409*1b481fc3SMaciej Żenczykowski }
5410*1b481fc3SMaciej Żenczykowski 
parse_named_u8(struct cmd_context * ctx,const char * name,u8 * val)5411*1b481fc3SMaciej Żenczykowski static int parse_named_u8(struct cmd_context *ctx, const char *name, u8 *val)
5412*1b481fc3SMaciej Żenczykowski {
5413*1b481fc3SMaciej Żenczykowski 	unsigned long long val1;
5414*1b481fc3SMaciej Żenczykowski 	int ret;
5415*1b481fc3SMaciej Żenczykowski 
5416*1b481fc3SMaciej Żenczykowski 	ret = parse_named_uint(ctx, name, &val1, 0xff);
5417*1b481fc3SMaciej Żenczykowski 	if (ret)
5418*1b481fc3SMaciej Żenczykowski 		*val = val1;
5419*1b481fc3SMaciej Żenczykowski 
5420*1b481fc3SMaciej Żenczykowski 	return ret;
5421*1b481fc3SMaciej Żenczykowski }
5422*1b481fc3SMaciej Żenczykowski 
parse_named_u16(struct cmd_context * ctx,const char * name,u16 * val)5423*1b481fc3SMaciej Żenczykowski static int parse_named_u16(struct cmd_context *ctx, const char *name, u16 *val)
5424*1b481fc3SMaciej Żenczykowski {
5425*1b481fc3SMaciej Żenczykowski 	unsigned long long val1;
5426*1b481fc3SMaciej Żenczykowski 	int ret;
5427*1b481fc3SMaciej Żenczykowski 
5428*1b481fc3SMaciej Żenczykowski 	ret = parse_named_uint(ctx, name, &val1, 0xffff);
5429*1b481fc3SMaciej Żenczykowski 	if (ret)
5430*1b481fc3SMaciej Żenczykowski 		*val = val1;
5431*1b481fc3SMaciej Żenczykowski 
5432*1b481fc3SMaciej Żenczykowski 	return ret;
5433*1b481fc3SMaciej Żenczykowski }
5434*1b481fc3SMaciej Żenczykowski 
do_set_phy_tunable(struct cmd_context * ctx)5435*1b481fc3SMaciej Żenczykowski static int do_set_phy_tunable(struct cmd_context *ctx)
5436*1b481fc3SMaciej Żenczykowski {
5437*1b481fc3SMaciej Żenczykowski 	int err = 0;
5438*1b481fc3SMaciej Żenczykowski 	u8 ds_cnt = DOWNSHIFT_DEV_DEFAULT_COUNT;
5439*1b481fc3SMaciej Żenczykowski 	u8 ds_changed = 0, ds_has_cnt = 0, ds_enable = 0;
5440*1b481fc3SMaciej Żenczykowski 	u8 fld_changed = 0, fld_enable = 0;
5441*1b481fc3SMaciej Żenczykowski 	u8 fld_msecs = ETHTOOL_PHY_FAST_LINK_DOWN_ON;
5442*1b481fc3SMaciej Żenczykowski 	u8 edpd_changed = 0, edpd_enable = 0;
5443*1b481fc3SMaciej Żenczykowski 	u16 edpd_tx_interval = ETHTOOL_PHY_EDPD_DFLT_TX_MSECS;
5444*1b481fc3SMaciej Żenczykowski 
5445*1b481fc3SMaciej Żenczykowski 	/* Parse arguments */
5446*1b481fc3SMaciej Żenczykowski 	if (parse_named_bool(ctx, "downshift", &ds_enable)) {
5447*1b481fc3SMaciej Żenczykowski 		ds_changed = 1;
5448*1b481fc3SMaciej Żenczykowski 		ds_has_cnt = parse_named_u8(ctx, "count", &ds_cnt);
5449*1b481fc3SMaciej Żenczykowski 	} else if (parse_named_bool(ctx, "fast-link-down", &fld_enable)) {
5450*1b481fc3SMaciej Żenczykowski 		fld_changed = 1;
5451*1b481fc3SMaciej Żenczykowski 		if (fld_enable)
5452*1b481fc3SMaciej Żenczykowski 			parse_named_u8(ctx, "msecs", &fld_msecs);
5453*1b481fc3SMaciej Żenczykowski 	} else if (parse_named_bool(ctx, "energy-detect-power-down",
5454*1b481fc3SMaciej Żenczykowski 				    &edpd_enable)) {
5455*1b481fc3SMaciej Żenczykowski 		edpd_changed = 1;
5456*1b481fc3SMaciej Żenczykowski 		if (edpd_enable)
5457*1b481fc3SMaciej Żenczykowski 			parse_named_u16(ctx, "msecs", &edpd_tx_interval);
5458*1b481fc3SMaciej Żenczykowski 	} else {
5459*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
5460*1b481fc3SMaciej Żenczykowski 	}
5461*1b481fc3SMaciej Żenczykowski 
5462*1b481fc3SMaciej Żenczykowski 	/* Validate parameters */
5463*1b481fc3SMaciej Żenczykowski 	if (ds_changed) {
5464*1b481fc3SMaciej Żenczykowski 		if (!ds_enable && ds_has_cnt) {
5465*1b481fc3SMaciej Żenczykowski 			fprintf(stderr, "'count' may not be set when downshift "
5466*1b481fc3SMaciej Żenczykowski 				        "is off.\n");
5467*1b481fc3SMaciej Żenczykowski 			exit_bad_args();
5468*1b481fc3SMaciej Żenczykowski 		}
5469*1b481fc3SMaciej Żenczykowski 
5470*1b481fc3SMaciej Żenczykowski 		if (ds_enable && ds_has_cnt && ds_cnt == 0) {
5471*1b481fc3SMaciej Żenczykowski 			fprintf(stderr, "'count' may not be zero.\n");
5472*1b481fc3SMaciej Żenczykowski 			exit_bad_args();
5473*1b481fc3SMaciej Żenczykowski 		}
5474*1b481fc3SMaciej Żenczykowski 
5475*1b481fc3SMaciej Żenczykowski 		if (!ds_enable)
5476*1b481fc3SMaciej Żenczykowski 			ds_cnt = DOWNSHIFT_DEV_DISABLE;
5477*1b481fc3SMaciej Żenczykowski 	} else if (fld_changed) {
5478*1b481fc3SMaciej Żenczykowski 		if (!fld_enable)
5479*1b481fc3SMaciej Żenczykowski 			fld_msecs = ETHTOOL_PHY_FAST_LINK_DOWN_OFF;
5480*1b481fc3SMaciej Żenczykowski 		else if (fld_msecs == ETHTOOL_PHY_FAST_LINK_DOWN_OFF)
5481*1b481fc3SMaciej Żenczykowski 			exit_bad_args();
5482*1b481fc3SMaciej Żenczykowski 	} else if (edpd_changed) {
5483*1b481fc3SMaciej Żenczykowski 		if (!edpd_enable)
5484*1b481fc3SMaciej Żenczykowski 			edpd_tx_interval = ETHTOOL_PHY_EDPD_DISABLE;
5485*1b481fc3SMaciej Żenczykowski 		else if (edpd_tx_interval == 0)
5486*1b481fc3SMaciej Żenczykowski 			edpd_tx_interval = ETHTOOL_PHY_EDPD_NO_TX;
5487*1b481fc3SMaciej Żenczykowski 		else if (edpd_tx_interval > ETHTOOL_PHY_EDPD_NO_TX) {
5488*1b481fc3SMaciej Żenczykowski 			fprintf(stderr, "'msecs' max value is %d.\n",
5489*1b481fc3SMaciej Żenczykowski 				(ETHTOOL_PHY_EDPD_NO_TX - 1));
5490*1b481fc3SMaciej Żenczykowski 			exit_bad_args();
5491*1b481fc3SMaciej Żenczykowski 		}
5492*1b481fc3SMaciej Żenczykowski 	}
5493*1b481fc3SMaciej Żenczykowski 
5494*1b481fc3SMaciej Żenczykowski 	/* Do it */
5495*1b481fc3SMaciej Żenczykowski 	if (ds_changed) {
5496*1b481fc3SMaciej Żenczykowski 		struct {
5497*1b481fc3SMaciej Żenczykowski 			struct ethtool_tunable ds;
5498*1b481fc3SMaciej Żenczykowski 			u8 count;
5499*1b481fc3SMaciej Żenczykowski 		} cont;
5500*1b481fc3SMaciej Żenczykowski 
5501*1b481fc3SMaciej Żenczykowski 		cont.ds.cmd = ETHTOOL_PHY_STUNABLE;
5502*1b481fc3SMaciej Żenczykowski 		cont.ds.id = ETHTOOL_PHY_DOWNSHIFT;
5503*1b481fc3SMaciej Żenczykowski 		cont.ds.type_id = ETHTOOL_TUNABLE_U8;
5504*1b481fc3SMaciej Żenczykowski 		cont.ds.len = 1;
5505*1b481fc3SMaciej Żenczykowski 		cont.count = ds_cnt;
5506*1b481fc3SMaciej Żenczykowski 		err = send_ioctl(ctx, &cont.ds);
5507*1b481fc3SMaciej Żenczykowski 		if (err < 0) {
5508*1b481fc3SMaciej Żenczykowski 			perror("Cannot Set PHY downshift count");
5509*1b481fc3SMaciej Żenczykowski 			err = 87;
5510*1b481fc3SMaciej Żenczykowski 		}
5511*1b481fc3SMaciej Żenczykowski 	} else if (fld_changed) {
5512*1b481fc3SMaciej Żenczykowski 		struct {
5513*1b481fc3SMaciej Żenczykowski 			struct ethtool_tunable fld;
5514*1b481fc3SMaciej Żenczykowski 			u8 msecs;
5515*1b481fc3SMaciej Żenczykowski 		} cont;
5516*1b481fc3SMaciej Żenczykowski 
5517*1b481fc3SMaciej Żenczykowski 		cont.fld.cmd = ETHTOOL_PHY_STUNABLE;
5518*1b481fc3SMaciej Żenczykowski 		cont.fld.id = ETHTOOL_PHY_FAST_LINK_DOWN;
5519*1b481fc3SMaciej Żenczykowski 		cont.fld.type_id = ETHTOOL_TUNABLE_U8;
5520*1b481fc3SMaciej Żenczykowski 		cont.fld.len = 1;
5521*1b481fc3SMaciej Żenczykowski 		cont.msecs = fld_msecs;
5522*1b481fc3SMaciej Żenczykowski 		err = send_ioctl(ctx, &cont.fld);
5523*1b481fc3SMaciej Żenczykowski 		if (err < 0) {
5524*1b481fc3SMaciej Żenczykowski 			perror("Cannot Set PHY Fast Link Down value");
5525*1b481fc3SMaciej Żenczykowski 			err = 87;
5526*1b481fc3SMaciej Żenczykowski 		}
5527*1b481fc3SMaciej Żenczykowski 	} else if (edpd_changed) {
5528*1b481fc3SMaciej Żenczykowski 		struct {
5529*1b481fc3SMaciej Żenczykowski 			struct ethtool_tunable fld;
5530*1b481fc3SMaciej Żenczykowski 			u16 msecs;
5531*1b481fc3SMaciej Żenczykowski 		} cont;
5532*1b481fc3SMaciej Żenczykowski 
5533*1b481fc3SMaciej Żenczykowski 		cont.fld.cmd = ETHTOOL_PHY_STUNABLE;
5534*1b481fc3SMaciej Żenczykowski 		cont.fld.id = ETHTOOL_PHY_EDPD;
5535*1b481fc3SMaciej Żenczykowski 		cont.fld.type_id = ETHTOOL_TUNABLE_U16;
5536*1b481fc3SMaciej Żenczykowski 		cont.fld.len = 2;
5537*1b481fc3SMaciej Żenczykowski 		cont.msecs = edpd_tx_interval;
5538*1b481fc3SMaciej Żenczykowski 		err = send_ioctl(ctx, &cont.fld);
5539*1b481fc3SMaciej Żenczykowski 		if (err < 0) {
5540*1b481fc3SMaciej Żenczykowski 			perror("Cannot Set PHY Energy Detect Power Down");
5541*1b481fc3SMaciej Żenczykowski 			err = 87;
5542*1b481fc3SMaciej Żenczykowski 		}
5543*1b481fc3SMaciej Żenczykowski 	}
5544*1b481fc3SMaciej Żenczykowski 
5545*1b481fc3SMaciej Żenczykowski 	return err;
5546*1b481fc3SMaciej Żenczykowski }
5547*1b481fc3SMaciej Żenczykowski 
fecmode_str_to_type(const char * str)5548*1b481fc3SMaciej Żenczykowski static int fecmode_str_to_type(const char *str)
5549*1b481fc3SMaciej Żenczykowski {
5550*1b481fc3SMaciej Żenczykowski 	if (!strcasecmp(str, "auto"))
5551*1b481fc3SMaciej Żenczykowski 		return ETHTOOL_FEC_AUTO;
5552*1b481fc3SMaciej Żenczykowski 	if (!strcasecmp(str, "off"))
5553*1b481fc3SMaciej Żenczykowski 		return ETHTOOL_FEC_OFF;
5554*1b481fc3SMaciej Żenczykowski 	if (!strcasecmp(str, "rs"))
5555*1b481fc3SMaciej Żenczykowski 		return ETHTOOL_FEC_RS;
5556*1b481fc3SMaciej Żenczykowski 	if (!strcasecmp(str, "baser"))
5557*1b481fc3SMaciej Żenczykowski 		return ETHTOOL_FEC_BASER;
5558*1b481fc3SMaciej Żenczykowski 	if (!strcasecmp(str, "llrs"))
5559*1b481fc3SMaciej Żenczykowski 		return ETHTOOL_FEC_LLRS;
5560*1b481fc3SMaciej Żenczykowski 	return 0;
5561*1b481fc3SMaciej Żenczykowski }
5562*1b481fc3SMaciej Żenczykowski 
do_gfec(struct cmd_context * ctx)5563*1b481fc3SMaciej Żenczykowski static int do_gfec(struct cmd_context *ctx)
5564*1b481fc3SMaciej Żenczykowski {
5565*1b481fc3SMaciej Żenczykowski 	struct ethtool_fecparam feccmd = { 0 };
5566*1b481fc3SMaciej Żenczykowski 	int rv;
5567*1b481fc3SMaciej Żenczykowski 
5568*1b481fc3SMaciej Żenczykowski 	if (ctx->argc != 0)
5569*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
5570*1b481fc3SMaciej Żenczykowski 
5571*1b481fc3SMaciej Żenczykowski 	feccmd.cmd = ETHTOOL_GFECPARAM;
5572*1b481fc3SMaciej Żenczykowski 	rv = send_ioctl(ctx, &feccmd);
5573*1b481fc3SMaciej Żenczykowski 	if (rv != 0) {
5574*1b481fc3SMaciej Żenczykowski 		perror("Cannot get FEC settings");
5575*1b481fc3SMaciej Żenczykowski 		return rv;
5576*1b481fc3SMaciej Żenczykowski 	}
5577*1b481fc3SMaciej Żenczykowski 
5578*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "FEC parameters for %s:\n", ctx->devname);
5579*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "Supported/Configured FEC encodings:");
5580*1b481fc3SMaciej Żenczykowski 	dump_fec(feccmd.fec);
5581*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "\n");
5582*1b481fc3SMaciej Żenczykowski 
5583*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "Active FEC encoding:");
5584*1b481fc3SMaciej Żenczykowski 	dump_fec(feccmd.active_fec);
5585*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "\n");
5586*1b481fc3SMaciej Żenczykowski 
5587*1b481fc3SMaciej Żenczykowski 	return 0;
5588*1b481fc3SMaciej Żenczykowski }
5589*1b481fc3SMaciej Żenczykowski 
do_sfec(struct cmd_context * ctx)5590*1b481fc3SMaciej Żenczykowski static int do_sfec(struct cmd_context *ctx)
5591*1b481fc3SMaciej Żenczykowski {
5592*1b481fc3SMaciej Żenczykowski 	enum { ARG_NONE, ARG_ENCODING } state = ARG_NONE;
5593*1b481fc3SMaciej Żenczykowski 	struct ethtool_fecparam feccmd;
5594*1b481fc3SMaciej Żenczykowski 	int fecmode = 0, newmode;
5595*1b481fc3SMaciej Żenczykowski 	unsigned int i;
5596*1b481fc3SMaciej Żenczykowski 	int rv;
5597*1b481fc3SMaciej Żenczykowski 
5598*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < ctx->argc; i++) {
5599*1b481fc3SMaciej Żenczykowski 		if (!strcmp(ctx->argp[i], "encoding")) {
5600*1b481fc3SMaciej Żenczykowski 			state = ARG_ENCODING;
5601*1b481fc3SMaciej Żenczykowski 			continue;
5602*1b481fc3SMaciej Żenczykowski 		}
5603*1b481fc3SMaciej Żenczykowski 		if (state == ARG_ENCODING) {
5604*1b481fc3SMaciej Żenczykowski 			newmode = fecmode_str_to_type(ctx->argp[i]);
5605*1b481fc3SMaciej Żenczykowski 			if (!newmode)
5606*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
5607*1b481fc3SMaciej Żenczykowski 			fecmode |= newmode;
5608*1b481fc3SMaciej Żenczykowski 			continue;
5609*1b481fc3SMaciej Żenczykowski 		}
5610*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
5611*1b481fc3SMaciej Żenczykowski 	}
5612*1b481fc3SMaciej Żenczykowski 
5613*1b481fc3SMaciej Żenczykowski 	if (!fecmode)
5614*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
5615*1b481fc3SMaciej Żenczykowski 
5616*1b481fc3SMaciej Żenczykowski 	feccmd.cmd = ETHTOOL_SFECPARAM;
5617*1b481fc3SMaciej Żenczykowski 	feccmd.fec = fecmode;
5618*1b481fc3SMaciej Żenczykowski 	rv = send_ioctl(ctx, &feccmd);
5619*1b481fc3SMaciej Żenczykowski 	if (rv != 0) {
5620*1b481fc3SMaciej Żenczykowski 		perror("Cannot set FEC settings");
5621*1b481fc3SMaciej Żenczykowski 		return rv;
5622*1b481fc3SMaciej Żenczykowski 	}
5623*1b481fc3SMaciej Żenczykowski 
5624*1b481fc3SMaciej Żenczykowski 	return 0;
5625*1b481fc3SMaciej Żenczykowski }
5626*1b481fc3SMaciej Żenczykowski 
5627*1b481fc3SMaciej Żenczykowski static int do_perqueue(struct cmd_context *ctx);
5628*1b481fc3SMaciej Żenczykowski 
5629*1b481fc3SMaciej Żenczykowski #ifndef TEST_ETHTOOL
send_ioctl(struct cmd_context * ctx,void * cmd)5630*1b481fc3SMaciej Żenczykowski int send_ioctl(struct cmd_context *ctx, void *cmd)
5631*1b481fc3SMaciej Żenczykowski {
5632*1b481fc3SMaciej Żenczykowski 	ctx->ifr.ifr_data = cmd;
5633*1b481fc3SMaciej Żenczykowski 	return ioctl(ctx->fd, SIOCETHTOOL, &ctx->ifr);
5634*1b481fc3SMaciej Żenczykowski }
5635*1b481fc3SMaciej Żenczykowski #endif
5636*1b481fc3SMaciej Żenczykowski 
5637*1b481fc3SMaciej Żenczykowski static int show_usage(struct cmd_context *ctx);
5638*1b481fc3SMaciej Żenczykowski 
5639*1b481fc3SMaciej Żenczykowski struct option {
5640*1b481fc3SMaciej Żenczykowski 	const char	*opts;
5641*1b481fc3SMaciej Żenczykowski 	bool		no_dev;
5642*1b481fc3SMaciej Żenczykowski 	bool		json;
5643*1b481fc3SMaciej Żenczykowski 	int		(*func)(struct cmd_context *);
5644*1b481fc3SMaciej Żenczykowski 	nl_chk_t	nlchk;
5645*1b481fc3SMaciej Żenczykowski 	nl_func_t	nlfunc;
5646*1b481fc3SMaciej Żenczykowski 	const char	*help;
5647*1b481fc3SMaciej Żenczykowski 	const char	*xhelp;
5648*1b481fc3SMaciej Żenczykowski };
5649*1b481fc3SMaciej Żenczykowski 
5650*1b481fc3SMaciej Żenczykowski static const struct option args[] = {
5651*1b481fc3SMaciej Żenczykowski 	{
5652*1b481fc3SMaciej Żenczykowski 		/* "default" entry when no switch is used */
5653*1b481fc3SMaciej Żenczykowski 		.opts	= "",
5654*1b481fc3SMaciej Żenczykowski 		.func	= do_gset,
5655*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_gset,
5656*1b481fc3SMaciej Żenczykowski 		.help	= "Display standard information about device",
5657*1b481fc3SMaciej Żenczykowski 	},
5658*1b481fc3SMaciej Żenczykowski 	{
5659*1b481fc3SMaciej Żenczykowski 		.opts	= "-s|--change",
5660*1b481fc3SMaciej Żenczykowski 		.func	= do_sset,
5661*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_sset,
5662*1b481fc3SMaciej Żenczykowski 		.help	= "Change generic options",
5663*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ speed %d ]\n"
5664*1b481fc3SMaciej Żenczykowski 			  "		[ lanes %d ]\n"
5665*1b481fc3SMaciej Żenczykowski 			  "		[ duplex half|full ]\n"
5666*1b481fc3SMaciej Żenczykowski 			  "		[ port tp|aui|bnc|mii|fibre|da ]\n"
5667*1b481fc3SMaciej Żenczykowski 			  "		[ mdix auto|on|off ]\n"
5668*1b481fc3SMaciej Żenczykowski 			  "		[ autoneg on|off ]\n"
5669*1b481fc3SMaciej Żenczykowski 			  "		[ advertise %x[/%x] | mode on|off ... [--] ]\n"
5670*1b481fc3SMaciej Żenczykowski 			  "		[ phyad %d ]\n"
5671*1b481fc3SMaciej Żenczykowski 			  "		[ xcvr internal|external ]\n"
5672*1b481fc3SMaciej Żenczykowski 			  "		[ wol %d[/%d] | p|u|m|b|a|g|s|f|d... ]\n"
5673*1b481fc3SMaciej Żenczykowski 			  "		[ sopass %x:%x:%x:%x:%x:%x ]\n"
5674*1b481fc3SMaciej Żenczykowski 			  "		[ msglvl %d[/%d] | type on|off ... [--] ]\n"
5675*1b481fc3SMaciej Żenczykowski 			  "		[ master-slave preferred-master|preferred-slave|forced-master|forced-slave ]\n"
5676*1b481fc3SMaciej Żenczykowski 	},
5677*1b481fc3SMaciej Żenczykowski 	{
5678*1b481fc3SMaciej Żenczykowski 		.opts	= "-a|--show-pause",
5679*1b481fc3SMaciej Żenczykowski 		.json	= true,
5680*1b481fc3SMaciej Żenczykowski 		.func	= do_gpause,
5681*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_gpause,
5682*1b481fc3SMaciej Żenczykowski 		.help	= "Show pause options",
5683*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ --src aggregate | emac | pmac ]\n"
5684*1b481fc3SMaciej Żenczykowski 	},
5685*1b481fc3SMaciej Żenczykowski 	{
5686*1b481fc3SMaciej Żenczykowski 		.opts	= "-A|--pause",
5687*1b481fc3SMaciej Żenczykowski 		.func	= do_spause,
5688*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_spause,
5689*1b481fc3SMaciej Żenczykowski 		.help	= "Set pause options",
5690*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ autoneg on|off ]\n"
5691*1b481fc3SMaciej Żenczykowski 			  "		[ rx on|off ]\n"
5692*1b481fc3SMaciej Żenczykowski 			  "		[ tx on|off ]\n"
5693*1b481fc3SMaciej Żenczykowski 	},
5694*1b481fc3SMaciej Żenczykowski 	{
5695*1b481fc3SMaciej Żenczykowski 		.opts	= "-c|--show-coalesce",
5696*1b481fc3SMaciej Żenczykowski 		.json	= true,
5697*1b481fc3SMaciej Żenczykowski 		.func	= do_gcoalesce,
5698*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_gcoalesce,
5699*1b481fc3SMaciej Żenczykowski 		.help	= "Show coalesce options"
5700*1b481fc3SMaciej Żenczykowski 	},
5701*1b481fc3SMaciej Żenczykowski 	{
5702*1b481fc3SMaciej Żenczykowski 		.opts	= "-C|--coalesce",
5703*1b481fc3SMaciej Żenczykowski 		.func	= do_scoalesce,
5704*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_scoalesce,
5705*1b481fc3SMaciej Żenczykowski 		.help	= "Set coalesce options",
5706*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[adaptive-rx on|off]\n"
5707*1b481fc3SMaciej Żenczykowski 			  "		[adaptive-tx on|off]\n"
5708*1b481fc3SMaciej Żenczykowski 			  "		[rx-usecs N]\n"
5709*1b481fc3SMaciej Żenczykowski 			  "		[rx-frames N]\n"
5710*1b481fc3SMaciej Żenczykowski 			  "		[rx-usecs-irq N]\n"
5711*1b481fc3SMaciej Żenczykowski 			  "		[rx-frames-irq N]\n"
5712*1b481fc3SMaciej Żenczykowski 			  "		[tx-usecs N]\n"
5713*1b481fc3SMaciej Żenczykowski 			  "		[tx-frames N]\n"
5714*1b481fc3SMaciej Żenczykowski 			  "		[tx-usecs-irq N]\n"
5715*1b481fc3SMaciej Żenczykowski 			  "		[tx-frames-irq N]\n"
5716*1b481fc3SMaciej Żenczykowski 			  "		[stats-block-usecs N]\n"
5717*1b481fc3SMaciej Żenczykowski 			  "		[pkt-rate-low N]\n"
5718*1b481fc3SMaciej Żenczykowski 			  "		[rx-usecs-low N]\n"
5719*1b481fc3SMaciej Żenczykowski 			  "		[rx-frames-low N]\n"
5720*1b481fc3SMaciej Żenczykowski 			  "		[tx-usecs-low N]\n"
5721*1b481fc3SMaciej Żenczykowski 			  "		[tx-frames-low N]\n"
5722*1b481fc3SMaciej Żenczykowski 			  "		[pkt-rate-high N]\n"
5723*1b481fc3SMaciej Żenczykowski 			  "		[rx-usecs-high N]\n"
5724*1b481fc3SMaciej Żenczykowski 			  "		[rx-frames-high N]\n"
5725*1b481fc3SMaciej Żenczykowski 			  "		[tx-usecs-high N]\n"
5726*1b481fc3SMaciej Żenczykowski 			  "		[tx-frames-high N]\n"
5727*1b481fc3SMaciej Żenczykowski 			  "		[sample-interval N]\n"
5728*1b481fc3SMaciej Żenczykowski 			  "		[cqe-mode-rx on|off]\n"
5729*1b481fc3SMaciej Żenczykowski 			  "		[cqe-mode-tx on|off]\n"
5730*1b481fc3SMaciej Żenczykowski 			  "		[tx-aggr-max-bytes N]\n"
5731*1b481fc3SMaciej Żenczykowski 			  "		[tx-aggr-max-frames N]\n"
5732*1b481fc3SMaciej Żenczykowski 			  "		[tx-aggr-time-usecs N]\n"
5733*1b481fc3SMaciej Żenczykowski 	},
5734*1b481fc3SMaciej Żenczykowski 	{
5735*1b481fc3SMaciej Żenczykowski 		.opts	= "-g|--show-ring",
5736*1b481fc3SMaciej Żenczykowski 		.json	= true,
5737*1b481fc3SMaciej Żenczykowski 		.func	= do_gring,
5738*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_gring,
5739*1b481fc3SMaciej Żenczykowski 		.help	= "Query RX/TX ring parameters"
5740*1b481fc3SMaciej Żenczykowski 	},
5741*1b481fc3SMaciej Żenczykowski 	{
5742*1b481fc3SMaciej Żenczykowski 		.opts	= "-G|--set-ring",
5743*1b481fc3SMaciej Żenczykowski 		.func	= do_sring,
5744*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_sring,
5745*1b481fc3SMaciej Żenczykowski 		.help	= "Set RX/TX ring parameters",
5746*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ rx N ]\n"
5747*1b481fc3SMaciej Żenczykowski 			  "		[ rx-mini N ]\n"
5748*1b481fc3SMaciej Żenczykowski 			  "		[ rx-jumbo N ]\n"
5749*1b481fc3SMaciej Żenczykowski 			  "		[ tx N ]\n"
5750*1b481fc3SMaciej Żenczykowski 			  "		[ rx-buf-len N ]\n"
5751*1b481fc3SMaciej Żenczykowski 			  "		[ cqe-size N ]\n"
5752*1b481fc3SMaciej Żenczykowski 			  "		[ tx-push on|off ]\n"
5753*1b481fc3SMaciej Żenczykowski 			  "		[ rx-push on|off ]\n"
5754*1b481fc3SMaciej Żenczykowski 			  "		[ tx-push-buf-len N]\n"
5755*1b481fc3SMaciej Żenczykowski 	},
5756*1b481fc3SMaciej Żenczykowski 	{
5757*1b481fc3SMaciej Żenczykowski 		.opts	= "-k|--show-features|--show-offload",
5758*1b481fc3SMaciej Żenczykowski 		.json	= true,
5759*1b481fc3SMaciej Żenczykowski 		.func	= do_gfeatures,
5760*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_gfeatures,
5761*1b481fc3SMaciej Żenczykowski 		.help	= "Get state of protocol offload and other features"
5762*1b481fc3SMaciej Żenczykowski 	},
5763*1b481fc3SMaciej Żenczykowski 	{
5764*1b481fc3SMaciej Żenczykowski 		.opts	= "-K|--features|--offload",
5765*1b481fc3SMaciej Żenczykowski 		.func	= do_sfeatures,
5766*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_sfeatures,
5767*1b481fc3SMaciej Żenczykowski 		.help	= "Set protocol offload and other features",
5768*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		FEATURE on|off ...\n"
5769*1b481fc3SMaciej Żenczykowski 	},
5770*1b481fc3SMaciej Żenczykowski 	{
5771*1b481fc3SMaciej Żenczykowski 		.opts	= "-i|--driver",
5772*1b481fc3SMaciej Żenczykowski 		.func	= do_gdrv,
5773*1b481fc3SMaciej Żenczykowski 		.help	= "Show driver information"
5774*1b481fc3SMaciej Żenczykowski 	},
5775*1b481fc3SMaciej Żenczykowski 	{
5776*1b481fc3SMaciej Żenczykowski 		.opts	= "-d|--register-dump",
5777*1b481fc3SMaciej Żenczykowski 		.func	= do_gregs,
5778*1b481fc3SMaciej Żenczykowski 		.help	= "Do a register dump",
5779*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ raw on|off ]\n"
5780*1b481fc3SMaciej Żenczykowski 			  "		[ file FILENAME ]\n"
5781*1b481fc3SMaciej Żenczykowski 	},
5782*1b481fc3SMaciej Żenczykowski 	{
5783*1b481fc3SMaciej Żenczykowski 		.opts	= "-e|--eeprom-dump",
5784*1b481fc3SMaciej Żenczykowski 		.func	= do_geeprom,
5785*1b481fc3SMaciej Żenczykowski 		.help	= "Do a EEPROM dump",
5786*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ raw on|off ]\n"
5787*1b481fc3SMaciej Żenczykowski 			  "		[ offset N ]\n"
5788*1b481fc3SMaciej Żenczykowski 			  "		[ length N ]\n"
5789*1b481fc3SMaciej Żenczykowski 	},
5790*1b481fc3SMaciej Żenczykowski 	{
5791*1b481fc3SMaciej Żenczykowski 		.opts	= "-E|--change-eeprom",
5792*1b481fc3SMaciej Żenczykowski 		.func	= do_seeprom,
5793*1b481fc3SMaciej Żenczykowski 		.help	= "Change bytes in device EEPROM",
5794*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ magic N ]\n"
5795*1b481fc3SMaciej Żenczykowski 			  "		[ offset N ]\n"
5796*1b481fc3SMaciej Żenczykowski 			  "		[ length N ]\n"
5797*1b481fc3SMaciej Żenczykowski 			  "		[ value N ]\n"
5798*1b481fc3SMaciej Żenczykowski 	},
5799*1b481fc3SMaciej Żenczykowski 	{
5800*1b481fc3SMaciej Żenczykowski 		.opts	= "-r|--negotiate",
5801*1b481fc3SMaciej Żenczykowski 		.func	= do_nway_rst,
5802*1b481fc3SMaciej Żenczykowski 		.help	= "Restart N-WAY negotiation"
5803*1b481fc3SMaciej Żenczykowski 	},
5804*1b481fc3SMaciej Żenczykowski 	{
5805*1b481fc3SMaciej Żenczykowski 		.opts	= "-p|--identify",
5806*1b481fc3SMaciej Żenczykowski 		.func	= do_phys_id,
5807*1b481fc3SMaciej Żenczykowski 		.help	= "Show visible port identification (e.g. blinking)",
5808*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ TIME-IN-SECONDS ]\n"
5809*1b481fc3SMaciej Żenczykowski 	},
5810*1b481fc3SMaciej Żenczykowski 	{
5811*1b481fc3SMaciej Żenczykowski 		.opts	= "-t|--test",
5812*1b481fc3SMaciej Żenczykowski 		.func	= do_test,
5813*1b481fc3SMaciej Żenczykowski 		.help	= "Execute adapter self test",
5814*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ online | offline | external_lb ]\n"
5815*1b481fc3SMaciej Żenczykowski 	},
5816*1b481fc3SMaciej Żenczykowski 	{
5817*1b481fc3SMaciej Żenczykowski 		.opts	= "-S|--statistics",
5818*1b481fc3SMaciej Żenczykowski 		.json	= true,
5819*1b481fc3SMaciej Żenczykowski 		.func	= do_gnicstats,
5820*1b481fc3SMaciej Żenczykowski 		.nlchk	= nl_gstats_chk,
5821*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_gstats,
5822*1b481fc3SMaciej Żenczykowski 		.help	= "Show adapter statistics",
5823*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ --all-groups | --groups [eth-phy] [eth-mac] [eth-ctrl] [rmon] ]\n"
5824*1b481fc3SMaciej Żenczykowski 			  "		[ --src aggregate | emac | pmac ]\n"
5825*1b481fc3SMaciej Żenczykowski 	},
5826*1b481fc3SMaciej Żenczykowski 	{
5827*1b481fc3SMaciej Żenczykowski 		.opts	= "--phy-statistics",
5828*1b481fc3SMaciej Żenczykowski 		.func	= do_gphystats,
5829*1b481fc3SMaciej Żenczykowski 		.help	= "Show phy statistics"
5830*1b481fc3SMaciej Żenczykowski 	},
5831*1b481fc3SMaciej Żenczykowski 	{
5832*1b481fc3SMaciej Żenczykowski 		.opts	= "-n|-u|--show-nfc|--show-ntuple",
5833*1b481fc3SMaciej Żenczykowski 		.func	= do_grxclass,
5834*1b481fc3SMaciej Żenczykowski 		.help	= "Show Rx network flow classification options or rules",
5835*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
5836*1b481fc3SMaciej Żenczykowski 			  "tcp6|udp6|ah6|esp6|sctp6 [context %d] |\n"
5837*1b481fc3SMaciej Żenczykowski 			  "		  rule %d ]\n"
5838*1b481fc3SMaciej Żenczykowski 	},
5839*1b481fc3SMaciej Żenczykowski 	{
5840*1b481fc3SMaciej Żenczykowski 		.opts	= "-N|-U|--config-nfc|--config-ntuple",
5841*1b481fc3SMaciej Żenczykowski 		.func	= do_srxclass,
5842*1b481fc3SMaciej Żenczykowski 		.help	= "Configure Rx network flow classification options or rules",
5843*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
5844*1b481fc3SMaciej Żenczykowski 			  "tcp6|udp6|ah6|esp6|sctp6 m|v|t|s|d|f|n|r... [context %d] |\n"
5845*1b481fc3SMaciej Żenczykowski 			  "		flow-type ether|ip4|tcp4|udp4|sctp4|ah4|esp4|"
5846*1b481fc3SMaciej Żenczykowski 			  "ip6|tcp6|udp6|ah6|esp6|sctp6\n"
5847*1b481fc3SMaciej Żenczykowski 			  "			[ src %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
5848*1b481fc3SMaciej Żenczykowski 			  "			[ dst %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
5849*1b481fc3SMaciej Żenczykowski 			  "			[ proto %d [m %x] ]\n"
5850*1b481fc3SMaciej Żenczykowski 			  "			[ src-ip IP-ADDRESS [m IP-ADDRESS] ]\n"
5851*1b481fc3SMaciej Żenczykowski 			  "			[ dst-ip IP-ADDRESS [m IP-ADDRESS] ]\n"
5852*1b481fc3SMaciej Żenczykowski 			  "			[ tos %d [m %x] ]\n"
5853*1b481fc3SMaciej Żenczykowski 			  "			[ tclass %d [m %x] ]\n"
5854*1b481fc3SMaciej Żenczykowski 			  "			[ l4proto %d [m %x] ]\n"
5855*1b481fc3SMaciej Żenczykowski 			  "			[ src-port %d [m %x] ]\n"
5856*1b481fc3SMaciej Żenczykowski 			  "			[ dst-port %d [m %x] ]\n"
5857*1b481fc3SMaciej Żenczykowski 			  "			[ spi %d [m %x] ]\n"
5858*1b481fc3SMaciej Żenczykowski 			  "			[ vlan-etype %x [m %x] ]\n"
5859*1b481fc3SMaciej Żenczykowski 			  "			[ vlan %x [m %x] ]\n"
5860*1b481fc3SMaciej Żenczykowski 			  "			[ user-def %x [m %x] ]\n"
5861*1b481fc3SMaciej Żenczykowski 			  "			[ dst-mac %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
5862*1b481fc3SMaciej Żenczykowski 			  "			[ action %d ] | [ vf %d queue %d ]\n"
5863*1b481fc3SMaciej Żenczykowski 			  "			[ context %d ]\n"
5864*1b481fc3SMaciej Żenczykowski 			  "			[ loc %d ] |\n"
5865*1b481fc3SMaciej Żenczykowski 			  "		delete %d\n"
5866*1b481fc3SMaciej Żenczykowski 	},
5867*1b481fc3SMaciej Żenczykowski 	{
5868*1b481fc3SMaciej Żenczykowski 		.opts	= "-T|--show-time-stamping",
5869*1b481fc3SMaciej Żenczykowski 		.func	= do_tsinfo,
5870*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_tsinfo,
5871*1b481fc3SMaciej Żenczykowski 		.help	= "Show time stamping capabilities"
5872*1b481fc3SMaciej Żenczykowski 	},
5873*1b481fc3SMaciej Żenczykowski 	{
5874*1b481fc3SMaciej Żenczykowski 		.opts	= "-x|--show-rxfh-indir|--show-rxfh",
5875*1b481fc3SMaciej Żenczykowski 		.json	= true,
5876*1b481fc3SMaciej Żenczykowski 		.func	= do_grxfh,
5877*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_grss,
5878*1b481fc3SMaciej Żenczykowski 		.help	= "Show Rx flow hash indirection table and/or RSS hash key",
5879*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ context %d ]\n"
5880*1b481fc3SMaciej Żenczykowski 	},
5881*1b481fc3SMaciej Żenczykowski 	{
5882*1b481fc3SMaciej Żenczykowski 		.opts	= "-X|--set-rxfh-indir|--rxfh",
5883*1b481fc3SMaciej Żenczykowski 		.func	= do_srxfh,
5884*1b481fc3SMaciej Żenczykowski 		.help	= "Set Rx flow hash indirection table and/or RSS hash key",
5885*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ context %d|new ]\n"
5886*1b481fc3SMaciej Żenczykowski 			  "		[ equal N | weight W0 W1 ... | default ]\n"
5887*1b481fc3SMaciej Żenczykowski 			  "		[ hkey %x:%x:%x:%x:%x:.... ]\n"
5888*1b481fc3SMaciej Żenczykowski 			  "		[ hfunc FUNC ]\n"
5889*1b481fc3SMaciej Żenczykowski 			  "		[ delete ]\n"
5890*1b481fc3SMaciej Żenczykowski 	},
5891*1b481fc3SMaciej Żenczykowski 	{
5892*1b481fc3SMaciej Żenczykowski 		.opts	= "-f|--flash",
5893*1b481fc3SMaciej Żenczykowski 		.func	= do_flash,
5894*1b481fc3SMaciej Żenczykowski 		.help	= "Flash firmware image from the specified file to a region on the device",
5895*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		FILENAME [ REGION-NUMBER-TO-FLASH ]\n"
5896*1b481fc3SMaciej Żenczykowski 	},
5897*1b481fc3SMaciej Żenczykowski 	{
5898*1b481fc3SMaciej Żenczykowski 		.opts	= "-P|--show-permaddr",
5899*1b481fc3SMaciej Żenczykowski 		.func	= do_permaddr,
5900*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_permaddr,
5901*1b481fc3SMaciej Żenczykowski 		.help	= "Show permanent hardware address"
5902*1b481fc3SMaciej Żenczykowski 	},
5903*1b481fc3SMaciej Żenczykowski 	{
5904*1b481fc3SMaciej Żenczykowski 		.opts	= "-w|--get-dump",
5905*1b481fc3SMaciej Żenczykowski 		.func	= do_getfwdump,
5906*1b481fc3SMaciej Żenczykowski 		.help	= "Get dump flag, data",
5907*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ data FILENAME ]\n"
5908*1b481fc3SMaciej Żenczykowski 	},
5909*1b481fc3SMaciej Żenczykowski 	{
5910*1b481fc3SMaciej Żenczykowski 		.opts	= "-W|--set-dump",
5911*1b481fc3SMaciej Żenczykowski 		.func	= do_setfwdump,
5912*1b481fc3SMaciej Żenczykowski 		.help	= "Set dump flag of the device",
5913*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		N\n"
5914*1b481fc3SMaciej Żenczykowski 	},
5915*1b481fc3SMaciej Żenczykowski 	{
5916*1b481fc3SMaciej Żenczykowski 		.opts	= "-l|--show-channels",
5917*1b481fc3SMaciej Żenczykowski 		.func	= do_gchannels,
5918*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_gchannels,
5919*1b481fc3SMaciej Żenczykowski 		.help	= "Query Channels"
5920*1b481fc3SMaciej Żenczykowski 	},
5921*1b481fc3SMaciej Żenczykowski 	{
5922*1b481fc3SMaciej Żenczykowski 		.opts	= "-L|--set-channels",
5923*1b481fc3SMaciej Żenczykowski 		.func	= do_schannels,
5924*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_schannels,
5925*1b481fc3SMaciej Żenczykowski 		.help	= "Set Channels",
5926*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ rx N ]\n"
5927*1b481fc3SMaciej Żenczykowski 			  "		[ tx N ]\n"
5928*1b481fc3SMaciej Żenczykowski 			  "		[ other N ]\n"
5929*1b481fc3SMaciej Żenczykowski 			  "		[ combined N ]\n"
5930*1b481fc3SMaciej Żenczykowski 	},
5931*1b481fc3SMaciej Żenczykowski 	{
5932*1b481fc3SMaciej Żenczykowski 		.opts	= "--show-priv-flags",
5933*1b481fc3SMaciej Żenczykowski 		.func	= do_gprivflags,
5934*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_gprivflags,
5935*1b481fc3SMaciej Żenczykowski 		.help	= "Query private flags"
5936*1b481fc3SMaciej Żenczykowski 	},
5937*1b481fc3SMaciej Żenczykowski 	{
5938*1b481fc3SMaciej Żenczykowski 		.opts	= "--set-priv-flags",
5939*1b481fc3SMaciej Żenczykowski 		.func	= do_sprivflags,
5940*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_sprivflags,
5941*1b481fc3SMaciej Żenczykowski 		.help	= "Set private flags",
5942*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		FLAG on|off ...\n"
5943*1b481fc3SMaciej Żenczykowski 	},
5944*1b481fc3SMaciej Żenczykowski 	{
5945*1b481fc3SMaciej Żenczykowski 		.opts	= "-m|--dump-module-eeprom|--module-info",
5946*1b481fc3SMaciej Żenczykowski 		.func	= do_getmodule,
5947*1b481fc3SMaciej Żenczykowski 		.nlfunc = nl_getmodule,
5948*1b481fc3SMaciej Żenczykowski 		.help	= "Query/Decode Module EEPROM information and optical diagnostics if available",
5949*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ raw on|off ]\n"
5950*1b481fc3SMaciej Żenczykowski 			  "		[ hex on|off ]\n"
5951*1b481fc3SMaciej Żenczykowski 			  "		[ offset N ]\n"
5952*1b481fc3SMaciej Żenczykowski 			  "		[ length N ]\n"
5953*1b481fc3SMaciej Żenczykowski 			  "		[ page N ]\n"
5954*1b481fc3SMaciej Żenczykowski 			  "		[ bank N ]\n"
5955*1b481fc3SMaciej Żenczykowski 			  "		[ i2c N ]\n"
5956*1b481fc3SMaciej Żenczykowski 	},
5957*1b481fc3SMaciej Żenczykowski 	{
5958*1b481fc3SMaciej Żenczykowski 		.opts	= "--show-eee",
5959*1b481fc3SMaciej Żenczykowski 		.func	= do_geee,
5960*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_geee,
5961*1b481fc3SMaciej Żenczykowski 		.help	= "Show EEE settings",
5962*1b481fc3SMaciej Żenczykowski 	},
5963*1b481fc3SMaciej Żenczykowski 	{
5964*1b481fc3SMaciej Żenczykowski 		.opts	= "--set-eee",
5965*1b481fc3SMaciej Żenczykowski 		.func	= do_seee,
5966*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_seee,
5967*1b481fc3SMaciej Żenczykowski 		.help	= "Set EEE settings",
5968*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ eee on|off ]\n"
5969*1b481fc3SMaciej Żenczykowski 			  "		[ advertise %x ]\n"
5970*1b481fc3SMaciej Żenczykowski 			  "		[ tx-lpi on|off ]\n"
5971*1b481fc3SMaciej Żenczykowski 			  "		[ tx-timer %d ]\n"
5972*1b481fc3SMaciej Żenczykowski 	},
5973*1b481fc3SMaciej Żenczykowski 	{
5974*1b481fc3SMaciej Żenczykowski 		.opts	= "--set-phy-tunable",
5975*1b481fc3SMaciej Żenczykowski 		.func	= do_set_phy_tunable,
5976*1b481fc3SMaciej Żenczykowski 		.help	= "Set PHY tunable",
5977*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ downshift on|off [count N] ]\n"
5978*1b481fc3SMaciej Żenczykowski 			  "		[ fast-link-down on|off [msecs N] ]\n"
5979*1b481fc3SMaciej Żenczykowski 			  "		[ energy-detect-power-down on|off [msecs N] ]\n"
5980*1b481fc3SMaciej Żenczykowski 	},
5981*1b481fc3SMaciej Żenczykowski 	{
5982*1b481fc3SMaciej Żenczykowski 		.opts	= "--get-phy-tunable",
5983*1b481fc3SMaciej Żenczykowski 		.func	= do_get_phy_tunable,
5984*1b481fc3SMaciej Żenczykowski 		.help	= "Get PHY tunable",
5985*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ downshift ]\n"
5986*1b481fc3SMaciej Żenczykowski 			  "		[ fast-link-down ]\n"
5987*1b481fc3SMaciej Żenczykowski 			  "		[ energy-detect-power-down ]\n"
5988*1b481fc3SMaciej Żenczykowski 	},
5989*1b481fc3SMaciej Żenczykowski 	{
5990*1b481fc3SMaciej Żenczykowski 		.opts	= "--get-tunable",
5991*1b481fc3SMaciej Żenczykowski 		.func	= do_gtunable,
5992*1b481fc3SMaciej Żenczykowski 		.help	= "Get tunable",
5993*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ rx-copybreak ]\n"
5994*1b481fc3SMaciej Żenczykowski 			  "		[ tx-copybreak ]\n"
5995*1b481fc3SMaciej Żenczykowski 			  "		[ tx-buf-size ]\n"
5996*1b481fc3SMaciej Żenczykowski 			  "		[ pfc-prevention-tout ]\n"
5997*1b481fc3SMaciej Żenczykowski 	},
5998*1b481fc3SMaciej Żenczykowski 	{
5999*1b481fc3SMaciej Żenczykowski 		.opts	= "--set-tunable",
6000*1b481fc3SMaciej Żenczykowski 		.func	= do_stunable,
6001*1b481fc3SMaciej Żenczykowski 		.help	= "Set tunable",
6002*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ rx-copybreak N ]\n"
6003*1b481fc3SMaciej Żenczykowski 			  "		[ tx-copybreak N ]\n"
6004*1b481fc3SMaciej Żenczykowski 			  "		[ tx-buf-size N ]\n"
6005*1b481fc3SMaciej Żenczykowski 			  "		[ pfc-prevention-tout N ]\n"
6006*1b481fc3SMaciej Żenczykowski 	},
6007*1b481fc3SMaciej Żenczykowski 	{
6008*1b481fc3SMaciej Żenczykowski 		.opts	= "--reset",
6009*1b481fc3SMaciej Żenczykowski 		.func	= do_reset,
6010*1b481fc3SMaciej Żenczykowski 		.help	= "Reset components",
6011*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ flags %x ]\n"
6012*1b481fc3SMaciej Żenczykowski 			  "		[ mgmt ]\n"
6013*1b481fc3SMaciej Żenczykowski 			  "		[ mgmt-shared ]\n"
6014*1b481fc3SMaciej Żenczykowski 			  "		[ irq ]\n"
6015*1b481fc3SMaciej Żenczykowski 			  "		[ irq-shared ]\n"
6016*1b481fc3SMaciej Żenczykowski 			  "		[ dma ]\n"
6017*1b481fc3SMaciej Żenczykowski 			  "		[ dma-shared ]\n"
6018*1b481fc3SMaciej Żenczykowski 			  "		[ filter ]\n"
6019*1b481fc3SMaciej Żenczykowski 			  "		[ filter-shared ]\n"
6020*1b481fc3SMaciej Żenczykowski 			  "		[ offload ]\n"
6021*1b481fc3SMaciej Żenczykowski 			  "		[ offload-shared ]\n"
6022*1b481fc3SMaciej Żenczykowski 			  "		[ mac ]\n"
6023*1b481fc3SMaciej Żenczykowski 			  "		[ mac-shared ]\n"
6024*1b481fc3SMaciej Żenczykowski 			  "		[ phy ]\n"
6025*1b481fc3SMaciej Żenczykowski 			  "		[ phy-shared ]\n"
6026*1b481fc3SMaciej Żenczykowski 			  "		[ ram ]\n"
6027*1b481fc3SMaciej Żenczykowski 			  "		[ ram-shared ]\n"
6028*1b481fc3SMaciej Żenczykowski 			  "		[ ap ]\n"
6029*1b481fc3SMaciej Żenczykowski 			  "		[ ap-shared ]\n"
6030*1b481fc3SMaciej Żenczykowski 			  "		[ dedicated ]\n"
6031*1b481fc3SMaciej Żenczykowski 			  "		[ all ]\n"
6032*1b481fc3SMaciej Żenczykowski 	},
6033*1b481fc3SMaciej Żenczykowski 	{
6034*1b481fc3SMaciej Żenczykowski 		.opts	= "--show-fec",
6035*1b481fc3SMaciej Żenczykowski 		.json	= true,
6036*1b481fc3SMaciej Żenczykowski 		.func	= do_gfec,
6037*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_gfec,
6038*1b481fc3SMaciej Żenczykowski 		.help	= "Show FEC settings",
6039*1b481fc3SMaciej Żenczykowski 	},
6040*1b481fc3SMaciej Żenczykowski 	{
6041*1b481fc3SMaciej Żenczykowski 		.opts	= "--set-fec",
6042*1b481fc3SMaciej Żenczykowski 		.func	= do_sfec,
6043*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_sfec,
6044*1b481fc3SMaciej Żenczykowski 		.help	= "Set FEC settings",
6045*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ encoding auto|off|rs|baser|llrs [...] ]\n"
6046*1b481fc3SMaciej Żenczykowski 	},
6047*1b481fc3SMaciej Żenczykowski 	{
6048*1b481fc3SMaciej Żenczykowski 		.opts	= "-Q|--per-queue",
6049*1b481fc3SMaciej Żenczykowski 		.func	= do_perqueue,
6050*1b481fc3SMaciej Żenczykowski 		.help	= "Apply per-queue command. ",
6051*1b481fc3SMaciej Żenczykowski 		.xhelp	= "The supported sub commands include --show-coalesce, --coalesce"
6052*1b481fc3SMaciej Żenczykowski 			  "		[queue_mask %x] SUB_COMMAND\n",
6053*1b481fc3SMaciej Żenczykowski 	},
6054*1b481fc3SMaciej Żenczykowski 	{
6055*1b481fc3SMaciej Żenczykowski 		.opts	= "--cable-test",
6056*1b481fc3SMaciej Żenczykowski 		.json	= true,
6057*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_cable_test,
6058*1b481fc3SMaciej Żenczykowski 		.help	= "Perform a cable test",
6059*1b481fc3SMaciej Żenczykowski 	},
6060*1b481fc3SMaciej Żenczykowski 	{
6061*1b481fc3SMaciej Żenczykowski 		.opts	= "--cable-test-tdr",
6062*1b481fc3SMaciej Żenczykowski 		.json	= true,
6063*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_cable_test_tdr,
6064*1b481fc3SMaciej Żenczykowski 		.help	= "Print cable test time domain reflectrometery data",
6065*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ first N ]\n"
6066*1b481fc3SMaciej Żenczykowski 			  "		[ last N ]\n"
6067*1b481fc3SMaciej Żenczykowski 			  "		[ step N ]\n"
6068*1b481fc3SMaciej Żenczykowski 			  "		[ pair N ]\n"
6069*1b481fc3SMaciej Żenczykowski 	},
6070*1b481fc3SMaciej Żenczykowski 	{
6071*1b481fc3SMaciej Żenczykowski 		.opts	= "--show-tunnels",
6072*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_gtunnels,
6073*1b481fc3SMaciej Żenczykowski 		.help	= "Show NIC tunnel offload information",
6074*1b481fc3SMaciej Żenczykowski 	},
6075*1b481fc3SMaciej Żenczykowski 	{
6076*1b481fc3SMaciej Żenczykowski 		.opts	= "--show-module",
6077*1b481fc3SMaciej Żenczykowski 		.json	= true,
6078*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_gmodule,
6079*1b481fc3SMaciej Żenczykowski 		.help	= "Show transceiver module settings",
6080*1b481fc3SMaciej Żenczykowski 	},
6081*1b481fc3SMaciej Żenczykowski 	{
6082*1b481fc3SMaciej Żenczykowski 		.opts	= "--set-module",
6083*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_smodule,
6084*1b481fc3SMaciej Żenczykowski 		.help	= "Set transceiver module settings",
6085*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ power-mode-policy high|auto ]\n"
6086*1b481fc3SMaciej Żenczykowski 	},
6087*1b481fc3SMaciej Żenczykowski 	{
6088*1b481fc3SMaciej Żenczykowski 		.opts	= "--get-plca-cfg",
6089*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_plca_get_cfg,
6090*1b481fc3SMaciej Żenczykowski 		.help	= "Get PLCA configuration",
6091*1b481fc3SMaciej Żenczykowski 	},
6092*1b481fc3SMaciej Żenczykowski 	{
6093*1b481fc3SMaciej Żenczykowski 		.opts	= "--set-plca-cfg",
6094*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_plca_set_cfg,
6095*1b481fc3SMaciej Żenczykowski 		.help	= "Set PLCA configuration",
6096*1b481fc3SMaciej Żenczykowski 		.xhelp  = "		[ enable on|off ]\n"
6097*1b481fc3SMaciej Żenczykowski 			  "		[ node-id N ]\n"
6098*1b481fc3SMaciej Żenczykowski 			  "		[ node-cnt N ]\n"
6099*1b481fc3SMaciej Żenczykowski 			  "		[ to-tmr N ]\n"
6100*1b481fc3SMaciej Żenczykowski 			  "		[ burst-cnt N ]\n"
6101*1b481fc3SMaciej Żenczykowski 			  "		[ burst-tmr N ]\n"
6102*1b481fc3SMaciej Żenczykowski 	},
6103*1b481fc3SMaciej Żenczykowski 	{
6104*1b481fc3SMaciej Żenczykowski 		.opts	= "--get-plca-status",
6105*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_plca_get_status,
6106*1b481fc3SMaciej Żenczykowski 		.help	= "Get PLCA status information",
6107*1b481fc3SMaciej Żenczykowski 	},
6108*1b481fc3SMaciej Żenczykowski 	{
6109*1b481fc3SMaciej Żenczykowski 		.opts	= "--show-mm",
6110*1b481fc3SMaciej Żenczykowski 		.json	= true,
6111*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_get_mm,
6112*1b481fc3SMaciej Żenczykowski 		.help	= "Show MAC merge layer state",
6113*1b481fc3SMaciej Żenczykowski 	},
6114*1b481fc3SMaciej Żenczykowski 	{
6115*1b481fc3SMaciej Żenczykowski 		.opts	= "--set-mm",
6116*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_set_mm,
6117*1b481fc3SMaciej Żenczykowski 		.help	= "Set MAC merge layer parameters",
6118*1b481fc3SMaciej Żenczykowski 			  "		[ verify-enabled on|off ]\n"
6119*1b481fc3SMaciej Żenczykowski 			  "		[ verify-time N ]\n"
6120*1b481fc3SMaciej Żenczykowski 			  "		[ tx-enabled on|off ]\n"
6121*1b481fc3SMaciej Żenczykowski 			  "		[ pmac-enabled on|off ]\n"
6122*1b481fc3SMaciej Żenczykowski 			  "		[ tx-min-frag-size 60-252 ]\n"
6123*1b481fc3SMaciej Żenczykowski 	},
6124*1b481fc3SMaciej Żenczykowski 	{
6125*1b481fc3SMaciej Żenczykowski 		.opts	= "--show-pse",
6126*1b481fc3SMaciej Żenczykowski 		.json	= true,
6127*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_gpse,
6128*1b481fc3SMaciej Żenczykowski 		.help	= "Show settings for Power Sourcing Equipment",
6129*1b481fc3SMaciej Żenczykowski 	},
6130*1b481fc3SMaciej Żenczykowski 	{
6131*1b481fc3SMaciej Żenczykowski 		.opts	= "--set-pse",
6132*1b481fc3SMaciej Żenczykowski 		.nlfunc	= nl_spse,
6133*1b481fc3SMaciej Żenczykowski 		.help	= "Set Power Sourcing Equipment settings",
6134*1b481fc3SMaciej Żenczykowski 		.xhelp	= "		[ podl-pse-admin-control enable|disable ]\n"
6135*1b481fc3SMaciej Żenczykowski 	},
6136*1b481fc3SMaciej Żenczykowski 	{
6137*1b481fc3SMaciej Żenczykowski 		.opts	= "-h|--help",
6138*1b481fc3SMaciej Żenczykowski 		.no_dev	= true,
6139*1b481fc3SMaciej Żenczykowski 		.func	= show_usage,
6140*1b481fc3SMaciej Żenczykowski 		.help	= "Show this help"
6141*1b481fc3SMaciej Żenczykowski 	},
6142*1b481fc3SMaciej Żenczykowski 	{
6143*1b481fc3SMaciej Żenczykowski 		.opts	= "--version",
6144*1b481fc3SMaciej Żenczykowski 		.no_dev	= true,
6145*1b481fc3SMaciej Żenczykowski 		.func	= do_version,
6146*1b481fc3SMaciej Żenczykowski 		.help	= "Show version number"
6147*1b481fc3SMaciej Żenczykowski 	},
6148*1b481fc3SMaciej Żenczykowski 	{}
6149*1b481fc3SMaciej Żenczykowski };
6150*1b481fc3SMaciej Żenczykowski 
show_usage(struct cmd_context * ctx __maybe_unused)6151*1b481fc3SMaciej Żenczykowski static int show_usage(struct cmd_context *ctx __maybe_unused)
6152*1b481fc3SMaciej Żenczykowski {
6153*1b481fc3SMaciej Żenczykowski 	int i;
6154*1b481fc3SMaciej Żenczykowski 
6155*1b481fc3SMaciej Żenczykowski 	/* ethtool -h */
6156*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, PACKAGE " version " VERSION "\n");
6157*1b481fc3SMaciej Żenczykowski 	fprintf(stdout,	"Usage:\n");
6158*1b481fc3SMaciej Żenczykowski 	for (i = 0; args[i].opts; i++) {
6159*1b481fc3SMaciej Żenczykowski 		fputs("        ethtool [ FLAGS ] ", stdout);
6160*1b481fc3SMaciej Żenczykowski 		fprintf(stdout, "%s %s\t%s\n",
6161*1b481fc3SMaciej Żenczykowski 			args[i].opts,
6162*1b481fc3SMaciej Żenczykowski 			args[i].no_dev ? "\t" : "DEVNAME",
6163*1b481fc3SMaciej Żenczykowski 			args[i].help);
6164*1b481fc3SMaciej Żenczykowski 		if (args[i].xhelp)
6165*1b481fc3SMaciej Żenczykowski 			fputs(args[i].xhelp, stdout);
6166*1b481fc3SMaciej Żenczykowski 	}
6167*1b481fc3SMaciej Żenczykowski 	nl_monitor_usage();
6168*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "\n");
6169*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "FLAGS:\n");
6170*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "	--debug MASK	turn on debugging messages\n");
6171*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "	--json		enable JSON output format (not supported by all commands)\n");
6172*1b481fc3SMaciej Żenczykowski 	fprintf(stdout, "	-I|--include-statistics		request device statistics related to the command (not supported by all commands)\n");
6173*1b481fc3SMaciej Żenczykowski 
6174*1b481fc3SMaciej Żenczykowski 	return 0;
6175*1b481fc3SMaciej Żenczykowski }
6176*1b481fc3SMaciej Żenczykowski 
find_option(char * arg)6177*1b481fc3SMaciej Żenczykowski static int find_option(char *arg)
6178*1b481fc3SMaciej Żenczykowski {
6179*1b481fc3SMaciej Żenczykowski 	const char *opt;
6180*1b481fc3SMaciej Żenczykowski 	size_t len;
6181*1b481fc3SMaciej Żenczykowski 	int k;
6182*1b481fc3SMaciej Żenczykowski 
6183*1b481fc3SMaciej Żenczykowski 	for (k = 1; args[k].opts; k++) {
6184*1b481fc3SMaciej Żenczykowski 		opt = args[k].opts;
6185*1b481fc3SMaciej Żenczykowski 		for (;;) {
6186*1b481fc3SMaciej Żenczykowski 			len = strcspn(opt, "|");
6187*1b481fc3SMaciej Żenczykowski 			if (strncmp(arg, opt, len) == 0 && arg[len] == 0)
6188*1b481fc3SMaciej Żenczykowski 				return k;
6189*1b481fc3SMaciej Żenczykowski 
6190*1b481fc3SMaciej Żenczykowski 			if (opt[len] == 0)
6191*1b481fc3SMaciej Żenczykowski 				break;
6192*1b481fc3SMaciej Żenczykowski 			opt += len + 1;
6193*1b481fc3SMaciej Żenczykowski 		}
6194*1b481fc3SMaciej Żenczykowski 	}
6195*1b481fc3SMaciej Żenczykowski 
6196*1b481fc3SMaciej Żenczykowski 	return -1;
6197*1b481fc3SMaciej Żenczykowski }
6198*1b481fc3SMaciej Żenczykowski 
6199*1b481fc3SMaciej Żenczykowski #define MAX(x, y) (x > y ? x : y)
6200*1b481fc3SMaciej Żenczykowski 
find_max_num_queues(struct cmd_context * ctx)6201*1b481fc3SMaciej Żenczykowski static int find_max_num_queues(struct cmd_context *ctx)
6202*1b481fc3SMaciej Żenczykowski {
6203*1b481fc3SMaciej Żenczykowski 	struct ethtool_channels echannels;
6204*1b481fc3SMaciej Żenczykowski 
6205*1b481fc3SMaciej Żenczykowski 	echannels.cmd = ETHTOOL_GCHANNELS;
6206*1b481fc3SMaciej Żenczykowski 	if (send_ioctl(ctx, &echannels))
6207*1b481fc3SMaciej Żenczykowski 		return -1;
6208*1b481fc3SMaciej Żenczykowski 
6209*1b481fc3SMaciej Żenczykowski 	return MAX(echannels.rx_count, echannels.tx_count) +
6210*1b481fc3SMaciej Żenczykowski 		echannels.combined_count;
6211*1b481fc3SMaciej Żenczykowski }
6212*1b481fc3SMaciej Żenczykowski 
6213*1b481fc3SMaciej Żenczykowski static struct ethtool_per_queue_op *
get_per_queue_coalesce(struct cmd_context * ctx,__u32 * queue_mask,int n_queues)6214*1b481fc3SMaciej Żenczykowski get_per_queue_coalesce(struct cmd_context *ctx, __u32 *queue_mask, int n_queues)
6215*1b481fc3SMaciej Żenczykowski {
6216*1b481fc3SMaciej Żenczykowski 	struct ethtool_per_queue_op *per_queue_opt;
6217*1b481fc3SMaciej Żenczykowski 
6218*1b481fc3SMaciej Żenczykowski 	per_queue_opt = malloc(sizeof(*per_queue_opt) + n_queues *
6219*1b481fc3SMaciej Żenczykowski 			sizeof(struct ethtool_coalesce));
6220*1b481fc3SMaciej Żenczykowski 	if (!per_queue_opt)
6221*1b481fc3SMaciej Żenczykowski 		return NULL;
6222*1b481fc3SMaciej Żenczykowski 
6223*1b481fc3SMaciej Żenczykowski 	memcpy(per_queue_opt->queue_mask, queue_mask,
6224*1b481fc3SMaciej Żenczykowski 	       __KERNEL_DIV_ROUND_UP(MAX_NUM_QUEUE, 32) * sizeof(__u32));
6225*1b481fc3SMaciej Żenczykowski 	per_queue_opt->cmd = ETHTOOL_PERQUEUE;
6226*1b481fc3SMaciej Żenczykowski 	per_queue_opt->sub_command = ETHTOOL_GCOALESCE;
6227*1b481fc3SMaciej Żenczykowski 	if (send_ioctl(ctx, per_queue_opt)) {
6228*1b481fc3SMaciej Żenczykowski 		free(per_queue_opt);
6229*1b481fc3SMaciej Żenczykowski 		perror("Cannot get device per queue parameters");
6230*1b481fc3SMaciej Żenczykowski 		return NULL;
6231*1b481fc3SMaciej Żenczykowski 	}
6232*1b481fc3SMaciej Żenczykowski 
6233*1b481fc3SMaciej Żenczykowski 	return per_queue_opt;
6234*1b481fc3SMaciej Żenczykowski }
6235*1b481fc3SMaciej Żenczykowski 
set_per_queue_coalesce(struct cmd_context * ctx,struct ethtool_per_queue_op * per_queue_opt,int n_queues)6236*1b481fc3SMaciej Żenczykowski static void set_per_queue_coalesce(struct cmd_context *ctx,
6237*1b481fc3SMaciej Żenczykowski 				   struct ethtool_per_queue_op *per_queue_opt,
6238*1b481fc3SMaciej Żenczykowski 				   int n_queues)
6239*1b481fc3SMaciej Żenczykowski {
6240*1b481fc3SMaciej Żenczykowski 	struct ethtool_coalesce ecoal;
6241*1b481fc3SMaciej Żenczykowski 	DECLARE_COALESCE_OPTION_VARS();
6242*1b481fc3SMaciej Żenczykowski 	struct cmdline_info cmdline_coalesce[] = COALESCE_CMDLINE_INFO(ecoal);
6243*1b481fc3SMaciej Żenczykowski 	__u32 *queue_mask = per_queue_opt->queue_mask;
6244*1b481fc3SMaciej Żenczykowski 	struct ethtool_coalesce *ecoal_q;
6245*1b481fc3SMaciej Żenczykowski 	int gcoalesce_changed = 0;
6246*1b481fc3SMaciej Żenczykowski 	int i, idx = 0;
6247*1b481fc3SMaciej Żenczykowski 
6248*1b481fc3SMaciej Żenczykowski 	parse_generic_cmdline(ctx, &gcoalesce_changed,
6249*1b481fc3SMaciej Żenczykowski 			      cmdline_coalesce, ARRAY_SIZE(cmdline_coalesce));
6250*1b481fc3SMaciej Żenczykowski 
6251*1b481fc3SMaciej Żenczykowski 	ecoal_q = (struct ethtool_coalesce *)(per_queue_opt + 1);
6252*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < __KERNEL_DIV_ROUND_UP(MAX_NUM_QUEUE, 32); i++) {
6253*1b481fc3SMaciej Żenczykowski 		int queue = i * 32;
6254*1b481fc3SMaciej Żenczykowski 		__u32 mask = queue_mask[i];
6255*1b481fc3SMaciej Żenczykowski 
6256*1b481fc3SMaciej Żenczykowski 		while (mask > 0) {
6257*1b481fc3SMaciej Żenczykowski 			if (mask & 0x1) {
6258*1b481fc3SMaciej Żenczykowski 				int changed = 0;
6259*1b481fc3SMaciej Żenczykowski 
6260*1b481fc3SMaciej Żenczykowski 				memcpy(&ecoal, ecoal_q + idx,
6261*1b481fc3SMaciej Żenczykowski 				       sizeof(struct ethtool_coalesce));
6262*1b481fc3SMaciej Żenczykowski 				do_generic_set(cmdline_coalesce,
6263*1b481fc3SMaciej Żenczykowski 					       ARRAY_SIZE(cmdline_coalesce),
6264*1b481fc3SMaciej Żenczykowski 					       &changed);
6265*1b481fc3SMaciej Żenczykowski 				if (!changed)
6266*1b481fc3SMaciej Żenczykowski 					fprintf(stderr,
6267*1b481fc3SMaciej Żenczykowski 						"Queue %d, no coalesce parameters changed\n",
6268*1b481fc3SMaciej Żenczykowski 						queue);
6269*1b481fc3SMaciej Żenczykowski 				memcpy(ecoal_q + idx, &ecoal,
6270*1b481fc3SMaciej Żenczykowski 				       sizeof(struct ethtool_coalesce));
6271*1b481fc3SMaciej Żenczykowski 				idx++;
6272*1b481fc3SMaciej Żenczykowski 			}
6273*1b481fc3SMaciej Żenczykowski 			mask = mask >> 1;
6274*1b481fc3SMaciej Żenczykowski 			queue++;
6275*1b481fc3SMaciej Żenczykowski 		}
6276*1b481fc3SMaciej Żenczykowski 		if (idx == n_queues)
6277*1b481fc3SMaciej Żenczykowski 			break;
6278*1b481fc3SMaciej Żenczykowski 	}
6279*1b481fc3SMaciej Żenczykowski 
6280*1b481fc3SMaciej Żenczykowski 	per_queue_opt->cmd = ETHTOOL_PERQUEUE;
6281*1b481fc3SMaciej Żenczykowski 	per_queue_opt->sub_command = ETHTOOL_SCOALESCE;
6282*1b481fc3SMaciej Żenczykowski 
6283*1b481fc3SMaciej Żenczykowski 	if (send_ioctl(ctx, per_queue_opt))
6284*1b481fc3SMaciej Żenczykowski 		perror("Cannot set device per queue parameters");
6285*1b481fc3SMaciej Żenczykowski }
6286*1b481fc3SMaciej Żenczykowski 
do_perqueue(struct cmd_context * ctx)6287*1b481fc3SMaciej Żenczykowski static int do_perqueue(struct cmd_context *ctx)
6288*1b481fc3SMaciej Żenczykowski {
6289*1b481fc3SMaciej Żenczykowski 	struct ethtool_per_queue_op *per_queue_opt;
6290*1b481fc3SMaciej Żenczykowski 	__u32 queue_mask[__KERNEL_DIV_ROUND_UP(MAX_NUM_QUEUE, 32)] = {0};
6291*1b481fc3SMaciej Żenczykowski 	int i, n_queues = 0;
6292*1b481fc3SMaciej Żenczykowski 
6293*1b481fc3SMaciej Żenczykowski 	if (ctx->argc == 0)
6294*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
6295*1b481fc3SMaciej Żenczykowski 
6296*1b481fc3SMaciej Żenczykowski 	/*
6297*1b481fc3SMaciej Żenczykowski 	 * The sub commands will be applied to
6298*1b481fc3SMaciej Żenczykowski 	 * all queues if no queue_mask set
6299*1b481fc3SMaciej Żenczykowski 	 */
6300*1b481fc3SMaciej Żenczykowski 	if (strncmp(*ctx->argp, "queue_mask", 11)) {
6301*1b481fc3SMaciej Żenczykowski 		n_queues = find_max_num_queues(ctx);
6302*1b481fc3SMaciej Żenczykowski 		if (n_queues < 0) {
6303*1b481fc3SMaciej Żenczykowski 			perror("Cannot get number of queues");
6304*1b481fc3SMaciej Żenczykowski 			return -EFAULT;
6305*1b481fc3SMaciej Żenczykowski 		} else if (n_queues > MAX_NUM_QUEUE) {
6306*1b481fc3SMaciej Żenczykowski 			n_queues = MAX_NUM_QUEUE;
6307*1b481fc3SMaciej Żenczykowski 		}
6308*1b481fc3SMaciej Żenczykowski 		for (i = 0; i < n_queues / 32; i++)
6309*1b481fc3SMaciej Żenczykowski 			queue_mask[i] = ~0;
6310*1b481fc3SMaciej Żenczykowski 		if (n_queues % 32)
6311*1b481fc3SMaciej Żenczykowski 			queue_mask[i] = (1 << (n_queues - i * 32)) - 1;
6312*1b481fc3SMaciej Żenczykowski 		fprintf(stdout,
6313*1b481fc3SMaciej Żenczykowski 			"The sub commands will be applied to all %d queues\n",
6314*1b481fc3SMaciej Żenczykowski 			n_queues);
6315*1b481fc3SMaciej Żenczykowski 	} else {
6316*1b481fc3SMaciej Żenczykowski 		if (ctx->argc <= 2)
6317*1b481fc3SMaciej Żenczykowski 			exit_bad_args();
6318*1b481fc3SMaciej Żenczykowski 		ctx->argc--;
6319*1b481fc3SMaciej Żenczykowski 		ctx->argp++;
6320*1b481fc3SMaciej Żenczykowski 		if (parse_hex_u32_bitmap(*ctx->argp, MAX_NUM_QUEUE,
6321*1b481fc3SMaciej Żenczykowski 		    queue_mask)) {
6322*1b481fc3SMaciej Żenczykowski 			fprintf(stdout, "Invalid queue mask\n");
6323*1b481fc3SMaciej Żenczykowski 			return -1;
6324*1b481fc3SMaciej Żenczykowski 		}
6325*1b481fc3SMaciej Żenczykowski 		for (i = 0; i < __KERNEL_DIV_ROUND_UP(MAX_NUM_QUEUE, 32); i++) {
6326*1b481fc3SMaciej Żenczykowski 			__u32 mask = queue_mask[i];
6327*1b481fc3SMaciej Żenczykowski 
6328*1b481fc3SMaciej Żenczykowski 			while (mask > 0) {
6329*1b481fc3SMaciej Żenczykowski 				if (mask & 0x1)
6330*1b481fc3SMaciej Żenczykowski 					n_queues++;
6331*1b481fc3SMaciej Żenczykowski 				mask = mask >> 1;
6332*1b481fc3SMaciej Żenczykowski 			}
6333*1b481fc3SMaciej Żenczykowski 		}
6334*1b481fc3SMaciej Żenczykowski 		ctx->argc--;
6335*1b481fc3SMaciej Żenczykowski 		ctx->argp++;
6336*1b481fc3SMaciej Żenczykowski 	}
6337*1b481fc3SMaciej Żenczykowski 
6338*1b481fc3SMaciej Żenczykowski 	i = find_option(ctx->argp[0]);
6339*1b481fc3SMaciej Żenczykowski 	if (i < 0)
6340*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
6341*1b481fc3SMaciej Żenczykowski 
6342*1b481fc3SMaciej Żenczykowski 	if (strstr(args[i].opts, "--show-coalesce") != NULL) {
6343*1b481fc3SMaciej Żenczykowski 		per_queue_opt = get_per_queue_coalesce(ctx, queue_mask,
6344*1b481fc3SMaciej Żenczykowski 						       n_queues);
6345*1b481fc3SMaciej Żenczykowski 		if (per_queue_opt == NULL) {
6346*1b481fc3SMaciej Żenczykowski 			perror("Cannot get device per queue parameters");
6347*1b481fc3SMaciej Żenczykowski 			return -EFAULT;
6348*1b481fc3SMaciej Żenczykowski 		}
6349*1b481fc3SMaciej Żenczykowski 		dump_per_queue_coalesce(per_queue_opt, queue_mask, n_queues);
6350*1b481fc3SMaciej Żenczykowski 		free(per_queue_opt);
6351*1b481fc3SMaciej Żenczykowski 	} else if (strstr(args[i].opts, "--coalesce") != NULL) {
6352*1b481fc3SMaciej Żenczykowski 		ctx->argc--;
6353*1b481fc3SMaciej Żenczykowski 		ctx->argp++;
6354*1b481fc3SMaciej Żenczykowski 		per_queue_opt = get_per_queue_coalesce(ctx, queue_mask,
6355*1b481fc3SMaciej Żenczykowski 						       n_queues);
6356*1b481fc3SMaciej Żenczykowski 		if (per_queue_opt == NULL) {
6357*1b481fc3SMaciej Żenczykowski 			perror("Cannot get device per queue parameters");
6358*1b481fc3SMaciej Żenczykowski 			return -EFAULT;
6359*1b481fc3SMaciej Żenczykowski 		}
6360*1b481fc3SMaciej Żenczykowski 		set_per_queue_coalesce(ctx, per_queue_opt, n_queues);
6361*1b481fc3SMaciej Żenczykowski 		free(per_queue_opt);
6362*1b481fc3SMaciej Żenczykowski 	} else {
6363*1b481fc3SMaciej Żenczykowski 		perror("The subcommand is not supported yet");
6364*1b481fc3SMaciej Żenczykowski 		return -EOPNOTSUPP;
6365*1b481fc3SMaciej Żenczykowski 	}
6366*1b481fc3SMaciej Żenczykowski 
6367*1b481fc3SMaciej Żenczykowski 	return 0;
6368*1b481fc3SMaciej Żenczykowski }
6369*1b481fc3SMaciej Żenczykowski 
ioctl_init(struct cmd_context * ctx,bool no_dev)6370*1b481fc3SMaciej Żenczykowski static int ioctl_init(struct cmd_context *ctx, bool no_dev)
6371*1b481fc3SMaciej Żenczykowski {
6372*1b481fc3SMaciej Żenczykowski 	if (no_dev) {
6373*1b481fc3SMaciej Żenczykowski 		ctx->fd = -1;
6374*1b481fc3SMaciej Żenczykowski 		return 0;
6375*1b481fc3SMaciej Żenczykowski 	}
6376*1b481fc3SMaciej Żenczykowski 	if (strlen(ctx->devname) >= IFNAMSIZ) {
6377*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "Device name longer than %u characters\n",
6378*1b481fc3SMaciej Żenczykowski 			IFNAMSIZ - 1);
6379*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
6380*1b481fc3SMaciej Żenczykowski 	}
6381*1b481fc3SMaciej Żenczykowski 
6382*1b481fc3SMaciej Żenczykowski 	/* Setup our control structures. */
6383*1b481fc3SMaciej Żenczykowski 	memset(&ctx->ifr, 0, sizeof(ctx->ifr));
6384*1b481fc3SMaciej Żenczykowski 	strcpy(ctx->ifr.ifr_name, ctx->devname);
6385*1b481fc3SMaciej Żenczykowski 
6386*1b481fc3SMaciej Żenczykowski 	/* Open control socket. */
6387*1b481fc3SMaciej Żenczykowski 	ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
6388*1b481fc3SMaciej Żenczykowski 	if (ctx->fd < 0)
6389*1b481fc3SMaciej Żenczykowski 		ctx->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
6390*1b481fc3SMaciej Żenczykowski 	if (ctx->fd < 0) {
6391*1b481fc3SMaciej Żenczykowski 		perror("Cannot get control socket");
6392*1b481fc3SMaciej Żenczykowski 		return 70;
6393*1b481fc3SMaciej Żenczykowski 	}
6394*1b481fc3SMaciej Żenczykowski 
6395*1b481fc3SMaciej Żenczykowski 	return 0;
6396*1b481fc3SMaciej Żenczykowski }
6397*1b481fc3SMaciej Żenczykowski 
main(int argc,char ** argp)6398*1b481fc3SMaciej Żenczykowski int main(int argc, char **argp)
6399*1b481fc3SMaciej Żenczykowski {
6400*1b481fc3SMaciej Żenczykowski 	struct cmd_context ctx = {};
6401*1b481fc3SMaciej Żenczykowski 	int ret;
6402*1b481fc3SMaciej Żenczykowski 	int k;
6403*1b481fc3SMaciej Żenczykowski 
6404*1b481fc3SMaciej Żenczykowski 	init_global_link_mode_masks();
6405*1b481fc3SMaciej Żenczykowski 
6406*1b481fc3SMaciej Żenczykowski 	if (argc < 2)
6407*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
6408*1b481fc3SMaciej Żenczykowski 
6409*1b481fc3SMaciej Żenczykowski 	/* Skip command name */
6410*1b481fc3SMaciej Żenczykowski 	argp++;
6411*1b481fc3SMaciej Żenczykowski 	argc--;
6412*1b481fc3SMaciej Żenczykowski 
6413*1b481fc3SMaciej Żenczykowski 	while (true) {
6414*1b481fc3SMaciej Żenczykowski 		if (*argp && !strcmp(*argp, "--debug")) {
6415*1b481fc3SMaciej Żenczykowski 			char *eptr;
6416*1b481fc3SMaciej Żenczykowski 
6417*1b481fc3SMaciej Żenczykowski 			if (argc < 2)
6418*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
6419*1b481fc3SMaciej Żenczykowski 			ctx.debug = strtoul(argp[1], &eptr, 0);
6420*1b481fc3SMaciej Żenczykowski 			if (!argp[1][0] || *eptr)
6421*1b481fc3SMaciej Żenczykowski 				exit_bad_args();
6422*1b481fc3SMaciej Żenczykowski 
6423*1b481fc3SMaciej Żenczykowski 			argp += 2;
6424*1b481fc3SMaciej Żenczykowski 			argc -= 2;
6425*1b481fc3SMaciej Żenczykowski 			continue;
6426*1b481fc3SMaciej Żenczykowski 		}
6427*1b481fc3SMaciej Żenczykowski 		if (*argp && !strcmp(*argp, "--json")) {
6428*1b481fc3SMaciej Żenczykowski 			ctx.json = true;
6429*1b481fc3SMaciej Żenczykowski 			argp += 1;
6430*1b481fc3SMaciej Żenczykowski 			argc -= 1;
6431*1b481fc3SMaciej Żenczykowski 			continue;
6432*1b481fc3SMaciej Żenczykowski 		}
6433*1b481fc3SMaciej Żenczykowski 		if (*argp && (!strcmp(*argp, "--include-statistics") ||
6434*1b481fc3SMaciej Żenczykowski 			      !strcmp(*argp, "-I"))) {
6435*1b481fc3SMaciej Żenczykowski 			ctx.show_stats = true;
6436*1b481fc3SMaciej Żenczykowski 			argp += 1;
6437*1b481fc3SMaciej Żenczykowski 			argc -= 1;
6438*1b481fc3SMaciej Żenczykowski 			continue;
6439*1b481fc3SMaciej Żenczykowski 		}
6440*1b481fc3SMaciej Żenczykowski 		break;
6441*1b481fc3SMaciej Żenczykowski 	}
6442*1b481fc3SMaciej Żenczykowski 	if (*argp && !strcmp(*argp, "--monitor")) {
6443*1b481fc3SMaciej Żenczykowski 		ctx.argp = ++argp;
6444*1b481fc3SMaciej Żenczykowski 		ctx.argc = --argc;
6445*1b481fc3SMaciej Żenczykowski 		ret = nl_monitor(&ctx);
6446*1b481fc3SMaciej Żenczykowski 		return ret ? 1 : 0;
6447*1b481fc3SMaciej Żenczykowski 	}
6448*1b481fc3SMaciej Żenczykowski 
6449*1b481fc3SMaciej Żenczykowski 	/* First argument must be either a valid option or a device
6450*1b481fc3SMaciej Żenczykowski 	 * name to get settings for (which we don't expect to begin
6451*1b481fc3SMaciej Żenczykowski 	 * with '-').
6452*1b481fc3SMaciej Żenczykowski 	 */
6453*1b481fc3SMaciej Żenczykowski 	if (!*argp)
6454*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
6455*1b481fc3SMaciej Żenczykowski 
6456*1b481fc3SMaciej Żenczykowski 	k = find_option(*argp);
6457*1b481fc3SMaciej Żenczykowski 	if (k > 0) {
6458*1b481fc3SMaciej Żenczykowski 		argp++;
6459*1b481fc3SMaciej Żenczykowski 		argc--;
6460*1b481fc3SMaciej Żenczykowski 	} else {
6461*1b481fc3SMaciej Żenczykowski 		if ((*argp)[0] == '-')
6462*1b481fc3SMaciej Żenczykowski 			exit_bad_args();
6463*1b481fc3SMaciej Żenczykowski 		k = 0;
6464*1b481fc3SMaciej Żenczykowski 	}
6465*1b481fc3SMaciej Żenczykowski 
6466*1b481fc3SMaciej Żenczykowski 	if (!args[k].no_dev) {
6467*1b481fc3SMaciej Żenczykowski 		ctx.devname = *argp++;
6468*1b481fc3SMaciej Żenczykowski 		argc--;
6469*1b481fc3SMaciej Żenczykowski 
6470*1b481fc3SMaciej Żenczykowski 		if (!ctx.devname)
6471*1b481fc3SMaciej Żenczykowski 			exit_bad_args();
6472*1b481fc3SMaciej Żenczykowski 	}
6473*1b481fc3SMaciej Żenczykowski 	if (ctx.json && !args[k].json)
6474*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
6475*1b481fc3SMaciej Żenczykowski 	ctx.argc = argc;
6476*1b481fc3SMaciej Żenczykowski 	ctx.argp = argp;
6477*1b481fc3SMaciej Żenczykowski 	netlink_run_handler(&ctx, args[k].nlchk, args[k].nlfunc, !args[k].func);
6478*1b481fc3SMaciej Żenczykowski 
6479*1b481fc3SMaciej Żenczykowski 	if (ctx.json) /* no IOCTL command supports JSON output */
6480*1b481fc3SMaciej Żenczykowski 		exit_bad_args();
6481*1b481fc3SMaciej Żenczykowski 
6482*1b481fc3SMaciej Żenczykowski 	ret = ioctl_init(&ctx, args[k].no_dev);
6483*1b481fc3SMaciej Żenczykowski 	if (ret)
6484*1b481fc3SMaciej Żenczykowski 		return ret;
6485*1b481fc3SMaciej Żenczykowski 
6486*1b481fc3SMaciej Żenczykowski 	return args[k].func(&ctx);
6487*1b481fc3SMaciej Żenczykowski }
6488