blob: acf183dc55860eaa6f6e2034243ad71b2039e88d [file] [log] [blame]
Jeff Garzik32c80372005-10-25 01:56:48 -04001/*
2 * ethtool.c: Linux ethernet device configuration tool.
3 *
4 * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com)
5 * Portions Copyright 2001 Sun Microsystems
6 * Kernel 2.4 update Copyright 2001 Jeff Garzik <jgarzik@mandrakesoft.com>
7 * Wake-on-LAN,natsemi,misc support by Tim Hockin <thockin@sun.com>
8 * Portions Copyright 2002 Intel
Alexander Duyck8d63f722011-05-04 11:41:51 -07009 * Portions Copyright (C) Sun Microsystems 2008
Jeff Garzik32c80372005-10-25 01:56:48 -040010 * do_test support by Eli Kupermann <eli.kupermann@intel.com>
11 * ETHTOOL_PHYS_ID support by Chris Leech <christopher.leech@intel.com>
12 * e1000 support by Scott Feldman <scott.feldman@intel.com>
13 * e100 support by Wen Tao <wen-hwa.tao@intel.com>
Nicholas Nunleyfb522ac2006-09-19 11:27:35 -070014 * ixgb support by Nicholas Nunley <Nicholas.d.nunley@intel.com>
Jeff Garzik32c80372005-10-25 01:56:48 -040015 * amd8111e support by Reeja John <reeja.john@amd.com>
Andi Kleen527a5622005-06-13 21:06:47 +020016 * long arguments by Andi Kleen.
Steve Glendinninga5f8ce22007-07-16 20:04:40 +010017 * SMSC LAN911x support by Steve Glendinning <steve.glendinning@smsc.com>
Alexander Duyck8d63f722011-05-04 11:41:51 -070018 * Rx Network Flow Control configuration support <santwona.behera@sun.com>
Ben Hutchings65c37632010-09-23 22:50:12 +010019 * Various features by Ben Hutchings <bhutchings@solarflare.com>;
20 * Copyright 2009, 2010 Solarflare Communications
Jesse Brandeburg75e67912012-08-21 01:37:16 -070021 * MDI-X set support by Jesse Brandeburg <jesse.brandeburg@intel.com>
22 * Copyright 2012 Intel Corporation
Shrikrishna Khare009799a2015-09-23 15:19:12 -070023 * vmxnet3 support by Shrikrishna Khare <skhare@vmware.com>
Ben Hutchings5b9541d2016-06-26 17:27:22 +020024 * Various features by Ben Hutchings <ben@decadent.org.uk>;
25 * Copyright 2008-2010, 2013-2016 Ben Hutchings
Vidya Sagar Ravipati59a04672016-08-28 23:56:50 -070026 * QSFP+/QSFP28 DOM support by Vidya Sagar Ravipati <vidya@cumulusnetworks.com>
Jeff Garzik32c80372005-10-25 01:56:48 -040027 *
28 * TODO:
Ben Hutchingsf3393b22010-12-15 19:21:07 +000029 * * show settings for all devices
Jeff Garzik32c80372005-10-25 01:56:48 -040030 */
31
Ben Hutchings5ba70c02011-11-01 16:48:31 +000032#include "internal.h"
Jeff Garzik32c80372005-10-25 01:56:48 -040033#include <string.h>
34#include <stdlib.h>
Stephen Hemmingerfd3dc7b2006-10-23 10:57:03 -070035#include <sys/stat.h>
Jeff Garzik32c80372005-10-25 01:56:48 -040036#include <stdio.h>
Anirban Chakraborty95b924e2011-06-02 12:00:26 -070037#include <stddef.h>
Edward Creeb56b9512016-03-17 19:17:16 +000038#include <stdbool.h>
Jeff Garzik32c80372005-10-25 01:56:48 -040039#include <errno.h>
Jeff Garzika97a2ec2009-03-06 06:12:13 -050040#include <sys/utsname.h>
Jay Fenlason35f08082009-07-17 15:08:41 -040041#include <limits.h>
Ben Hutchings97d0ee22010-06-25 15:49:45 +010042#include <ctype.h>
Jeff Garzik32c80372005-10-25 01:56:48 -040043
Ben Hutchings58fad3a2010-07-22 20:11:39 +010044#include <sys/socket.h>
45#include <netinet/in.h>
46#include <arpa/inet.h>
47
Jeff Garzik32c80372005-10-25 01:56:48 -040048#include <linux/sockios.h>
David Decotigny225fdc62016-06-26 10:52:59 +020049#include <linux/netlink.h>
Jeff Garzik32c80372005-10-25 01:56:48 -040050
Stephen Hemmingerfef1c4a2010-11-16 19:14:33 +000051#ifndef MAX_ADDR_LEN
52#define MAX_ADDR_LEN 32
53#endif
Jeff Garzik32c80372005-10-25 01:56:48 -040054
Ben Hutchings97d0ee22010-06-25 15:49:45 +010055#ifndef HAVE_NETIF_MSG
56enum {
57 NETIF_MSG_DRV = 0x0001,
58 NETIF_MSG_PROBE = 0x0002,
59 NETIF_MSG_LINK = 0x0004,
60 NETIF_MSG_TIMER = 0x0008,
61 NETIF_MSG_IFDOWN = 0x0010,
62 NETIF_MSG_IFUP = 0x0020,
63 NETIF_MSG_RX_ERR = 0x0040,
64 NETIF_MSG_TX_ERR = 0x0080,
65 NETIF_MSG_TX_QUEUED = 0x0100,
66 NETIF_MSG_INTR = 0x0200,
67 NETIF_MSG_TX_DONE = 0x0400,
68 NETIF_MSG_RX_STATUS = 0x0800,
69 NETIF_MSG_PKTDATA = 0x1000,
70 NETIF_MSG_HW = 0x2000,
71 NETIF_MSG_WOL = 0x4000,
72};
73#endif
74
David Decotigny225fdc62016-06-26 10:52:59 +020075#ifndef NETLINK_GENERIC
76#define NETLINK_GENERIC 16
77#endif
78
Ben Hutchingsec0ff772013-09-19 22:12:46 +010079#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
80
Ben Hutchings97a8e6a2011-02-21 18:47:58 +000081static void exit_bad_args(void) __attribute__((noreturn));
Ben Hutchings24d71eb2010-06-25 15:48:46 +010082
Ben Hutchings97a8e6a2011-02-21 18:47:58 +000083static void exit_bad_args(void)
84{
85 fprintf(stderr,
86 "ethtool: bad command line argument(s)\n"
87 "For more information run ethtool -h\n");
88 exit(1);
89}
90
Jeff Garzik32c80372005-10-25 01:56:48 -040091typedef enum {
92 CMDL_NONE,
93 CMDL_BOOL,
Ben Hutchings18caa782010-06-25 15:46:58 +010094 CMDL_S32,
Ben Hutchingsbec03632011-06-06 11:35:19 +010095 CMDL_U8,
Ben Hutchings18caa782010-06-25 15:46:58 +010096 CMDL_U16,
97 CMDL_U32,
98 CMDL_U64,
99 CMDL_BE16,
Ben Hutchings58fad3a2010-07-22 20:11:39 +0100100 CMDL_IP4,
Stephen Hemmingerfd3dc7b2006-10-23 10:57:03 -0700101 CMDL_STR,
Ben Hutchings99a2b6b2010-06-25 15:49:19 +0100102 CMDL_FLAG,
Ben Hutchings9362cee2010-09-23 22:49:10 +0100103 CMDL_MAC,
Jeff Garzik32c80372005-10-25 01:56:48 -0400104} cmdline_type_t;
105
106struct cmdline_info {
107 const char *name;
108 cmdline_type_t type;
Ben Hutchings9362cee2010-09-23 22:49:10 +0100109 /* Points to int (BOOL), s32, u16, u32 (U32/FLAG/IP4), u64,
110 * char * (STR) or u8[6] (MAC). For FLAG, the value accumulates
111 * all flags to be set. */
Jeff Garzik32c80372005-10-25 01:56:48 -0400112 void *wanted_val;
113 void *ioctl_val;
Ben Hutchings99a2b6b2010-06-25 15:49:19 +0100114 /* For FLAG, the flag value to be set/cleared */
115 u32 flag_val;
Ben Hutchings967cb312010-09-23 22:48:14 +0100116 /* For FLAG, points to u32 and accumulates all flags seen.
117 * For anything else, points to int and is set if the option is
118 * seen. */
119 void *seen_val;
Jeff Garzik32c80372005-10-25 01:56:48 -0400120};
121
Ben Hutchings5ec0d812011-10-31 22:50:25 +0000122struct flag_info {
123 const char *name;
124 u32 value;
125};
126
Ben Hutchings5ec0d812011-10-31 22:50:25 +0000127static const struct flag_info flags_msglvl[] = {
128 { "drv", NETIF_MSG_DRV },
129 { "probe", NETIF_MSG_PROBE },
130 { "link", NETIF_MSG_LINK },
131 { "timer", NETIF_MSG_TIMER },
132 { "ifdown", NETIF_MSG_IFDOWN },
133 { "ifup", NETIF_MSG_IFUP },
134 { "rx_err", NETIF_MSG_RX_ERR },
135 { "tx_err", NETIF_MSG_TX_ERR },
136 { "tx_queued", NETIF_MSG_TX_QUEUED },
137 { "intr", NETIF_MSG_INTR },
138 { "tx_done", NETIF_MSG_TX_DONE },
139 { "rx_status", NETIF_MSG_RX_STATUS },
140 { "pktdata", NETIF_MSG_PKTDATA },
141 { "hw", NETIF_MSG_HW },
142 { "wol", NETIF_MSG_WOL },
Ben Hutchings97d0ee22010-06-25 15:49:45 +0100143};
144
Ben Hutchings60428042012-06-01 23:08:32 +0100145struct off_flag_def {
Ben Hutchingse5c984a2011-05-13 23:25:26 +0100146 const char *short_name;
147 const char *long_name;
Ben Hutchings60428042012-06-01 23:08:32 +0100148 const char *kernel_name;
Ben Hutchingse5c984a2011-05-13 23:25:26 +0100149 u32 get_cmd, set_cmd;
150 u32 value;
Ben Hutchingsec0ff772013-09-19 22:12:46 +0100151 /* For features exposed through ETHTOOL_GFLAGS, the oldest
152 * kernel version for which we can trust the result. Where
153 * the flag was added at the same time the kernel started
154 * supporting the feature, this is 0 (to allow for backports).
155 * Where the feature was supported before the flag was added,
156 * it is the version that introduced the flag.
157 */
158 u32 min_kernel_ver;
Ben Hutchings60428042012-06-01 23:08:32 +0100159};
160static const struct off_flag_def off_flag_def[] = {
161 { "rx", "rx-checksumming", "rx-checksum",
Ben Hutchingsec0ff772013-09-19 22:12:46 +0100162 ETHTOOL_GRXCSUM, ETHTOOL_SRXCSUM, ETH_FLAG_RXCSUM, 0 },
Ben Hutchings60428042012-06-01 23:08:32 +0100163 { "tx", "tx-checksumming", "tx-checksum-*",
Ben Hutchingsec0ff772013-09-19 22:12:46 +0100164 ETHTOOL_GTXCSUM, ETHTOOL_STXCSUM, ETH_FLAG_TXCSUM, 0 },
Ben Hutchings60428042012-06-01 23:08:32 +0100165 { "sg", "scatter-gather", "tx-scatter-gather*",
Ben Hutchingsec0ff772013-09-19 22:12:46 +0100166 ETHTOOL_GSG, ETHTOOL_SSG, ETH_FLAG_SG, 0 },
Ben Hutchings60428042012-06-01 23:08:32 +0100167 { "tso", "tcp-segmentation-offload", "tx-tcp*-segmentation",
Ben Hutchingsec0ff772013-09-19 22:12:46 +0100168 ETHTOOL_GTSO, ETHTOOL_STSO, ETH_FLAG_TSO, 0 },
Ben Hutchings60428042012-06-01 23:08:32 +0100169 { "ufo", "udp-fragmentation-offload", "tx-udp-fragmentation",
Ben Hutchingsec0ff772013-09-19 22:12:46 +0100170 ETHTOOL_GUFO, ETHTOOL_SUFO, ETH_FLAG_UFO, 0 },
Ben Hutchings60428042012-06-01 23:08:32 +0100171 { "gso", "generic-segmentation-offload", "tx-generic-segmentation",
Ben Hutchingsec0ff772013-09-19 22:12:46 +0100172 ETHTOOL_GGSO, ETHTOOL_SGSO, ETH_FLAG_GSO, 0 },
Ben Hutchings60428042012-06-01 23:08:32 +0100173 { "gro", "generic-receive-offload", "rx-gro",
Ben Hutchingsec0ff772013-09-19 22:12:46 +0100174 ETHTOOL_GGRO, ETHTOOL_SGRO, ETH_FLAG_GRO, 0 },
Ben Hutchings60428042012-06-01 23:08:32 +0100175 { "lro", "large-receive-offload", "rx-lro",
Ben Hutchingsec0ff772013-09-19 22:12:46 +0100176 0, 0, ETH_FLAG_LRO,
177 KERNEL_VERSION(2,6,24) },
Ben Hutchings60428042012-06-01 23:08:32 +0100178 { "rxvlan", "rx-vlan-offload", "rx-vlan-hw-parse",
Ben Hutchingsec0ff772013-09-19 22:12:46 +0100179 0, 0, ETH_FLAG_RXVLAN,
180 KERNEL_VERSION(2,6,37) },
Ben Hutchings60428042012-06-01 23:08:32 +0100181 { "txvlan", "tx-vlan-offload", "tx-vlan-hw-insert",
Ben Hutchingsec0ff772013-09-19 22:12:46 +0100182 0, 0, ETH_FLAG_TXVLAN,
183 KERNEL_VERSION(2,6,37) },
Ben Hutchings60428042012-06-01 23:08:32 +0100184 { "ntuple", "ntuple-filters", "rx-ntuple-filter",
Ben Hutchingsec0ff772013-09-19 22:12:46 +0100185 0, 0, ETH_FLAG_NTUPLE, 0 },
Ben Hutchings60428042012-06-01 23:08:32 +0100186 { "rxhash", "receive-hashing", "rx-hashing",
Ben Hutchingsec0ff772013-09-19 22:12:46 +0100187 0, 0, ETH_FLAG_RXHASH, 0 },
Ben Hutchingse5c984a2011-05-13 23:25:26 +0100188};
189
Ben Hutchings60428042012-06-01 23:08:32 +0100190struct feature_def {
191 char name[ETH_GSTRING_LEN];
192 int off_flag_index; /* index in off_flag_def; negative if none match */
193};
194
195struct feature_defs {
196 size_t n_features;
197 /* Number of features each offload flag is associated with */
198 unsigned int off_flag_matched[ARRAY_SIZE(off_flag_def)];
199 /* Name and offload flag index for each feature */
200 struct feature_def def[0];
201};
202
203#define FEATURE_BITS_TO_BLOCKS(n_bits) DIV_ROUND_UP(n_bits, 32U)
204#define FEATURE_WORD(blocks, index, field) ((blocks)[(index) / 32U].field)
205#define FEATURE_FIELD_FLAG(index) (1U << (index) % 32U)
206#define FEATURE_BIT_SET(blocks, index, field) \
207 (FEATURE_WORD(blocks, index, field) |= FEATURE_FIELD_FLAG(index))
208#define FEATURE_BIT_CLEAR(blocks, index, field) \
209 (FEATURE_WORD(blocks, index, filed) &= ~FEATURE_FIELD_FLAG(index))
210#define FEATURE_BIT_IS_SET(blocks, index, field) \
211 (FEATURE_WORD(blocks, index, field) & FEATURE_FIELD_FLAG(index))
212
Ben Hutchings18caa782010-06-25 15:46:58 +0100213static long long
214get_int_range(char *str, int base, long long min, long long max)
215{
216 long long v;
217 char *endp;
218
219 if (!str)
Ben Hutchings97a8e6a2011-02-21 18:47:58 +0000220 exit_bad_args();
Ben Hutchings18caa782010-06-25 15:46:58 +0100221 errno = 0;
222 v = strtoll(str, &endp, base);
223 if (errno || *endp || v < min || v > max)
Ben Hutchings97a8e6a2011-02-21 18:47:58 +0000224 exit_bad_args();
Ben Hutchings18caa782010-06-25 15:46:58 +0100225 return v;
226}
227
228static unsigned long long
229get_uint_range(char *str, int base, unsigned long long max)
230{
231 unsigned long long v;
232 char *endp;
233
234 if (!str)
Ben Hutchings97a8e6a2011-02-21 18:47:58 +0000235 exit_bad_args();
Ben Hutchings18caa782010-06-25 15:46:58 +0100236 errno = 0;
237 v = strtoull(str, &endp, base);
Gal Pressman5a20e542017-10-26 17:44:43 +0300238 if (errno || *endp || v > max)
Ben Hutchings97a8e6a2011-02-21 18:47:58 +0000239 exit_bad_args();
Ben Hutchings18caa782010-06-25 15:46:58 +0100240 return v;
241}
242
Jay Fenlason35f08082009-07-17 15:08:41 -0400243static int get_int(char *str, int base)
244{
Ben Hutchings18caa782010-06-25 15:46:58 +0100245 return get_int_range(str, base, INT_MIN, INT_MAX);
Jay Fenlason35f08082009-07-17 15:08:41 -0400246}
247
Ben Hutchings048038f2010-06-30 16:13:12 +0100248static u32 get_u32(char *str, int base)
249{
250 return get_uint_range(str, base, 0xffffffff);
251}
252
Ben Hutchings56b11482011-10-31 23:44:42 +0000253static void get_mac_addr(char *src, unsigned char *dest)
254{
255 int count;
256 int i;
257 int buf[ETH_ALEN];
258
259 count = sscanf(src, "%2x:%2x:%2x:%2x:%2x:%2x",
260 &buf[0], &buf[1], &buf[2], &buf[3], &buf[4], &buf[5]);
261 if (count != ETH_ALEN)
262 exit_bad_args();
263
Gal Pressman5a20e542017-10-26 17:44:43 +0300264 for (i = 0; i < count; i++)
Ben Hutchings56b11482011-10-31 23:44:42 +0000265 dest[i] = buf[i];
Ben Hutchings56b11482011-10-31 23:44:42 +0000266}
267
David Decotigny33133ab2016-03-25 09:21:01 -0700268static int parse_hex_u32_bitmap(const char *s,
269 unsigned int nbits, u32 *result)
270{
271 const unsigned int nwords = __KERNEL_DIV_ROUND_UP(nbits, 32);
272 size_t slen = strlen(s);
273 size_t i;
274
275 /* ignore optional '0x' prefix */
276 if ((slen > 2) && (strncasecmp(s, "0x", 2) == 0)) {
277 slen -= 2;
278 s += 2;
279 }
280
281 if (slen > 8 * nwords) /* up to 2 digits per byte */
282 return -1;
283
284 memset(result, 0, 4 * nwords);
285 for (i = 0; i < slen; ++i) {
286 const unsigned int shift = (slen - 1 - i) * 4;
287 u32 *dest = &result[shift / 32];
288 u32 nibble;
289
290 if ('a' <= s[i] && s[i] <= 'f')
291 nibble = 0xa + (s[i] - 'a');
292 else if ('A' <= s[i] && s[i] <= 'F')
293 nibble = 0xa + (s[i] - 'A');
294 else if ('0' <= s[i] && s[i] <= '9')
295 nibble = (s[i] - '0');
296 else
297 return -1;
298
299 *dest |= (nibble << (shift % 32));
300 }
301
302 return 0;
303}
304
Ben Hutchings127f8062011-10-29 01:15:34 +0100305static void parse_generic_cmdline(struct cmd_context *ctx,
306 int *changed,
Jeff Garzik32c80372005-10-25 01:56:48 -0400307 struct cmdline_info *info,
308 unsigned int n_info)
309{
Ben Hutchings127f8062011-10-29 01:15:34 +0100310 int argc = ctx->argc;
311 char **argp = ctx->argp;
Ben Hutchings18caa782010-06-25 15:46:58 +0100312 int i, idx;
Jay Fenlason35f08082009-07-17 15:08:41 -0400313 int found;
Jeff Garzik32c80372005-10-25 01:56:48 -0400314
Ben Hutchings127f8062011-10-29 01:15:34 +0100315 for (i = 0; i < argc; i++) {
Jay Fenlason35f08082009-07-17 15:08:41 -0400316 found = 0;
Jeff Garzik32c80372005-10-25 01:56:48 -0400317 for (idx = 0; idx < n_info; idx++) {
318 if (!strcmp(info[idx].name, argp[i])) {
Jay Fenlason35f08082009-07-17 15:08:41 -0400319 found = 1;
Jeff Garzik32c80372005-10-25 01:56:48 -0400320 *changed = 1;
Ben Hutchings967cb312010-09-23 22:48:14 +0100321 if (info[idx].type != CMDL_FLAG &&
322 info[idx].seen_val)
323 *(int *)info[idx].seen_val = 1;
Jeff Garzik32c80372005-10-25 01:56:48 -0400324 i += 1;
325 if (i >= argc)
Ben Hutchings97a8e6a2011-02-21 18:47:58 +0000326 exit_bad_args();
Stephen Hemmingerfd3dc7b2006-10-23 10:57:03 -0700327 switch (info[idx].type) {
Ben Hutchings18caa782010-06-25 15:46:58 +0100328 case CMDL_BOOL: {
329 int *p = info[idx].wanted_val;
Jeff Garzik32c80372005-10-25 01:56:48 -0400330 if (!strcmp(argp[i], "on"))
331 *p = 1;
332 else if (!strcmp(argp[i], "off"))
333 *p = 0;
334 else
Ben Hutchings97a8e6a2011-02-21 18:47:58 +0000335 exit_bad_args();
Stephen Hemmingerfd3dc7b2006-10-23 10:57:03 -0700336 break;
Ben Hutchings18caa782010-06-25 15:46:58 +0100337 }
338 case CMDL_S32: {
339 s32 *p = info[idx].wanted_val;
340 *p = get_int_range(argp[i], 0,
341 -0x80000000LL,
342 0x7fffffff);
Stephen Hemmingerfd3dc7b2006-10-23 10:57:03 -0700343 break;
344 }
Ben Hutchingsbec03632011-06-06 11:35:19 +0100345 case CMDL_U8: {
346 u8 *p = info[idx].wanted_val;
347 *p = get_uint_range(argp[i], 0, 0xff);
348 break;
349 }
Ben Hutchings18caa782010-06-25 15:46:58 +0100350 case CMDL_U16: {
351 u16 *p = info[idx].wanted_val;
352 *p = get_uint_range(argp[i], 0, 0xffff);
353 break;
354 }
355 case CMDL_U32: {
356 u32 *p = info[idx].wanted_val;
357 *p = get_uint_range(argp[i], 0,
358 0xffffffff);
359 break;
360 }
361 case CMDL_U64: {
362 u64 *p = info[idx].wanted_val;
363 *p = get_uint_range(
364 argp[i], 0,
365 0xffffffffffffffffLL);
366 break;
367 }
368 case CMDL_BE16: {
369 u16 *p = info[idx].wanted_val;
370 *p = cpu_to_be16(
371 get_uint_range(argp[i], 0,
372 0xffff));
373 break;
374 }
Ben Hutchings58fad3a2010-07-22 20:11:39 +0100375 case CMDL_IP4: {
Ben Hutchings18caa782010-06-25 15:46:58 +0100376 u32 *p = info[idx].wanted_val;
Ben Hutchings58fad3a2010-07-22 20:11:39 +0100377 struct in_addr in;
378 if (!inet_aton(argp[i], &in))
Ben Hutchings97a8e6a2011-02-21 18:47:58 +0000379 exit_bad_args();
Ben Hutchings58fad3a2010-07-22 20:11:39 +0100380 *p = in.s_addr;
PJ Waskiewicze2b05022009-12-23 23:22:08 -0800381 break;
382 }
Ben Hutchings9362cee2010-09-23 22:49:10 +0100383 case CMDL_MAC:
384 get_mac_addr(argp[i],
385 info[idx].wanted_val);
386 break;
Ben Hutchings99a2b6b2010-06-25 15:49:19 +0100387 case CMDL_FLAG: {
388 u32 *p;
Ben Hutchings967cb312010-09-23 22:48:14 +0100389 p = info[idx].seen_val;
Ben Hutchings99a2b6b2010-06-25 15:49:19 +0100390 *p |= info[idx].flag_val;
Ben Hutchings967cb312010-09-23 22:48:14 +0100391 if (!strcmp(argp[i], "on")) {
392 p = info[idx].wanted_val;
393 *p |= info[idx].flag_val;
394 } else if (strcmp(argp[i], "off")) {
Ben Hutchings97a8e6a2011-02-21 18:47:58 +0000395 exit_bad_args();
Ben Hutchings967cb312010-09-23 22:48:14 +0100396 }
Ben Hutchings99a2b6b2010-06-25 15:49:19 +0100397 break;
398 }
Stephen Hemmingerfd3dc7b2006-10-23 10:57:03 -0700399 case CMDL_STR: {
400 char **s = info[idx].wanted_val;
401 *s = strdup(argp[i]);
402 break;
403 }
404 default:
Ben Hutchings97a8e6a2011-02-21 18:47:58 +0000405 exit_bad_args();
Jeff Garzik32c80372005-10-25 01:56:48 -0400406 }
Jay Fenlason35f08082009-07-17 15:08:41 -0400407 break;
Jeff Garzik32c80372005-10-25 01:56:48 -0400408 }
409 }
Gal Pressman5a20e542017-10-26 17:44:43 +0300410 if (!found)
Ben Hutchings97a8e6a2011-02-21 18:47:58 +0000411 exit_bad_args();
Jeff Garzik32c80372005-10-25 01:56:48 -0400412 }
413}
414
Ben Hutchings5ec0d812011-10-31 22:50:25 +0000415static void flag_to_cmdline_info(const char *name, u32 value,
416 u32 *wanted, u32 *mask,
417 struct cmdline_info *cli)
418{
419 memset(cli, 0, sizeof(*cli));
420 cli->name = name;
421 cli->type = CMDL_FLAG;
422 cli->flag_val = value;
423 cli->wanted_val = wanted;
424 cli->seen_val = mask;
425}
426
Ben Hutchings99a2b6b2010-06-25 15:49:19 +0100427static void
Ben Hutchings5ec0d812011-10-31 22:50:25 +0000428print_flags(const struct flag_info *info, unsigned int n_info, u32 value)
Ben Hutchings99a2b6b2010-06-25 15:49:19 +0100429{
430 const char *sep = "";
431
432 while (n_info) {
Ben Hutchings5ec0d812011-10-31 22:50:25 +0000433 if (value & info->value) {
Ben Hutchings99a2b6b2010-06-25 15:49:19 +0100434 printf("%s%s", sep, info->name);
435 sep = " ";
Ben Hutchings5ec0d812011-10-31 22:50:25 +0000436 value &= ~info->value;
Ben Hutchings99a2b6b2010-06-25 15:49:19 +0100437 }
438 ++info;
439 --n_info;
440 }
441
442 /* Print any unrecognised flags in hex */
443 if (value)
444 printf("%s%#x", sep, value);
445}
446
Santwona Behera1bd87122008-06-27 17:06:20 -0700447static int rxflow_str_to_type(const char *str)
448{
449 int flow_type = 0;
450
451 if (!strcmp(str, "tcp4"))
452 flow_type = TCP_V4_FLOW;
453 else if (!strcmp(str, "udp4"))
454 flow_type = UDP_V4_FLOW;
Alexander Duyckb4001112011-04-21 13:40:20 -0700455 else if (!strcmp(str, "ah4") || !strcmp(str, "esp4"))
Santwona Behera1bd87122008-06-27 17:06:20 -0700456 flow_type = AH_ESP_V4_FLOW;
457 else if (!strcmp(str, "sctp4"))
458 flow_type = SCTP_V4_FLOW;
459 else if (!strcmp(str, "tcp6"))
460 flow_type = TCP_V6_FLOW;
461 else if (!strcmp(str, "udp6"))
462 flow_type = UDP_V6_FLOW;
Alexander Duyckb4001112011-04-21 13:40:20 -0700463 else if (!strcmp(str, "ah6") || !strcmp(str, "esp6"))
Santwona Behera1bd87122008-06-27 17:06:20 -0700464 flow_type = AH_ESP_V6_FLOW;
465 else if (!strcmp(str, "sctp6"))
466 flow_type = SCTP_V6_FLOW;
Ben Hutchingsf5286cd2010-09-23 22:49:43 +0100467 else if (!strcmp(str, "ether"))
468 flow_type = ETHER_FLOW;
Santwona Behera1bd87122008-06-27 17:06:20 -0700469
470 return flow_type;
471}
472
Maciej Żenczykowskid5432a92019-10-17 11:20:50 -0700473static int do_version(struct cmd_context *ctx maybe_unused)
Jeff Garzik32c80372005-10-25 01:56:48 -0400474{
Ben Hutchings127f8062011-10-29 01:15:34 +0100475 fprintf(stdout,
Florian Fainelli875616d2014-02-27 15:43:01 -0800476 PACKAGE " version " VERSION
477#ifndef ETHTOOL_ENABLE_PRETTY_DUMP
478 " (pretty dumps disabled)"
479#endif
480 "\n");
Ben Hutchings127f8062011-10-29 01:15:34 +0100481 return 0;
Jeff Garzik32c80372005-10-25 01:56:48 -0400482}
483
David Decotigny33133ab2016-03-25 09:21:01 -0700484/* link mode routines */
Ben Hutchingsd6c816b2011-06-01 23:27:17 +0100485
David Decotigny33133ab2016-03-25 09:21:01 -0700486static ETHTOOL_DECLARE_LINK_MODE_MASK(all_advertised_modes);
487static ETHTOOL_DECLARE_LINK_MODE_MASK(all_advertised_flags);
488
489static void init_global_link_mode_masks(void)
Jeff Garzik32c80372005-10-25 01:56:48 -0400490{
David Decotigny33133ab2016-03-25 09:21:01 -0700491 static const enum ethtool_link_mode_bit_indices
492 all_advertised_modes_bits[] = {
493 ETHTOOL_LINK_MODE_10baseT_Half_BIT,
494 ETHTOOL_LINK_MODE_10baseT_Full_BIT,
495 ETHTOOL_LINK_MODE_100baseT_Half_BIT,
496 ETHTOOL_LINK_MODE_100baseT_Full_BIT,
497 ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
498 ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
499 ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
500 ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
501 ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
502 ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
503 ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
504 ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
505 ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT,
506 ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT,
507 ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
508 ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
509 ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
510 ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
511 ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT,
512 ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT,
513 ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT,
514 ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT,
Vidya Sagar Ravipatiac2f96d2016-08-23 06:30:33 -0700515 ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
516 ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
517 ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
518 ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
519 ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
520 ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
521 ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
522 ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
523 ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
524 ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
Vidya Sagar Ravipati59a04672016-08-28 23:56:50 -0700525 ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
526 ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
527 ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
528 ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
529 ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
530 ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
Pavel Belous64dfc5e2017-01-30 20:03:30 +0300531 ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
532 ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
Aya Levincaa4bbe2019-02-25 17:44:34 +0200533 ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
534 ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
535 ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
536 ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
537 ETHTOOL_LINK_MODE_50000baseDR_Full_BIT,
538 ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
539 ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
540 ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
541 ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
542 ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT,
543 ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT,
544 ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT,
545 ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT,
546 ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT,
547 ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT,
Andrew Lunn2bce6d92019-05-31 15:57:48 +0200548 ETHTOOL_LINK_MODE_100baseT1_Full_BIT,
549 ETHTOOL_LINK_MODE_1000baseT1_Full_BIT,
David Decotigny33133ab2016-03-25 09:21:01 -0700550 };
551 static const enum ethtool_link_mode_bit_indices
552 additional_advertised_flags_bits[] = {
553 ETHTOOL_LINK_MODE_Autoneg_BIT,
554 ETHTOOL_LINK_MODE_TP_BIT,
555 ETHTOOL_LINK_MODE_AUI_BIT,
556 ETHTOOL_LINK_MODE_MII_BIT,
557 ETHTOOL_LINK_MODE_FIBRE_BIT,
558 ETHTOOL_LINK_MODE_BNC_BIT,
559 ETHTOOL_LINK_MODE_Pause_BIT,
560 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
561 ETHTOOL_LINK_MODE_Backplane_BIT,
Dustin Byford8db75d12017-12-18 14:57:41 -0800562 ETHTOOL_LINK_MODE_FEC_NONE_BIT,
563 ETHTOOL_LINK_MODE_FEC_RS_BIT,
564 ETHTOOL_LINK_MODE_FEC_BASER_BIT,
David Decotigny33133ab2016-03-25 09:21:01 -0700565 };
566 unsigned int i;
Jeff Garzik32c80372005-10-25 01:56:48 -0400567
David Decotigny33133ab2016-03-25 09:21:01 -0700568 ethtool_link_mode_zero(all_advertised_modes);
569 ethtool_link_mode_zero(all_advertised_flags);
570 for (i = 0; i < ARRAY_SIZE(all_advertised_modes_bits); ++i) {
571 ethtool_link_mode_set_bit(all_advertised_modes_bits[i],
572 all_advertised_modes);
573 ethtool_link_mode_set_bit(all_advertised_modes_bits[i],
574 all_advertised_flags);
575 }
576
577 for (i = 0; i < ARRAY_SIZE(additional_advertised_flags_bits); ++i) {
578 ethtool_link_mode_set_bit(
579 additional_advertised_flags_bits[i],
580 all_advertised_flags);
581 }
582}
583
584static void dump_link_caps(const char *prefix, const char *an_prefix,
585 const u32 *mask, int link_mode_only);
586
587static void dump_supported(const struct ethtool_link_usettings *link_usettings)
588{
Jeff Garzik32c80372005-10-25 01:56:48 -0400589 fprintf(stdout, " Supported ports: [ ");
David Decotigny33133ab2016-03-25 09:21:01 -0700590 if (ethtool_link_mode_test_bit(
591 ETHTOOL_LINK_MODE_TP_BIT,
592 link_usettings->link_modes.supported))
Jeff Garzik32c80372005-10-25 01:56:48 -0400593 fprintf(stdout, "TP ");
David Decotigny33133ab2016-03-25 09:21:01 -0700594 if (ethtool_link_mode_test_bit(
595 ETHTOOL_LINK_MODE_AUI_BIT,
596 link_usettings->link_modes.supported))
Jeff Garzik32c80372005-10-25 01:56:48 -0400597 fprintf(stdout, "AUI ");
David Decotigny33133ab2016-03-25 09:21:01 -0700598 if (ethtool_link_mode_test_bit(
599 ETHTOOL_LINK_MODE_BNC_BIT,
600 link_usettings->link_modes.supported))
Jeff Garzik32c80372005-10-25 01:56:48 -0400601 fprintf(stdout, "BNC ");
David Decotigny33133ab2016-03-25 09:21:01 -0700602 if (ethtool_link_mode_test_bit(
603 ETHTOOL_LINK_MODE_MII_BIT,
604 link_usettings->link_modes.supported))
Jeff Garzik32c80372005-10-25 01:56:48 -0400605 fprintf(stdout, "MII ");
David Decotigny33133ab2016-03-25 09:21:01 -0700606 if (ethtool_link_mode_test_bit(
607 ETHTOOL_LINK_MODE_FIBRE_BIT,
608 link_usettings->link_modes.supported))
Jeff Garzik32c80372005-10-25 01:56:48 -0400609 fprintf(stdout, "FIBRE ");
David Decotigny33133ab2016-03-25 09:21:01 -0700610 if (ethtool_link_mode_test_bit(
611 ETHTOOL_LINK_MODE_Backplane_BIT,
612 link_usettings->link_modes.supported))
Ivan Vecera6cb43222014-02-20 18:48:56 +0100613 fprintf(stdout, "Backplane ");
Jeff Garzik32c80372005-10-25 01:56:48 -0400614 fprintf(stdout, "]\n");
615
David Decotigny33133ab2016-03-25 09:21:01 -0700616 dump_link_caps("Supported", "Supports",
617 link_usettings->link_modes.supported, 0);
Jeff Garzik32c80372005-10-25 01:56:48 -0400618}
619
Ben Hutchingsd6c816b2011-06-01 23:27:17 +0100620/* Print link capability flags (supported, advertised or lp_advertised).
621 * Assumes that the corresponding SUPPORTED and ADVERTISED flags are equal.
622 */
David Decotigny33133ab2016-03-25 09:21:01 -0700623static void dump_link_caps(const char *prefix, const char *an_prefix,
624 const u32 *mask, int link_mode_only)
Jeff Garzik32c80372005-10-25 01:56:48 -0400625{
Ben Hutchings74c42802012-06-08 19:19:08 +0100626 static const struct {
627 int same_line; /* print on same line as previous */
David Decotigny33133ab2016-03-25 09:21:01 -0700628 unsigned int bit_index;
Ben Hutchings74c42802012-06-08 19:19:08 +0100629 const char *name;
630 } mode_defs[] = {
David Decotigny33133ab2016-03-25 09:21:01 -0700631 { 0, ETHTOOL_LINK_MODE_10baseT_Half_BIT,
632 "10baseT/Half" },
633 { 1, ETHTOOL_LINK_MODE_10baseT_Full_BIT,
634 "10baseT/Full" },
635 { 0, ETHTOOL_LINK_MODE_100baseT_Half_BIT,
636 "100baseT/Half" },
637 { 1, ETHTOOL_LINK_MODE_100baseT_Full_BIT,
638 "100baseT/Full" },
Andrew Lunn2bce6d92019-05-31 15:57:48 +0200639 { 0, ETHTOOL_LINK_MODE_100baseT1_Full_BIT,
640 "100baseT1/Full" },
David Decotigny33133ab2016-03-25 09:21:01 -0700641 { 0, ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
642 "1000baseT/Half" },
643 { 1, ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
644 "1000baseT/Full" },
Andrew Lunn2bce6d92019-05-31 15:57:48 +0200645 { 0, ETHTOOL_LINK_MODE_1000baseT1_Full_BIT,
646 "1000baseT1/Full" },
David Decotigny33133ab2016-03-25 09:21:01 -0700647 { 0, ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
648 "1000baseKX/Full" },
649 { 0, ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
650 "2500baseX/Full" },
651 { 0, ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
652 "10000baseT/Full" },
653 { 0, ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
654 "10000baseKX4/Full" },
655 { 0, ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
656 "10000baseKR/Full" },
Michal Kubecek085813b2019-02-27 14:49:04 +0100657 { 0, ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
658 "10000baseR_FEC" },
David Decotigny33133ab2016-03-25 09:21:01 -0700659 { 0, ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT,
660 "20000baseMLD2/Full" },
661 { 0, ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT,
662 "20000baseKR2/Full" },
663 { 0, ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
664 "40000baseKR4/Full" },
665 { 0, ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
666 "40000baseCR4/Full" },
667 { 0, ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
668 "40000baseSR4/Full" },
669 { 0, ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
670 "40000baseLR4/Full" },
671 { 0, ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT,
672 "56000baseKR4/Full" },
673 { 0, ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT,
674 "56000baseCR4/Full" },
675 { 0, ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT,
676 "56000baseSR4/Full" },
677 { 0, ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT,
678 "56000baseLR4/Full" },
Vidya Sagar Ravipatiac2f96d2016-08-23 06:30:33 -0700679 { 0, ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
680 "25000baseCR/Full" },
681 { 0, ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
682 "25000baseKR/Full" },
683 { 0, ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
684 "25000baseSR/Full" },
685 { 0, ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
686 "50000baseCR2/Full" },
687 { 0, ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
688 "50000baseKR2/Full" },
689 { 0, ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
690 "100000baseKR4/Full" },
691 { 0, ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
692 "100000baseSR4/Full" },
693 { 0, ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
694 "100000baseCR4/Full" },
695 { 0, ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
696 "100000baseLR4_ER4/Full" },
697 { 0, ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
698 "50000baseSR2/Full" },
Vidya Sagar Ravipati59a04672016-08-28 23:56:50 -0700699 { 0, ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
700 "1000baseX/Full" },
701 { 0, ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
702 "10000baseCR/Full" },
703 { 0, ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
704 "10000baseSR/Full" },
705 { 0, ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
706 "10000baseLR/Full" },
707 { 0, ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
708 "10000baseLRM/Full" },
709 { 0, ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
710 "10000baseER/Full" },
Gal Pressman5a20e542017-10-26 17:44:43 +0300711 { 0, ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
712 "2500baseT/Full" },
713 { 0, ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
714 "5000baseT/Full" },
Aya Levincaa4bbe2019-02-25 17:44:34 +0200715 { 0, ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
716 "50000baseKR/Full" },
717 { 0, ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
718 "50000baseSR/Full" },
719 { 0, ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
720 "50000baseCR/Full" },
721 { 0, ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
722 "50000baseLR_ER_FR/Full" },
723 { 0, ETHTOOL_LINK_MODE_50000baseDR_Full_BIT,
724 "50000baseDR/Full" },
725 { 0, ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
726 "100000baseKR2/Full" },
727 { 0, ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
728 "100000baseSR2/Full" },
729 { 0, ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
730 "100000baseCR2/Full" },
731 { 0, ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
732 "100000baseLR2_ER2_FR2/Full" },
733 { 0, ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT,
734 "100000baseDR2/Full" },
735 { 0, ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT,
736 "200000baseKR4/Full" },
737 { 0, ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT,
738 "200000baseSR4/Full" },
739 { 0, ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT,
740 "200000baseLR4_ER4_FR4/Full" },
741 { 0, ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT,
742 "200000baseDR4/Full" },
743 { 0, ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT,
744 "200000baseCR4/Full" },
Ben Hutchings74c42802012-06-08 19:19:08 +0100745 };
Ben Hutchingsd6c816b2011-06-01 23:27:17 +0100746 int indent;
Ben Hutchings74c42802012-06-08 19:19:08 +0100747 int did1, new_line_pend, i;
Dustin Byford8db75d12017-12-18 14:57:41 -0800748 int fecreported = 0;
Jeff Garzik32c80372005-10-25 01:56:48 -0400749
Ben Hutchingsd6c816b2011-06-01 23:27:17 +0100750 /* Indent just like the separate functions used to */
751 indent = strlen(prefix) + 14;
752 if (indent < 24)
753 indent = 24;
754
755 fprintf(stdout, " %s link modes:%*s", prefix,
Ben Hutchings42928202011-06-02 20:20:12 +0100756 indent - (int)strlen(prefix) - 12, "");
Jeff Garzik32c80372005-10-25 01:56:48 -0400757 did1 = 0;
Ben Hutchings74c42802012-06-08 19:19:08 +0100758 new_line_pend = 0;
759 for (i = 0; i < ARRAY_SIZE(mode_defs); i++) {
760 if (did1 && !mode_defs[i].same_line)
761 new_line_pend = 1;
David Decotigny33133ab2016-03-25 09:21:01 -0700762 if (ethtool_link_mode_test_bit(mode_defs[i].bit_index,
763 mask)) {
Ben Hutchings74c42802012-06-08 19:19:08 +0100764 if (new_line_pend) {
765 fprintf(stdout, "\n");
766 fprintf(stdout, " %*s", indent, "");
767 new_line_pend = 0;
768 }
769 did1++;
770 fprintf(stdout, "%s ", mode_defs[i].name);
771 }
Yaniv Rosner42a76be2011-06-05 20:39:43 +0300772 }
Jeff Garzik32c80372005-10-25 01:56:48 -0400773 if (did1 == 0)
Gal Pressman5a20e542017-10-26 17:44:43 +0300774 fprintf(stdout, "Not reported");
Jeff Garzik32c80372005-10-25 01:56:48 -0400775 fprintf(stdout, "\n");
776
Yuval Mintza9fc8272012-06-10 11:48:08 +0300777 if (!link_mode_only) {
778 fprintf(stdout, " %s pause frame use: ", prefix);
David Decotigny33133ab2016-03-25 09:21:01 -0700779 if (ethtool_link_mode_test_bit(
780 ETHTOOL_LINK_MODE_Pause_BIT, mask)) {
Yuval Mintza9fc8272012-06-10 11:48:08 +0300781 fprintf(stdout, "Symmetric");
David Decotigny33133ab2016-03-25 09:21:01 -0700782 if (ethtool_link_mode_test_bit(
783 ETHTOOL_LINK_MODE_Asym_Pause_BIT, mask))
Yuval Mintza9fc8272012-06-10 11:48:08 +0300784 fprintf(stdout, " Receive-only");
785 fprintf(stdout, "\n");
786 } else {
David Decotigny33133ab2016-03-25 09:21:01 -0700787 if (ethtool_link_mode_test_bit(
788 ETHTOOL_LINK_MODE_Asym_Pause_BIT, mask))
Yuval Mintza9fc8272012-06-10 11:48:08 +0300789 fprintf(stdout, "Transmit-only\n");
790 else
791 fprintf(stdout, "No\n");
792 }
793
794 fprintf(stdout, " %s auto-negotiation: ", an_prefix);
David Decotigny33133ab2016-03-25 09:21:01 -0700795 if (ethtool_link_mode_test_bit(
796 ETHTOOL_LINK_MODE_Autoneg_BIT, mask))
Yuval Mintza9fc8272012-06-10 11:48:08 +0300797 fprintf(stdout, "Yes\n");
Ben Hutchings0bae9242009-04-30 13:38:06 +0100798 else
799 fprintf(stdout, "No\n");
Dustin Byford8db75d12017-12-18 14:57:41 -0800800
801 fprintf(stdout, " %s FEC modes:", prefix);
802 if (ethtool_link_mode_test_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT,
803 mask)) {
804 fprintf(stdout, " None");
805 fecreported = 1;
806 }
807 if (ethtool_link_mode_test_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT,
808 mask)) {
809 fprintf(stdout, " BaseR");
810 fecreported = 1;
811 }
812 if (ethtool_link_mode_test_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT,
813 mask)) {
814 fprintf(stdout, " RS");
815 fecreported = 1;
816 }
817 if (!fecreported)
818 fprintf(stdout, " Not reported");
819 fprintf(stdout, "\n");
Ben Hutchings0bae9242009-04-30 13:38:06 +0100820 }
Jeff Garzik32c80372005-10-25 01:56:48 -0400821}
822
David Decotigny33133ab2016-03-25 09:21:01 -0700823static int
824dump_link_usettings(const struct ethtool_link_usettings *link_usettings)
Jeff Garzik32c80372005-10-25 01:56:48 -0400825{
David Decotigny33133ab2016-03-25 09:21:01 -0700826 dump_supported(link_usettings);
827 dump_link_caps("Advertised", "Advertised",
828 link_usettings->link_modes.advertising, 0);
829 if (!ethtool_link_mode_is_empty(
830 link_usettings->link_modes.lp_advertising))
Ben Hutchingsd6c816b2011-06-01 23:27:17 +0100831 dump_link_caps("Link partner advertised",
David Decotigny33133ab2016-03-25 09:21:01 -0700832 "Link partner advertised",
833 link_usettings->link_modes.lp_advertising, 0);
Jeff Garzik32c80372005-10-25 01:56:48 -0400834
835 fprintf(stdout, " Speed: ");
David Decotigny33133ab2016-03-25 09:21:01 -0700836 if (link_usettings->base.speed == 0
837 || link_usettings->base.speed == (u16)(-1)
838 || link_usettings->base.speed == (u32)(-1))
Ben Hutchings580cc502009-01-09 13:16:14 +0000839 fprintf(stdout, "Unknown!\n");
840 else
David Decotigny33133ab2016-03-25 09:21:01 -0700841 fprintf(stdout, "%uMb/s\n", link_usettings->base.speed);
Jeff Garzik32c80372005-10-25 01:56:48 -0400842
843 fprintf(stdout, " Duplex: ");
David Decotigny33133ab2016-03-25 09:21:01 -0700844 switch (link_usettings->base.duplex) {
Jeff Garzik32c80372005-10-25 01:56:48 -0400845 case DUPLEX_HALF:
846 fprintf(stdout, "Half\n");
847 break;
848 case DUPLEX_FULL:
849 fprintf(stdout, "Full\n");
850 break;
851 default:
David Decotigny33133ab2016-03-25 09:21:01 -0700852 fprintf(stdout, "Unknown! (%i)\n", link_usettings->base.duplex);
Jeff Garzik32c80372005-10-25 01:56:48 -0400853 break;
854 };
855
856 fprintf(stdout, " Port: ");
David Decotigny33133ab2016-03-25 09:21:01 -0700857 switch (link_usettings->base.port) {
Jeff Garzik32c80372005-10-25 01:56:48 -0400858 case PORT_TP:
859 fprintf(stdout, "Twisted Pair\n");
860 break;
861 case PORT_AUI:
862 fprintf(stdout, "AUI\n");
863 break;
864 case PORT_BNC:
865 fprintf(stdout, "BNC\n");
866 break;
867 case PORT_MII:
868 fprintf(stdout, "MII\n");
869 break;
870 case PORT_FIBRE:
871 fprintf(stdout, "FIBRE\n");
872 break;
Ben Hutchingsf58f2642009-12-01 16:06:55 +0000873 case PORT_DA:
874 fprintf(stdout, "Direct Attach Copper\n");
875 break;
876 case PORT_NONE:
877 fprintf(stdout, "None\n");
878 break;
Ben Hutchings6a8940f2009-04-30 13:37:14 +0100879 case PORT_OTHER:
880 fprintf(stdout, "Other\n");
881 break;
Jeff Garzik32c80372005-10-25 01:56:48 -0400882 default:
David Decotigny33133ab2016-03-25 09:21:01 -0700883 fprintf(stdout, "Unknown! (%i)\n", link_usettings->base.port);
Jeff Garzik32c80372005-10-25 01:56:48 -0400884 break;
885 };
886
David Decotigny33133ab2016-03-25 09:21:01 -0700887 fprintf(stdout, " PHYAD: %d\n", link_usettings->base.phy_address);
Jeff Garzik32c80372005-10-25 01:56:48 -0400888 fprintf(stdout, " Transceiver: ");
David Decotigny33133ab2016-03-25 09:21:01 -0700889 switch (link_usettings->deprecated.transceiver) {
Jeff Garzik32c80372005-10-25 01:56:48 -0400890 case XCVR_INTERNAL:
891 fprintf(stdout, "internal\n");
892 break;
893 case XCVR_EXTERNAL:
894 fprintf(stdout, "external\n");
895 break;
896 default:
897 fprintf(stdout, "Unknown!\n");
898 break;
899 };
900
901 fprintf(stdout, " Auto-negotiation: %s\n",
David Decotigny33133ab2016-03-25 09:21:01 -0700902 (link_usettings->base.autoneg == AUTONEG_DISABLE) ?
Jeff Garzik32c80372005-10-25 01:56:48 -0400903 "off" : "on");
Ben Hutchingsda7d16a2009-12-01 16:00:30 +0000904
David Decotigny33133ab2016-03-25 09:21:01 -0700905 if (link_usettings->base.port == PORT_TP) {
Ben Hutchingsda7d16a2009-12-01 16:00:30 +0000906 fprintf(stdout, " MDI-X: ");
David Decotigny33133ab2016-03-25 09:21:01 -0700907 if (link_usettings->base.eth_tp_mdix_ctrl == ETH_TP_MDI) {
Jesse Brandeburg75e67912012-08-21 01:37:16 -0700908 fprintf(stdout, "off (forced)\n");
David Decotigny33133ab2016-03-25 09:21:01 -0700909 } else if (link_usettings->base.eth_tp_mdix_ctrl
910 == ETH_TP_MDI_X) {
Jesse Brandeburg75e67912012-08-21 01:37:16 -0700911 fprintf(stdout, "on (forced)\n");
912 } else {
David Decotigny33133ab2016-03-25 09:21:01 -0700913 switch (link_usettings->base.eth_tp_mdix) {
Jesse Brandeburg75e67912012-08-21 01:37:16 -0700914 case ETH_TP_MDI:
915 fprintf(stdout, "off");
916 break;
917 case ETH_TP_MDI_X:
918 fprintf(stdout, "on");
919 break;
920 default:
921 fprintf(stdout, "Unknown");
922 break;
923 }
David Decotigny33133ab2016-03-25 09:21:01 -0700924 if (link_usettings->base.eth_tp_mdix_ctrl
925 == ETH_TP_MDI_AUTO)
Jesse Brandeburg75e67912012-08-21 01:37:16 -0700926 fprintf(stdout, " (auto)");
927 fprintf(stdout, "\n");
Ben Hutchingsda7d16a2009-12-01 16:00:30 +0000928 }
929 }
930
Jeff Garzik32c80372005-10-25 01:56:48 -0400931 return 0;
932}
933
934static int dump_drvinfo(struct ethtool_drvinfo *info)
935{
936 fprintf(stdout,
Ben Hutchingsa983fb72012-06-14 20:34:35 +0100937 "driver: %.*s\n"
938 "version: %.*s\n"
939 "firmware-version: %.*s\n"
Hariprasad Shenaicc1b6872015-02-09 12:07:31 +0530940 "expansion-rom-version: %.*s\n"
Ben Hutchingsa983fb72012-06-14 20:34:35 +0100941 "bus-info: %.*s\n"
Ben Hutchingsc5bcaca2011-03-18 22:35:44 +0000942 "supports-statistics: %s\n"
943 "supports-test: %s\n"
944 "supports-eeprom-access: %s\n"
Ben Hutchingse1ee5962011-11-30 02:29:21 +0000945 "supports-register-dump: %s\n"
946 "supports-priv-flags: %s\n",
Ben Hutchingsa983fb72012-06-14 20:34:35 +0100947 (int)sizeof(info->driver), info->driver,
948 (int)sizeof(info->version), info->version,
949 (int)sizeof(info->fw_version), info->fw_version,
Hariprasad Shenaicc1b6872015-02-09 12:07:31 +0530950 (int)sizeof(info->erom_version), info->erom_version,
Ben Hutchingsa983fb72012-06-14 20:34:35 +0100951 (int)sizeof(info->bus_info), info->bus_info,
Ben Hutchingsc5bcaca2011-03-18 22:35:44 +0000952 info->n_stats ? "yes" : "no",
953 info->testinfo_len ? "yes" : "no",
954 info->eedump_len ? "yes" : "no",
Ben Hutchingse1ee5962011-11-30 02:29:21 +0000955 info->regdump_len ? "yes" : "no",
956 info->n_priv_flags ? "yes" : "no");
Jeff Garzik32c80372005-10-25 01:56:48 -0400957
958 return 0;
959}
960
Jeff Garzika4f48f02005-10-25 02:06:01 -0400961static int parse_wolopts(char *optstr, u32 *data)
Jeff Garzik32c80372005-10-25 01:56:48 -0400962{
963 *data = 0;
964 while (*optstr) {
965 switch (*optstr) {
Gal Pressman5a20e542017-10-26 17:44:43 +0300966 case 'p':
967 *data |= WAKE_PHY;
968 break;
969 case 'u':
970 *data |= WAKE_UCAST;
971 break;
972 case 'm':
973 *data |= WAKE_MCAST;
974 break;
975 case 'b':
976 *data |= WAKE_BCAST;
977 break;
978 case 'a':
979 *data |= WAKE_ARP;
980 break;
981 case 'g':
982 *data |= WAKE_MAGIC;
983 break;
984 case 's':
985 *data |= WAKE_MAGICSECURE;
986 break;
Florian Fainellieff0bb32018-08-09 11:04:01 -0700987 case 'f':
988 *data |= WAKE_FILTER;
989 break;
Gal Pressman5a20e542017-10-26 17:44:43 +0300990 case 'd':
991 *data = 0;
992 break;
993 default:
994 return -1;
Jeff Garzik32c80372005-10-25 01:56:48 -0400995 }
996 optstr++;
997 }
998 return 0;
999}
1000
1001static char *unparse_wolopts(int wolopts)
1002{
1003 static char buf[16];
1004 char *p = buf;
1005
1006 memset(buf, 0, sizeof(buf));
1007
1008 if (wolopts) {
1009 if (wolopts & WAKE_PHY)
1010 *p++ = 'p';
1011 if (wolopts & WAKE_UCAST)
1012 *p++ = 'u';
1013 if (wolopts & WAKE_MCAST)
1014 *p++ = 'm';
1015 if (wolopts & WAKE_BCAST)
1016 *p++ = 'b';
1017 if (wolopts & WAKE_ARP)
1018 *p++ = 'a';
1019 if (wolopts & WAKE_MAGIC)
1020 *p++ = 'g';
1021 if (wolopts & WAKE_MAGICSECURE)
1022 *p++ = 's';
Florian Fainellieff0bb32018-08-09 11:04:01 -07001023 if (wolopts & WAKE_FILTER)
1024 *p++ = 'f';
Jeff Garzik32c80372005-10-25 01:56:48 -04001025 } else {
1026 *p = 'd';
1027 }
1028
1029 return buf;
1030}
1031
Ben Hutchings56b11482011-10-31 23:44:42 +00001032static int dump_wol(struct ethtool_wolinfo *wol)
Jeff Garzik32c80372005-10-25 01:56:48 -04001033{
Ben Hutchings56b11482011-10-31 23:44:42 +00001034 fprintf(stdout, " Supports Wake-on: %s\n",
1035 unparse_wolopts(wol->supported));
1036 fprintf(stdout, " Wake-on: %s\n",
1037 unparse_wolopts(wol->wolopts));
1038 if (wol->supported & WAKE_MAGICSECURE) {
1039 int i;
1040 int delim = 0;
Gal Pressman5a20e542017-10-26 17:44:43 +03001041
Ben Hutchings56b11482011-10-31 23:44:42 +00001042 fprintf(stdout, " SecureOn password: ");
1043 for (i = 0; i < SOPASS_MAX; i++) {
1044 fprintf(stdout, "%s%02x", delim?":":"", wol->sopass[i]);
Gal Pressman5a20e542017-10-26 17:44:43 +03001045 delim = 1;
Ben Hutchings56b11482011-10-31 23:44:42 +00001046 }
1047 fprintf(stdout, "\n");
Jeff Garzik32c80372005-10-25 01:56:48 -04001048 }
Ben Hutchings56b11482011-10-31 23:44:42 +00001049
1050 return 0;
Jeff Garzik32c80372005-10-25 01:56:48 -04001051}
1052
Santwona Behera1bd87122008-06-27 17:06:20 -07001053static int parse_rxfhashopts(char *optstr, u32 *data)
1054{
1055 *data = 0;
1056 while (*optstr) {
1057 switch (*optstr) {
Gal Pressman5a20e542017-10-26 17:44:43 +03001058 case 'm':
1059 *data |= RXH_L2DA;
1060 break;
1061 case 'v':
1062 *data |= RXH_VLAN;
1063 break;
1064 case 't':
1065 *data |= RXH_L3_PROTO;
1066 break;
1067 case 's':
1068 *data |= RXH_IP_SRC;
1069 break;
1070 case 'd':
1071 *data |= RXH_IP_DST;
1072 break;
1073 case 'f':
1074 *data |= RXH_L4_B_0_1;
1075 break;
1076 case 'n':
1077 *data |= RXH_L4_B_2_3;
1078 break;
1079 case 'r':
1080 *data |= RXH_DISCARD;
1081 break;
1082 default:
1083 return -1;
Santwona Behera1bd87122008-06-27 17:06:20 -07001084 }
1085 optstr++;
1086 }
1087 return 0;
1088}
1089
1090static char *unparse_rxfhashopts(u64 opts)
1091{
1092 static char buf[300];
1093
1094 memset(buf, 0, sizeof(buf));
1095
1096 if (opts) {
Gal Pressman5a20e542017-10-26 17:44:43 +03001097 if (opts & RXH_L2DA)
Santwona Behera1bd87122008-06-27 17:06:20 -07001098 strcat(buf, "L2DA\n");
Gal Pressman5a20e542017-10-26 17:44:43 +03001099 if (opts & RXH_VLAN)
Santwona Behera1bd87122008-06-27 17:06:20 -07001100 strcat(buf, "VLAN tag\n");
Gal Pressman5a20e542017-10-26 17:44:43 +03001101 if (opts & RXH_L3_PROTO)
Santwona Behera1bd87122008-06-27 17:06:20 -07001102 strcat(buf, "L3 proto\n");
Gal Pressman5a20e542017-10-26 17:44:43 +03001103 if (opts & RXH_IP_SRC)
Santwona Behera1bd87122008-06-27 17:06:20 -07001104 strcat(buf, "IP SA\n");
Gal Pressman5a20e542017-10-26 17:44:43 +03001105 if (opts & RXH_IP_DST)
Santwona Behera1bd87122008-06-27 17:06:20 -07001106 strcat(buf, "IP DA\n");
Gal Pressman5a20e542017-10-26 17:44:43 +03001107 if (opts & RXH_L4_B_0_1)
Santwona Behera1bd87122008-06-27 17:06:20 -07001108 strcat(buf, "L4 bytes 0 & 1 [TCP/UDP src port]\n");
Gal Pressman5a20e542017-10-26 17:44:43 +03001109 if (opts & RXH_L4_B_2_3)
Santwona Behera1bd87122008-06-27 17:06:20 -07001110 strcat(buf, "L4 bytes 2 & 3 [TCP/UDP dst port]\n");
Santwona Behera1bd87122008-06-27 17:06:20 -07001111 } else {
1112 sprintf(buf, "None");
1113 }
1114
1115 return buf;
1116}
1117
Venkat Duvvuru86c03262014-07-22 17:51:07 +05301118static int convert_string_to_hashkey(char *rss_hkey, u32 key_size,
1119 const char *rss_hkey_string)
1120{
1121 u32 i = 0;
1122 int hex_byte, len;
1123
1124 do {
1125 if (i > (key_size - 1)) {
1126 fprintf(stderr,
1127 "Key is too long for device (%u > %u)\n",
1128 i + 1, key_size);
1129 goto err;
1130 }
1131
1132 if (sscanf(rss_hkey_string, "%2x%n", &hex_byte, &len) < 1 ||
1133 len != 2) {
1134 fprintf(stderr, "Invalid RSS hash key format\n");
1135 goto err;
1136 }
1137
1138 rss_hkey[i++] = hex_byte;
1139 rss_hkey_string += 2;
1140
1141 if (*rss_hkey_string == ':') {
1142 rss_hkey_string++;
1143 } else if (*rss_hkey_string != '\0') {
1144 fprintf(stderr, "Invalid RSS hash key format\n");
1145 goto err;
1146 }
1147
1148 } while (*rss_hkey_string);
1149
1150 if (i != key_size) {
1151 fprintf(stderr, "Key is too short for device (%u < %u)\n",
1152 i, key_size);
1153 goto err;
1154 }
1155
1156 return 0;
1157err:
1158 return 2;
1159}
1160
1161static int parse_hkey(char **rss_hkey, u32 key_size,
1162 const char *rss_hkey_string)
1163{
1164 if (!key_size) {
1165 fprintf(stderr,
1166 "Cannot set RX flow hash configuration:\n"
1167 " Hash key setting not supported\n");
1168 return 1;
1169 }
1170
1171 *rss_hkey = malloc(key_size);
1172 if (!(*rss_hkey)) {
1173 perror("Cannot allocate memory for RSS hash key");
1174 return 1;
1175 }
1176
1177 if (convert_string_to_hashkey(*rss_hkey, key_size,
1178 rss_hkey_string)) {
1179 free(*rss_hkey);
1180 *rss_hkey = NULL;
1181 return 2;
1182 }
1183 return 0;
1184}
1185
Ben Hutchings02af8c22011-10-31 23:06:52 +00001186static const struct {
Jeff Garzik32c80372005-10-25 01:56:48 -04001187 const char *name;
1188 int (*func)(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
1189
1190} driver_list[] = {
Florian Fainelli875616d2014-02-27 15:43:01 -08001191#ifdef ETHTOOL_ENABLE_PRETTY_DUMP
Jeff Garzik32c80372005-10-25 01:56:48 -04001192 { "8139cp", realtek_dump_regs },
1193 { "8139too", realtek_dump_regs },
1194 { "r8169", realtek_dump_regs },
1195 { "de2104x", de2104x_dump_regs },
1196 { "e1000", e1000_dump_regs },
Auke Koke52c3a02007-10-04 11:37:31 -07001197 { "e1000e", e1000_dump_regs },
Nicholas Nunleyae5505e2007-08-15 10:44:01 -07001198 { "igb", igb_dump_regs },
Nicholas Nunleyfb522ac2006-09-19 11:27:35 -07001199 { "ixgb", ixgb_dump_regs },
Nicholas Nunley4b448ec2007-08-15 10:44:11 -07001200 { "ixgbe", ixgbe_dump_regs },
Jacob Keller5c271a22013-08-27 17:08:49 -07001201 { "ixgbevf", ixgbevf_dump_regs },
Jeff Garzik32c80372005-10-25 01:56:48 -04001202 { "natsemi", natsemi_dump_regs },
1203 { "e100", e100_dump_regs },
1204 { "amd8111e", amd8111e_dump_regs },
1205 { "pcnet32", pcnet32_dump_regs },
1206 { "fec_8xx", fec_8xx_dump_regs },
Eugene Surovegina69768a2005-10-25 02:29:27 -04001207 { "ibm_emac", ibm_emac_dump_regs },
Michael Chan14004d12005-11-08 12:24:23 -08001208 { "tg3", tg3_dump_regs },
Stephen Hemminger8f3b48b2006-08-23 14:16:09 -07001209 { "skge", skge_dump_regs },
Stephen Hemmingerad702592006-09-26 13:09:14 -07001210 { "sky2", sky2_dump_regs },
Gal Pressman5a20e542017-10-26 17:44:43 +03001211 { "vioc", vioc_dump_regs },
1212 { "smsc911x", smsc911x_dump_regs },
1213 { "at76c50x-usb", at76c50x_usb_dump_regs },
1214 { "sfc", sfc_dump_regs },
Giuseppe CAVALLARO02ea0ac2010-10-13 10:52:25 +02001215 { "st_mac100", st_mac100_dump_regs },
1216 { "st_gmac", st_gmac_dump_regs },
Mark Einon08f7d492012-10-30 21:57:23 +00001217 { "et131x", et131x_dump_regs },
Vince Bridgers0bbd4f52014-06-22 19:16:59 -05001218 { "altera_tse", altera_tse_dump_regs },
Shrikrishna Khare009799a2015-09-23 15:19:12 -07001219 { "vmxnet3", vmxnet3_dump_regs },
Taku Izumiacc3d3a2016-11-16 09:55:32 +09001220 { "fjes", fjes_dump_regs },
Raghuram Chary Jbf668742018-04-05 11:41:28 +05301221 { "lan78xx", lan78xx_dump_regs },
Vivien Didelotcb8e9802018-12-18 14:06:35 -05001222 { "dsa", dsa_dump_regs },
Vivien Didelot8612d8b2019-02-14 11:15:36 -05001223 { "fec", fec_dump_regs },
Florian Fainelli875616d2014-02-27 15:43:01 -08001224#endif
Jeff Garzik32c80372005-10-25 01:56:48 -04001225};
1226
Ben Hutchings2038e9e2012-02-17 21:30:06 +00001227void dump_hex(FILE *file, const u8 *data, int len, int offset)
Stuart Hodgson0d53f252012-05-18 15:58:24 +01001228{
1229 int i;
1230
Ben Hutchings2038e9e2012-02-17 21:30:06 +00001231 fprintf(file, "Offset\t\tValues\n");
1232 fprintf(file, "------\t\t------");
Stuart Hodgson0d53f252012-05-18 15:58:24 +01001233 for (i = 0; i < len; i++) {
1234 if (i % 16 == 0)
Ben Hutchings2038e9e2012-02-17 21:30:06 +00001235 fprintf(file, "\n0x%04x:\t\t", i + offset);
1236 fprintf(file, "%02x ", data[i]);
Stuart Hodgson0d53f252012-05-18 15:58:24 +01001237 }
Ben Hutchings2038e9e2012-02-17 21:30:06 +00001238 fprintf(file, "\n");
Stuart Hodgson0d53f252012-05-18 15:58:24 +01001239}
1240
Ben Hutchings52adc492011-10-31 22:28:20 +00001241static int dump_regs(int gregs_dump_raw, int gregs_dump_hex,
Ben Hutchings52adc492011-10-31 22:28:20 +00001242 struct ethtool_drvinfo *info, struct ethtool_regs *regs)
Jeff Garzik32c80372005-10-25 01:56:48 -04001243{
1244 int i;
1245
1246 if (gregs_dump_raw) {
1247 fwrite(regs->data, regs->len, 1, stdout);
Vivien Didelot3870efc2019-08-02 15:34:54 -04001248 goto nested;
Jeff Garzik32c80372005-10-25 01:56:48 -04001249 }
1250
Stephen Hemminger5ab06db2006-10-23 10:58:37 -07001251 if (!gregs_dump_hex)
1252 for (i = 0; i < ARRAY_SIZE(driver_list); i++)
1253 if (!strncmp(driver_list[i].name, info->driver,
Ben Hutchings963faa02012-10-10 22:19:15 +01001254 ETHTOOL_BUSINFO_LEN)) {
1255 if (driver_list[i].func(info, regs) == 0)
Vivien Didelot3870efc2019-08-02 15:34:54 -04001256 goto nested;
Ben Hutchings963faa02012-10-10 22:19:15 +01001257 /* This version (or some other
1258 * variation in the dump format) is
1259 * not handled; fall back to hex
1260 */
1261 break;
1262 }
Jeff Garzik32c80372005-10-25 01:56:48 -04001263
Ben Hutchings2038e9e2012-02-17 21:30:06 +00001264 dump_hex(stdout, regs->data, regs->len, 0);
Stuart Hodgson0d53f252012-05-18 15:58:24 +01001265
Vivien Didelot3870efc2019-08-02 15:34:54 -04001266nested:
1267 /* Recurse dump if some drvinfo and regs structures are nested */
1268 if (info->regdump_len > regs->len + sizeof(*info) + sizeof(*regs)) {
1269 info = (struct ethtool_drvinfo *)(&regs->data[0] + regs->len);
1270 regs = (struct ethtool_regs *)(&regs->data[0] + regs->len + sizeof(*info));
1271
1272 return dump_regs(gregs_dump_raw, gregs_dump_hex, info, regs);
1273 }
1274
Jeff Garzik32c80372005-10-25 01:56:48 -04001275 return 0;
1276}
1277
Maciej Żenczykowski302e91a2019-10-17 11:20:52 -07001278static int dump_eeprom(int geeprom_dump_raw,
1279 struct ethtool_drvinfo *info maybe_unused,
Ben Hutchings52adc492011-10-31 22:28:20 +00001280 struct ethtool_eeprom *ee)
Jeff Garzik32c80372005-10-25 01:56:48 -04001281{
Jeff Garzik32c80372005-10-25 01:56:48 -04001282 if (geeprom_dump_raw) {
1283 fwrite(ee->data, 1, ee->len, stdout);
1284 return 0;
1285 }
Ben Hutchings9832a4c2014-04-21 22:51:46 +01001286#ifdef ETHTOOL_ENABLE_PRETTY_DUMP
Jeff Garzik32c80372005-10-25 01:56:48 -04001287 if (!strncmp("natsemi", info->driver, ETHTOOL_BUSINFO_LEN)) {
1288 return natsemi_dump_eeprom(info, ee);
1289 } else if (!strncmp("tg3", info->driver, ETHTOOL_BUSINFO_LEN)) {
1290 return tg3_dump_eeprom(info, ee);
1291 }
Florian Fainelli875616d2014-02-27 15:43:01 -08001292#endif
Ben Hutchings2038e9e2012-02-17 21:30:06 +00001293 dump_hex(stdout, ee->data, ee->len, ee->offset);
Stuart Hodgson0d53f252012-05-18 15:58:24 +01001294
Jeff Garzik32c80372005-10-25 01:56:48 -04001295 return 0;
1296}
1297
Ben Hutchingsd7c4a372011-11-30 01:46:36 +00001298static int dump_test(struct ethtool_test *test,
1299 struct ethtool_gstrings *strings)
Jeff Garzik32c80372005-10-25 01:56:48 -04001300{
1301 int i, rc;
1302
1303 rc = test->flags & ETH_TEST_FL_FAILED;
1304 fprintf(stdout, "The test result is %s\n", rc ? "FAIL" : "PASS");
1305
Ben Hutchings52adc492011-10-31 22:28:20 +00001306 if (test->flags & ETH_TEST_FL_EXTERNAL_LB)
Sucheta Chakrabortybeceb092011-09-20 03:31:34 -07001307 fprintf(stdout, "External loopback test was %sexecuted\n",
1308 (test->flags & ETH_TEST_FL_EXTERNAL_LB_DONE) ?
1309 "" : "not ");
1310
Ben Hutchingsd7c4a372011-11-30 01:46:36 +00001311 if (strings->len)
Jeff Garzik32c80372005-10-25 01:56:48 -04001312 fprintf(stdout, "The test extra info:\n");
1313
Ben Hutchingsd7c4a372011-11-30 01:46:36 +00001314 for (i = 0; i < strings->len; i++) {
Jeff Garzik32c80372005-10-25 01:56:48 -04001315 fprintf(stdout, "%s\t %d\n",
1316 (char *)(strings->data + i * ETH_GSTRING_LEN),
1317 (u32) test->data[i]);
1318 }
1319
1320 fprintf(stdout, "\n");
1321 return rc;
1322}
1323
Ben Hutchings52adc492011-10-31 22:28:20 +00001324static int dump_pause(const struct ethtool_pauseparam *epause,
1325 u32 advertising, u32 lp_advertising)
Jeff Garzik32c80372005-10-25 01:56:48 -04001326{
1327 fprintf(stdout,
1328 "Autonegotiate: %s\n"
1329 "RX: %s\n"
1330 "TX: %s\n",
Ben Hutchings52adc492011-10-31 22:28:20 +00001331 epause->autoneg ? "on" : "off",
1332 epause->rx_pause ? "on" : "off",
1333 epause->tx_pause ? "on" : "off");
Jeff Garzik32c80372005-10-25 01:56:48 -04001334
Ben Hutchings6e50ac02011-10-19 20:52:12 +01001335 if (lp_advertising) {
1336 int an_rx = 0, an_tx = 0;
1337
1338 /* Work out negotiated pause frame usage per
1339 * IEEE 802.3-2005 table 28B-3.
1340 */
1341 if (advertising & lp_advertising & ADVERTISED_Pause) {
1342 an_tx = 1;
1343 an_rx = 1;
1344 } else if (advertising & lp_advertising &
1345 ADVERTISED_Asym_Pause) {
1346 if (advertising & ADVERTISED_Pause)
1347 an_rx = 1;
1348 else if (lp_advertising & ADVERTISED_Pause)
1349 an_tx = 1;
1350 }
1351
1352 fprintf(stdout,
1353 "RX negotiated: %s\n"
1354 "TX negotiated: %s\n",
1355 an_rx ? "on" : "off",
1356 an_tx ? "on" : "off");
1357 }
1358
Jeff Garzik32c80372005-10-25 01:56:48 -04001359 fprintf(stdout, "\n");
1360 return 0;
1361}
1362
Ben Hutchings52adc492011-10-31 22:28:20 +00001363static int dump_ring(const struct ethtool_ringparam *ering)
Jeff Garzik32c80372005-10-25 01:56:48 -04001364{
1365 fprintf(stdout,
1366 "Pre-set maximums:\n"
1367 "RX: %u\n"
1368 "RX Mini: %u\n"
1369 "RX Jumbo: %u\n"
1370 "TX: %u\n",
Ben Hutchings52adc492011-10-31 22:28:20 +00001371 ering->rx_max_pending,
1372 ering->rx_mini_max_pending,
1373 ering->rx_jumbo_max_pending,
1374 ering->tx_max_pending);
Jeff Garzik32c80372005-10-25 01:56:48 -04001375
1376 fprintf(stdout,
1377 "Current hardware settings:\n"
1378 "RX: %u\n"
1379 "RX Mini: %u\n"
1380 "RX Jumbo: %u\n"
1381 "TX: %u\n",
Ben Hutchings52adc492011-10-31 22:28:20 +00001382 ering->rx_pending,
1383 ering->rx_mini_pending,
1384 ering->rx_jumbo_pending,
1385 ering->tx_pending);
Jeff Garzik32c80372005-10-25 01:56:48 -04001386
1387 fprintf(stdout, "\n");
1388 return 0;
1389}
1390
Ben Hutchings52adc492011-10-31 22:28:20 +00001391static int dump_channels(const struct ethtool_channels *echannels)
Sucheta Chakrabortyca910802011-10-07 04:58:50 -07001392{
1393 fprintf(stdout,
1394 "Pre-set maximums:\n"
1395 "RX: %u\n"
1396 "TX: %u\n"
1397 "Other: %u\n"
1398 "Combined: %u\n",
Ben Hutchings52adc492011-10-31 22:28:20 +00001399 echannels->max_rx, echannels->max_tx,
1400 echannels->max_other,
1401 echannels->max_combined);
Sucheta Chakrabortyca910802011-10-07 04:58:50 -07001402
1403 fprintf(stdout,
1404 "Current hardware settings:\n"
1405 "RX: %u\n"
1406 "TX: %u\n"
1407 "Other: %u\n"
1408 "Combined: %u\n",
Ben Hutchings52adc492011-10-31 22:28:20 +00001409 echannels->rx_count, echannels->tx_count,
1410 echannels->other_count,
1411 echannels->combined_count);
Sucheta Chakrabortyca910802011-10-07 04:58:50 -07001412
1413 fprintf(stdout, "\n");
1414 return 0;
1415}
1416
Ben Hutchings52adc492011-10-31 22:28:20 +00001417static int dump_coalesce(const struct ethtool_coalesce *ecoal)
Jeff Garzik32c80372005-10-25 01:56:48 -04001418{
1419 fprintf(stdout, "Adaptive RX: %s TX: %s\n",
Ben Hutchings52adc492011-10-31 22:28:20 +00001420 ecoal->use_adaptive_rx_coalesce ? "on" : "off",
1421 ecoal->use_adaptive_tx_coalesce ? "on" : "off");
Jeff Garzik32c80372005-10-25 01:56:48 -04001422
1423 fprintf(stdout,
1424 "stats-block-usecs: %u\n"
1425 "sample-interval: %u\n"
1426 "pkt-rate-low: %u\n"
1427 "pkt-rate-high: %u\n"
1428 "\n"
1429 "rx-usecs: %u\n"
1430 "rx-frames: %u\n"
1431 "rx-usecs-irq: %u\n"
1432 "rx-frames-irq: %u\n"
1433 "\n"
1434 "tx-usecs: %u\n"
1435 "tx-frames: %u\n"
1436 "tx-usecs-irq: %u\n"
1437 "tx-frames-irq: %u\n"
1438 "\n"
1439 "rx-usecs-low: %u\n"
Nicholas Nunley66501a72019-03-01 00:15:32 -08001440 "rx-frames-low: %u\n"
Jeff Garzik32c80372005-10-25 01:56:48 -04001441 "tx-usecs-low: %u\n"
Nicholas Nunley66501a72019-03-01 00:15:32 -08001442 "tx-frames-low: %u\n"
Jeff Garzik32c80372005-10-25 01:56:48 -04001443 "\n"
1444 "rx-usecs-high: %u\n"
Nicholas Nunley66501a72019-03-01 00:15:32 -08001445 "rx-frames-high: %u\n"
Jeff Garzik32c80372005-10-25 01:56:48 -04001446 "tx-usecs-high: %u\n"
Nicholas Nunley66501a72019-03-01 00:15:32 -08001447 "tx-frames-high: %u\n"
Jeff Garzik32c80372005-10-25 01:56:48 -04001448 "\n",
Ben Hutchings52adc492011-10-31 22:28:20 +00001449 ecoal->stats_block_coalesce_usecs,
1450 ecoal->rate_sample_interval,
1451 ecoal->pkt_rate_low,
1452 ecoal->pkt_rate_high,
Jeff Garzik32c80372005-10-25 01:56:48 -04001453
Ben Hutchings52adc492011-10-31 22:28:20 +00001454 ecoal->rx_coalesce_usecs,
1455 ecoal->rx_max_coalesced_frames,
1456 ecoal->rx_coalesce_usecs_irq,
1457 ecoal->rx_max_coalesced_frames_irq,
Jeff Garzik32c80372005-10-25 01:56:48 -04001458
Ben Hutchings52adc492011-10-31 22:28:20 +00001459 ecoal->tx_coalesce_usecs,
1460 ecoal->tx_max_coalesced_frames,
1461 ecoal->tx_coalesce_usecs_irq,
1462 ecoal->tx_max_coalesced_frames_irq,
Jeff Garzik32c80372005-10-25 01:56:48 -04001463
Ben Hutchings52adc492011-10-31 22:28:20 +00001464 ecoal->rx_coalesce_usecs_low,
1465 ecoal->rx_max_coalesced_frames_low,
1466 ecoal->tx_coalesce_usecs_low,
1467 ecoal->tx_max_coalesced_frames_low,
Jeff Garzik32c80372005-10-25 01:56:48 -04001468
Ben Hutchings52adc492011-10-31 22:28:20 +00001469 ecoal->rx_coalesce_usecs_high,
1470 ecoal->rx_max_coalesced_frames_high,
1471 ecoal->tx_coalesce_usecs_high,
1472 ecoal->tx_max_coalesced_frames_high);
Jeff Garzik32c80372005-10-25 01:56:48 -04001473
1474 return 0;
1475}
1476
Nicholas Nunley52ecd6e2019-03-01 00:15:30 -08001477void dump_per_queue_coalesce(struct ethtool_per_queue_op *per_queue_opt,
1478 __u32 *queue_mask, int n_queues)
1479{
1480 struct ethtool_coalesce *ecoal;
1481 int i, idx = 0;
1482
1483 ecoal = (struct ethtool_coalesce *)(per_queue_opt + 1);
1484 for (i = 0; i < __KERNEL_DIV_ROUND_UP(MAX_NUM_QUEUE, 32); i++) {
1485 int queue = i * 32;
1486 __u32 mask = queue_mask[i];
1487
1488 while (mask > 0) {
1489 if (mask & 0x1) {
1490 fprintf(stdout, "Queue: %d\n", queue);
1491 dump_coalesce(ecoal + idx);
1492 idx++;
1493 }
1494 mask = mask >> 1;
1495 queue++;
1496 }
1497 if (idx == n_queues)
1498 break;
1499 }
1500}
1501
Ben Hutchings60428042012-06-01 23:08:32 +01001502struct feature_state {
1503 u32 off_flags;
1504 struct ethtool_gfeatures features;
1505};
1506
1507static void dump_one_feature(const char *indent, const char *name,
1508 const struct feature_state *state,
1509 const struct feature_state *ref_state,
1510 u32 index)
1511{
1512 if (ref_state &&
1513 !(FEATURE_BIT_IS_SET(state->features.features, index, active) ^
1514 FEATURE_BIT_IS_SET(ref_state->features.features, index, active)))
1515 return;
1516
1517 printf("%s%s: %s%s\n",
1518 indent, name,
1519 FEATURE_BIT_IS_SET(state->features.features, index, active) ?
1520 "on" : "off",
1521 (!FEATURE_BIT_IS_SET(state->features.features, index, available)
1522 || FEATURE_BIT_IS_SET(state->features.features, index,
1523 never_changed))
1524 ? " [fixed]"
1525 : (FEATURE_BIT_IS_SET(state->features.features, index, requested)
1526 ^ FEATURE_BIT_IS_SET(state->features.features, index, active))
1527 ? (FEATURE_BIT_IS_SET(state->features.features, index, requested)
1528 ? " [requested on]" : " [requested off]")
1529 : "");
1530}
1531
Ben Hutchingsec0ff772013-09-19 22:12:46 +01001532static int linux_version_code(void)
1533{
1534 struct utsname utsname;
1535 unsigned version, patchlevel, sublevel = 0;
1536
1537 if (uname(&utsname))
1538 return -1;
1539 if (sscanf(utsname.release, "%u.%u.%u", &version, &patchlevel, &sublevel) < 2)
1540 return -1;
1541 return KERNEL_VERSION(version, patchlevel, sublevel);
1542}
1543
Ben Hutchings60428042012-06-01 23:08:32 +01001544static void dump_features(const struct feature_defs *defs,
1545 const struct feature_state *state,
1546 const struct feature_state *ref_state)
Jeff Garzik32c80372005-10-25 01:56:48 -04001547{
Ben Hutchingsec0ff772013-09-19 22:12:46 +01001548 int kernel_ver = linux_version_code();
Ben Hutchingse5c984a2011-05-13 23:25:26 +01001549 u32 value;
Ben Hutchings60428042012-06-01 23:08:32 +01001550 int indent;
1551 int i, j;
Ben Hutchingse5c984a2011-05-13 23:25:26 +01001552
1553 for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
Ben Hutchingsec0ff772013-09-19 22:12:46 +01001554 /* Don't show features whose state is unknown on this
1555 * kernel version
1556 */
1557 if (defs->off_flag_matched[i] == 0 &&
Ivan Vecera8f055382018-11-29 16:36:53 +01001558 ((off_flag_def[i].get_cmd == 0 &&
1559 kernel_ver < off_flag_def[i].min_kernel_ver) ||
1560 (off_flag_def[i].get_cmd == ETHTOOL_GUFO &&
1561 kernel_ver >= KERNEL_VERSION(4, 14, 0))))
Ben Hutchingsec0ff772013-09-19 22:12:46 +01001562 continue;
1563
Ben Hutchingse5c984a2011-05-13 23:25:26 +01001564 value = off_flag_def[i].value;
Ben Hutchings60428042012-06-01 23:08:32 +01001565
1566 /* If this offload flag matches exactly one generic
1567 * feature then it's redundant to show the flag and
1568 * feature states separately. Otherwise, show the
1569 * flag state first.
1570 */
1571 if (defs->off_flag_matched[i] != 1 &&
1572 (!ref_state ||
1573 (state->off_flags ^ ref_state->off_flags) & value)) {
1574 printf("%s: %s\n",
1575 off_flag_def[i].long_name,
1576 (state->off_flags & value) ? "on" : "off");
1577 indent = 1;
1578 } else {
1579 indent = 0;
1580 }
1581
1582 /* Show matching features */
1583 for (j = 0; j < defs->n_features; j++) {
1584 if (defs->def[j].off_flag_index != i)
1585 continue;
1586 if (defs->off_flag_matched[i] != 1)
1587 /* Show all matching feature states */
1588 dump_one_feature(indent ? "\t" : "",
1589 defs->def[j].name,
1590 state, ref_state, j);
1591 else
1592 /* Show full state with the old flag name */
1593 dump_one_feature("", off_flag_def[i].long_name,
1594 state, ref_state, j);
1595 }
Ben Hutchingse5c984a2011-05-13 23:25:26 +01001596 }
Jeff Garzik32c80372005-10-25 01:56:48 -04001597
Ben Hutchings60428042012-06-01 23:08:32 +01001598 /* Show all unmatched features that have non-null names */
1599 for (j = 0; j < defs->n_features; j++)
1600 if (defs->def[j].off_flag_index < 0 && defs->def[j].name[0])
1601 dump_one_feature("", defs->def[j].name,
1602 state, ref_state, j);
Jeff Garzik32c80372005-10-25 01:56:48 -04001603}
1604
Santwona Behera1bd87122008-06-27 17:06:20 -07001605static int dump_rxfhash(int fhash, u64 val)
1606{
Edward Creef5d55b92018-03-09 15:04:12 +00001607 switch (fhash & ~FLOW_RSS) {
Santwona Behera1bd87122008-06-27 17:06:20 -07001608 case TCP_V4_FLOW:
1609 fprintf(stdout, "TCP over IPV4 flows");
1610 break;
1611 case UDP_V4_FLOW:
1612 fprintf(stdout, "UDP over IPV4 flows");
1613 break;
1614 case SCTP_V4_FLOW:
1615 fprintf(stdout, "SCTP over IPV4 flows");
1616 break;
1617 case AH_ESP_V4_FLOW:
Alexander Duyckb4001112011-04-21 13:40:20 -07001618 case AH_V4_FLOW:
1619 case ESP_V4_FLOW:
1620 fprintf(stdout, "IPSEC AH/ESP over IPV4 flows");
Santwona Behera1bd87122008-06-27 17:06:20 -07001621 break;
1622 case TCP_V6_FLOW:
1623 fprintf(stdout, "TCP over IPV6 flows");
1624 break;
1625 case UDP_V6_FLOW:
1626 fprintf(stdout, "UDP over IPV6 flows");
1627 break;
1628 case SCTP_V6_FLOW:
1629 fprintf(stdout, "SCTP over IPV6 flows");
1630 break;
1631 case AH_ESP_V6_FLOW:
Alexander Duyckb4001112011-04-21 13:40:20 -07001632 case AH_V6_FLOW:
1633 case ESP_V6_FLOW:
1634 fprintf(stdout, "IPSEC AH/ESP over IPV6 flows");
Santwona Behera1bd87122008-06-27 17:06:20 -07001635 break;
1636 default:
1637 break;
1638 }
1639
1640 if (val & RXH_DISCARD) {
1641 fprintf(stdout, " - All matching flows discarded on RX\n");
1642 return 0;
1643 }
1644 fprintf(stdout, " use these fields for computing Hash flow key:\n");
1645
1646 fprintf(stdout, "%s\n", unparse_rxfhashopts(val));
Jeff Garzika97a2ec2009-03-06 06:12:13 -05001647
Santwona Behera1bd87122008-06-27 17:06:20 -07001648 return 0;
1649}
1650
Yuval Mintza9fc8272012-06-10 11:48:08 +03001651static void dump_eeecmd(struct ethtool_eee *ep)
1652{
David Decotigny33133ab2016-03-25 09:21:01 -07001653 ETHTOOL_DECLARE_LINK_MODE_MASK(link_mode);
Yuval Mintza9fc8272012-06-10 11:48:08 +03001654
1655 fprintf(stdout, " EEE status: ");
1656 if (!ep->supported) {
1657 fprintf(stdout, "not supported\n");
1658 return;
1659 } else if (!ep->eee_enabled) {
1660 fprintf(stdout, "disabled\n");
1661 } else {
1662 fprintf(stdout, "enabled - ");
1663 if (ep->eee_active)
1664 fprintf(stdout, "active\n");
1665 else
1666 fprintf(stdout, "inactive\n");
1667 }
1668
1669 fprintf(stdout, " Tx LPI:");
1670 if (ep->tx_lpi_enabled)
1671 fprintf(stdout, " %d (us)\n", ep->tx_lpi_timer);
1672 else
1673 fprintf(stdout, " disabled\n");
1674
David Decotigny33133ab2016-03-25 09:21:01 -07001675 ethtool_link_mode_zero(link_mode);
1676
1677 link_mode[0] = ep->supported;
1678 dump_link_caps("Supported EEE", "", link_mode, 1);
1679
1680 link_mode[0] = ep->advertised;
1681 dump_link_caps("Advertised EEE", "", link_mode, 1);
1682
1683 link_mode[0] = ep->lp_advertised;
1684 dump_link_caps("Link partner advertised EEE", "", link_mode, 1);
Yuval Mintza9fc8272012-06-10 11:48:08 +03001685}
1686
Dustin Byford8db75d12017-12-18 14:57:41 -08001687static void dump_fec(u32 fec)
1688{
1689 if (fec & ETHTOOL_FEC_NONE)
1690 fprintf(stdout, " None");
1691 if (fec & ETHTOOL_FEC_AUTO)
1692 fprintf(stdout, " Auto");
1693 if (fec & ETHTOOL_FEC_OFF)
1694 fprintf(stdout, " Off");
1695 if (fec & ETHTOOL_FEC_BASER)
1696 fprintf(stdout, " BaseR");
1697 if (fec & ETHTOOL_FEC_RS)
1698 fprintf(stdout, " RS");
1699}
1700
Richard Cochran0fdcc8c2012-04-03 19:58:23 +02001701#define N_SOTS 7
1702
1703static char *so_timestamping_labels[N_SOTS] = {
1704 "hardware-transmit (SOF_TIMESTAMPING_TX_HARDWARE)",
1705 "software-transmit (SOF_TIMESTAMPING_TX_SOFTWARE)",
1706 "hardware-receive (SOF_TIMESTAMPING_RX_HARDWARE)",
1707 "software-receive (SOF_TIMESTAMPING_RX_SOFTWARE)",
1708 "software-system-clock (SOF_TIMESTAMPING_SOFTWARE)",
1709 "hardware-legacy-clock (SOF_TIMESTAMPING_SYS_HARDWARE)",
1710 "hardware-raw-clock (SOF_TIMESTAMPING_RAW_HARDWARE)",
1711};
1712
1713#define N_TX_TYPES (HWTSTAMP_TX_ONESTEP_SYNC + 1)
1714
1715static char *tx_type_labels[N_TX_TYPES] = {
1716 "off (HWTSTAMP_TX_OFF)",
1717 "on (HWTSTAMP_TX_ON)",
1718 "one-step-sync (HWTSTAMP_TX_ONESTEP_SYNC)",
1719};
1720
Miroslav Lichvard976d5d2017-05-23 16:29:30 +02001721#define N_RX_FILTERS (HWTSTAMP_FILTER_NTP_ALL + 1)
Richard Cochran0fdcc8c2012-04-03 19:58:23 +02001722
1723static char *rx_filter_labels[N_RX_FILTERS] = {
1724 "none (HWTSTAMP_FILTER_NONE)",
1725 "all (HWTSTAMP_FILTER_ALL)",
1726 "some (HWTSTAMP_FILTER_SOME)",
1727 "ptpv1-l4-event (HWTSTAMP_FILTER_PTP_V1_L4_EVENT)",
1728 "ptpv1-l4-sync (HWTSTAMP_FILTER_PTP_V1_L4_SYNC)",
1729 "ptpv1-l4-delay-req (HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ)",
1730 "ptpv2-l4-event (HWTSTAMP_FILTER_PTP_V2_L4_EVENT)",
1731 "ptpv2-l4-sync (HWTSTAMP_FILTER_PTP_V2_L4_SYNC)",
1732 "ptpv2-l4-delay-req (HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ)",
1733 "ptpv2-l2-event (HWTSTAMP_FILTER_PTP_V2_L2_EVENT)",
1734 "ptpv2-l2-sync (HWTSTAMP_FILTER_PTP_V2_L2_SYNC)",
1735 "ptpv2-l2-delay-req (HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ)",
1736 "ptpv2-event (HWTSTAMP_FILTER_PTP_V2_EVENT)",
1737 "ptpv2-sync (HWTSTAMP_FILTER_PTP_V2_SYNC)",
1738 "ptpv2-delay-req (HWTSTAMP_FILTER_PTP_V2_DELAY_REQ)",
Miroslav Lichvard976d5d2017-05-23 16:29:30 +02001739 "ntp-all (HWTSTAMP_FILTER_NTP_ALL)",
Richard Cochran0fdcc8c2012-04-03 19:58:23 +02001740};
1741
1742static int dump_tsinfo(const struct ethtool_ts_info *info)
1743{
1744 int i;
1745
1746 fprintf(stdout, "Capabilities:\n");
1747
1748 for (i = 0; i < N_SOTS; i++) {
1749 if (info->so_timestamping & (1 << i))
1750 fprintf(stdout, "\t%s\n", so_timestamping_labels[i]);
1751 }
1752
1753 fprintf(stdout, "PTP Hardware Clock: ");
1754
1755 if (info->phc_index < 0)
1756 fprintf(stdout, "none\n");
1757 else
1758 fprintf(stdout, "%d\n", info->phc_index);
1759
1760 fprintf(stdout, "Hardware Transmit Timestamp Modes:");
1761
1762 if (!info->tx_types)
1763 fprintf(stdout, " none\n");
1764 else
1765 fprintf(stdout, "\n");
1766
1767 for (i = 0; i < N_TX_TYPES; i++) {
1768 if (info->tx_types & (1 << i))
1769 fprintf(stdout, "\t%s\n", tx_type_labels[i]);
1770 }
1771
1772 fprintf(stdout, "Hardware Receive Filter Modes:");
1773
1774 if (!info->rx_filters)
1775 fprintf(stdout, " none\n");
1776 else
1777 fprintf(stdout, "\n");
1778
1779 for (i = 0; i < N_RX_FILTERS; i++) {
1780 if (info->rx_filters & (1 << i))
1781 fprintf(stdout, "\t%s\n", rx_filter_labels[i]);
1782 }
1783
1784 return 0;
1785}
1786
Ben Hutchingsd7c4a372011-11-30 01:46:36 +00001787static struct ethtool_gstrings *
1788get_stringset(struct cmd_context *ctx, enum ethtool_stringset set_id,
Ben Hutchingsa983fb72012-06-14 20:34:35 +01001789 ptrdiff_t drvinfo_offset, int null_terminate)
Ben Hutchingsd7c4a372011-11-30 01:46:36 +00001790{
1791 struct {
1792 struct ethtool_sset_info hdr;
1793 u32 buf[1];
1794 } sset_info;
1795 struct ethtool_drvinfo drvinfo;
Ben Hutchingsa983fb72012-06-14 20:34:35 +01001796 u32 len, i;
Ben Hutchingsd7c4a372011-11-30 01:46:36 +00001797 struct ethtool_gstrings *strings;
1798
1799 sset_info.hdr.cmd = ETHTOOL_GSSET_INFO;
1800 sset_info.hdr.reserved = 0;
1801 sset_info.hdr.sset_mask = 1ULL << set_id;
1802 if (send_ioctl(ctx, &sset_info) == 0) {
1803 len = sset_info.hdr.sset_mask ? sset_info.hdr.data[0] : 0;
1804 } else if (errno == EOPNOTSUPP && drvinfo_offset != 0) {
1805 /* Fallback for old kernel versions */
1806 drvinfo.cmd = ETHTOOL_GDRVINFO;
1807 if (send_ioctl(ctx, &drvinfo))
1808 return NULL;
1809 len = *(u32 *)((char *)&drvinfo + drvinfo_offset);
1810 } else {
1811 return NULL;
1812 }
1813
1814 strings = calloc(1, sizeof(*strings) + len * ETH_GSTRING_LEN);
1815 if (!strings)
1816 return NULL;
1817
1818 strings->cmd = ETHTOOL_GSTRINGS;
1819 strings->string_set = set_id;
1820 strings->len = len;
1821 if (len != 0 && send_ioctl(ctx, strings)) {
1822 free(strings);
1823 return NULL;
1824 }
1825
Ben Hutchingsa983fb72012-06-14 20:34:35 +01001826 if (null_terminate)
1827 for (i = 0; i < len; i++)
1828 strings->data[(i + 1) * ETH_GSTRING_LEN - 1] = 0;
1829
Ben Hutchingsd7c4a372011-11-30 01:46:36 +00001830 return strings;
1831}
1832
Ben Hutchings60428042012-06-01 23:08:32 +01001833static struct feature_defs *get_feature_defs(struct cmd_context *ctx)
1834{
1835 struct ethtool_gstrings *names;
1836 struct feature_defs *defs;
1837 u32 n_features;
1838 int i, j;
1839
Ben Hutchingsa983fb72012-06-14 20:34:35 +01001840 names = get_stringset(ctx, ETH_SS_FEATURES, 0, 1);
Ben Hutchings60428042012-06-01 23:08:32 +01001841 if (names) {
1842 n_features = names->len;
1843 } else if (errno == EOPNOTSUPP || errno == EINVAL) {
1844 /* Kernel doesn't support named features; not an error */
1845 n_features = 0;
Ben Hutchings1eef6772012-06-13 00:57:06 +01001846 } else if (errno == EPERM) {
1847 /* Kernel bug: ETHTOOL_GSSET_INFO was privileged.
1848 * Work around it. */
1849 n_features = 0;
Ben Hutchings60428042012-06-01 23:08:32 +01001850 } else {
1851 return NULL;
1852 }
1853
1854 defs = malloc(sizeof(*defs) + sizeof(defs->def[0]) * n_features);
John W. Linville9674a822016-09-30 14:57:27 -04001855 if (!defs) {
1856 free(names);
Ben Hutchings60428042012-06-01 23:08:32 +01001857 return NULL;
John W. Linville9674a822016-09-30 14:57:27 -04001858 }
Ben Hutchings60428042012-06-01 23:08:32 +01001859
1860 defs->n_features = n_features;
1861 memset(defs->off_flag_matched, 0, sizeof(defs->off_flag_matched));
1862
1863 /* Copy out feature names and find those associated with legacy flags */
1864 for (i = 0; i < defs->n_features; i++) {
1865 memcpy(defs->def[i].name, names->data + i * ETH_GSTRING_LEN,
1866 ETH_GSTRING_LEN);
1867 defs->def[i].off_flag_index = -1;
1868
1869 for (j = 0;
1870 j < ARRAY_SIZE(off_flag_def) &&
1871 defs->def[i].off_flag_index < 0;
1872 j++) {
1873 const char *pattern =
1874 off_flag_def[j].kernel_name;
1875 const char *name = defs->def[i].name;
1876 for (;;) {
1877 if (*pattern == '*') {
1878 /* There is only one wildcard; so
1879 * switch to a suffix comparison */
1880 size_t pattern_len =
1881 strlen(pattern + 1);
1882 size_t name_len = strlen(name);
1883 if (name_len < pattern_len)
1884 break; /* name is too short */
1885 name += name_len - pattern_len;
1886 ++pattern;
1887 } else if (*pattern != *name) {
1888 break; /* mismatch */
1889 } else if (*pattern == 0) {
1890 defs->def[i].off_flag_index = j;
1891 defs->off_flag_matched[j]++;
1892 break;
1893 } else {
1894 ++name;
1895 ++pattern;
1896 }
1897 }
1898 }
1899 }
1900
1901 free(names);
1902 return defs;
1903}
1904
Ben Hutchings37897ca2011-10-29 02:33:30 +01001905static int do_gdrv(struct cmd_context *ctx)
Jeff Garzik32c80372005-10-25 01:56:48 -04001906{
1907 int err;
1908 struct ethtool_drvinfo drvinfo;
1909
Ben Hutchings127f8062011-10-29 01:15:34 +01001910 if (ctx->argc != 0)
1911 exit_bad_args();
1912
Jeff Garzik32c80372005-10-25 01:56:48 -04001913 drvinfo.cmd = ETHTOOL_GDRVINFO;
Ben Hutchings37897ca2011-10-29 02:33:30 +01001914 err = send_ioctl(ctx, &drvinfo);
Jeff Garzik32c80372005-10-25 01:56:48 -04001915 if (err < 0) {
1916 perror("Cannot get driver information");
1917 return 71;
1918 }
1919 return dump_drvinfo(&drvinfo);
1920}
1921
Ben Hutchings37897ca2011-10-29 02:33:30 +01001922static int do_gpause(struct cmd_context *ctx)
Jeff Garzik32c80372005-10-25 01:56:48 -04001923{
Ben Hutchings52adc492011-10-31 22:28:20 +00001924 struct ethtool_pauseparam epause;
Ben Hutchings6e50ac02011-10-19 20:52:12 +01001925 struct ethtool_cmd ecmd;
Jeff Garzik32c80372005-10-25 01:56:48 -04001926 int err;
1927
Ben Hutchings127f8062011-10-29 01:15:34 +01001928 if (ctx->argc != 0)
1929 exit_bad_args();
1930
Ben Hutchings743eb0b2011-10-29 02:36:48 +01001931 fprintf(stdout, "Pause parameters for %s:\n", ctx->devname);
Jeff Garzik32c80372005-10-25 01:56:48 -04001932
1933 epause.cmd = ETHTOOL_GPAUSEPARAM;
Ben Hutchings37897ca2011-10-29 02:33:30 +01001934 err = send_ioctl(ctx, &epause);
Ben Hutchings6e50ac02011-10-19 20:52:12 +01001935 if (err) {
Jeff Garzik32c80372005-10-25 01:56:48 -04001936 perror("Cannot get device pause settings");
1937 return 76;
1938 }
1939
Ben Hutchings6e50ac02011-10-19 20:52:12 +01001940 if (epause.autoneg) {
1941 ecmd.cmd = ETHTOOL_GSET;
Ben Hutchings37897ca2011-10-29 02:33:30 +01001942 err = send_ioctl(ctx, &ecmd);
Ben Hutchings6e50ac02011-10-19 20:52:12 +01001943 if (err) {
1944 perror("Cannot get device settings");
1945 return 1;
1946 }
Ben Hutchings52adc492011-10-31 22:28:20 +00001947 dump_pause(&epause, ecmd.advertising, ecmd.lp_advertising);
Ben Hutchings6e50ac02011-10-19 20:52:12 +01001948 } else {
Ben Hutchings52adc492011-10-31 22:28:20 +00001949 dump_pause(&epause, 0, 0);
Ben Hutchings6e50ac02011-10-19 20:52:12 +01001950 }
1951
Jeff Garzik32c80372005-10-25 01:56:48 -04001952 return 0;
1953}
1954
1955static void do_generic_set1(struct cmdline_info *info, int *changed_out)
1956{
1957 int wanted, *v1, *v2;
1958
1959 v1 = info->wanted_val;
1960 wanted = *v1;
1961
1962 if (wanted < 0)
1963 return;
1964
1965 v2 = info->ioctl_val;
1966 if (wanted == *v2) {
1967 fprintf(stderr, "%s unmodified, ignoring\n", info->name);
1968 } else {
1969 *v2 = wanted;
1970 *changed_out = 1;
1971 }
1972}
1973
1974static void do_generic_set(struct cmdline_info *info,
1975 unsigned int n_info,
1976 int *changed_out)
1977{
1978 unsigned int i;
1979
1980 for (i = 0; i < n_info; i++)
1981 do_generic_set1(&info[i], changed_out);
1982}
1983
Ben Hutchings37897ca2011-10-29 02:33:30 +01001984static int do_spause(struct cmd_context *ctx)
Jeff Garzik32c80372005-10-25 01:56:48 -04001985{
Ben Hutchings52adc492011-10-31 22:28:20 +00001986 struct ethtool_pauseparam epause;
1987 int gpause_changed = 0;
1988 int pause_autoneg_wanted = -1;
1989 int pause_rx_wanted = -1;
1990 int pause_tx_wanted = -1;
1991 struct cmdline_info cmdline_pause[] = {
1992 { "autoneg", CMDL_BOOL, &pause_autoneg_wanted,
1993 &epause.autoneg },
1994 { "rx", CMDL_BOOL, &pause_rx_wanted, &epause.rx_pause },
1995 { "tx", CMDL_BOOL, &pause_tx_wanted, &epause.tx_pause },
1996 };
Jeff Garzik32c80372005-10-25 01:56:48 -04001997 int err, changed = 0;
1998
Ben Hutchings127f8062011-10-29 01:15:34 +01001999 parse_generic_cmdline(ctx, &gpause_changed,
2000 cmdline_pause, ARRAY_SIZE(cmdline_pause));
2001
Jeff Garzik32c80372005-10-25 01:56:48 -04002002 epause.cmd = ETHTOOL_GPAUSEPARAM;
Ben Hutchings37897ca2011-10-29 02:33:30 +01002003 err = send_ioctl(ctx, &epause);
Jeff Garzik32c80372005-10-25 01:56:48 -04002004 if (err) {
2005 perror("Cannot get device pause settings");
2006 return 77;
2007 }
2008
2009 do_generic_set(cmdline_pause, ARRAY_SIZE(cmdline_pause), &changed);
2010
2011 if (!changed) {
2012 fprintf(stderr, "no pause parameters changed, aborting\n");
2013 return 78;
2014 }
2015
2016 epause.cmd = ETHTOOL_SPAUSEPARAM;
Ben Hutchings37897ca2011-10-29 02:33:30 +01002017 err = send_ioctl(ctx, &epause);
Jeff Garzik32c80372005-10-25 01:56:48 -04002018 if (err) {
2019 perror("Cannot set device pause parameters");
2020 return 79;
2021 }
2022
2023 return 0;
2024}
2025
Ben Hutchings37897ca2011-10-29 02:33:30 +01002026static int do_sring(struct cmd_context *ctx)
Jeff Garzik32c80372005-10-25 01:56:48 -04002027{
Ben Hutchings52adc492011-10-31 22:28:20 +00002028 struct ethtool_ringparam ering;
2029 int gring_changed = 0;
2030 s32 ring_rx_wanted = -1;
2031 s32 ring_rx_mini_wanted = -1;
2032 s32 ring_rx_jumbo_wanted = -1;
2033 s32 ring_tx_wanted = -1;
2034 struct cmdline_info cmdline_ring[] = {
2035 { "rx", CMDL_S32, &ring_rx_wanted, &ering.rx_pending },
2036 { "rx-mini", CMDL_S32, &ring_rx_mini_wanted,
2037 &ering.rx_mini_pending },
2038 { "rx-jumbo", CMDL_S32, &ring_rx_jumbo_wanted,
2039 &ering.rx_jumbo_pending },
2040 { "tx", CMDL_S32, &ring_tx_wanted, &ering.tx_pending },
2041 };
Jeff Garzik32c80372005-10-25 01:56:48 -04002042 int err, changed = 0;
2043
Ben Hutchings127f8062011-10-29 01:15:34 +01002044 parse_generic_cmdline(ctx, &gring_changed,
2045 cmdline_ring, ARRAY_SIZE(cmdline_ring));
2046
Jeff Garzik32c80372005-10-25 01:56:48 -04002047 ering.cmd = ETHTOOL_GRINGPARAM;
Ben Hutchings37897ca2011-10-29 02:33:30 +01002048 err = send_ioctl(ctx, &ering);
Jeff Garzik32c80372005-10-25 01:56:48 -04002049 if (err) {
2050 perror("Cannot get device ring settings");
2051 return 76;
2052 }
2053
2054 do_generic_set(cmdline_ring, ARRAY_SIZE(cmdline_ring), &changed);
2055
2056 if (!changed) {
2057 fprintf(stderr, "no ring parameters changed, aborting\n");
2058 return 80;
2059 }
2060
2061 ering.cmd = ETHTOOL_SRINGPARAM;
Ben Hutchings37897ca2011-10-29 02:33:30 +01002062 err = send_ioctl(ctx, &ering);
Jeff Garzik32c80372005-10-25 01:56:48 -04002063 if (err) {
2064 perror("Cannot set device ring parameters");
2065 return 81;
2066 }
2067
2068 return 0;
2069}
2070
Ben Hutchings37897ca2011-10-29 02:33:30 +01002071static int do_gring(struct cmd_context *ctx)
Jeff Garzik32c80372005-10-25 01:56:48 -04002072{
Ben Hutchings52adc492011-10-31 22:28:20 +00002073 struct ethtool_ringparam ering;
Jeff Garzik32c80372005-10-25 01:56:48 -04002074 int err;
2075
Ben Hutchings127f8062011-10-29 01:15:34 +01002076 if (ctx->argc != 0)
2077 exit_bad_args();
2078
Ben Hutchings743eb0b2011-10-29 02:36:48 +01002079 fprintf(stdout, "Ring parameters for %s:\n", ctx->devname);
Jeff Garzik32c80372005-10-25 01:56:48 -04002080
2081 ering.cmd = ETHTOOL_GRINGPARAM;
Ben Hutchings37897ca2011-10-29 02:33:30 +01002082 err = send_ioctl(ctx, &ering);
Jeff Garzik32c80372005-10-25 01:56:48 -04002083 if (err == 0) {
Ben Hutchings52adc492011-10-31 22:28:20 +00002084 err = dump_ring(&ering);
Jeff Garzik32c80372005-10-25 01:56:48 -04002085 if (err)
2086 return err;
2087 } else {
2088 perror("Cannot get device ring settings");
2089 return 76;
2090 }
2091
2092 return 0;
2093}
2094
Ben Hutchings37897ca2011-10-29 02:33:30 +01002095static int do_schannels(struct cmd_context *ctx)
Sucheta Chakrabortyca910802011-10-07 04:58:50 -07002096{
Ben Hutchings52adc492011-10-31 22:28:20 +00002097 struct ethtool_channels echannels;
2098 int gchannels_changed;
2099 s32 channels_rx_wanted = -1;
2100 s32 channels_tx_wanted = -1;
2101 s32 channels_other_wanted = -1;
2102 s32 channels_combined_wanted = -1;
2103 struct cmdline_info cmdline_channels[] = {
2104 { "rx", CMDL_S32, &channels_rx_wanted, &echannels.rx_count },
2105 { "tx", CMDL_S32, &channels_tx_wanted, &echannels.tx_count },
2106 { "other", CMDL_S32, &channels_other_wanted,
2107 &echannels.other_count },
2108 { "combined", CMDL_S32, &channels_combined_wanted,
2109 &echannels.combined_count },
2110 };
Sucheta Chakrabortyca910802011-10-07 04:58:50 -07002111 int err, changed = 0;
2112
Ben Hutchings127f8062011-10-29 01:15:34 +01002113 parse_generic_cmdline(ctx, &gchannels_changed,
Ben Hutchingsc816d662011-10-31 22:30:38 +00002114 cmdline_channels, ARRAY_SIZE(cmdline_channels));
Ben Hutchings127f8062011-10-29 01:15:34 +01002115
Sucheta Chakrabortyca910802011-10-07 04:58:50 -07002116 echannels.cmd = ETHTOOL_GCHANNELS;
Ben Hutchings37897ca2011-10-29 02:33:30 +01002117 err = send_ioctl(ctx, &echannels);
Sucheta Chakrabortyca910802011-10-07 04:58:50 -07002118 if (err) {
2119 perror("Cannot get device channel parameters");
2120 return 1;
2121 }
2122
2123 do_generic_set(cmdline_channels, ARRAY_SIZE(cmdline_channels),
2124 &changed);
2125
2126 if (!changed) {
Ben Greear5954d262017-10-19 14:01:19 -07002127 fprintf(stderr, "no channel parameters changed.\n");
Jakub Kicinski410e33b2017-07-18 19:02:32 -07002128 fprintf(stderr, "current values: rx %u tx %u other %u"
Amos Kong72b683b2014-04-18 09:39:59 +08002129 " combined %u\n", echannels.rx_count,
Sucheta Chakrabortyca910802011-10-07 04:58:50 -07002130 echannels.tx_count, echannels.other_count,
2131 echannels.combined_count);
Ben Greear5954d262017-10-19 14:01:19 -07002132 return 0;
Sucheta Chakrabortyca910802011-10-07 04:58:50 -07002133 }
2134
2135 echannels.cmd = ETHTOOL_SCHANNELS;
Ben Hutchings37897ca2011-10-29 02:33:30 +01002136 err = send_ioctl(ctx, &echannels);
Sucheta Chakrabortyca910802011-10-07 04:58:50 -07002137 if (err) {
2138 perror("Cannot set device channel parameters");
2139 return 1;
2140 }
2141
2142 return 0;
2143}
2144
Ben Hutchings37897ca2011-10-29 02:33:30 +01002145static int do_gchannels(struct cmd_context *ctx)
Sucheta Chakrabortyca910802011-10-07 04:58:50 -07002146{
Ben Hutchings52adc492011-10-31 22:28:20 +00002147 struct ethtool_channels echannels;
Sucheta Chakrabortyca910802011-10-07 04:58:50 -07002148 int err;
2149
Ben Hutchings127f8062011-10-29 01:15:34 +01002150 if (ctx->argc != 0)
2151 exit_bad_args();
2152
Ben Hutchings743eb0b2011-10-29 02:36:48 +01002153 fprintf(stdout, "Channel parameters for %s:\n", ctx->devname);
Sucheta Chakrabortyca910802011-10-07 04:58:50 -07002154
2155 echannels.cmd = ETHTOOL_GCHANNELS;
Ben Hutchings37897ca2011-10-29 02:33:30 +01002156 err = send_ioctl(ctx, &echannels);
Sucheta Chakrabortyca910802011-10-07 04:58:50 -07002157 if (err == 0) {
Ben Hutchings52adc492011-10-31 22:28:20 +00002158 err = dump_channels(&echannels);
Sucheta Chakrabortyca910802011-10-07 04:58:50 -07002159 if (err)
2160 return err;
2161 } else {
2162 perror("Cannot get device channel parameters\n");
2163 return 1;
2164 }
2165 return 0;
2166
2167}
2168
Ben Hutchings37897ca2011-10-29 02:33:30 +01002169static int do_gcoalesce(struct cmd_context *ctx)
Jeff Garzik32c80372005-10-25 01:56:48 -04002170{
Maciej Żenczykowski0cb963e2018-12-14 17:19:23 -08002171 struct ethtool_coalesce ecoal = {};
Jeff Garzik32c80372005-10-25 01:56:48 -04002172 int err;
2173
Ben Hutchings127f8062011-10-29 01:15:34 +01002174 if (ctx->argc != 0)
2175 exit_bad_args();
2176
Ben Hutchings743eb0b2011-10-29 02:36:48 +01002177 fprintf(stdout, "Coalesce parameters for %s:\n", ctx->devname);
Jeff Garzik32c80372005-10-25 01:56:48 -04002178
2179 ecoal.cmd = ETHTOOL_GCOALESCE;
Ben Hutchings37897ca2011-10-29 02:33:30 +01002180 err = send_ioctl(ctx, &ecoal);
Jeff Garzik32c80372005-10-25 01:56:48 -04002181 if (err == 0) {
Ben Hutchings52adc492011-10-31 22:28:20 +00002182 err = dump_coalesce(&ecoal);
Jeff Garzik32c80372005-10-25 01:56:48 -04002183 if (err)
2184 return err;
2185 } else {
2186 perror("Cannot get device coalesce settings");
2187 return 82;
2188 }
2189
2190 return 0;
2191}
2192
Nicholas Nunley8fb3b262019-03-01 00:15:28 -08002193#define DECLARE_COALESCE_OPTION_VARS() \
2194 s32 coal_stats_wanted = -1; \
2195 int coal_adaptive_rx_wanted = -1; \
2196 int coal_adaptive_tx_wanted = -1; \
2197 s32 coal_sample_rate_wanted = -1; \
2198 s32 coal_pkt_rate_low_wanted = -1; \
2199 s32 coal_pkt_rate_high_wanted = -1; \
2200 s32 coal_rx_usec_wanted = -1; \
2201 s32 coal_rx_frames_wanted = -1; \
2202 s32 coal_rx_usec_irq_wanted = -1; \
2203 s32 coal_rx_frames_irq_wanted = -1; \
2204 s32 coal_tx_usec_wanted = -1; \
2205 s32 coal_tx_frames_wanted = -1; \
2206 s32 coal_tx_usec_irq_wanted = -1; \
2207 s32 coal_tx_frames_irq_wanted = -1; \
2208 s32 coal_rx_usec_low_wanted = -1; \
2209 s32 coal_rx_frames_low_wanted = -1; \
2210 s32 coal_tx_usec_low_wanted = -1; \
2211 s32 coal_tx_frames_low_wanted = -1; \
2212 s32 coal_rx_usec_high_wanted = -1; \
2213 s32 coal_rx_frames_high_wanted = -1; \
2214 s32 coal_tx_usec_high_wanted = -1; \
2215 s32 coal_tx_frames_high_wanted = -1
2216
2217#define COALESCE_CMDLINE_INFO(__ecoal) \
2218{ \
2219 { "adaptive-rx", CMDL_BOOL, &coal_adaptive_rx_wanted, \
2220 &__ecoal.use_adaptive_rx_coalesce }, \
2221 { "adaptive-tx", CMDL_BOOL, &coal_adaptive_tx_wanted, \
2222 &__ecoal.use_adaptive_tx_coalesce }, \
2223 { "sample-interval", CMDL_S32, &coal_sample_rate_wanted, \
2224 &__ecoal.rate_sample_interval }, \
2225 { "stats-block-usecs", CMDL_S32, &coal_stats_wanted, \
2226 &__ecoal.stats_block_coalesce_usecs }, \
2227 { "pkt-rate-low", CMDL_S32, &coal_pkt_rate_low_wanted, \
2228 &__ecoal.pkt_rate_low }, \
2229 { "pkt-rate-high", CMDL_S32, &coal_pkt_rate_high_wanted, \
2230 &__ecoal.pkt_rate_high }, \
2231 { "rx-usecs", CMDL_S32, &coal_rx_usec_wanted, \
2232 &__ecoal.rx_coalesce_usecs }, \
2233 { "rx-frames", CMDL_S32, &coal_rx_frames_wanted, \
2234 &__ecoal.rx_max_coalesced_frames }, \
2235 { "rx-usecs-irq", CMDL_S32, &coal_rx_usec_irq_wanted, \
2236 &__ecoal.rx_coalesce_usecs_irq }, \
2237 { "rx-frames-irq", CMDL_S32, &coal_rx_frames_irq_wanted, \
2238 &__ecoal.rx_max_coalesced_frames_irq }, \
2239 { "tx-usecs", CMDL_S32, &coal_tx_usec_wanted, \
2240 &__ecoal.tx_coalesce_usecs }, \
2241 { "tx-frames", CMDL_S32, &coal_tx_frames_wanted, \
2242 &__ecoal.tx_max_coalesced_frames }, \
2243 { "tx-usecs-irq", CMDL_S32, &coal_tx_usec_irq_wanted, \
2244 &__ecoal.tx_coalesce_usecs_irq }, \
2245 { "tx-frames-irq", CMDL_S32, &coal_tx_frames_irq_wanted, \
2246 &__ecoal.tx_max_coalesced_frames_irq }, \
2247 { "rx-usecs-low", CMDL_S32, &coal_rx_usec_low_wanted, \
2248 &__ecoal.rx_coalesce_usecs_low }, \
2249 { "rx-frames-low", CMDL_S32, &coal_rx_frames_low_wanted, \
2250 &__ecoal.rx_max_coalesced_frames_low }, \
2251 { "tx-usecs-low", CMDL_S32, &coal_tx_usec_low_wanted, \
2252 &__ecoal.tx_coalesce_usecs_low }, \
2253 { "tx-frames-low", CMDL_S32, &coal_tx_frames_low_wanted, \
2254 &__ecoal.tx_max_coalesced_frames_low }, \
2255 { "rx-usecs-high", CMDL_S32, &coal_rx_usec_high_wanted, \
2256 &__ecoal.rx_coalesce_usecs_high }, \
2257 { "rx-frames-high", CMDL_S32, &coal_rx_frames_high_wanted, \
2258 &__ecoal.rx_max_coalesced_frames_high }, \
2259 { "tx-usecs-high", CMDL_S32, &coal_tx_usec_high_wanted, \
2260 &__ecoal.tx_coalesce_usecs_high }, \
2261 { "tx-frames-high", CMDL_S32, &coal_tx_frames_high_wanted, \
2262 &__ecoal.tx_max_coalesced_frames_high }, \
2263}
2264
Ben Hutchings37897ca2011-10-29 02:33:30 +01002265static int do_scoalesce(struct cmd_context *ctx)
Jeff Garzik32c80372005-10-25 01:56:48 -04002266{
Ben Hutchings52adc492011-10-31 22:28:20 +00002267 struct ethtool_coalesce ecoal;
2268 int gcoalesce_changed = 0;
Nicholas Nunley8fb3b262019-03-01 00:15:28 -08002269 DECLARE_COALESCE_OPTION_VARS();
2270 struct cmdline_info cmdline_coalesce[] = COALESCE_CMDLINE_INFO(ecoal);
Jeff Garzik32c80372005-10-25 01:56:48 -04002271 int err, changed = 0;
2272
Ben Hutchings127f8062011-10-29 01:15:34 +01002273 parse_generic_cmdline(ctx, &gcoalesce_changed,
2274 cmdline_coalesce, ARRAY_SIZE(cmdline_coalesce));
2275
Jeff Garzik32c80372005-10-25 01:56:48 -04002276 ecoal.cmd = ETHTOOL_GCOALESCE;
Ben Hutchings37897ca2011-10-29 02:33:30 +01002277 err = send_ioctl(ctx, &ecoal);
Jeff Garzik32c80372005-10-25 01:56:48 -04002278 if (err) {
2279 perror("Cannot get device coalesce settings");
2280 return 76;
2281 }
2282
2283 do_generic_set(cmdline_coalesce, ARRAY_SIZE(cmdline_coalesce),
2284 &changed);
2285
2286 if (!changed) {
Auke Kok2b91ca42007-11-12 10:28:42 -08002287 fprintf(stderr, "no coalesce parameters changed, aborting\n");
Jeff Garzik32c80372005-10-25 01:56:48 -04002288 return 80;
2289 }
2290
2291 ecoal.cmd = ETHTOOL_SCOALESCE;
Ben Hutchings37897ca2011-10-29 02:33:30 +01002292 err = send_ioctl(ctx, &ecoal);
Jeff Garzik32c80372005-10-25 01:56:48 -04002293 if (err) {
Auke Kok2b91ca42007-11-12 10:28:42 -08002294 perror("Cannot set device coalesce parameters");
Jeff Garzik32c80372005-10-25 01:56:48 -04002295 return 81;
2296 }
2297
2298 return 0;
2299}
2300
Ben Hutchings60428042012-06-01 23:08:32 +01002301static struct feature_state *
2302get_features(struct cmd_context *ctx, const struct feature_defs *defs)
Jeff Garzik32c80372005-10-25 01:56:48 -04002303{
Ben Hutchings60428042012-06-01 23:08:32 +01002304 struct feature_state *state;
Jeff Garzik32c80372005-10-25 01:56:48 -04002305 struct ethtool_value eval;
Ben Hutchingse5c984a2011-05-13 23:25:26 +01002306 int err, allfail = 1;
Ben Hutchings5bebf1e2011-10-27 14:17:59 +01002307 u32 value;
Ben Hutchingse5c984a2011-05-13 23:25:26 +01002308 int i;
Jeff Garzik32c80372005-10-25 01:56:48 -04002309
Ben Hutchings60428042012-06-01 23:08:32 +01002310 state = malloc(sizeof(*state) +
2311 FEATURE_BITS_TO_BLOCKS(defs->n_features) *
2312 sizeof(state->features.features[0]));
2313 if (!state)
2314 return NULL;
2315
2316 state->off_flags = 0;
Jeff Garzik32c80372005-10-25 01:56:48 -04002317
Ben Hutchingse5c984a2011-05-13 23:25:26 +01002318 for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
2319 value = off_flag_def[i].value;
2320 if (!off_flag_def[i].get_cmd)
2321 continue;
2322 eval.cmd = off_flag_def[i].get_cmd;
2323 err = send_ioctl(ctx, &eval);
2324 if (err) {
Shaker Daibesd5d35d82017-09-18 10:35:38 +03002325 if (errno == EOPNOTSUPP &&
2326 off_flag_def[i].get_cmd == ETHTOOL_GUFO)
2327 continue;
2328
Ben Hutchingse5c984a2011-05-13 23:25:26 +01002329 fprintf(stderr,
2330 "Cannot get device %s settings: %m\n",
2331 off_flag_def[i].long_name);
2332 } else {
2333 if (eval.data)
Ben Hutchings60428042012-06-01 23:08:32 +01002334 state->off_flags |= value;
Ben Hutchingse5c984a2011-05-13 23:25:26 +01002335 allfail = 0;
2336 }
$B5HF#1QL@(B20fd1642006-08-22 11:40:04 +09002337 }
2338
Ben Hutchingsc36a51c2008-04-17 13:11:21 +01002339 eval.cmd = ETHTOOL_GFLAGS;
Ben Hutchings37897ca2011-10-29 02:33:30 +01002340 err = send_ioctl(ctx, &eval);
Ben Hutchingsc36a51c2008-04-17 13:11:21 +01002341 if (err) {
2342 perror("Cannot get device flags");
2343 } else {
Ben Hutchings60428042012-06-01 23:08:32 +01002344 state->off_flags |= eval.data & ETH_FLAG_EXT_MASK;
Jeff Garzik5c368cd2009-03-06 05:58:15 -05002345 allfail = 0;
2346 }
2347
Ben Hutchings60428042012-06-01 23:08:32 +01002348 if (defs->n_features) {
2349 state->features.cmd = ETHTOOL_GFEATURES;
2350 state->features.size = FEATURE_BITS_TO_BLOCKS(defs->n_features);
2351 err = send_ioctl(ctx, &state->features);
2352 if (err)
2353 perror("Cannot get device generic features");
2354 else
2355 allfail = 0;
2356 }
2357
2358 if (allfail) {
2359 free(state);
2360 return NULL;
2361 }
2362
2363 return state;
Ben Hutchings5bebf1e2011-10-27 14:17:59 +01002364}
2365
Ben Hutchings60428042012-06-01 23:08:32 +01002366static int do_gfeatures(struct cmd_context *ctx)
Ben Hutchings5bebf1e2011-10-27 14:17:59 +01002367{
Ben Hutchings60428042012-06-01 23:08:32 +01002368 struct feature_defs *defs;
2369 struct feature_state *features;
Ben Hutchings5bebf1e2011-10-27 14:17:59 +01002370
2371 if (ctx->argc != 0)
2372 exit_bad_args();
2373
Ben Hutchings60428042012-06-01 23:08:32 +01002374 defs = get_feature_defs(ctx);
Ben Hutchings1eef6772012-06-13 00:57:06 +01002375 if (!defs) {
2376 perror("Cannot get device feature names");
Ben Hutchings60428042012-06-01 23:08:32 +01002377 return 1;
Ben Hutchings1eef6772012-06-13 00:57:06 +01002378 }
Ben Hutchings5bebf1e2011-10-27 14:17:59 +01002379
Ben Hutchings60428042012-06-01 23:08:32 +01002380 fprintf(stdout, "Features for %s:\n", ctx->devname);
2381
2382 features = get_features(ctx, defs);
2383 if (!features) {
2384 fprintf(stdout, "no feature info available\n");
John W. Linville210ffb12016-09-29 15:26:55 -04002385 free(defs);
Ben Hutchings60428042012-06-01 23:08:32 +01002386 return 1;
Jeff Garzik32c80372005-10-25 01:56:48 -04002387 }
2388
Ben Hutchings60428042012-06-01 23:08:32 +01002389 dump_features(defs, features, NULL);
John W. Linville210ffb12016-09-29 15:26:55 -04002390 free(features);
2391 free(defs);
Ben Hutchings60428042012-06-01 23:08:32 +01002392 return 0;
Jeff Garzik32c80372005-10-25 01:56:48 -04002393}
2394
Ben Hutchings60428042012-06-01 23:08:32 +01002395static int do_sfeatures(struct cmd_context *ctx)
Jeff Garzik32c80372005-10-25 01:56:48 -04002396{
Ben Hutchings60428042012-06-01 23:08:32 +01002397 struct feature_defs *defs;
2398 int any_changed = 0, any_mismatch = 0;
Ben Hutchings52adc492011-10-31 22:28:20 +00002399 u32 off_flags_wanted = 0;
2400 u32 off_flags_mask = 0;
Ben Hutchings60428042012-06-01 23:08:32 +01002401 struct ethtool_sfeatures *efeatures;
2402 struct cmdline_info *cmdline_features;
2403 struct feature_state *old_state, *new_state;
Jeff Garzik32c80372005-10-25 01:56:48 -04002404 struct ethtool_value eval;
John W. Linvilleaab2c232016-09-30 14:33:35 -04002405 int err, rc;
Ben Hutchings60428042012-06-01 23:08:32 +01002406 int i, j;
Ben Hutchingse5c984a2011-05-13 23:25:26 +01002407
Ben Hutchings60428042012-06-01 23:08:32 +01002408 defs = get_feature_defs(ctx);
Ben Hutchings1eef6772012-06-13 00:57:06 +01002409 if (!defs) {
2410 perror("Cannot get device feature names");
Ben Hutchings60428042012-06-01 23:08:32 +01002411 return 1;
Ben Hutchings1eef6772012-06-13 00:57:06 +01002412 }
Ben Hutchings60428042012-06-01 23:08:32 +01002413 if (defs->n_features) {
2414 efeatures = malloc(sizeof(*efeatures) +
2415 FEATURE_BITS_TO_BLOCKS(defs->n_features) *
2416 sizeof(efeatures->features[0]));
2417 if (!efeatures) {
2418 perror("Cannot parse arguments");
John W. Linvilleaab2c232016-09-30 14:33:35 -04002419 rc = 1;
2420 goto err;
Ben Hutchings60428042012-06-01 23:08:32 +01002421 }
2422 efeatures->cmd = ETHTOOL_SFEATURES;
2423 efeatures->size = FEATURE_BITS_TO_BLOCKS(defs->n_features);
2424 memset(efeatures->features, 0,
2425 FEATURE_BITS_TO_BLOCKS(defs->n_features) *
2426 sizeof(efeatures->features[0]));
2427 } else {
2428 efeatures = NULL;
2429 }
2430
2431 /* Generate cmdline_info for legacy flags and kernel-named
2432 * features, and parse our arguments.
2433 */
2434 cmdline_features = calloc(ARRAY_SIZE(off_flag_def) + defs->n_features,
2435 sizeof(cmdline_features[0]));
2436 if (!cmdline_features) {
2437 perror("Cannot parse arguments");
John W. Linvilleaab2c232016-09-30 14:33:35 -04002438 rc = 1;
2439 goto err;
Ben Hutchings60428042012-06-01 23:08:32 +01002440 }
Ben Hutchingse5c984a2011-05-13 23:25:26 +01002441 for (i = 0; i < ARRAY_SIZE(off_flag_def); i++)
2442 flag_to_cmdline_info(off_flag_def[i].short_name,
2443 off_flag_def[i].value,
2444 &off_flags_wanted, &off_flags_mask,
Ben Hutchings60428042012-06-01 23:08:32 +01002445 &cmdline_features[i]);
2446 for (i = 0; i < defs->n_features; i++)
2447 flag_to_cmdline_info(
2448 defs->def[i].name, FEATURE_FIELD_FLAG(i),
2449 &FEATURE_WORD(efeatures->features, i, requested),
2450 &FEATURE_WORD(efeatures->features, i, valid),
2451 &cmdline_features[ARRAY_SIZE(off_flag_def) + i]);
2452 parse_generic_cmdline(ctx, &any_changed, cmdline_features,
2453 ARRAY_SIZE(off_flag_def) + defs->n_features);
2454 free(cmdline_features);
Jeff Garzik32c80372005-10-25 01:56:48 -04002455
Ben Hutchings60428042012-06-01 23:08:32 +01002456 if (!any_changed) {
2457 fprintf(stdout, "no features changed\n");
John W. Linvilleaab2c232016-09-30 14:33:35 -04002458 rc = 0;
2459 goto err;
Ben Hutchings5bebf1e2011-10-27 14:17:59 +01002460 }
2461
Ben Hutchings60428042012-06-01 23:08:32 +01002462 old_state = get_features(ctx, defs);
John W. Linvilleaab2c232016-09-30 14:33:35 -04002463 if (!old_state) {
2464 rc = 1;
2465 goto err;
2466 }
Ben Hutchings60428042012-06-01 23:08:32 +01002467
Ben Hutchingsb9827552012-07-16 21:48:39 +01002468 if (efeatures) {
2469 /* For each offload that the user specified, update any
2470 * related features that the user did not specify and that
2471 * are not fixed. Warn if all related features are fixed.
2472 */
2473 for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
2474 int fixed = 1;
Ben Hutchings60428042012-06-01 23:08:32 +01002475
Ben Hutchingsb9827552012-07-16 21:48:39 +01002476 if (!(off_flags_mask & off_flag_def[i].value))
Ben Hutchings60428042012-06-01 23:08:32 +01002477 continue;
2478
Ben Hutchingsb9827552012-07-16 21:48:39 +01002479 for (j = 0; j < defs->n_features; j++) {
2480 if (defs->def[j].off_flag_index != i ||
2481 !FEATURE_BIT_IS_SET(
2482 old_state->features.features,
2483 j, available) ||
2484 FEATURE_BIT_IS_SET(
2485 old_state->features.features,
2486 j, never_changed))
2487 continue;
2488
2489 fixed = 0;
2490 if (!FEATURE_BIT_IS_SET(efeatures->features,
2491 j, valid)) {
2492 FEATURE_BIT_SET(efeatures->features,
2493 j, valid);
2494 if (off_flags_wanted &
2495 off_flag_def[i].value)
2496 FEATURE_BIT_SET(
2497 efeatures->features,
2498 j, requested);
2499 }
Ben Hutchings60428042012-06-01 23:08:32 +01002500 }
Ben Hutchingsb9827552012-07-16 21:48:39 +01002501
2502 if (fixed)
2503 fprintf(stderr, "Cannot change %s\n",
2504 off_flag_def[i].long_name);
Ben Hutchings60428042012-06-01 23:08:32 +01002505 }
2506
Ben Hutchings60428042012-06-01 23:08:32 +01002507 err = send_ioctl(ctx, efeatures);
2508 if (err < 0) {
2509 perror("Cannot set device feature settings");
John W. Linvilleaab2c232016-09-30 14:33:35 -04002510 rc = 1;
2511 goto err;
Ben Hutchings60428042012-06-01 23:08:32 +01002512 }
2513 } else {
2514 for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
2515 if (!off_flag_def[i].set_cmd)
2516 continue;
2517 if (off_flags_mask & off_flag_def[i].value) {
2518 eval.cmd = off_flag_def[i].set_cmd;
2519 eval.data = !!(off_flags_wanted &
2520 off_flag_def[i].value);
2521 err = send_ioctl(ctx, &eval);
2522 if (err) {
2523 fprintf(stderr,
2524 "Cannot set device %s settings: %m\n",
2525 off_flag_def[i].long_name);
John W. Linvilleaab2c232016-09-30 14:33:35 -04002526 rc = 1;
2527 goto err;
Ben Hutchings60428042012-06-01 23:08:32 +01002528 }
2529 }
2530 }
2531
2532 if (off_flags_mask & ETH_FLAG_EXT_MASK) {
2533 eval.cmd = ETHTOOL_SFLAGS;
2534 eval.data = (old_state->off_flags & ~off_flags_mask &
2535 ETH_FLAG_EXT_MASK);
2536 eval.data |= off_flags_wanted & ETH_FLAG_EXT_MASK;
2537
2538 err = send_ioctl(ctx, &eval);
2539 if (err) {
2540 perror("Cannot set device flag settings");
John W. Linvilleaab2c232016-09-30 14:33:35 -04002541 rc = 92;
2542 goto err;
Ben Hutchings60428042012-06-01 23:08:32 +01002543 }
2544 }
2545 }
2546
2547 /* Compare new state with requested state */
2548 new_state = get_features(ctx, defs);
John W. Linvilleaab2c232016-09-30 14:33:35 -04002549 if (!new_state) {
2550 rc = 1;
2551 goto err;
2552 }
Ben Hutchings60428042012-06-01 23:08:32 +01002553 any_changed = new_state->off_flags != old_state->off_flags;
2554 any_mismatch = (new_state->off_flags !=
2555 ((old_state->off_flags & ~off_flags_mask) |
2556 off_flags_wanted));
2557 for (i = 0; i < FEATURE_BITS_TO_BLOCKS(defs->n_features); i++) {
2558 if (new_state->features.features[i].active !=
2559 old_state->features.features[i].active)
2560 any_changed = 1;
2561 if (new_state->features.features[i].active !=
2562 ((old_state->features.features[i].active &
2563 ~efeatures->features[i].valid) |
2564 efeatures->features[i].requested))
2565 any_mismatch = 1;
2566 }
2567 if (any_mismatch) {
2568 if (!any_changed) {
Ben Hutchings5bebf1e2011-10-27 14:17:59 +01002569 fprintf(stderr,
Ben Hutchings60428042012-06-01 23:08:32 +01002570 "Could not change any device features\n");
John W. Linvilleaab2c232016-09-30 14:33:35 -04002571 rc = 1;
2572 goto err;
Ben Hutchings5bebf1e2011-10-27 14:17:59 +01002573 }
2574 printf("Actual changes:\n");
Ben Hutchings60428042012-06-01 23:08:32 +01002575 dump_features(defs, new_state, old_state);
Jeff Garzik32c80372005-10-25 01:56:48 -04002576 }
2577
John W. Linvilleaab2c232016-09-30 14:33:35 -04002578 rc = 0;
2579
2580err:
2581 free(defs);
John W. Linvillef2378962016-09-30 14:50:26 -04002582 if (efeatures)
2583 free(efeatures);
John W. Linvilleaab2c232016-09-30 14:33:35 -04002584 return rc;
Jeff Garzik32c80372005-10-25 01:56:48 -04002585}
2586
David Decotigny33133ab2016-03-25 09:21:01 -07002587static struct ethtool_link_usettings *
2588do_ioctl_glinksettings(struct cmd_context *ctx)
2589{
2590 int err;
2591 struct {
2592 struct ethtool_link_settings req;
2593 __u32 link_mode_data[3 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32];
2594 } ecmd;
2595 struct ethtool_link_usettings *link_usettings;
2596 unsigned int u32_offs;
2597
2598 /* Handshake with kernel to determine number of words for link
2599 * mode bitmaps. When requested number of bitmap words is not
2600 * the one expected by kernel, the latter returns the integer
2601 * opposite of what it is expecting. We request length 0 below
2602 * (aka. invalid bitmap length) to get this info.
2603 */
2604 memset(&ecmd, 0, sizeof(ecmd));
2605 ecmd.req.cmd = ETHTOOL_GLINKSETTINGS;
2606 err = send_ioctl(ctx, &ecmd);
2607 if (err < 0)
2608 return NULL;
2609
2610 /* see above: we expect a strictly negative value from kernel.
2611 */
2612 if (ecmd.req.link_mode_masks_nwords >= 0
2613 || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS)
2614 return NULL;
2615
2616 /* got the real ecmd.req.link_mode_masks_nwords,
2617 * now send the real request
2618 */
2619 ecmd.req.cmd = ETHTOOL_GLINKSETTINGS;
2620 ecmd.req.link_mode_masks_nwords = -ecmd.req.link_mode_masks_nwords;
2621 err = send_ioctl(ctx, &ecmd);
2622 if (err < 0)
2623 return NULL;
2624
2625 if (ecmd.req.link_mode_masks_nwords <= 0
2626 || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS)
2627 return NULL;
2628
2629 /* Convert to usettings struct */
2630 link_usettings = calloc(1, sizeof(*link_usettings));
2631 if (link_usettings == NULL)
2632 return NULL;
2633
2634 /* keep transceiver 0 */
2635 memcpy(&link_usettings->base, &ecmd.req, sizeof(link_usettings->base));
2636
2637 /* copy link mode bitmaps */
2638 u32_offs = 0;
2639 memcpy(link_usettings->link_modes.supported,
2640 &ecmd.link_mode_data[u32_offs],
2641 4 * ecmd.req.link_mode_masks_nwords);
2642
2643 u32_offs += ecmd.req.link_mode_masks_nwords;
2644 memcpy(link_usettings->link_modes.advertising,
2645 &ecmd.link_mode_data[u32_offs],
2646 4 * ecmd.req.link_mode_masks_nwords);
2647
2648 u32_offs += ecmd.req.link_mode_masks_nwords;
2649 memcpy(link_usettings->link_modes.lp_advertising,
2650 &ecmd.link_mode_data[u32_offs],
2651 4 * ecmd.req.link_mode_masks_nwords);
2652
2653 return link_usettings;
2654}
2655
2656static int
2657do_ioctl_slinksettings(struct cmd_context *ctx,
2658 const struct ethtool_link_usettings *link_usettings)
2659{
2660 struct {
2661 struct ethtool_link_settings req;
2662 __u32 link_mode_data[3 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32];
2663 } ecmd;
2664 unsigned int u32_offs;
2665
2666 /* refuse to send ETHTOOL_SLINKSETTINGS ioctl if
2667 * link_usettings was retrieved with ETHTOOL_GSET
2668 */
2669 if (link_usettings->base.cmd != ETHTOOL_GLINKSETTINGS)
2670 return -1;
2671
2672 /* refuse to send ETHTOOL_SLINKSETTINGS ioctl if deprecated fields
2673 * were set
2674 */
2675 if (link_usettings->deprecated.transceiver)
2676 return -1;
2677
2678 if (link_usettings->base.link_mode_masks_nwords <= 0)
2679 return -1;
2680
2681 memcpy(&ecmd.req, &link_usettings->base, sizeof(ecmd.req));
2682 ecmd.req.cmd = ETHTOOL_SLINKSETTINGS;
2683
2684 /* copy link mode bitmaps */
2685 u32_offs = 0;
2686 memcpy(&ecmd.link_mode_data[u32_offs],
2687 link_usettings->link_modes.supported,
2688 4 * ecmd.req.link_mode_masks_nwords);
2689
2690 u32_offs += ecmd.req.link_mode_masks_nwords;
2691 memcpy(&ecmd.link_mode_data[u32_offs],
2692 link_usettings->link_modes.advertising,
2693 4 * ecmd.req.link_mode_masks_nwords);
2694
2695 u32_offs += ecmd.req.link_mode_masks_nwords;
2696 memcpy(&ecmd.link_mode_data[u32_offs],
2697 link_usettings->link_modes.lp_advertising,
2698 4 * ecmd.req.link_mode_masks_nwords);
2699
2700 return send_ioctl(ctx, &ecmd);
2701}
2702
2703static struct ethtool_link_usettings *
2704do_ioctl_gset(struct cmd_context *ctx)
Jeff Garzik32c80372005-10-25 01:56:48 -04002705{
2706 int err;
2707 struct ethtool_cmd ecmd;
David Decotigny33133ab2016-03-25 09:21:01 -07002708 struct ethtool_link_usettings *link_usettings;
2709
2710 memset(&ecmd, 0, sizeof(ecmd));
2711 ecmd.cmd = ETHTOOL_GSET;
2712 err = send_ioctl(ctx, &ecmd);
2713 if (err < 0)
2714 return NULL;
2715
2716 link_usettings = calloc(1, sizeof(*link_usettings));
2717 if (link_usettings == NULL)
2718 return NULL;
2719
2720 /* remember that ETHTOOL_GSET was used */
2721 link_usettings->base.cmd = ETHTOOL_GSET;
2722
2723 link_usettings->base.link_mode_masks_nwords = 1;
2724 link_usettings->link_modes.supported[0] = ecmd.supported;
2725 link_usettings->link_modes.advertising[0] = ecmd.advertising;
2726 link_usettings->link_modes.lp_advertising[0] = ecmd.lp_advertising;
2727 link_usettings->base.speed = ethtool_cmd_speed(&ecmd);
2728 link_usettings->base.duplex = ecmd.duplex;
2729 link_usettings->base.port = ecmd.port;
2730 link_usettings->base.phy_address = ecmd.phy_address;
2731 link_usettings->deprecated.transceiver = ecmd.transceiver;
2732 link_usettings->base.autoneg = ecmd.autoneg;
2733 link_usettings->base.mdio_support = ecmd.mdio_support;
2734 /* ignored (fully deprecated): maxrxpkt, maxtxpkt */
2735 link_usettings->base.eth_tp_mdix = ecmd.eth_tp_mdix;
2736 link_usettings->base.eth_tp_mdix_ctrl = ecmd.eth_tp_mdix_ctrl;
2737
2738 return link_usettings;
2739}
2740
2741static bool ethtool_link_mode_is_backward_compatible(const u32 *mask)
2742{
2743 unsigned int i;
2744
2745 for (i = 1; i < ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32; ++i)
2746 if (mask[i])
2747 return false;
2748
2749 return true;
2750}
2751
2752static int
2753do_ioctl_sset(struct cmd_context *ctx,
2754 const struct ethtool_link_usettings *link_usettings)
2755{
2756 struct ethtool_cmd ecmd;
2757
2758 /* refuse to send ETHTOOL_SSET ioctl if link_usettings was
2759 * retrieved with ETHTOOL_GLINKSETTINGS
2760 */
2761 if (link_usettings->base.cmd != ETHTOOL_GSET)
2762 return -1;
2763
2764 if (link_usettings->base.link_mode_masks_nwords <= 0)
2765 return -1;
2766
2767 /* refuse to sset if any bit > 31 is set */
2768 if (!ethtool_link_mode_is_backward_compatible(
2769 link_usettings->link_modes.supported))
2770 return -1;
2771 if (!ethtool_link_mode_is_backward_compatible(
2772 link_usettings->link_modes.advertising))
2773 return -1;
2774 if (!ethtool_link_mode_is_backward_compatible(
2775 link_usettings->link_modes.lp_advertising))
2776 return -1;
2777
2778 memset(&ecmd, 0, sizeof(ecmd));
2779 ecmd.cmd = ETHTOOL_SSET;
2780
2781 ecmd.supported = link_usettings->link_modes.supported[0];
2782 ecmd.advertising = link_usettings->link_modes.advertising[0];
2783 ecmd.lp_advertising = link_usettings->link_modes.lp_advertising[0];
2784 ethtool_cmd_speed_set(&ecmd, link_usettings->base.speed);
2785 ecmd.duplex = link_usettings->base.duplex;
2786 ecmd.port = link_usettings->base.port;
2787 ecmd.phy_address = link_usettings->base.phy_address;
2788 ecmd.transceiver = link_usettings->deprecated.transceiver;
2789 ecmd.autoneg = link_usettings->base.autoneg;
2790 ecmd.mdio_support = link_usettings->base.mdio_support;
2791 /* ignored (fully deprecated): maxrxpkt, maxtxpkt */
2792 ecmd.eth_tp_mdix = link_usettings->base.eth_tp_mdix;
2793 ecmd.eth_tp_mdix_ctrl = link_usettings->base.eth_tp_mdix_ctrl;
2794 return send_ioctl(ctx, &ecmd);
2795}
2796
2797static int do_gset(struct cmd_context *ctx)
2798{
2799 int err;
2800 struct ethtool_link_usettings *link_usettings;
Jeff Garzik32c80372005-10-25 01:56:48 -04002801 struct ethtool_wolinfo wolinfo;
2802 struct ethtool_value edata;
2803 int allfail = 1;
2804
Ben Hutchings127f8062011-10-29 01:15:34 +01002805 if (ctx->argc != 0)
2806 exit_bad_args();
2807
Ben Hutchings743eb0b2011-10-29 02:36:48 +01002808 fprintf(stdout, "Settings for %s:\n", ctx->devname);
Jeff Garzik32c80372005-10-25 01:56:48 -04002809
David Decotigny33133ab2016-03-25 09:21:01 -07002810 link_usettings = do_ioctl_glinksettings(ctx);
2811 if (link_usettings == NULL)
2812 link_usettings = do_ioctl_gset(ctx);
2813 if (link_usettings != NULL) {
2814 err = dump_link_usettings(link_usettings);
2815 free(link_usettings);
Jeff Garzik32c80372005-10-25 01:56:48 -04002816 if (err)
2817 return err;
2818 allfail = 0;
2819 } else if (errno != EOPNOTSUPP) {
2820 perror("Cannot get device settings");
2821 }
2822
2823 wolinfo.cmd = ETHTOOL_GWOL;
Ben Hutchings37897ca2011-10-29 02:33:30 +01002824 err = send_ioctl(ctx, &wolinfo);
Jeff Garzik32c80372005-10-25 01:56:48 -04002825 if (err == 0) {
2826 err = dump_wol(&wolinfo);
2827 if (err)
2828 return err;
2829 allfail = 0;
2830 } else if (errno != EOPNOTSUPP) {
2831 perror("Cannot get wake-on-lan settings");
2832 }
2833
2834 edata.cmd = ETHTOOL_GMSGLVL;
Ben Hutchings37897ca2011-10-29 02:33:30 +01002835 err = send_ioctl(ctx, &edata);
Jeff Garzik32c80372005-10-25 01:56:48 -04002836 if (err == 0) {
Ben Hutchings97d0ee22010-06-25 15:49:45 +01002837 fprintf(stdout, " Current message level: 0x%08x (%d)\n"
2838 " ",
Jeff Garzik32c80372005-10-25 01:56:48 -04002839 edata.data, edata.data);
Ben Hutchings5ec0d812011-10-31 22:50:25 +00002840 print_flags(flags_msglvl, ARRAY_SIZE(flags_msglvl),
Ben Hutchings97d0ee22010-06-25 15:49:45 +01002841 edata.data);
2842 fprintf(stdout, "\n");
Jeff Garzik32c80372005-10-25 01:56:48 -04002843 allfail = 0;
2844 } else if (errno != EOPNOTSUPP) {
2845 perror("Cannot get message level");
2846 }
2847
2848 edata.cmd = ETHTOOL_GLINK;
Ben Hutchings37897ca2011-10-29 02:33:30 +01002849 err = send_ioctl(ctx, &edata);
Jeff Garzik32c80372005-10-25 01:56:48 -04002850 if (err == 0) {
2851 fprintf(stdout, " Link detected: %s\n",
2852 edata.data ? "yes":"no");
2853 allfail = 0;
2854 } else if (errno != EOPNOTSUPP) {
2855 perror("Cannot get link status");
2856 }
2857
2858 if (allfail) {
2859 fprintf(stdout, "No data available\n");
2860 return 75;
2861 }
2862 return 0;
2863}
2864
Ben Hutchings37897ca2011-10-29 02:33:30 +01002865static int do_sset(struct cmd_context *ctx)
Jeff Garzik32c80372005-10-25 01:56:48 -04002866{
Ben Hutchings52adc492011-10-31 22:28:20 +00002867 int speed_wanted = -1;
2868 int duplex_wanted = -1;
2869 int port_wanted = -1;
Jesse Brandeburg75e67912012-08-21 01:37:16 -07002870 int mdix_wanted = -1;
Ben Hutchings52adc492011-10-31 22:28:20 +00002871 int autoneg_wanted = -1;
2872 int phyad_wanted = -1;
2873 int xcvr_wanted = -1;
David Decotigny33133ab2016-03-25 09:21:01 -07002874 u32 *full_advertising_wanted = NULL;
2875 u32 *advertising_wanted = NULL;
2876 ETHTOOL_DECLARE_LINK_MODE_MASK(mask_full_advertising_wanted);
2877 ETHTOOL_DECLARE_LINK_MODE_MASK(mask_advertising_wanted);
Ben Hutchings52adc492011-10-31 22:28:20 +00002878 int gset_changed = 0; /* did anything in GSET change? */
2879 u32 wol_wanted = 0;
2880 int wol_change = 0;
2881 u8 sopass_wanted[SOPASS_MAX];
2882 int sopass_change = 0;
2883 int gwol_changed = 0; /* did anything in GWOL change? */
2884 int msglvl_changed = 0;
2885 u32 msglvl_wanted = 0;
2886 u32 msglvl_mask = 0;
Ben Hutchings5ec0d812011-10-31 22:50:25 +00002887 struct cmdline_info cmdline_msglvl[ARRAY_SIZE(flags_msglvl)];
Ben Hutchings127f8062011-10-29 01:15:34 +01002888 int argc = ctx->argc;
2889 char **argp = ctx->argp;
2890 int i;
David Decotigny33133ab2016-03-25 09:21:01 -07002891 int err = 0;
Jeff Garzik32c80372005-10-25 01:56:48 -04002892
Ben Hutchings5ec0d812011-10-31 22:50:25 +00002893 for (i = 0; i < ARRAY_SIZE(flags_msglvl); i++)
2894 flag_to_cmdline_info(flags_msglvl[i].name,
2895 flags_msglvl[i].value,
2896 &msglvl_wanted, &msglvl_mask,
2897 &cmdline_msglvl[i]);
2898
Ben Hutchings127f8062011-10-29 01:15:34 +01002899 for (i = 0; i < argc; i++) {
2900 if (!strcmp(argp[i], "speed")) {
2901 gset_changed = 1;
2902 i += 1;
2903 if (i >= argc)
2904 exit_bad_args();
Gal Pressman5a20e542017-10-26 17:44:43 +03002905 speed_wanted = get_int(argp[i], 10);
Ben Hutchings127f8062011-10-29 01:15:34 +01002906 } else if (!strcmp(argp[i], "duplex")) {
2907 gset_changed = 1;
2908 i += 1;
2909 if (i >= argc)
2910 exit_bad_args();
2911 if (!strcmp(argp[i], "half"))
2912 duplex_wanted = DUPLEX_HALF;
2913 else if (!strcmp(argp[i], "full"))
2914 duplex_wanted = DUPLEX_FULL;
2915 else
2916 exit_bad_args();
2917 } else if (!strcmp(argp[i], "port")) {
2918 gset_changed = 1;
2919 i += 1;
2920 if (i >= argc)
2921 exit_bad_args();
2922 if (!strcmp(argp[i], "tp"))
2923 port_wanted = PORT_TP;
2924 else if (!strcmp(argp[i], "aui"))
2925 port_wanted = PORT_AUI;
2926 else if (!strcmp(argp[i], "bnc"))
2927 port_wanted = PORT_BNC;
2928 else if (!strcmp(argp[i], "mii"))
2929 port_wanted = PORT_MII;
2930 else if (!strcmp(argp[i], "fibre"))
2931 port_wanted = PORT_FIBRE;
2932 else
2933 exit_bad_args();
Jesse Brandeburg75e67912012-08-21 01:37:16 -07002934 } else if (!strcmp(argp[i], "mdix")) {
2935 gset_changed = 1;
2936 i += 1;
2937 if (i >= argc)
2938 exit_bad_args();
2939 if (!strcmp(argp[i], "auto"))
2940 mdix_wanted = ETH_TP_MDI_AUTO;
2941 else if (!strcmp(argp[i], "on"))
2942 mdix_wanted = ETH_TP_MDI_X;
2943 else if (!strcmp(argp[i], "off"))
2944 mdix_wanted = ETH_TP_MDI;
2945 else
2946 exit_bad_args();
Ben Hutchings127f8062011-10-29 01:15:34 +01002947 } else if (!strcmp(argp[i], "autoneg")) {
2948 i += 1;
2949 if (i >= argc)
2950 exit_bad_args();
2951 if (!strcmp(argp[i], "on")) {
2952 gset_changed = 1;
2953 autoneg_wanted = AUTONEG_ENABLE;
2954 } else if (!strcmp(argp[i], "off")) {
2955 gset_changed = 1;
2956 autoneg_wanted = AUTONEG_DISABLE;
2957 } else {
2958 exit_bad_args();
2959 }
2960 } else if (!strcmp(argp[i], "advertise")) {
2961 gset_changed = 1;
2962 i += 1;
2963 if (i >= argc)
2964 exit_bad_args();
David Decotigny33133ab2016-03-25 09:21:01 -07002965 if (parse_hex_u32_bitmap(
2966 argp[i],
2967 ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBITS,
2968 mask_full_advertising_wanted))
2969 exit_bad_args();
2970 full_advertising_wanted = mask_full_advertising_wanted;
Ben Hutchings127f8062011-10-29 01:15:34 +01002971 } else if (!strcmp(argp[i], "phyad")) {
2972 gset_changed = 1;
2973 i += 1;
2974 if (i >= argc)
2975 exit_bad_args();
2976 phyad_wanted = get_int(argp[i], 0);
2977 } else if (!strcmp(argp[i], "xcvr")) {
2978 gset_changed = 1;
2979 i += 1;
2980 if (i >= argc)
2981 exit_bad_args();
2982 if (!strcmp(argp[i], "internal"))
2983 xcvr_wanted = XCVR_INTERNAL;
2984 else if (!strcmp(argp[i], "external"))
2985 xcvr_wanted = XCVR_EXTERNAL;
2986 else
2987 exit_bad_args();
2988 } else if (!strcmp(argp[i], "wol")) {
2989 gwol_changed = 1;
2990 i++;
2991 if (i >= argc)
2992 exit_bad_args();
2993 if (parse_wolopts(argp[i], &wol_wanted) < 0)
2994 exit_bad_args();
2995 wol_change = 1;
2996 } else if (!strcmp(argp[i], "sopass")) {
2997 gwol_changed = 1;
2998 i++;
2999 if (i >= argc)
3000 exit_bad_args();
3001 get_mac_addr(argp[i], sopass_wanted);
3002 sopass_change = 1;
3003 } else if (!strcmp(argp[i], "msglvl")) {
3004 i++;
3005 if (i >= argc)
3006 exit_bad_args();
3007 if (isdigit((unsigned char)argp[i][0])) {
3008 msglvl_changed = 1;
3009 msglvl_mask = ~0;
3010 msglvl_wanted =
3011 get_uint_range(argp[i], 0,
3012 0xffffffff);
3013 } else {
3014 ctx->argc -= i;
3015 ctx->argp += i;
3016 parse_generic_cmdline(
3017 ctx, &msglvl_changed,
3018 cmdline_msglvl,
3019 ARRAY_SIZE(cmdline_msglvl));
3020 break;
3021 }
3022 } else {
3023 exit_bad_args();
3024 }
3025 }
3026
David Decotigny33133ab2016-03-25 09:21:01 -07003027 if (full_advertising_wanted == NULL) {
Johan Gunnarsson517f88b2012-08-24 13:32:45 +02003028 /* User didn't supply a full advertisement bitfield:
3029 * construct one from the specified speed and duplex.
3030 */
David Decotigny33133ab2016-03-25 09:21:01 -07003031 int adv_bit = -1;
3032
Ben Hutchings127f8062011-10-29 01:15:34 +01003033 if (speed_wanted == SPEED_10 && duplex_wanted == DUPLEX_HALF)
David Decotigny33133ab2016-03-25 09:21:01 -07003034 adv_bit = ETHTOOL_LINK_MODE_10baseT_Half_BIT;
Ben Hutchings127f8062011-10-29 01:15:34 +01003035 else if (speed_wanted == SPEED_10 &&
3036 duplex_wanted == DUPLEX_FULL)
David Decotigny33133ab2016-03-25 09:21:01 -07003037 adv_bit = ETHTOOL_LINK_MODE_10baseT_Full_BIT;
Ben Hutchings127f8062011-10-29 01:15:34 +01003038 else if (speed_wanted == SPEED_100 &&
3039 duplex_wanted == DUPLEX_HALF)
David Decotigny33133ab2016-03-25 09:21:01 -07003040 adv_bit = ETHTOOL_LINK_MODE_100baseT_Half_BIT;
Ben Hutchings127f8062011-10-29 01:15:34 +01003041 else if (speed_wanted == SPEED_100 &&
3042 duplex_wanted == DUPLEX_FULL)
David Decotigny33133ab2016-03-25 09:21:01 -07003043 adv_bit = ETHTOOL_LINK_MODE_100baseT_Full_BIT;
Ben Hutchings127f8062011-10-29 01:15:34 +01003044 else if (speed_wanted == SPEED_1000 &&
3045 duplex_wanted == DUPLEX_HALF)
David Decotigny33133ab2016-03-25 09:21:01 -07003046 adv_bit = ETHTOOL_LINK_MODE_1000baseT_Half_BIT;
Ben Hutchings127f8062011-10-29 01:15:34 +01003047 else if (speed_wanted == SPEED_1000 &&
3048 duplex_wanted == DUPLEX_FULL)
David Decotigny33133ab2016-03-25 09:21:01 -07003049 adv_bit = ETHTOOL_LINK_MODE_1000baseT_Full_BIT;
Ben Hutchings127f8062011-10-29 01:15:34 +01003050 else if (speed_wanted == SPEED_2500 &&
3051 duplex_wanted == DUPLEX_FULL)
David Decotigny33133ab2016-03-25 09:21:01 -07003052 adv_bit = ETHTOOL_LINK_MODE_2500baseX_Full_BIT;
Ben Hutchings127f8062011-10-29 01:15:34 +01003053 else if (speed_wanted == SPEED_10000 &&
3054 duplex_wanted == DUPLEX_FULL)
David Decotigny33133ab2016-03-25 09:21:01 -07003055 adv_bit = ETHTOOL_LINK_MODE_10000baseT_Full_BIT;
3056
3057 if (adv_bit >= 0) {
3058 advertising_wanted = mask_advertising_wanted;
3059 ethtool_link_mode_zero(advertising_wanted);
3060 ethtool_link_mode_set_bit(
3061 adv_bit, advertising_wanted);
3062 }
3063 /* otherwise: auto negotiate without forcing,
3064 * all supported speed will be assigned below
3065 */
Ben Hutchings127f8062011-10-29 01:15:34 +01003066 }
3067
Jeff Garzik32c80372005-10-25 01:56:48 -04003068 if (gset_changed) {
David Decotigny33133ab2016-03-25 09:21:01 -07003069 struct ethtool_link_usettings *link_usettings;
Jeff Garzik32c80372005-10-25 01:56:48 -04003070
David Decotigny33133ab2016-03-25 09:21:01 -07003071 link_usettings = do_ioctl_glinksettings(ctx);
3072 if (link_usettings == NULL)
3073 link_usettings = do_ioctl_gset(ctx);
3074 if (link_usettings == NULL) {
Jeff Garzik32c80372005-10-25 01:56:48 -04003075 perror("Cannot get current device settings");
David Decotigny33133ab2016-03-25 09:21:01 -07003076 err = -1;
Jeff Garzik32c80372005-10-25 01:56:48 -04003077 } else {
3078 /* Change everything the user specified. */
3079 if (speed_wanted != -1)
David Decotigny33133ab2016-03-25 09:21:01 -07003080 link_usettings->base.speed = speed_wanted;
Jeff Garzik32c80372005-10-25 01:56:48 -04003081 if (duplex_wanted != -1)
David Decotigny33133ab2016-03-25 09:21:01 -07003082 link_usettings->base.duplex = duplex_wanted;
Jeff Garzik32c80372005-10-25 01:56:48 -04003083 if (port_wanted != -1)
David Decotigny33133ab2016-03-25 09:21:01 -07003084 link_usettings->base.port = port_wanted;
Jesse Brandeburg75e67912012-08-21 01:37:16 -07003085 if (mdix_wanted != -1) {
3086 /* check driver supports MDI-X */
David Decotigny33133ab2016-03-25 09:21:01 -07003087 if (link_usettings->base.eth_tp_mdix_ctrl
3088 != ETH_TP_MDI_INVALID)
3089 link_usettings->base.eth_tp_mdix_ctrl
3090 = mdix_wanted;
Jesse Brandeburg75e67912012-08-21 01:37:16 -07003091 else
David Decotigny33133ab2016-03-25 09:21:01 -07003092 fprintf(stderr,
3093 "setting MDI not supported\n");
Jesse Brandeburg75e67912012-08-21 01:37:16 -07003094 }
Jeff Garzik32c80372005-10-25 01:56:48 -04003095 if (autoneg_wanted != -1)
David Decotigny33133ab2016-03-25 09:21:01 -07003096 link_usettings->base.autoneg = autoneg_wanted;
Jeff Garzik32c80372005-10-25 01:56:48 -04003097 if (phyad_wanted != -1)
David Decotigny33133ab2016-03-25 09:21:01 -07003098 link_usettings->base.phy_address = phyad_wanted;
Jeff Garzik32c80372005-10-25 01:56:48 -04003099 if (xcvr_wanted != -1)
David Decotigny33133ab2016-03-25 09:21:01 -07003100 link_usettings->deprecated.transceiver
3101 = xcvr_wanted;
Ben Hutchings1f4ae802011-02-17 18:51:15 +00003102 /* XXX If the user specified speed or duplex
3103 * then we should mask the advertised modes
3104 * accordingly. For now, warn that we aren't
3105 * doing that.
3106 */
3107 if ((speed_wanted != -1 || duplex_wanted != -1) &&
David Decotigny33133ab2016-03-25 09:21:01 -07003108 link_usettings->base.autoneg &&
3109 advertising_wanted == NULL) {
Ben Hutchings1f4ae802011-02-17 18:51:15 +00003110 fprintf(stderr, "Cannot advertise");
3111 if (speed_wanted >= 0)
3112 fprintf(stderr, " speed %d",
3113 speed_wanted);
3114 if (duplex_wanted >= 0)
3115 fprintf(stderr, " duplex %s",
Gal Pressman5a20e542017-10-26 17:44:43 +03003116 duplex_wanted ?
Ben Hutchings1f4ae802011-02-17 18:51:15 +00003117 "full" : "half");
3118 fprintf(stderr, "\n");
3119 }
3120 if (autoneg_wanted == AUTONEG_ENABLE &&
Michael Chan13523222016-11-22 18:55:47 -05003121 advertising_wanted == NULL &&
3122 full_advertising_wanted == NULL) {
David Decotigny33133ab2016-03-25 09:21:01 -07003123 unsigned int i;
3124
Johan Gunnarsson517f88b2012-08-24 13:32:45 +02003125 /* Auto negotiation enabled, but with
3126 * unspecified speed and duplex: enable all
3127 * supported speeds and duplexes.
3128 */
David Decotigny33133ab2016-03-25 09:21:01 -07003129 ethtool_link_mode_for_each_u32(i) {
3130 u32 sup = link_usettings->link_modes.supported[i];
3131 u32 *adv = link_usettings->link_modes.advertising + i;
3132
3133 *adv = ((*adv & ~all_advertised_modes[i])
3134 | (sup & all_advertised_modes[i]));
3135 }
Johan Gunnarsson517f88b2012-08-24 13:32:45 +02003136
3137 /* If driver supports unknown flags, we cannot
3138 * be sure that we enable all link modes.
3139 */
David Decotigny33133ab2016-03-25 09:21:01 -07003140 ethtool_link_mode_for_each_u32(i) {
3141 u32 sup = link_usettings->link_modes.supported[i];
3142
3143 if ((sup & all_advertised_flags[i]) != sup) {
3144 fprintf(stderr, "Driver supports one or more unknown flags\n");
3145 break;
3146 }
Johan Gunnarsson517f88b2012-08-24 13:32:45 +02003147 }
David Decotigny33133ab2016-03-25 09:21:01 -07003148 } else if (advertising_wanted != NULL) {
3149 unsigned int i;
3150
Johan Gunnarsson517f88b2012-08-24 13:32:45 +02003151 /* Enable all requested modes */
David Decotigny33133ab2016-03-25 09:21:01 -07003152 ethtool_link_mode_for_each_u32(i) {
3153 u32 *adv = link_usettings->link_modes.advertising + i;
3154
3155 *adv = ((*adv & ~all_advertised_modes[i])
3156 | advertising_wanted[i]);
3157 }
3158 } else if (full_advertising_wanted != NULL) {
3159 ethtool_link_mode_copy(
3160 link_usettings->link_modes.advertising,
3161 full_advertising_wanted);
Michael Chanaf2dbf72005-10-07 13:45:10 -07003162 }
Jeff Garzik32c80372005-10-25 01:56:48 -04003163
3164 /* Try to perform the update. */
David Decotigny33133ab2016-03-25 09:21:01 -07003165 if (link_usettings->base.cmd == ETHTOOL_GLINKSETTINGS)
3166 err = do_ioctl_slinksettings(ctx,
3167 link_usettings);
3168 else
3169 err = do_ioctl_sset(ctx, link_usettings);
3170 free(link_usettings);
Jeff Garzik32c80372005-10-25 01:56:48 -04003171 if (err < 0)
3172 perror("Cannot set new settings");
3173 }
3174 if (err < 0) {
3175 if (speed_wanted != -1)
3176 fprintf(stderr, " not setting speed\n");
3177 if (duplex_wanted != -1)
3178 fprintf(stderr, " not setting duplex\n");
3179 if (port_wanted != -1)
3180 fprintf(stderr, " not setting port\n");
3181 if (autoneg_wanted != -1)
3182 fprintf(stderr, " not setting autoneg\n");
3183 if (phyad_wanted != -1)
3184 fprintf(stderr, " not setting phy_address\n");
3185 if (xcvr_wanted != -1)
3186 fprintf(stderr, " not setting transceiver\n");
Jesse Brandeburg75e67912012-08-21 01:37:16 -07003187 if (mdix_wanted != -1)
3188 fprintf(stderr, " not setting mdix\n");
Jeff Garzik32c80372005-10-25 01:56:48 -04003189 }
3190 }
3191
3192 if (gwol_changed) {
3193 struct ethtool_wolinfo wol;
3194
3195 wol.cmd = ETHTOOL_GWOL;
Ben Hutchings37897ca2011-10-29 02:33:30 +01003196 err = send_ioctl(ctx, &wol);
Jeff Garzik32c80372005-10-25 01:56:48 -04003197 if (err < 0) {
3198 perror("Cannot get current wake-on-lan settings");
3199 } else {
3200 /* Change everything the user specified. */
Gal Pressman5a20e542017-10-26 17:44:43 +03003201 if (wol_change)
Jeff Garzik32c80372005-10-25 01:56:48 -04003202 wol.wolopts = wol_wanted;
Jeff Garzik32c80372005-10-25 01:56:48 -04003203 if (sopass_change) {
3204 int i;
Gal Pressman5a20e542017-10-26 17:44:43 +03003205 for (i = 0; i < SOPASS_MAX; i++)
Jeff Garzik32c80372005-10-25 01:56:48 -04003206 wol.sopass[i] = sopass_wanted[i];
Jeff Garzik32c80372005-10-25 01:56:48 -04003207 }
3208
3209 /* Try to perform the update. */
3210 wol.cmd = ETHTOOL_SWOL;
Ben Hutchings37897ca2011-10-29 02:33:30 +01003211 err = send_ioctl(ctx, &wol);
Jeff Garzik32c80372005-10-25 01:56:48 -04003212 if (err < 0)
3213 perror("Cannot set new wake-on-lan settings");
3214 }
3215 if (err < 0) {
3216 if (wol_change)
3217 fprintf(stderr, " not setting wol\n");
3218 if (sopass_change)
3219 fprintf(stderr, " not setting sopass\n");
3220 }
3221 }
3222
Ben Hutchings97d0ee22010-06-25 15:49:45 +01003223 if (msglvl_changed) {
Jeff Garzik32c80372005-10-25 01:56:48 -04003224 struct ethtool_value edata;
3225
Ben Hutchings97d0ee22010-06-25 15:49:45 +01003226 edata.cmd = ETHTOOL_GMSGLVL;
Ben Hutchings37897ca2011-10-29 02:33:30 +01003227 err = send_ioctl(ctx, &edata);
Ben Hutchings97d0ee22010-06-25 15:49:45 +01003228 if (err < 0) {
3229 perror("Cannot get msglvl");
3230 } else {
3231 edata.cmd = ETHTOOL_SMSGLVL;
Ben Hutchings967cb312010-09-23 22:48:14 +01003232 edata.data = ((edata.data & ~msglvl_mask) |
Ben Hutchings97d0ee22010-06-25 15:49:45 +01003233 msglvl_wanted);
Ben Hutchings37897ca2011-10-29 02:33:30 +01003234 err = send_ioctl(ctx, &edata);
Ben Hutchings97d0ee22010-06-25 15:49:45 +01003235 if (err < 0)
3236 perror("Cannot set new msglvl");
3237 }
Jeff Garzik32c80372005-10-25 01:56:48 -04003238 }
3239
3240 return 0;
3241}
3242
Ben Hutchings37897ca2011-10-29 02:33:30 +01003243static int do_gregs(struct cmd_context *ctx)
Jeff Garzik32c80372005-10-25 01:56:48 -04003244{
Ben Hutchings52adc492011-10-31 22:28:20 +00003245 int gregs_changed = 0;
3246 int gregs_dump_raw = 0;
3247 int gregs_dump_hex = 0;
3248 char *gregs_dump_file = NULL;
3249 struct cmdline_info cmdline_gregs[] = {
3250 { "raw", CMDL_BOOL, &gregs_dump_raw, NULL },
3251 { "hex", CMDL_BOOL, &gregs_dump_hex, NULL },
3252 { "file", CMDL_STR, &gregs_dump_file, NULL },
3253 };
Jeff Garzik32c80372005-10-25 01:56:48 -04003254 int err;
3255 struct ethtool_drvinfo drvinfo;
3256 struct ethtool_regs *regs;
3257
Ben Hutchings127f8062011-10-29 01:15:34 +01003258 parse_generic_cmdline(ctx, &gregs_changed,
3259 cmdline_gregs, ARRAY_SIZE(cmdline_gregs));
3260
Jeff Garzik32c80372005-10-25 01:56:48 -04003261 drvinfo.cmd = ETHTOOL_GDRVINFO;
Ben Hutchings37897ca2011-10-29 02:33:30 +01003262 err = send_ioctl(ctx, &drvinfo);
Jeff Garzik32c80372005-10-25 01:56:48 -04003263 if (err < 0) {
3264 perror("Cannot get driver information");
3265 return 72;
3266 }
3267
3268 regs = calloc(1, sizeof(*regs)+drvinfo.regdump_len);
3269 if (!regs) {
3270 perror("Cannot allocate memory for register dump");
3271 return 73;
3272 }
3273 regs->cmd = ETHTOOL_GREGS;
3274 regs->len = drvinfo.regdump_len;
Ben Hutchings37897ca2011-10-29 02:33:30 +01003275 err = send_ioctl(ctx, regs);
Jeff Garzik32c80372005-10-25 01:56:48 -04003276 if (err < 0) {
3277 perror("Cannot get register dump");
3278 free(regs);
3279 return 74;
3280 }
David Decotignybe4c2d02016-03-11 09:58:16 -08003281
3282 if (!gregs_dump_raw && gregs_dump_file != NULL) {
3283 /* overwrite reg values from file dump */
3284 FILE *f = fopen(gregs_dump_file, "r");
Ivan Vecerab610b272018-06-08 11:20:08 +02003285 struct ethtool_regs *nregs;
David Decotignybe4c2d02016-03-11 09:58:16 -08003286 struct stat st;
3287 size_t nread;
3288
3289 if (!f || fstat(fileno(f), &st) < 0) {
3290 fprintf(stderr, "Can't open '%s': %s\n",
3291 gregs_dump_file, strerror(errno));
Ivan Vecerab610b272018-06-08 11:20:08 +02003292 if (f)
3293 fclose(f);
David Decotignybe4c2d02016-03-11 09:58:16 -08003294 free(regs);
3295 return 75;
3296 }
3297
Ivan Vecerab610b272018-06-08 11:20:08 +02003298 nregs = realloc(regs, sizeof(*regs) + st.st_size);
3299 if (!nregs) {
3300 perror("Cannot allocate memory for register dump");
3301 free(regs); /* was not freed by realloc */
3302 return 73;
3303 }
3304 regs = nregs;
David Decotignybe4c2d02016-03-11 09:58:16 -08003305 regs->len = st.st_size;
3306 nread = fread(regs->data, regs->len, 1, f);
3307 fclose(f);
3308 if (nread != 1) {
3309 free(regs);
3310 return 75;
3311 }
Gal Pressman5a20e542017-10-26 17:44:43 +03003312 }
David Decotignybe4c2d02016-03-11 09:58:16 -08003313
3314 if (dump_regs(gregs_dump_raw, gregs_dump_hex,
Ben Hutchings52adc492011-10-31 22:28:20 +00003315 &drvinfo, regs) < 0) {
Ben Hutchings963faa02012-10-10 22:19:15 +01003316 fprintf(stderr, "Cannot dump registers\n");
Jeff Garzik32c80372005-10-25 01:56:48 -04003317 free(regs);
3318 return 75;
3319 }
3320 free(regs);
3321
3322 return 0;
3323}
3324
Ben Hutchings37897ca2011-10-29 02:33:30 +01003325static int do_nway_rst(struct cmd_context *ctx)
Jeff Garzik32c80372005-10-25 01:56:48 -04003326{
3327 struct ethtool_value edata;
3328 int err;
3329
Ben Hutchings127f8062011-10-29 01:15:34 +01003330 if (ctx->argc != 0)
3331 exit_bad_args();
3332
Jeff Garzik32c80372005-10-25 01:56:48 -04003333 edata.cmd = ETHTOOL_NWAY_RST;
Ben Hutchings37897ca2011-10-29 02:33:30 +01003334 err = send_ioctl(ctx, &edata);
Jeff Garzik32c80372005-10-25 01:56:48 -04003335 if (err < 0)
3336 perror("Cannot restart autonegotiation");
3337
3338 return err;
3339}
3340
Ben Hutchings37897ca2011-10-29 02:33:30 +01003341static int do_geeprom(struct cmd_context *ctx)
Jeff Garzik32c80372005-10-25 01:56:48 -04003342{
Ben Hutchings52adc492011-10-31 22:28:20 +00003343 int geeprom_changed = 0;
3344 int geeprom_dump_raw = 0;
3345 u32 geeprom_offset = 0;
3346 u32 geeprom_length = -1;
3347 struct cmdline_info cmdline_geeprom[] = {
3348 { "offset", CMDL_U32, &geeprom_offset, NULL },
3349 { "length", CMDL_U32, &geeprom_length, NULL },
3350 { "raw", CMDL_BOOL, &geeprom_dump_raw, NULL },
3351 };
Jeff Garzik32c80372005-10-25 01:56:48 -04003352 int err;
3353 struct ethtool_drvinfo drvinfo;
3354 struct ethtool_eeprom *eeprom;
3355
Ben Hutchings127f8062011-10-29 01:15:34 +01003356 parse_generic_cmdline(ctx, &geeprom_changed,
3357 cmdline_geeprom, ARRAY_SIZE(cmdline_geeprom));
3358
Jeff Garzik32c80372005-10-25 01:56:48 -04003359 drvinfo.cmd = ETHTOOL_GDRVINFO;
Ben Hutchings37897ca2011-10-29 02:33:30 +01003360 err = send_ioctl(ctx, &drvinfo);
Jeff Garzik32c80372005-10-25 01:56:48 -04003361 if (err < 0) {
3362 perror("Cannot get driver information");
3363 return 74;
3364 }
3365
Ben Hutchingsbec03632011-06-06 11:35:19 +01003366 if (geeprom_length == -1)
Jeff Garzik32c80372005-10-25 01:56:48 -04003367 geeprom_length = drvinfo.eedump_len;
3368
3369 if (drvinfo.eedump_len < geeprom_offset + geeprom_length)
3370 geeprom_length = drvinfo.eedump_len - geeprom_offset;
3371
3372 eeprom = calloc(1, sizeof(*eeprom)+geeprom_length);
3373 if (!eeprom) {
3374 perror("Cannot allocate memory for EEPROM data");
3375 return 75;
3376 }
3377 eeprom->cmd = ETHTOOL_GEEPROM;
3378 eeprom->len = geeprom_length;
3379 eeprom->offset = geeprom_offset;
Ben Hutchings37897ca2011-10-29 02:33:30 +01003380 err = send_ioctl(ctx, eeprom);
Jeff Garzik32c80372005-10-25 01:56:48 -04003381 if (err < 0) {
3382 perror("Cannot get EEPROM data");
3383 free(eeprom);
3384 return 74;
3385 }
Ben Hutchings52adc492011-10-31 22:28:20 +00003386 err = dump_eeprom(geeprom_dump_raw, &drvinfo, eeprom);
Jeff Garzik32c80372005-10-25 01:56:48 -04003387 free(eeprom);
3388
3389 return err;
3390}
3391
Ben Hutchings37897ca2011-10-29 02:33:30 +01003392static int do_seeprom(struct cmd_context *ctx)
Jeff Garzik32c80372005-10-25 01:56:48 -04003393{
Ben Hutchings52adc492011-10-31 22:28:20 +00003394 int seeprom_changed = 0;
3395 u32 seeprom_magic = 0;
3396 u32 seeprom_length = -1;
3397 u32 seeprom_offset = 0;
3398 u8 seeprom_value = 0;
3399 int seeprom_value_seen = 0;
3400 struct cmdline_info cmdline_seeprom[] = {
3401 { "magic", CMDL_U32, &seeprom_magic, NULL },
3402 { "offset", CMDL_U32, &seeprom_offset, NULL },
3403 { "length", CMDL_U32, &seeprom_length, NULL },
3404 { "value", CMDL_U8, &seeprom_value, NULL,
3405 0, &seeprom_value_seen },
3406 };
Jeff Garzik32c80372005-10-25 01:56:48 -04003407 int err;
Mandeep Singh Baines2121eea2008-06-18 10:38:02 -07003408 struct ethtool_drvinfo drvinfo;
3409 struct ethtool_eeprom *eeprom;
Jeff Garzik32c80372005-10-25 01:56:48 -04003410
Ben Hutchings127f8062011-10-29 01:15:34 +01003411 parse_generic_cmdline(ctx, &seeprom_changed,
3412 cmdline_seeprom, ARRAY_SIZE(cmdline_seeprom));
3413
Mandeep Singh Baines2121eea2008-06-18 10:38:02 -07003414 drvinfo.cmd = ETHTOOL_GDRVINFO;
Ben Hutchings37897ca2011-10-29 02:33:30 +01003415 err = send_ioctl(ctx, &drvinfo);
Mandeep Singh Baines2121eea2008-06-18 10:38:02 -07003416 if (err < 0) {
3417 perror("Cannot get driver information");
3418 return 74;
3419 }
3420
Ben Hutchingsbec03632011-06-06 11:35:19 +01003421 if (seeprom_value_seen)
Mandeep Singh Baines2121eea2008-06-18 10:38:02 -07003422 seeprom_length = 1;
3423
Ben Hutchingsbec03632011-06-06 11:35:19 +01003424 if (seeprom_length == -1)
Mandeep Singh Baines2121eea2008-06-18 10:38:02 -07003425 seeprom_length = drvinfo.eedump_len;
3426
David Decotignyb03c8b42016-03-11 09:58:17 -08003427 if (drvinfo.eedump_len < seeprom_offset + seeprom_length) {
3428 fprintf(stderr, "offset & length out of bounds\n");
3429 return 1;
3430 }
Mandeep Singh Baines2121eea2008-06-18 10:38:02 -07003431
3432 eeprom = calloc(1, sizeof(*eeprom)+seeprom_length);
3433 if (!eeprom) {
3434 perror("Cannot allocate memory for EEPROM data");
3435 return 75;
3436 }
3437
3438 eeprom->cmd = ETHTOOL_SEEPROM;
3439 eeprom->len = seeprom_length;
3440 eeprom->offset = seeprom_offset;
3441 eeprom->magic = seeprom_magic;
3442 eeprom->data[0] = seeprom_value;
3443
3444 /* Multi-byte write: read input from stdin */
David Decotignyb03c8b42016-03-11 09:58:17 -08003445 if (!seeprom_value_seen) {
3446 if (fread(eeprom->data, eeprom->len, 1, stdin) != 1) {
3447 fprintf(stderr, "not enough data from stdin\n");
3448 free(eeprom);
3449 return 75;
3450 }
3451 if ((fgetc(stdin) != EOF) || !feof(stdin)) {
3452 fprintf(stderr, "too much data from stdin\n");
3453 free(eeprom);
3454 return 75;
3455 }
3456 }
Mandeep Singh Baines2121eea2008-06-18 10:38:02 -07003457
Ben Hutchings37897ca2011-10-29 02:33:30 +01003458 err = send_ioctl(ctx, eeprom);
Jeff Garzik32c80372005-10-25 01:56:48 -04003459 if (err < 0) {
3460 perror("Cannot set EEPROM data");
Mandeep Singh Baines2121eea2008-06-18 10:38:02 -07003461 err = 87;
Jeff Garzik32c80372005-10-25 01:56:48 -04003462 }
Mandeep Singh Baines2121eea2008-06-18 10:38:02 -07003463 free(eeprom);
Jeff Garzik32c80372005-10-25 01:56:48 -04003464
3465 return err;
3466}
3467
Ben Hutchings37897ca2011-10-29 02:33:30 +01003468static int do_test(struct cmd_context *ctx)
Jeff Garzik32c80372005-10-25 01:56:48 -04003469{
Ben Hutchings52adc492011-10-31 22:28:20 +00003470 enum {
Gal Pressman5a20e542017-10-26 17:44:43 +03003471 ONLINE = 0,
Ben Hutchings52adc492011-10-31 22:28:20 +00003472 OFFLINE,
3473 EXTERNAL_LB,
3474 } test_type;
Jeff Garzik32c80372005-10-25 01:56:48 -04003475 int err;
Jeff Garzik32c80372005-10-25 01:56:48 -04003476 struct ethtool_test *test;
3477 struct ethtool_gstrings *strings;
3478
Ben Hutchings127f8062011-10-29 01:15:34 +01003479 if (ctx->argc > 1)
3480 exit_bad_args();
3481 if (ctx->argc == 1) {
Gal Pressman5a20e542017-10-26 17:44:43 +03003482 if (!strcmp(ctx->argp[0], "online"))
Ben Hutchings127f8062011-10-29 01:15:34 +01003483 test_type = ONLINE;
Gal Pressman5a20e542017-10-26 17:44:43 +03003484 else if (!strcmp(*ctx->argp, "offline"))
Ben Hutchings127f8062011-10-29 01:15:34 +01003485 test_type = OFFLINE;
Gal Pressman5a20e542017-10-26 17:44:43 +03003486 else if (!strcmp(*ctx->argp, "external_lb"))
Ben Hutchings127f8062011-10-29 01:15:34 +01003487 test_type = EXTERNAL_LB;
Gal Pressman5a20e542017-10-26 17:44:43 +03003488 else
Ben Hutchings127f8062011-10-29 01:15:34 +01003489 exit_bad_args();
Ben Hutchings52adc492011-10-31 22:28:20 +00003490 } else {
3491 test_type = OFFLINE;
Ben Hutchings127f8062011-10-29 01:15:34 +01003492 }
3493
Ben Hutchingsd7c4a372011-11-30 01:46:36 +00003494 strings = get_stringset(ctx, ETH_SS_TEST,
Ben Hutchingsa983fb72012-06-14 20:34:35 +01003495 offsetof(struct ethtool_drvinfo, testinfo_len),
3496 1);
Ben Hutchingsd7c4a372011-11-30 01:46:36 +00003497 if (!strings) {
3498 perror("Cannot get strings");
3499 return 74;
Jeff Garzik32c80372005-10-25 01:56:48 -04003500 }
3501
Ben Hutchingsd7c4a372011-11-30 01:46:36 +00003502 test = calloc(1, sizeof(*test) + strings->len * sizeof(u64));
Jeff Garzik32c80372005-10-25 01:56:48 -04003503 if (!test) {
3504 perror("Cannot allocate memory for test info");
Ben Hutchingsd7c4a372011-11-30 01:46:36 +00003505 free(strings);
Jeff Garzik32c80372005-10-25 01:56:48 -04003506 return 73;
3507 }
Ben Hutchingsd7c4a372011-11-30 01:46:36 +00003508 memset(test->data, 0, strings->len * sizeof(u64));
Jeff Garzik32c80372005-10-25 01:56:48 -04003509 test->cmd = ETHTOOL_TEST;
Ben Hutchingsd7c4a372011-11-30 01:46:36 +00003510 test->len = strings->len;
Sucheta Chakrabortybeceb092011-09-20 03:31:34 -07003511 if (test_type == EXTERNAL_LB)
3512 test->flags = (ETH_TEST_FL_OFFLINE | ETH_TEST_FL_EXTERNAL_LB);
3513 else if (test_type == OFFLINE)
Jeff Garzik32c80372005-10-25 01:56:48 -04003514 test->flags = ETH_TEST_FL_OFFLINE;
3515 else
3516 test->flags = 0;
Ben Hutchings37897ca2011-10-29 02:33:30 +01003517 err = send_ioctl(ctx, test);
Jeff Garzik32c80372005-10-25 01:56:48 -04003518 if (err < 0) {
3519 perror("Cannot test");
Gal Pressman5a20e542017-10-26 17:44:43 +03003520 free(test);
Ben Hutchingsd7c4a372011-11-30 01:46:36 +00003521 free(strings);
Jeff Garzik32c80372005-10-25 01:56:48 -04003522 return 74;
3523 }
3524
Ben Hutchingsd7c4a372011-11-30 01:46:36 +00003525 err = dump_test(test, strings);
Jeff Garzik32c80372005-10-25 01:56:48 -04003526 free(test);
3527 free(strings);
3528
3529 return err;
3530}
3531
Ben Hutchings37897ca2011-10-29 02:33:30 +01003532static int do_phys_id(struct cmd_context *ctx)
Jeff Garzik32c80372005-10-25 01:56:48 -04003533{
3534 int err;
3535 struct ethtool_value edata;
Ben Hutchings52adc492011-10-31 22:28:20 +00003536 int phys_id_time;
Jeff Garzik32c80372005-10-25 01:56:48 -04003537
Ben Hutchings127f8062011-10-29 01:15:34 +01003538 if (ctx->argc > 1)
3539 exit_bad_args();
3540 if (ctx->argc == 1)
3541 phys_id_time = get_int(*ctx->argp, 0);
Ben Hutchings52adc492011-10-31 22:28:20 +00003542 else
3543 phys_id_time = 0;
Ben Hutchings127f8062011-10-29 01:15:34 +01003544
Jeff Garzik32c80372005-10-25 01:56:48 -04003545 edata.cmd = ETHTOOL_PHYS_ID;
3546 edata.data = phys_id_time;
Ben Hutchings37897ca2011-10-29 02:33:30 +01003547 err = send_ioctl(ctx, &edata);
Jeff Garzik32c80372005-10-25 01:56:48 -04003548 if (err < 0)
3549 perror("Cannot identify NIC");
3550
3551 return err;
3552}
3553
Ben Hutchings395d8302016-03-13 15:56:41 +00003554static int do_gstats(struct cmd_context *ctx, int cmd, int stringset,
3555 const char *name)
Jeff Garzik32c80372005-10-25 01:56:48 -04003556{
Jeff Garzik32c80372005-10-25 01:56:48 -04003557 struct ethtool_gstrings *strings;
3558 struct ethtool_stats *stats;
Ben Hutchingsd7c4a372011-11-30 01:46:36 +00003559 unsigned int n_stats, sz_stats, i;
Jeff Garzik32c80372005-10-25 01:56:48 -04003560 int err;
3561
Ben Hutchings127f8062011-10-29 01:15:34 +01003562 if (ctx->argc != 0)
3563 exit_bad_args();
3564
Ben Hutchings395d8302016-03-13 15:56:41 +00003565 strings = get_stringset(ctx, stringset,
Ben Hutchingsa983fb72012-06-14 20:34:35 +01003566 offsetof(struct ethtool_drvinfo, n_stats),
3567 0);
Ben Hutchingsd7c4a372011-11-30 01:46:36 +00003568 if (!strings) {
3569 perror("Cannot get stats strings information");
3570 return 96;
Jeff Garzik32c80372005-10-25 01:56:48 -04003571 }
3572
Ben Hutchingsd7c4a372011-11-30 01:46:36 +00003573 n_stats = strings->len;
Jeff Garzik32c80372005-10-25 01:56:48 -04003574 if (n_stats < 1) {
3575 fprintf(stderr, "no stats available\n");
Ben Hutchingsd7c4a372011-11-30 01:46:36 +00003576 free(strings);
Jeff Garzik32c80372005-10-25 01:56:48 -04003577 return 94;
3578 }
3579
Jeff Garzik32c80372005-10-25 01:56:48 -04003580 sz_stats = n_stats * sizeof(u64);
3581
Jeff Garzik32c80372005-10-25 01:56:48 -04003582 stats = calloc(1, sz_stats + sizeof(struct ethtool_stats));
Ben Hutchingsd7c4a372011-11-30 01:46:36 +00003583 if (!stats) {
Jeff Garzik32c80372005-10-25 01:56:48 -04003584 fprintf(stderr, "no memory available\n");
Jeff Garzik32c80372005-10-25 01:56:48 -04003585 free(strings);
Ben Hutchingsd7c4a372011-11-30 01:46:36 +00003586 return 95;
Jeff Garzik32c80372005-10-25 01:56:48 -04003587 }
3588
Ben Hutchings395d8302016-03-13 15:56:41 +00003589 stats->cmd = cmd;
Jeff Garzik32c80372005-10-25 01:56:48 -04003590 stats->n_stats = n_stats;
Ben Hutchings37897ca2011-10-29 02:33:30 +01003591 err = send_ioctl(ctx, stats);
Jeff Garzik32c80372005-10-25 01:56:48 -04003592 if (err < 0) {
3593 perror("Cannot get stats information");
3594 free(strings);
3595 free(stats);
3596 return 97;
3597 }
3598
3599 /* todo - pretty-print the strings per-driver */
Ben Hutchings395d8302016-03-13 15:56:41 +00003600 fprintf(stdout, "%s statistics:\n", name);
Jeff Garzik32c80372005-10-25 01:56:48 -04003601 for (i = 0; i < n_stats; i++) {
Stephen Hemminger77644302007-01-11 15:36:10 -08003602 fprintf(stdout, " %.*s: %llu\n",
Jeff Garzikba2f54b2007-07-26 13:24:59 -04003603 ETH_GSTRING_LEN,
Stephen Hemminger77644302007-01-11 15:36:10 -08003604 &strings->data[i * ETH_GSTRING_LEN],
3605 stats->data[i]);
Jeff Garzik32c80372005-10-25 01:56:48 -04003606 }
3607 free(strings);
3608 free(stats);
3609
3610 return 0;
3611}
3612
Ben Hutchings395d8302016-03-13 15:56:41 +00003613static int do_gnicstats(struct cmd_context *ctx)
3614{
3615 return do_gstats(ctx, ETHTOOL_GSTATS, ETH_SS_STATS, "NIC");
3616}
3617
Andrew Lunn8b4b8232015-12-23 12:58:31 +01003618static int do_gphystats(struct cmd_context *ctx)
3619{
Ben Hutchings395d8302016-03-13 15:56:41 +00003620 return do_gstats(ctx, ETHTOOL_GPHYSTATS, ETH_SS_PHY_STATS, "PHY");
Andrew Lunn8b4b8232015-12-23 12:58:31 +01003621}
3622
Ben Hutchings52e837f2012-01-21 00:35:55 +00003623static int do_srxntuple(struct cmd_context *ctx,
3624 struct ethtool_rx_flow_spec *rx_rule_fs);
Santwona Behera1bd87122008-06-27 17:06:20 -07003625
Ben Hutchings37897ca2011-10-29 02:33:30 +01003626static int do_srxclass(struct cmd_context *ctx)
Santwona Behera1bd87122008-06-27 17:06:20 -07003627{
3628 int err;
3629
Ben Hutchings52e837f2012-01-21 00:35:55 +00003630 if (ctx->argc < 2)
3631 exit_bad_args();
3632
Edward Creef5d55b92018-03-09 15:04:12 +00003633 if (!strcmp(ctx->argp[0], "rx-flow-hash")) {
Ben Hutchings52adc492011-10-31 22:28:20 +00003634 int rx_fhash_set;
3635 u32 rx_fhash_val;
3636 struct ethtool_rxnfc nfccmd;
Edward Creef5d55b92018-03-09 15:04:12 +00003637 bool flow_rss = false;
Ben Hutchings52adc492011-10-31 22:28:20 +00003638
Edward Creef5d55b92018-03-09 15:04:12 +00003639 if (ctx->argc == 5) {
3640 if (strcmp(ctx->argp[3], "context"))
3641 exit_bad_args();
3642 flow_rss = true;
3643 nfccmd.rss_context = get_u32(ctx->argp[4], 0);
3644 } else if (ctx->argc != 3) {
3645 exit_bad_args();
3646 }
Ben Hutchings127f8062011-10-29 01:15:34 +01003647 rx_fhash_set = rxflow_str_to_type(ctx->argp[1]);
3648 if (!rx_fhash_set)
3649 exit_bad_args();
3650 if (parse_rxfhashopts(ctx->argp[2], &rx_fhash_val) < 0)
3651 exit_bad_args();
Santwona Behera1bd87122008-06-27 17:06:20 -07003652
3653 nfccmd.cmd = ETHTOOL_SRXFH;
3654 nfccmd.flow_type = rx_fhash_set;
3655 nfccmd.data = rx_fhash_val;
Edward Creef5d55b92018-03-09 15:04:12 +00003656 if (flow_rss)
3657 nfccmd.flow_type |= FLOW_RSS;
Santwona Behera1bd87122008-06-27 17:06:20 -07003658
Ben Hutchings37897ca2011-10-29 02:33:30 +01003659 err = send_ioctl(ctx, &nfccmd);
Santwona Behera1bd87122008-06-27 17:06:20 -07003660 if (err < 0)
3661 perror("Cannot change RX network flow hashing options");
Gal Pressman5a20e542017-10-26 17:44:43 +03003662 } else if (!strcmp(ctx->argp[0], "flow-type")) {
Ben Hutchings52e837f2012-01-21 00:35:55 +00003663 struct ethtool_rx_flow_spec rx_rule_fs;
Edward Creef5d55b92018-03-09 15:04:12 +00003664 __u32 rss_context = 0;
Ben Hutchings52e837f2012-01-21 00:35:55 +00003665
3666 ctx->argc--;
3667 ctx->argp++;
Edward Creef5d55b92018-03-09 15:04:12 +00003668 if (rxclass_parse_ruleopts(ctx, &rx_rule_fs, &rss_context) < 0)
Ben Hutchings52e837f2012-01-21 00:35:55 +00003669 exit_bad_args();
3670
3671 /* attempt to add rule via N-tuple specifier */
3672 err = do_srxntuple(ctx, &rx_rule_fs);
3673 if (!err)
3674 return 0;
3675
3676 /* attempt to add rule via network flow classifier */
Edward Creef5d55b92018-03-09 15:04:12 +00003677 err = rxclass_rule_ins(ctx, &rx_rule_fs, rss_context);
Ben Hutchings52e837f2012-01-21 00:35:55 +00003678 if (err < 0) {
3679 fprintf(stderr, "Cannot insert"
3680 " classification rule\n");
3681 return 1;
3682 }
3683 } else if (!strcmp(ctx->argp[0], "delete")) {
3684 int rx_class_rule_del =
3685 get_uint_range(ctx->argp[1], 0, INT_MAX);
3686
3687 err = rxclass_rule_del(ctx, rx_class_rule_del);
3688
3689 if (err < 0) {
3690 fprintf(stderr, "Cannot delete"
3691 " classification rule\n");
3692 return 1;
3693 }
Ben Hutchings127f8062011-10-29 01:15:34 +01003694 } else {
3695 exit_bad_args();
Santwona Behera1bd87122008-06-27 17:06:20 -07003696 }
3697
3698 return 0;
3699}
3700
Ben Hutchings37897ca2011-10-29 02:33:30 +01003701static int do_grxclass(struct cmd_context *ctx)
Santwona Behera1bd87122008-06-27 17:06:20 -07003702{
Ben Hutchings127f8062011-10-29 01:15:34 +01003703 struct ethtool_rxnfc nfccmd;
Santwona Behera1bd87122008-06-27 17:06:20 -07003704 int err;
3705
Edward Creef5d55b92018-03-09 15:04:12 +00003706 if (ctx->argc > 0 && !strcmp(ctx->argp[0], "rx-flow-hash")) {
Ben Hutchings52adc492011-10-31 22:28:20 +00003707 int rx_fhash_get;
Edward Creef5d55b92018-03-09 15:04:12 +00003708 bool flow_rss = false;
3709
3710 if (ctx->argc == 4) {
3711 if (strcmp(ctx->argp[2], "context"))
3712 exit_bad_args();
3713 flow_rss = true;
3714 nfccmd.rss_context = get_u32(ctx->argp[3], 0);
3715 } else if (ctx->argc != 2) {
3716 exit_bad_args();
3717 }
Ben Hutchings52adc492011-10-31 22:28:20 +00003718
Ben Hutchings127f8062011-10-29 01:15:34 +01003719 rx_fhash_get = rxflow_str_to_type(ctx->argp[1]);
3720 if (!rx_fhash_get)
3721 exit_bad_args();
Santwona Behera1bd87122008-06-27 17:06:20 -07003722
3723 nfccmd.cmd = ETHTOOL_GRXFH;
3724 nfccmd.flow_type = rx_fhash_get;
Edward Creef5d55b92018-03-09 15:04:12 +00003725 if (flow_rss)
3726 nfccmd.flow_type |= FLOW_RSS;
Ben Hutchings37897ca2011-10-29 02:33:30 +01003727 err = send_ioctl(ctx, &nfccmd);
Edward Creef5d55b92018-03-09 15:04:12 +00003728 if (err < 0) {
Santwona Behera1bd87122008-06-27 17:06:20 -07003729 perror("Cannot get RX network flow hashing options");
Edward Creef5d55b92018-03-09 15:04:12 +00003730 } else {
3731 if (flow_rss)
3732 fprintf(stdout, "For RSS context %u:\n",
3733 nfccmd.rss_context);
Santwona Behera1bd87122008-06-27 17:06:20 -07003734 dump_rxfhash(rx_fhash_get, nfccmd.data);
Edward Creef5d55b92018-03-09 15:04:12 +00003735 }
Ben Hutchings52e837f2012-01-21 00:35:55 +00003736 } else if (ctx->argc == 2 && !strcmp(ctx->argp[0], "rule")) {
3737 int rx_class_rule_get =
3738 get_uint_range(ctx->argp[1], 0, INT_MAX);
3739
3740 err = rxclass_rule_get(ctx, rx_class_rule_get);
3741 if (err < 0)
3742 fprintf(stderr, "Cannot get RX classification rule\n");
3743 } else if (ctx->argc == 0) {
3744 nfccmd.cmd = ETHTOOL_GRXRINGS;
3745 err = send_ioctl(ctx, &nfccmd);
3746 if (err < 0)
3747 perror("Cannot get RX rings");
3748 else
3749 fprintf(stdout, "%d RX rings available\n",
3750 (int)nfccmd.data);
3751
3752 err = rxclass_rule_getall(ctx);
3753 if (err < 0)
3754 fprintf(stderr, "RX classification rule retrieval failed\n");
3755
Ben Hutchings127f8062011-10-29 01:15:34 +01003756 } else {
3757 exit_bad_args();
Santwona Behera1bd87122008-06-27 17:06:20 -07003758 }
3759
Ben Hutchings52e837f2012-01-21 00:35:55 +00003760 return err ? 1 : 0;
Santwona Behera1bd87122008-06-27 17:06:20 -07003761}
3762
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303763static void print_indir_table(struct cmd_context *ctx,
3764 struct ethtool_rxnfc *ring_count,
3765 u32 indir_size, u32 *indir)
Ben Hutchings048038f2010-06-30 16:13:12 +01003766{
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303767 u32 i;
3768
3769 printf("RX flow hash indirection table for %s with %llu RX ring(s):\n",
3770 ctx->devname, ring_count->data);
3771
3772 if (!indir_size)
3773 printf("Operation not supported\n");
3774
3775 for (i = 0; i < indir_size; i++) {
3776 if (i % 8 == 0)
3777 printf("%5u: ", i);
3778 printf(" %5u", indir[i]);
Ben Hutchings530765b2015-04-05 03:00:52 +01003779 if (i % 8 == 7 || i == indir_size - 1)
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303780 fputc('\n', stdout);
3781 }
3782}
3783
3784static int do_grxfhindir(struct cmd_context *ctx,
3785 struct ethtool_rxnfc *ring_count)
3786{
Ben Hutchings048038f2010-06-30 16:13:12 +01003787 struct ethtool_rxfh_indir indir_head;
3788 struct ethtool_rxfh_indir *indir;
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303789 int err;
3790
3791 indir_head.cmd = ETHTOOL_GRXFHINDIR;
3792 indir_head.size = 0;
3793 err = send_ioctl(ctx, &indir_head);
3794 if (err < 0) {
3795 perror("Cannot get RX flow hash indirection table size");
3796 return 1;
3797 }
3798
3799 indir = malloc(sizeof(*indir) +
3800 indir_head.size * sizeof(*indir->ring_index));
3801 if (!indir) {
3802 perror("Cannot allocate memory for indirection table");
3803 return 1;
3804 }
3805
3806 indir->cmd = ETHTOOL_GRXFHINDIR;
3807 indir->size = indir_head.size;
3808 err = send_ioctl(ctx, indir);
3809 if (err < 0) {
3810 perror("Cannot get RX flow hash indirection table");
3811 free(indir);
3812 return 1;
3813 }
3814
3815 print_indir_table(ctx, ring_count, indir->size, indir->ring_index);
3816
3817 free(indir);
3818 return 0;
3819}
3820
3821static int do_grxfh(struct cmd_context *ctx)
3822{
Gal Pressmanb888f352017-03-08 16:03:51 +02003823 struct ethtool_gstrings *hfuncs = NULL;
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303824 struct ethtool_rxfh rss_head = {0};
3825 struct ethtool_rxnfc ring_count;
3826 struct ethtool_rxfh *rss;
Edward Creef5d55b92018-03-09 15:04:12 +00003827 u32 rss_context = 0;
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303828 u32 i, indir_bytes;
Edward Creef5d55b92018-03-09 15:04:12 +00003829 int arg_num = 0;
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303830 char *hkey;
Ben Hutchings048038f2010-06-30 16:13:12 +01003831 int err;
3832
Edward Creef5d55b92018-03-09 15:04:12 +00003833 while (arg_num < ctx->argc) {
3834 if (!strcmp(ctx->argp[arg_num], "context")) {
3835 ++arg_num;
3836 rss_context = get_int_range(ctx->argp[arg_num], 0, 1,
3837 ETH_RXFH_CONTEXT_ALLOC - 1);
3838 ++arg_num;
3839 } else {
3840 exit_bad_args();
3841 }
3842 }
3843
Ben Hutchings048038f2010-06-30 16:13:12 +01003844 ring_count.cmd = ETHTOOL_GRXRINGS;
Ben Hutchings37897ca2011-10-29 02:33:30 +01003845 err = send_ioctl(ctx, &ring_count);
Ben Hutchings048038f2010-06-30 16:13:12 +01003846 if (err < 0) {
3847 perror("Cannot get RX ring count");
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303848 return 1;
Ben Hutchings048038f2010-06-30 16:13:12 +01003849 }
3850
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303851 rss_head.cmd = ETHTOOL_GRSSH;
Edward Creef5d55b92018-03-09 15:04:12 +00003852 rss_head.rss_context = rss_context;
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303853 err = send_ioctl(ctx, &rss_head);
Edward Cree7984d342018-03-19 16:52:06 +00003854 if (err < 0 && errno == EOPNOTSUPP && !rss_context) {
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303855 return do_grxfhindir(ctx, &ring_count);
3856 } else if (err < 0) {
3857 perror("Cannot get RX flow hash indir size and/or key size");
3858 return 1;
3859 }
3860
3861 rss = calloc(1, sizeof(*rss) +
3862 rss_head.indir_size * sizeof(rss_head.rss_config[0]) +
3863 rss_head.key_size);
3864 if (!rss) {
3865 perror("Cannot allocate memory for RX flow hash config");
3866 return 1;
3867 }
3868
3869 rss->cmd = ETHTOOL_GRSSH;
Edward Creef5d55b92018-03-09 15:04:12 +00003870 rss->rss_context = rss_context;
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303871 rss->indir_size = rss_head.indir_size;
3872 rss->key_size = rss_head.key_size;
3873 err = send_ioctl(ctx, rss);
Ben Hutchings048038f2010-06-30 16:13:12 +01003874 if (err < 0) {
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303875 perror("Cannot get RX flow hash configuration");
3876 free(rss);
3877 return 1;
Ben Hutchings048038f2010-06-30 16:13:12 +01003878 }
3879
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303880 print_indir_table(ctx, &ring_count, rss->indir_size, rss->rss_config);
3881
3882 indir_bytes = rss->indir_size * sizeof(rss->rss_config[0]);
3883 hkey = ((char *)rss->rss_config + indir_bytes);
3884
3885 printf("RSS hash key:\n");
3886 if (!rss->key_size)
3887 printf("Operation not supported\n");
3888
3889 for (i = 0; i < rss->key_size; i++) {
3890 if (i == (rss->key_size - 1))
3891 printf("%02x\n", (u8) hkey[i]);
3892 else
3893 printf("%02x:", (u8) hkey[i]);
Ben Hutchings048038f2010-06-30 16:13:12 +01003894 }
3895
Gal Pressmanb888f352017-03-08 16:03:51 +02003896 printf("RSS hash function:\n");
3897 if (!rss->hfunc) {
3898 printf(" Operation not supported\n");
3899 goto out;
3900 }
3901
3902 hfuncs = get_stringset(ctx, ETH_SS_RSS_HASH_FUNCS, 0, 1);
3903 if (!hfuncs) {
3904 perror("Cannot get hash functions names");
3905 free(rss);
3906 return 1;
3907 }
3908
3909 for (i = 0; i < hfuncs->len; i++)
3910 printf(" %s: %s\n",
3911 (const char *)hfuncs->data + i * ETH_GSTRING_LEN,
3912 (rss->hfunc & (1 << i)) ? "on" : "off");
3913
3914out:
3915 free(hfuncs);
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303916 free(rss);
Ben Hutchings048038f2010-06-30 16:13:12 +01003917 return 0;
3918}
3919
Jacob Keller9cdf0332016-02-08 16:05:06 -08003920static int fill_indir_table(u32 *indir_size, u32 *indir, int rxfhindir_default,
Jonathan Lemon8c8bfaa2019-04-01 11:42:45 -07003921 int rxfhindir_start, int rxfhindir_equal,
3922 char **rxfhindir_weight, u32 num_weights)
Ben Hutchings048038f2010-06-30 16:13:12 +01003923{
Ben Hutchings048038f2010-06-30 16:13:12 +01003924 u32 i;
Jonathan Lemon8c8bfaa2019-04-01 11:42:45 -07003925
Ben Hutchings048038f2010-06-30 16:13:12 +01003926 if (rxfhindir_equal) {
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303927 for (i = 0; i < *indir_size; i++)
Jonathan Lemon8c8bfaa2019-04-01 11:42:45 -07003928 indir[i] = rxfhindir_start + (i % rxfhindir_equal);
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303929 } else if (rxfhindir_weight) {
Ben Hutchings048038f2010-06-30 16:13:12 +01003930 u32 j, weight, sum = 0, partial = 0;
3931
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303932 for (j = 0; j < num_weights; j++) {
Ben Hutchings048038f2010-06-30 16:13:12 +01003933 weight = get_u32(rxfhindir_weight[j], 0);
3934 sum += weight;
3935 }
3936
3937 if (sum == 0) {
3938 fprintf(stderr,
3939 "At least one weight must be non-zero\n");
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303940 return 2;
Ben Hutchings048038f2010-06-30 16:13:12 +01003941 }
3942
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303943 if (sum > *indir_size) {
Ben Hutchings048038f2010-06-30 16:13:12 +01003944 fprintf(stderr,
3945 "Total weight exceeds the size of the "
3946 "indirection table\n");
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303947 return 2;
Ben Hutchings048038f2010-06-30 16:13:12 +01003948 }
3949
3950 j = -1;
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303951 for (i = 0; i < *indir_size; i++) {
3952 while (i >= (*indir_size) * partial / sum) {
Ben Hutchings048038f2010-06-30 16:13:12 +01003953 j += 1;
3954 weight = get_u32(rxfhindir_weight[j], 0);
3955 partial += weight;
3956 }
Jonathan Lemon8c8bfaa2019-04-01 11:42:45 -07003957 indir[i] = rxfhindir_start + j;
Ben Hutchings048038f2010-06-30 16:13:12 +01003958 }
Jacob Keller9cdf0332016-02-08 16:05:06 -08003959 } else if (rxfhindir_default) {
3960 /* "*indir_size == 0" ==> reset indir to default */
3961 *indir_size = 0;
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303962 } else {
3963 *indir_size = ETH_RXFH_INDIR_NO_CHANGE;
3964 }
3965
3966 return 0;
3967}
3968
Jacob Keller9cdf0332016-02-08 16:05:06 -08003969static int do_srxfhindir(struct cmd_context *ctx, int rxfhindir_default,
Jonathan Lemon8c8bfaa2019-04-01 11:42:45 -07003970 int rxfhindir_start, int rxfhindir_equal,
3971 char **rxfhindir_weight, u32 num_weights)
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303972{
3973 struct ethtool_rxfh_indir indir_head;
3974 struct ethtool_rxfh_indir *indir;
3975 int err;
3976
3977 indir_head.cmd = ETHTOOL_GRXFHINDIR;
3978 indir_head.size = 0;
3979 err = send_ioctl(ctx, &indir_head);
3980 if (err < 0) {
3981 perror("Cannot get RX flow hash indirection table size");
3982 return 1;
3983 }
3984
3985 indir = malloc(sizeof(*indir) +
3986 indir_head.size * sizeof(*indir->ring_index));
3987
3988 if (!indir) {
3989 perror("Cannot allocate memory for indirection table");
3990 return 1;
3991 }
3992
3993 indir->cmd = ETHTOOL_SRXFHINDIR;
3994 indir->size = indir_head.size;
3995
Jacob Keller9cdf0332016-02-08 16:05:06 -08003996 if (fill_indir_table(&indir->size, indir->ring_index,
Jonathan Lemon8c8bfaa2019-04-01 11:42:45 -07003997 rxfhindir_default, rxfhindir_start,
3998 rxfhindir_equal, rxfhindir_weight, num_weights)) {
Venkat Duvvuru86c03262014-07-22 17:51:07 +05303999 free(indir);
4000 return 1;
Ben Hutchings048038f2010-06-30 16:13:12 +01004001 }
4002
Ben Hutchings37897ca2011-10-29 02:33:30 +01004003 err = send_ioctl(ctx, indir);
Ben Hutchings048038f2010-06-30 16:13:12 +01004004 if (err < 0) {
4005 perror("Cannot set RX flow hash indirection table");
Venkat Duvvuru86c03262014-07-22 17:51:07 +05304006 free(indir);
4007 return 1;
Ben Hutchings048038f2010-06-30 16:13:12 +01004008 }
4009
Venkat Duvvuru86c03262014-07-22 17:51:07 +05304010 free(indir);
Ben Hutchings048038f2010-06-30 16:13:12 +01004011 return 0;
4012}
4013
Venkat Duvvuru86c03262014-07-22 17:51:07 +05304014static int do_srxfh(struct cmd_context *ctx)
4015{
4016 struct ethtool_rxfh rss_head = {0};
Ivan Vecerae0fabbc2018-06-08 11:20:09 +02004017 struct ethtool_rxfh *rss = NULL;
Venkat Duvvuru86c03262014-07-22 17:51:07 +05304018 struct ethtool_rxnfc ring_count;
Jonathan Lemon8c8bfaa2019-04-01 11:42:45 -07004019 int rxfhindir_equal = 0, rxfhindir_default = 0, rxfhindir_start = 0;
Gal Pressmanb888f352017-03-08 16:03:51 +02004020 struct ethtool_gstrings *hfuncs = NULL;
Venkat Duvvuru86c03262014-07-22 17:51:07 +05304021 char **rxfhindir_weight = NULL;
4022 char *rxfhindir_key = NULL;
Gal Pressmanb888f352017-03-08 16:03:51 +02004023 char *req_hfunc_name = NULL;
4024 char *hfunc_name = NULL;
Venkat Duvvuru86c03262014-07-22 17:51:07 +05304025 char *hkey = NULL;
4026 int err = 0;
Gal Pressmanb888f352017-03-08 16:03:51 +02004027 int i;
Venkat Duvvuru86c03262014-07-22 17:51:07 +05304028 u32 arg_num = 0, indir_bytes = 0;
Gal Pressmanb888f352017-03-08 16:03:51 +02004029 u32 req_hfunc = 0;
Venkat Duvvuru86c03262014-07-22 17:51:07 +05304030 u32 entry_size = sizeof(rss_head.rss_config[0]);
4031 u32 num_weights = 0;
Edward Creef5d55b92018-03-09 15:04:12 +00004032 u32 rss_context = 0;
4033 int delete = 0;
Venkat Duvvuru86c03262014-07-22 17:51:07 +05304034
Jacob Keller9cdf0332016-02-08 16:05:06 -08004035 if (ctx->argc < 1)
Venkat Duvvuru86c03262014-07-22 17:51:07 +05304036 exit_bad_args();
4037
4038 while (arg_num < ctx->argc) {
4039 if (!strcmp(ctx->argp[arg_num], "equal")) {
4040 ++arg_num;
4041 rxfhindir_equal = get_int_range(ctx->argp[arg_num],
4042 0, 1, INT_MAX);
4043 ++arg_num;
Jonathan Lemon8c8bfaa2019-04-01 11:42:45 -07004044 } else if (!strcmp(ctx->argp[arg_num], "start")) {
4045 ++arg_num;
4046 rxfhindir_start = get_int_range(ctx->argp[arg_num],
4047 0, 0, INT_MAX);
4048 ++arg_num;
Venkat Duvvuru86c03262014-07-22 17:51:07 +05304049 } else if (!strcmp(ctx->argp[arg_num], "weight")) {
4050 ++arg_num;
4051 rxfhindir_weight = ctx->argp + arg_num;
4052 while (arg_num < ctx->argc &&
4053 isdigit((unsigned char)ctx->argp[arg_num][0])) {
4054 ++arg_num;
4055 ++num_weights;
4056 }
4057 if (!num_weights)
4058 exit_bad_args();
4059 } else if (!strcmp(ctx->argp[arg_num], "hkey")) {
4060 ++arg_num;
4061 rxfhindir_key = ctx->argp[arg_num];
4062 if (!rxfhindir_key)
4063 exit_bad_args();
4064 ++arg_num;
Jacob Keller9cdf0332016-02-08 16:05:06 -08004065 } else if (!strcmp(ctx->argp[arg_num], "default")) {
4066 ++arg_num;
4067 rxfhindir_default = 1;
Gal Pressmanb888f352017-03-08 16:03:51 +02004068 } else if (!strcmp(ctx->argp[arg_num], "hfunc")) {
4069 ++arg_num;
4070 req_hfunc_name = ctx->argp[arg_num];
4071 if (!req_hfunc_name)
4072 exit_bad_args();
4073 ++arg_num;
Edward Creef5d55b92018-03-09 15:04:12 +00004074 } else if (!strcmp(ctx->argp[arg_num], "context")) {
4075 ++arg_num;
4076 if(!strcmp(ctx->argp[arg_num], "new"))
4077 rss_context = ETH_RXFH_CONTEXT_ALLOC;
4078 else
4079 rss_context = get_int_range(
4080 ctx->argp[arg_num], 0, 1,
4081 ETH_RXFH_CONTEXT_ALLOC - 1);
4082 ++arg_num;
4083 } else if (!strcmp(ctx->argp[arg_num], "delete")) {
4084 ++arg_num;
4085 delete = 1;
Venkat Duvvuru86c03262014-07-22 17:51:07 +05304086 } else {
4087 exit_bad_args();
4088 }
4089 }
4090
4091 if (rxfhindir_equal && rxfhindir_weight) {
4092 fprintf(stderr,
4093 "Equal and weight options are mutually exclusive\n");
4094 return 1;
4095 }
4096
Jacob Keller9cdf0332016-02-08 16:05:06 -08004097 if (rxfhindir_equal && rxfhindir_default) {
4098 fprintf(stderr,
4099 "Equal and default options are mutually exclusive\n");
4100 return 1;
4101 }
4102
4103 if (rxfhindir_weight && rxfhindir_default) {
4104 fprintf(stderr,
4105 "Weight and default options are mutually exclusive\n");
4106 return 1;
4107 }
4108
Jonathan Lemon8c8bfaa2019-04-01 11:42:45 -07004109 if (rxfhindir_start && rxfhindir_default) {
4110 fprintf(stderr,
4111 "Start and default options are mutually exclusive\n");
4112 return 1;
4113 }
4114
4115 if (rxfhindir_start && !(rxfhindir_equal || rxfhindir_weight)) {
4116 fprintf(stderr,
4117 "Start must be used with equal or weight options\n");
4118 return 1;
4119 }
4120
Edward Creef5d55b92018-03-09 15:04:12 +00004121 if (rxfhindir_default && rss_context) {
4122 fprintf(stderr,
4123 "Default and context options are mutually exclusive\n");
4124 return 1;
4125 }
4126
4127 if (delete && !rss_context) {
4128 fprintf(stderr, "Delete option requires context option\n");
4129 return 1;
4130 }
4131
4132 if (delete && rxfhindir_weight) {
4133 fprintf(stderr,
4134 "Delete and weight options are mutually exclusive\n");
4135 return 1;
4136 }
4137
4138 if (delete && rxfhindir_equal) {
4139 fprintf(stderr,
4140 "Delete and equal options are mutually exclusive\n");
4141 return 1;
4142 }
4143
4144 if (delete && rxfhindir_default) {
4145 fprintf(stderr,
4146 "Delete and default options are mutually exclusive\n");
4147 return 1;
4148 }
4149
4150 if (delete && rxfhindir_key) {
4151 fprintf(stderr,
4152 "Delete and hkey options are mutually exclusive\n");
4153 return 1;
4154 }
4155
Venkat Duvvuru86c03262014-07-22 17:51:07 +05304156 ring_count.cmd = ETHTOOL_GRXRINGS;
4157 err = send_ioctl(ctx, &ring_count);
4158 if (err < 0) {
4159 perror("Cannot get RX ring count");
4160 return 1;
4161 }
4162
4163 rss_head.cmd = ETHTOOL_GRSSH;
4164 err = send_ioctl(ctx, &rss_head);
Gal Pressmanb888f352017-03-08 16:03:51 +02004165 if (err < 0 && errno == EOPNOTSUPP && !rxfhindir_key &&
Edward Creef5d55b92018-03-09 15:04:12 +00004166 !req_hfunc_name && !rss_context) {
Jonathan Lemon8c8bfaa2019-04-01 11:42:45 -07004167 return do_srxfhindir(ctx, rxfhindir_default, rxfhindir_start,
4168 rxfhindir_equal, rxfhindir_weight,
4169 num_weights);
Venkat Duvvuru86c03262014-07-22 17:51:07 +05304170 } else if (err < 0) {
4171 perror("Cannot get RX flow hash indir size and key size");
4172 return 1;
4173 }
4174
4175 if (rxfhindir_key) {
4176 err = parse_hkey(&hkey, rss_head.key_size,
4177 rxfhindir_key);
4178 if (err)
4179 return err;
4180 }
4181
4182 if (rxfhindir_equal || rxfhindir_weight)
4183 indir_bytes = rss_head.indir_size * entry_size;
4184
Gal Pressmanb888f352017-03-08 16:03:51 +02004185 if (rss_head.hfunc && req_hfunc_name) {
4186 hfuncs = get_stringset(ctx, ETH_SS_RSS_HASH_FUNCS, 0, 1);
4187 if (!hfuncs) {
4188 perror("Cannot get hash functions names");
Ivan Vecerae0fabbc2018-06-08 11:20:09 +02004189 err = 1;
4190 goto free;
Gal Pressmanb888f352017-03-08 16:03:51 +02004191 }
4192
4193 for (i = 0; i < hfuncs->len && !req_hfunc ; i++) {
4194 hfunc_name = (char *)(hfuncs->data +
4195 i * ETH_GSTRING_LEN);
4196 if (!strncmp(hfunc_name, req_hfunc_name,
4197 ETH_GSTRING_LEN))
4198 req_hfunc = (u32)1 << i;
4199 }
4200
4201 if (!req_hfunc) {
4202 fprintf(stderr,
4203 "Unknown hash function: %s\n", req_hfunc_name);
Ivan Vecerae0fabbc2018-06-08 11:20:09 +02004204 err = 1;
4205 goto free;
Gal Pressmanb888f352017-03-08 16:03:51 +02004206 }
4207 }
4208
Venkat Duvvuru86c03262014-07-22 17:51:07 +05304209 rss = calloc(1, sizeof(*rss) + indir_bytes + rss_head.key_size);
4210 if (!rss) {
4211 perror("Cannot allocate memory for RX flow hash config");
Gal Pressmanb888f352017-03-08 16:03:51 +02004212 err = 1;
4213 goto free;
Venkat Duvvuru86c03262014-07-22 17:51:07 +05304214 }
4215 rss->cmd = ETHTOOL_SRSSH;
Edward Creef5d55b92018-03-09 15:04:12 +00004216 rss->rss_context = rss_context;
Gal Pressmanb888f352017-03-08 16:03:51 +02004217 rss->hfunc = req_hfunc;
Edward Creef5d55b92018-03-09 15:04:12 +00004218 if (delete) {
4219 rss->indir_size = rss->key_size = 0;
4220 } else {
4221 rss->indir_size = rss_head.indir_size;
4222 rss->key_size = rss_head.key_size;
4223 if (fill_indir_table(&rss->indir_size, rss->rss_config,
Jonathan Lemon8c8bfaa2019-04-01 11:42:45 -07004224 rxfhindir_default, rxfhindir_start,
4225 rxfhindir_equal, rxfhindir_weight,
4226 num_weights)) {
Edward Creef5d55b92018-03-09 15:04:12 +00004227 err = 1;
4228 goto free;
4229 }
Venkat Duvvuru86c03262014-07-22 17:51:07 +05304230 }
4231
4232 if (hkey)
4233 memcpy((char *)rss->rss_config + indir_bytes,
4234 hkey, rss->key_size);
4235 else
4236 rss->key_size = 0;
4237
4238 err = send_ioctl(ctx, rss);
4239 if (err < 0) {
4240 perror("Cannot set RX flow hash configuration");
4241 err = 1;
Edward Creef5d55b92018-03-09 15:04:12 +00004242 } else if (rss_context == ETH_RXFH_CONTEXT_ALLOC) {
4243 printf("New RSS context is %d\n", rss->rss_context);
Venkat Duvvuru86c03262014-07-22 17:51:07 +05304244 }
4245
4246free:
Ivan Vecerae0fabbc2018-06-08 11:20:09 +02004247 free(hkey);
Venkat Duvvuru86c03262014-07-22 17:51:07 +05304248 free(rss);
Gal Pressmanb888f352017-03-08 16:03:51 +02004249 free(hfuncs);
Venkat Duvvuru86c03262014-07-22 17:51:07 +05304250 return err;
4251}
4252
Ben Hutchings37897ca2011-10-29 02:33:30 +01004253static int do_flash(struct cmd_context *ctx)
Ajit Khaparde9efed0a2009-09-03 08:33:08 +05304254{
Ben Hutchings52adc492011-10-31 22:28:20 +00004255 char *flash_file;
4256 int flash_region;
Ajit Khaparde9efed0a2009-09-03 08:33:08 +05304257 struct ethtool_flash efl;
4258 int err;
4259
Ben Hutchings127f8062011-10-29 01:15:34 +01004260 if (ctx->argc < 1 || ctx->argc > 2)
Ben Hutchings97a8e6a2011-02-21 18:47:58 +00004261 exit_bad_args();
Ben Hutchings127f8062011-10-29 01:15:34 +01004262 flash_file = ctx->argp[0];
4263 if (ctx->argc == 2) {
4264 flash_region = strtol(ctx->argp[1], NULL, 0);
4265 if (flash_region < 0)
4266 exit_bad_args();
Ben Hutchings52adc492011-10-31 22:28:20 +00004267 } else {
4268 flash_region = -1;
Ajit Khaparde9efed0a2009-09-03 08:33:08 +05304269 }
4270
4271 if (strlen(flash_file) > ETHTOOL_FLASH_MAX_FILENAME - 1) {
4272 fprintf(stdout, "Filename too long\n");
4273 return 99;
4274 }
4275
4276 efl.cmd = ETHTOOL_FLASHDEV;
4277 strcpy(efl.data, flash_file);
4278
4279 if (flash_region < 0)
4280 efl.region = ETHTOOL_FLASH_ALL_REGIONS;
4281 else
4282 efl.region = flash_region;
4283
Ben Hutchings37897ca2011-10-29 02:33:30 +01004284 err = send_ioctl(ctx, &efl);
Ajit Khaparde9efed0a2009-09-03 08:33:08 +05304285 if (err < 0)
4286 perror("Flashing failed");
4287
4288 return err;
4289}
4290
Ben Hutchings37897ca2011-10-29 02:33:30 +01004291static int do_permaddr(struct cmd_context *ctx)
Stephen Hemmingerfef1c4a2010-11-16 19:14:33 +00004292{
4293 int i, err;
4294 struct ethtool_perm_addr *epaddr;
4295
4296 epaddr = malloc(sizeof(struct ethtool_perm_addr) + MAX_ADDR_LEN);
John W. Linvilled70e1eb2016-09-29 14:05:41 -04004297 if (!epaddr) {
4298 perror("Cannot allocate memory for operation");
4299 return 1;
4300 }
4301
Stephen Hemmingerfef1c4a2010-11-16 19:14:33 +00004302 epaddr->cmd = ETHTOOL_GPERMADDR;
4303 epaddr->size = MAX_ADDR_LEN;
Stephen Hemmingerfef1c4a2010-11-16 19:14:33 +00004304
Ben Hutchings37897ca2011-10-29 02:33:30 +01004305 err = send_ioctl(ctx, epaddr);
Stephen Hemmingerfef1c4a2010-11-16 19:14:33 +00004306 if (err < 0)
4307 perror("Cannot read permanent address");
4308 else {
4309 printf("Permanent address:");
4310 for (i = 0; i < epaddr->size; i++)
4311 printf("%c%02x", (i == 0) ? ' ' : ':',
4312 epaddr->data[i]);
4313 printf("\n");
4314 }
4315 free(epaddr);
4316
4317 return err;
4318}
4319
Edward Creeb56b9512016-03-17 19:17:16 +00004320static bool flow_type_is_ntuple_supported(__u32 flow_type)
4321{
4322 switch (flow_type) {
4323 case TCP_V4_FLOW:
4324 case UDP_V4_FLOW:
4325 case SCTP_V4_FLOW:
4326 case AH_V4_FLOW:
4327 case ESP_V4_FLOW:
4328 case IPV4_USER_FLOW:
4329 case ETHER_FLOW:
4330 return true;
4331 default:
4332 return false;
4333 }
4334}
4335
Alexander Duyck8d63f722011-05-04 11:41:51 -07004336static int flow_spec_to_ntuple(struct ethtool_rx_flow_spec *fsp,
4337 struct ethtool_rx_ntuple_flow_spec *ntuple)
4338{
4339 size_t i;
4340
4341 /* verify location is not specified */
Ben Hutchings578e6a52012-01-03 20:21:45 +00004342 if (fsp->location != RX_CLS_LOC_ANY)
Alexander Duyck8d63f722011-05-04 11:41:51 -07004343 return -1;
4344
Yan Burmanb29aa902012-12-11 14:03:56 +02004345 /* destination MAC address in L3/L4 rules is not supported by ntuple */
4346 if (fsp->flow_type & FLOW_MAC_EXT)
4347 return -1;
4348
Alexander Duyck8d63f722011-05-04 11:41:51 -07004349 /* verify ring cookie can transfer to action */
4350 if (fsp->ring_cookie > INT_MAX && fsp->ring_cookie < (u64)(-2))
4351 return -1;
4352
4353 /* verify only one field is setting data field */
4354 if ((fsp->flow_type & FLOW_EXT) &&
4355 (fsp->m_ext.data[0] || fsp->m_ext.data[1]) &&
4356 fsp->m_ext.vlan_etype)
4357 return -1;
4358
Edward Creeb56b9512016-03-17 19:17:16 +00004359 /* IPv6 flow types are not supported by ntuple */
4360 if (!flow_type_is_ntuple_supported(fsp->flow_type & ~FLOW_EXT))
4361 return -1;
4362
Alexander Duyck8d63f722011-05-04 11:41:51 -07004363 /* Set entire ntuple to ~0 to guarantee all masks are set */
4364 memset(ntuple, ~0, sizeof(*ntuple));
4365
4366 /* set non-filter values */
4367 ntuple->flow_type = fsp->flow_type;
4368 ntuple->action = fsp->ring_cookie;
4369
4370 /*
4371 * Copy over header union, they are identical in layout however
4372 * the ntuple union contains additional padding on the end
4373 */
4374 memcpy(&ntuple->h_u, &fsp->h_u, sizeof(fsp->h_u));
4375
4376 /*
4377 * The same rule mentioned above applies to the mask union. However,
4378 * in addition we need to invert the mask bits to match the ntuple
4379 * mask which is 1 for masked, versus 0 for masked as seen in nfc.
4380 */
4381 memcpy(&ntuple->m_u, &fsp->m_u, sizeof(fsp->m_u));
4382 for (i = 0; i < sizeof(fsp->m_u); i++)
4383 ntuple->m_u.hdata[i] ^= 0xFF;
4384
4385 /* copy extended fields */
4386 if (fsp->flow_type & FLOW_EXT) {
4387 ntuple->vlan_tag =
4388 ntohs(fsp->h_ext.vlan_tci);
4389 ntuple->vlan_tag_mask =
4390 ~ntohs(fsp->m_ext.vlan_tci);
4391 if (fsp->m_ext.vlan_etype) {
4392 /*
4393 * vlan_etype and user data are mutually exclusive
4394 * in ntuple configuration as they occupy the same
4395 * space.
4396 */
4397 if (fsp->m_ext.data[0] || fsp->m_ext.data[1])
4398 return -1;
4399 ntuple->data =
4400 ntohl(fsp->h_ext.vlan_etype);
4401 ntuple->data_mask =
4402 ~(u64)ntohl(fsp->m_ext.vlan_etype);
4403 } else {
4404 ntuple->data =
4405 (u64)ntohl(fsp->h_ext.data[0]) << 32;
4406 ntuple->data |=
4407 (u64)ntohl(fsp->h_ext.data[1]);
4408 ntuple->data_mask =
4409 (u64)ntohl(~fsp->m_ext.data[0]) << 32;
4410 ntuple->data_mask |=
4411 (u64)ntohl(~fsp->m_ext.data[1]);
4412 }
4413 }
4414
Sebastian Pöhnaa41a262011-05-23 15:53:55 +02004415 /* Mask out the extended bit, because ntuple does not know it! */
4416 ntuple->flow_type &= ~FLOW_EXT;
4417
Alexander Duyck8d63f722011-05-04 11:41:51 -07004418 return 0;
4419}
4420
Ben Hutchings52adc492011-10-31 22:28:20 +00004421static int do_srxntuple(struct cmd_context *ctx,
4422 struct ethtool_rx_flow_spec *rx_rule_fs)
Peter Waskiewiczb26637b2010-02-03 23:51:01 -08004423{
Alexander Duyck8d63f722011-05-04 11:41:51 -07004424 struct ethtool_rx_ntuple ntuplecmd;
4425 struct ethtool_value eval;
4426 int err;
4427
4428 /* attempt to convert the flow classifier to an ntuple classifier */
Ben Hutchings52adc492011-10-31 22:28:20 +00004429 err = flow_spec_to_ntuple(rx_rule_fs, &ntuplecmd.fs);
Alexander Duyck8d63f722011-05-04 11:41:51 -07004430 if (err)
4431 return -1;
4432
4433 /*
4434 * Check to see if the flag is set for N-tuple, this allows
4435 * us to avoid the possible EINVAL response for the N-tuple
4436 * flag not being set on the device
4437 */
4438 eval.cmd = ETHTOOL_GFLAGS;
Ben Hutchings37897ca2011-10-29 02:33:30 +01004439 err = send_ioctl(ctx, &eval);
Alexander Duyck8d63f722011-05-04 11:41:51 -07004440 if (err || !(eval.data & ETH_FLAG_NTUPLE))
4441 return -1;
4442
4443 /* send rule via N-tuple */
4444 ntuplecmd.cmd = ETHTOOL_SRXNTUPLE;
Ben Hutchings37897ca2011-10-29 02:33:30 +01004445 err = send_ioctl(ctx, &ntuplecmd);
Alexander Duyck8d63f722011-05-04 11:41:51 -07004446
4447 /*
Ville Skyttä500a9f42013-12-15 14:19:31 +02004448 * Display error only if response is something other than op not
Alexander Duyck8d63f722011-05-04 11:41:51 -07004449 * supported. It is possible that the interface uses the network
Gal Pressman5a20e542017-10-26 17:44:43 +03004450 * flow classifier interface instead of N-tuple.
4451 */
Ben Hutchingsa0e0cc42011-05-13 01:52:27 +01004452 if (err < 0) {
4453 if (errno != EOPNOTSUPP)
4454 perror("Cannot add new rule via N-tuple");
4455 return -1;
4456 }
Alexander Duyck8d63f722011-05-04 11:41:51 -07004457
Ben Hutchingsa0e0cc42011-05-13 01:52:27 +01004458 return 0;
Alexander Duyck8d63f722011-05-04 11:41:51 -07004459}
4460
Ben Hutchings52adc492011-10-31 22:28:20 +00004461static int do_writefwdump(struct ethtool_dump *dump, const char *dump_file)
Anirban Chakraborty95b924e2011-06-02 12:00:26 -07004462{
4463 int err = 0;
4464 FILE *f;
4465 size_t bytes;
4466
4467 f = fopen(dump_file, "wb+");
4468
4469 if (!f) {
4470 fprintf(stderr, "Can't open file %s: %s\n",
4471 dump_file, strerror(errno));
4472 return 1;
4473 }
4474 bytes = fwrite(dump->data, 1, dump->len, f);
4475 if (bytes != dump->len) {
4476 fprintf(stderr, "Can not write all of dump data\n");
4477 err = 1;
4478 }
4479 if (fclose(f)) {
4480 fprintf(stderr, "Can't close file %s: %s\n",
4481 dump_file, strerror(errno));
4482 err = 1;
4483 }
4484 return err;
4485}
4486
Ben Hutchings37897ca2011-10-29 02:33:30 +01004487static int do_getfwdump(struct cmd_context *ctx)
Anirban Chakraborty95b924e2011-06-02 12:00:26 -07004488{
Ben Hutchings52adc492011-10-31 22:28:20 +00004489 u32 dump_flag;
4490 char *dump_file;
Anirban Chakraborty95b924e2011-06-02 12:00:26 -07004491 int err;
4492 struct ethtool_dump edata;
4493 struct ethtool_dump *data;
4494
Ben Hutchings127f8062011-10-29 01:15:34 +01004495 if (ctx->argc == 2 && !strcmp(ctx->argp[0], "data")) {
4496 dump_flag = ETHTOOL_GET_DUMP_DATA;
4497 dump_file = ctx->argp[1];
Ben Hutchings52adc492011-10-31 22:28:20 +00004498 } else if (ctx->argc == 0) {
4499 dump_flag = 0;
4500 dump_file = NULL;
4501 } else {
Ben Hutchings127f8062011-10-29 01:15:34 +01004502 exit_bad_args();
4503 }
4504
Anirban Chakraborty95b924e2011-06-02 12:00:26 -07004505 edata.cmd = ETHTOOL_GET_DUMP_FLAG;
4506
Ben Hutchings37897ca2011-10-29 02:33:30 +01004507 err = send_ioctl(ctx, &edata);
Anirban Chakraborty95b924e2011-06-02 12:00:26 -07004508 if (err < 0) {
4509 perror("Can not get dump level\n");
4510 return 1;
4511 }
4512 if (dump_flag != ETHTOOL_GET_DUMP_DATA) {
4513 fprintf(stdout, "flag: %u, version: %u, length: %u\n",
4514 edata.flag, edata.version, edata.len);
4515 return 0;
4516 }
4517 data = calloc(1, offsetof(struct ethtool_dump, data) + edata.len);
4518 if (!data) {
4519 perror("Can not allocate enough memory\n");
4520 return 1;
4521 }
4522 data->cmd = ETHTOOL_GET_DUMP_DATA;
4523 data->len = edata.len;
Ben Hutchings37897ca2011-10-29 02:33:30 +01004524 err = send_ioctl(ctx, data);
Anirban Chakraborty95b924e2011-06-02 12:00:26 -07004525 if (err < 0) {
4526 perror("Can not get dump data\n");
4527 err = 1;
4528 goto free;
4529 }
Ben Hutchings52adc492011-10-31 22:28:20 +00004530 err = do_writefwdump(data, dump_file);
Anirban Chakraborty95b924e2011-06-02 12:00:26 -07004531free:
4532 free(data);
4533 return err;
4534}
4535
Ben Hutchings37897ca2011-10-29 02:33:30 +01004536static int do_setfwdump(struct cmd_context *ctx)
Anirban Chakraborty95b924e2011-06-02 12:00:26 -07004537{
Ben Hutchings52adc492011-10-31 22:28:20 +00004538 u32 dump_flag;
Anirban Chakraborty95b924e2011-06-02 12:00:26 -07004539 int err;
4540 struct ethtool_dump dump;
4541
Ben Hutchings127f8062011-10-29 01:15:34 +01004542 if (ctx->argc != 1)
4543 exit_bad_args();
4544 dump_flag = get_u32(ctx->argp[0], 0);
4545
Anirban Chakraborty95b924e2011-06-02 12:00:26 -07004546 dump.cmd = ETHTOOL_SET_DUMP;
4547 dump.flag = dump_flag;
Ben Hutchings37897ca2011-10-29 02:33:30 +01004548 err = send_ioctl(ctx, &dump);
Anirban Chakraborty95b924e2011-06-02 12:00:26 -07004549 if (err < 0) {
4550 perror("Can not set dump level\n");
4551 return 1;
4552 }
4553 return 0;
4554}
4555
Ben Hutchingse1ee5962011-11-30 02:29:21 +00004556static int do_gprivflags(struct cmd_context *ctx)
4557{
4558 struct ethtool_gstrings *strings;
4559 struct ethtool_value flags;
4560 unsigned int i;
John W. Linville69fd6d42016-09-29 14:30:31 -04004561 int max_len = 0, cur_len, rc;
Ben Hutchingse1ee5962011-11-30 02:29:21 +00004562
4563 if (ctx->argc != 0)
4564 exit_bad_args();
4565
4566 strings = get_stringset(ctx, ETH_SS_PRIV_FLAGS,
Ben Hutchingsa983fb72012-06-14 20:34:35 +01004567 offsetof(struct ethtool_drvinfo, n_priv_flags),
4568 1);
Ben Hutchingse1ee5962011-11-30 02:29:21 +00004569 if (!strings) {
4570 perror("Cannot get private flag names");
4571 return 1;
4572 }
4573 if (strings->len == 0) {
4574 fprintf(stderr, "No private flags defined\n");
John W. Linville69fd6d42016-09-29 14:30:31 -04004575 rc = 1;
4576 goto err;
Ben Hutchingse1ee5962011-11-30 02:29:21 +00004577 }
4578 if (strings->len > 32) {
4579 /* ETHTOOL_GPFLAGS can only cover 32 flags */
4580 fprintf(stderr, "Only showing first 32 private flags\n");
4581 strings->len = 32;
4582 }
4583
4584 flags.cmd = ETHTOOL_GPFLAGS;
4585 if (send_ioctl(ctx, &flags)) {
4586 perror("Cannot get private flags");
John W. Linville69fd6d42016-09-29 14:30:31 -04004587 rc = 1;
4588 goto err;
Ben Hutchingse1ee5962011-11-30 02:29:21 +00004589 }
4590
Yuval Mintz49ef7922013-05-26 07:55:55 +03004591 /* Find longest string and align all strings accordingly */
4592 for (i = 0; i < strings->len; i++) {
Gal Pressman5a20e542017-10-26 17:44:43 +03004593 cur_len = strlen((const char *)strings->data +
Yuval Mintz49ef7922013-05-26 07:55:55 +03004594 i * ETH_GSTRING_LEN);
4595 if (cur_len > max_len)
4596 max_len = cur_len;
4597 }
4598
Ben Hutchingse1ee5962011-11-30 02:29:21 +00004599 printf("Private flags for %s:\n", ctx->devname);
4600 for (i = 0; i < strings->len; i++)
Yuval Mintz49ef7922013-05-26 07:55:55 +03004601 printf("%-*s: %s\n",
4602 max_len,
Ben Hutchingse1ee5962011-11-30 02:29:21 +00004603 (const char *)strings->data + i * ETH_GSTRING_LEN,
4604 (flags.data & (1U << i)) ? "on" : "off");
4605
John W. Linville69fd6d42016-09-29 14:30:31 -04004606 rc = 0;
4607
4608err:
4609 free(strings);
4610 return rc;
Ben Hutchingse1ee5962011-11-30 02:29:21 +00004611}
4612
4613static int do_sprivflags(struct cmd_context *ctx)
4614{
4615 struct ethtool_gstrings *strings;
4616 struct cmdline_info *cmdline;
4617 struct ethtool_value flags;
4618 u32 wanted_flags = 0, seen_flags = 0;
John W. Linvilleecbd5ea2016-09-30 14:57:27 -04004619 int any_changed, rc;
Ben Hutchingse1ee5962011-11-30 02:29:21 +00004620 unsigned int i;
4621
4622 strings = get_stringset(ctx, ETH_SS_PRIV_FLAGS,
Ben Hutchingsa983fb72012-06-14 20:34:35 +01004623 offsetof(struct ethtool_drvinfo, n_priv_flags),
4624 1);
Ben Hutchingse1ee5962011-11-30 02:29:21 +00004625 if (!strings) {
4626 perror("Cannot get private flag names");
4627 return 1;
4628 }
4629 if (strings->len == 0) {
4630 fprintf(stderr, "No private flags defined\n");
John W. Linvilleecbd5ea2016-09-30 14:57:27 -04004631 rc = 1;
4632 goto err;
Ben Hutchingse1ee5962011-11-30 02:29:21 +00004633 }
4634 if (strings->len > 32) {
4635 /* ETHTOOL_{G,S}PFLAGS can only cover 32 flags */
4636 fprintf(stderr, "Only setting first 32 private flags\n");
4637 strings->len = 32;
4638 }
4639
4640 cmdline = calloc(strings->len, sizeof(*cmdline));
4641 if (!cmdline) {
4642 perror("Cannot parse arguments");
John W. Linvilleecbd5ea2016-09-30 14:57:27 -04004643 rc = 1;
4644 goto err;
Ben Hutchingse1ee5962011-11-30 02:29:21 +00004645 }
4646 for (i = 0; i < strings->len; i++) {
4647 cmdline[i].name = ((const char *)strings->data +
4648 i * ETH_GSTRING_LEN);
4649 cmdline[i].type = CMDL_FLAG;
4650 cmdline[i].wanted_val = &wanted_flags;
4651 cmdline[i].flag_val = 1U << i;
4652 cmdline[i].seen_val = &seen_flags;
4653 }
4654 parse_generic_cmdline(ctx, &any_changed, cmdline, strings->len);
Yuval Mintzc9fb9932013-06-12 14:59:58 +03004655 free(cmdline);
Ben Hutchingse1ee5962011-11-30 02:29:21 +00004656
4657 flags.cmd = ETHTOOL_GPFLAGS;
4658 if (send_ioctl(ctx, &flags)) {
4659 perror("Cannot get private flags");
John W. Linvilleecbd5ea2016-09-30 14:57:27 -04004660 rc = 1;
4661 goto err;
Ben Hutchingse1ee5962011-11-30 02:29:21 +00004662 }
4663
4664 flags.cmd = ETHTOOL_SPFLAGS;
4665 flags.data = (flags.data & ~seen_flags) | wanted_flags;
4666 if (send_ioctl(ctx, &flags)) {
4667 perror("Cannot set private flags");
John W. Linvilleecbd5ea2016-09-30 14:57:27 -04004668 rc = 1;
4669 goto err;
Ben Hutchingse1ee5962011-11-30 02:29:21 +00004670 }
4671
John W. Linvilleecbd5ea2016-09-30 14:57:27 -04004672 rc = 0;
4673err:
4674 free(strings);
4675 return rc;
Ben Hutchingse1ee5962011-11-30 02:29:21 +00004676}
4677
Richard Cochran0fdcc8c2012-04-03 19:58:23 +02004678static int do_tsinfo(struct cmd_context *ctx)
4679{
4680 struct ethtool_ts_info info;
4681
4682 if (ctx->argc != 0)
4683 exit_bad_args();
4684
4685 fprintf(stdout, "Time stamping parameters for %s:\n", ctx->devname);
4686 info.cmd = ETHTOOL_GET_TS_INFO;
4687 if (send_ioctl(ctx, &info)) {
4688 perror("Cannot get device time stamping settings");
4689 return -1;
4690 }
4691 dump_tsinfo(&info);
4692 return 0;
4693}
4694
Stuart Hodgson2edf5672012-05-18 15:58:45 +01004695static int do_getmodule(struct cmd_context *ctx)
4696{
4697 struct ethtool_modinfo modinfo;
4698 struct ethtool_eeprom *eeprom;
4699 u32 geeprom_offset = 0;
4700 u32 geeprom_length = -1;
4701 int geeprom_changed = 0;
4702 int geeprom_dump_raw = 0;
4703 int geeprom_dump_hex = 0;
4704 int err;
4705
4706 struct cmdline_info cmdline_geeprom[] = {
4707 { "offset", CMDL_U32, &geeprom_offset, NULL },
4708 { "length", CMDL_U32, &geeprom_length, NULL },
4709 { "raw", CMDL_BOOL, &geeprom_dump_raw, NULL },
4710 { "hex", CMDL_BOOL, &geeprom_dump_hex, NULL },
4711 };
4712
4713 parse_generic_cmdline(ctx, &geeprom_changed,
4714 cmdline_geeprom, ARRAY_SIZE(cmdline_geeprom));
4715
4716 if (geeprom_dump_raw && geeprom_dump_hex) {
4717 printf("Hex and raw dump cannot be specified together\n");
4718 return 1;
4719 }
4720
4721 modinfo.cmd = ETHTOOL_GMODULEINFO;
4722 err = send_ioctl(ctx, &modinfo);
4723 if (err < 0) {
4724 perror("Cannot get module EEPROM information");
4725 return 1;
4726 }
4727
4728 if (geeprom_length == -1)
4729 geeprom_length = modinfo.eeprom_len;
4730
4731 if (modinfo.eeprom_len < geeprom_offset + geeprom_length)
4732 geeprom_length = modinfo.eeprom_len - geeprom_offset;
4733
4734 eeprom = calloc(1, sizeof(*eeprom)+geeprom_length);
4735 if (!eeprom) {
4736 perror("Cannot allocate memory for Module EEPROM data");
4737 return 1;
4738 }
4739
4740 eeprom->cmd = ETHTOOL_GMODULEEEPROM;
4741 eeprom->len = geeprom_length;
4742 eeprom->offset = geeprom_offset;
4743 err = send_ioctl(ctx, eeprom);
4744 if (err < 0) {
4745 perror("Cannot get Module EEPROM data");
4746 free(eeprom);
4747 return 1;
4748 }
4749
Aurelien Guillaume749f3872012-12-02 21:21:01 +01004750 /*
4751 * SFF-8079 EEPROM layout contains the memory available at A0 address on
4752 * the PHY EEPROM.
4753 * SFF-8472 defines a virtual extension of the EEPROM, where the
4754 * microcontroller on the SFP/SFP+ generates a page at the A2 address,
4755 * which contains data relative to optical diagnostics.
4756 * The current kernel implementation returns a blob, which contains:
4757 * - ETH_MODULE_SFF_8079 => The A0 page only.
4758 * - ETH_MODULE_SFF_8472 => The A0 and A2 page concatenated.
4759 */
Stuart Hodgson2edf5672012-05-18 15:58:45 +01004760 if (geeprom_dump_raw) {
4761 fwrite(eeprom->data, 1, eeprom->len, stdout);
4762 } else {
4763 if (eeprom->offset != 0 ||
4764 (eeprom->len != modinfo.eeprom_len)) {
4765 geeprom_dump_hex = 1;
4766 } else if (!geeprom_dump_hex) {
4767 switch (modinfo.type) {
Florian Fainelli875616d2014-02-27 15:43:01 -08004768#ifdef ETHTOOL_ENABLE_PRETTY_DUMP
Stuart Hodgson2edf5672012-05-18 15:58:45 +01004769 case ETH_MODULE_SFF_8079:
Aurelien Guillaume749f3872012-12-02 21:21:01 +01004770 sff8079_show_all(eeprom->data);
4771 break;
Stuart Hodgson2edf5672012-05-18 15:58:45 +01004772 case ETH_MODULE_SFF_8472:
4773 sff8079_show_all(eeprom->data);
Aurelien Guillaume749f3872012-12-02 21:21:01 +01004774 sff8472_show_all(eeprom->data);
Stuart Hodgson2edf5672012-05-18 15:58:45 +01004775 break;
Vidya Sagar Ravipatia5e73bb2016-08-23 06:30:32 -07004776 case ETH_MODULE_SFF_8436:
4777 case ETH_MODULE_SFF_8636:
4778 sff8636_show_all(eeprom->data,
4779 modinfo.eeprom_len);
4780 break;
Florian Fainelli875616d2014-02-27 15:43:01 -08004781#endif
Stuart Hodgson2edf5672012-05-18 15:58:45 +01004782 default:
4783 geeprom_dump_hex = 1;
4784 break;
4785 }
4786 }
4787 if (geeprom_dump_hex)
Ben Hutchings2038e9e2012-02-17 21:30:06 +00004788 dump_hex(stdout, eeprom->data,
4789 eeprom->len, eeprom->offset);
Stuart Hodgson2edf5672012-05-18 15:58:45 +01004790 }
4791
4792 free(eeprom);
4793
4794 return 0;
4795}
4796
Yuval Mintza9fc8272012-06-10 11:48:08 +03004797static int do_geee(struct cmd_context *ctx)
4798{
4799 struct ethtool_eee eeecmd;
4800
4801 if (ctx->argc != 0)
4802 exit_bad_args();
4803
4804 eeecmd.cmd = ETHTOOL_GEEE;
4805 if (send_ioctl(ctx, &eeecmd)) {
4806 perror("Cannot get EEE settings");
4807 return 1;
4808 }
4809
4810 fprintf(stdout, "EEE Settings for %s:\n", ctx->devname);
4811 dump_eeecmd(&eeecmd);
4812
4813 return 0;
4814}
4815
4816static int do_seee(struct cmd_context *ctx)
4817{
4818 int adv_c = -1, lpi_c = -1, lpi_time_c = -1, eee_c = -1;
Bruce Allan70a58ff2012-09-18 20:20:19 -07004819 int change = -1, change2 = 0;
Yuval Mintza9fc8272012-06-10 11:48:08 +03004820 struct ethtool_eee eeecmd;
4821 struct cmdline_info cmdline_eee[] = {
4822 { "advertise", CMDL_U32, &adv_c, &eeecmd.advertised },
4823 { "tx-lpi", CMDL_BOOL, &lpi_c, &eeecmd.tx_lpi_enabled },
4824 { "tx-timer", CMDL_U32, &lpi_time_c, &eeecmd.tx_lpi_timer},
4825 { "eee", CMDL_BOOL, &eee_c, &eeecmd.eee_enabled},
4826 };
4827
4828 if (ctx->argc == 0)
4829 exit_bad_args();
4830
4831 parse_generic_cmdline(ctx, &change, cmdline_eee,
4832 ARRAY_SIZE(cmdline_eee));
4833
4834 eeecmd.cmd = ETHTOOL_GEEE;
4835 if (send_ioctl(ctx, &eeecmd)) {
4836 perror("Cannot get EEE settings");
4837 return 1;
4838 }
4839
4840 do_generic_set(cmdline_eee, ARRAY_SIZE(cmdline_eee), &change2);
4841
4842 if (change2) {
Yuval Mintza9fc8272012-06-10 11:48:08 +03004843 eeecmd.cmd = ETHTOOL_SEEE;
4844 if (send_ioctl(ctx, &eeecmd)) {
4845 perror("Cannot set EEE settings");
4846 return 1;
4847 }
4848 }
4849
4850 return 0;
4851}
4852
Raju Lakkarajub0fe96d2016-11-24 09:56:51 +01004853static int do_get_phy_tunable(struct cmd_context *ctx)
4854{
4855 int argc = ctx->argc;
4856 char **argp = ctx->argp;
Raju Lakkarajub0fe96d2016-11-24 09:56:51 +01004857
4858 if (argc < 1)
4859 exit_bad_args();
Raju Lakkarajub0fe96d2016-11-24 09:56:51 +01004860
Heiner Kallweit34a6dce2019-03-29 20:15:16 +01004861 if (!strcmp(argp[0], "downshift")) {
Michal Kubecekef49e582018-05-09 14:01:46 +02004862 struct {
4863 struct ethtool_tunable ds;
Heiner Kallweit34a6dce2019-03-29 20:15:16 +01004864 u8 count;
Michal Kubecekef49e582018-05-09 14:01:46 +02004865 } cont;
Raju Lakkarajub0fe96d2016-11-24 09:56:51 +01004866
Michal Kubecekef49e582018-05-09 14:01:46 +02004867 cont.ds.cmd = ETHTOOL_PHY_GTUNABLE;
4868 cont.ds.id = ETHTOOL_PHY_DOWNSHIFT;
4869 cont.ds.type_id = ETHTOOL_TUNABLE_U8;
4870 cont.ds.len = 1;
Ivan Vecera75303462018-06-08 11:20:05 +02004871 if (send_ioctl(ctx, &cont.ds) < 0) {
Raju Lakkarajub0fe96d2016-11-24 09:56:51 +01004872 perror("Cannot Get PHY downshift count");
4873 return 87;
4874 }
Heiner Kallweit34a6dce2019-03-29 20:15:16 +01004875 if (cont.count)
4876 fprintf(stdout, "Downshift count: %d\n", cont.count);
Raju Lakkarajub0fe96d2016-11-24 09:56:51 +01004877 else
4878 fprintf(stdout, "Downshift disabled\n");
Heiner Kallweit27c7bb12019-03-29 20:15:54 +01004879 } else if (!strcmp(argp[0], "fast-link-down")) {
4880 struct {
4881 struct ethtool_tunable fld;
4882 u8 msecs;
4883 } cont;
4884
4885 cont.fld.cmd = ETHTOOL_PHY_GTUNABLE;
4886 cont.fld.id = ETHTOOL_PHY_FAST_LINK_DOWN;
4887 cont.fld.type_id = ETHTOOL_TUNABLE_U8;
4888 cont.fld.len = 1;
4889 if (send_ioctl(ctx, &cont.fld) < 0) {
4890 perror("Cannot Get PHY Fast Link Down value");
4891 return 87;
4892 }
4893
4894 if (cont.msecs == ETHTOOL_PHY_FAST_LINK_DOWN_ON)
4895 fprintf(stdout, "Fast Link Down enabled\n");
4896 else if (cont.msecs == ETHTOOL_PHY_FAST_LINK_DOWN_OFF)
4897 fprintf(stdout, "Fast Link Down disabled\n");
4898 else
4899 fprintf(stdout, "Fast Link Down enabled, %d msecs\n",
4900 cont.msecs);
Alexandru Ardeleane5684312019-09-20 12:44:31 +03004901 } else if (!strcmp(argp[0], "energy-detect-power-down")) {
4902 struct {
4903 struct ethtool_tunable ds;
4904 u16 msecs;
4905 } cont;
4906
4907 cont.ds.cmd = ETHTOOL_PHY_GTUNABLE;
4908 cont.ds.id = ETHTOOL_PHY_EDPD;
4909 cont.ds.type_id = ETHTOOL_TUNABLE_U16;
4910 cont.ds.len = 2;
4911 if (send_ioctl(ctx, &cont.ds) < 0) {
4912 perror("Cannot Get PHY Energy Detect Power Down value");
4913 return 87;
4914 }
4915
4916 if (cont.msecs == ETHTOOL_PHY_EDPD_DISABLE)
4917 fprintf(stdout, "Energy Detect Power Down: disabled\n");
4918 else if (cont.msecs == ETHTOOL_PHY_EDPD_NO_TX)
4919 fprintf(stdout,
4920 "Energy Detect Power Down: enabled, TX disabled\n");
4921 else
4922 fprintf(stdout,
4923 "Energy Detect Power Down: enabled, TX %u msecs\n",
4924 cont.msecs);
Heiner Kallweit34a6dce2019-03-29 20:15:16 +01004925 } else {
4926 exit_bad_args();
Raju Lakkarajub0fe96d2016-11-24 09:56:51 +01004927 }
4928
Ivan Vecera75303462018-06-08 11:20:05 +02004929 return 0;
Raju Lakkarajub0fe96d2016-11-24 09:56:51 +01004930}
4931
Scott Branden1d3761c2017-12-12 12:20:03 -08004932static __u32 parse_reset(char *val, __u32 bitset, char *arg, __u32 *data)
4933{
4934 __u32 bitval = 0;
4935 int i;
4936
4937 /* Check for component match */
4938 for (i = 0; val[i] != '\0'; i++)
4939 if (arg[i] != val[i])
4940 return 0;
4941
4942 /* Check if component has -shared specified or not */
4943 if (arg[i] == '\0')
4944 bitval = bitset;
4945 else if (!strcmp(arg+i, "-shared"))
4946 bitval = bitset << ETH_RESET_SHARED_SHIFT;
4947
4948 if (bitval) {
4949 *data |= bitval;
4950 return 1;
4951 }
4952 return 0;
4953}
4954
4955static int do_reset(struct cmd_context *ctx)
4956{
4957 struct ethtool_value resetinfo;
4958 __u32 data;
4959 int argc = ctx->argc;
4960 char **argp = ctx->argp;
4961 int i;
4962
4963 if (argc == 0)
4964 exit_bad_args();
4965
4966 data = 0;
4967
4968 for (i = 0; i < argc; i++) {
4969 if (!strcmp(argp[i], "flags")) {
4970 __u32 flags;
4971
4972 i++;
4973 if (i >= argc)
4974 exit_bad_args();
4975 flags = strtoul(argp[i], NULL, 0);
4976 if (flags == 0)
4977 exit_bad_args();
4978 else
4979 data |= flags;
4980 } else if (parse_reset("mgmt", ETH_RESET_MGMT,
4981 argp[i], &data)) {
4982 } else if (parse_reset("irq", ETH_RESET_IRQ,
4983 argp[i], &data)) {
4984 } else if (parse_reset("dma", ETH_RESET_DMA,
4985 argp[i], &data)) {
4986 } else if (parse_reset("filter", ETH_RESET_FILTER,
4987 argp[i], &data)) {
4988 } else if (parse_reset("offload", ETH_RESET_OFFLOAD,
4989 argp[i], &data)) {
4990 } else if (parse_reset("mac", ETH_RESET_MAC,
4991 argp[i], &data)) {
4992 } else if (parse_reset("phy", ETH_RESET_PHY,
4993 argp[i], &data)) {
4994 } else if (parse_reset("ram", ETH_RESET_RAM,
4995 argp[i], &data)) {
4996 } else if (parse_reset("ap", ETH_RESET_AP,
4997 argp[i], &data)) {
4998 } else if (!strcmp(argp[i], "dedicated")) {
4999 data |= ETH_RESET_DEDICATED;
5000 } else if (!strcmp(argp[i], "all")) {
5001 data |= ETH_RESET_ALL;
5002 } else {
5003 exit_bad_args();
5004 }
5005 }
5006
5007 resetinfo.cmd = ETHTOOL_RESET;
5008 resetinfo.data = data;
5009 fprintf(stdout, "ETHTOOL_RESET 0x%x\n", resetinfo.data);
5010
5011 if (send_ioctl(ctx, &resetinfo)) {
5012 perror("Cannot issue ETHTOOL_RESET");
5013 return 1;
5014 }
5015
5016 fprintf(stdout, "Components reset: 0x%x\n", data & ~resetinfo.data);
5017 if (resetinfo.data)
5018 fprintf(stdout, "Components not reset: 0x%x\n", resetinfo.data);
5019
5020 return 0;
5021}
5022
Raju Lakkarajub0fe96d2016-11-24 09:56:51 +01005023static int parse_named_bool(struct cmd_context *ctx, const char *name, u8 *on)
5024{
5025 if (ctx->argc < 2)
5026 return 0;
5027
5028 if (strcmp(*ctx->argp, name))
5029 return 0;
5030
5031 if (!strcmp(*(ctx->argp + 1), "on")) {
5032 *on = 1;
5033 } else if (!strcmp(*(ctx->argp + 1), "off")) {
5034 *on = 0;
5035 } else {
5036 fprintf(stderr, "Invalid boolean\n");
5037 exit_bad_args();
5038 }
5039
5040 ctx->argc -= 2;
5041 ctx->argp += 2;
5042
5043 return 1;
5044}
5045
Alexandru Ardeleane5684312019-09-20 12:44:31 +03005046static int parse_named_uint(struct cmd_context *ctx,
5047 const char *name,
5048 unsigned long long *val,
5049 unsigned long long max)
Raju Lakkarajub0fe96d2016-11-24 09:56:51 +01005050{
5051 if (ctx->argc < 2)
5052 return 0;
5053
5054 if (strcmp(*ctx->argp, name))
5055 return 0;
5056
Alexandru Ardeleane5684312019-09-20 12:44:31 +03005057 *val = get_uint_range(*(ctx->argp + 1), 0, max);
Raju Lakkarajub0fe96d2016-11-24 09:56:51 +01005058
5059 ctx->argc -= 2;
5060 ctx->argp += 2;
5061
5062 return 1;
5063}
5064
Alexandru Ardeleane5684312019-09-20 12:44:31 +03005065static int parse_named_u8(struct cmd_context *ctx, const char *name, u8 *val)
5066{
5067 unsigned long long val1;
5068 int ret;
5069
5070 ret = parse_named_uint(ctx, name, &val1, 0xff);
5071 if (ret)
5072 *val = val1;
5073
5074 return ret;
5075}
5076
5077static int parse_named_u16(struct cmd_context *ctx, const char *name, u16 *val)
5078{
5079 unsigned long long val1;
5080 int ret;
5081
5082 ret = parse_named_uint(ctx, name, &val1, 0xffff);
5083 if (ret)
5084 *val = val1;
5085
5086 return ret;
5087}
5088
Raju Lakkarajub0fe96d2016-11-24 09:56:51 +01005089static int do_set_phy_tunable(struct cmd_context *ctx)
5090{
5091 int err = 0;
5092 u8 ds_cnt = DOWNSHIFT_DEV_DEFAULT_COUNT;
5093 u8 ds_changed = 0, ds_has_cnt = 0, ds_enable = 0;
Heiner Kallweit27c7bb12019-03-29 20:15:54 +01005094 u8 fld_changed = 0, fld_enable = 0;
5095 u8 fld_msecs = ETHTOOL_PHY_FAST_LINK_DOWN_ON;
Alexandru Ardeleane5684312019-09-20 12:44:31 +03005096 u8 edpd_changed = 0, edpd_enable = 0;
5097 u16 edpd_tx_interval = ETHTOOL_PHY_EDPD_DFLT_TX_MSECS;
Raju Lakkarajub0fe96d2016-11-24 09:56:51 +01005098
Raju Lakkarajub0fe96d2016-11-24 09:56:51 +01005099 /* Parse arguments */
Heiner Kallweit34a6dce2019-03-29 20:15:16 +01005100 if (parse_named_bool(ctx, "downshift", &ds_enable)) {
5101 ds_changed = 1;
5102 ds_has_cnt = parse_named_u8(ctx, "count", &ds_cnt);
Heiner Kallweit27c7bb12019-03-29 20:15:54 +01005103 } else if (parse_named_bool(ctx, "fast-link-down", &fld_enable)) {
5104 fld_changed = 1;
5105 if (fld_enable)
5106 parse_named_u8(ctx, "msecs", &fld_msecs);
Alexandru Ardeleane5684312019-09-20 12:44:31 +03005107 } else if (parse_named_bool(ctx, "energy-detect-power-down",
5108 &edpd_enable)) {
5109 edpd_changed = 1;
5110 if (edpd_enable)
5111 parse_named_u16(ctx, "msecs", &edpd_tx_interval);
Heiner Kallweit34a6dce2019-03-29 20:15:16 +01005112 } else {
5113 exit_bad_args();
Raju Lakkarajub0fe96d2016-11-24 09:56:51 +01005114 }
5115
5116 /* Validate parameters */
5117 if (ds_changed) {
5118 if (!ds_enable && ds_has_cnt) {
5119 fprintf(stderr, "'count' may not be set when downshift "
5120 "is off.\n");
5121 exit_bad_args();
5122 }
5123
5124 if (ds_enable && ds_has_cnt && ds_cnt == 0) {
5125 fprintf(stderr, "'count' may not be zero.\n");
5126 exit_bad_args();
5127 }
5128
5129 if (!ds_enable)
5130 ds_cnt = DOWNSHIFT_DEV_DISABLE;
Heiner Kallweit27c7bb12019-03-29 20:15:54 +01005131 } else if (fld_changed) {
5132 if (!fld_enable)
5133 fld_msecs = ETHTOOL_PHY_FAST_LINK_DOWN_OFF;
5134 else if (fld_msecs == ETHTOOL_PHY_FAST_LINK_DOWN_OFF)
5135 exit_bad_args();
Alexandru Ardeleane5684312019-09-20 12:44:31 +03005136 } else if (edpd_changed) {
5137 if (!edpd_enable)
5138 edpd_tx_interval = ETHTOOL_PHY_EDPD_DISABLE;
5139 else if (edpd_tx_interval == 0)
5140 edpd_tx_interval = ETHTOOL_PHY_EDPD_NO_TX;
5141 else if (edpd_tx_interval > ETHTOOL_PHY_EDPD_NO_TX) {
5142 fprintf(stderr, "'msecs' max value is %d.\n",
5143 (ETHTOOL_PHY_EDPD_NO_TX - 1));
5144 exit_bad_args();
5145 }
Raju Lakkarajub0fe96d2016-11-24 09:56:51 +01005146 }
5147
5148 /* Do it */
5149 if (ds_changed) {
Michal Kubecekef49e582018-05-09 14:01:46 +02005150 struct {
5151 struct ethtool_tunable ds;
Heiner Kallweit34a6dce2019-03-29 20:15:16 +01005152 u8 count;
Michal Kubecekef49e582018-05-09 14:01:46 +02005153 } cont;
Raju Lakkarajub0fe96d2016-11-24 09:56:51 +01005154
Michal Kubecekef49e582018-05-09 14:01:46 +02005155 cont.ds.cmd = ETHTOOL_PHY_STUNABLE;
5156 cont.ds.id = ETHTOOL_PHY_DOWNSHIFT;
5157 cont.ds.type_id = ETHTOOL_TUNABLE_U8;
5158 cont.ds.len = 1;
Heiner Kallweit34a6dce2019-03-29 20:15:16 +01005159 cont.count = ds_cnt;
Michal Kubecekef49e582018-05-09 14:01:46 +02005160 err = send_ioctl(ctx, &cont.ds);
Raju Lakkarajub0fe96d2016-11-24 09:56:51 +01005161 if (err < 0) {
5162 perror("Cannot Set PHY downshift count");
5163 err = 87;
5164 }
Heiner Kallweit27c7bb12019-03-29 20:15:54 +01005165 } else if (fld_changed) {
5166 struct {
5167 struct ethtool_tunable fld;
5168 u8 msecs;
5169 } cont;
5170
5171 cont.fld.cmd = ETHTOOL_PHY_STUNABLE;
5172 cont.fld.id = ETHTOOL_PHY_FAST_LINK_DOWN;
5173 cont.fld.type_id = ETHTOOL_TUNABLE_U8;
5174 cont.fld.len = 1;
5175 cont.msecs = fld_msecs;
5176 err = send_ioctl(ctx, &cont.fld);
5177 if (err < 0) {
5178 perror("Cannot Set PHY Fast Link Down value");
5179 err = 87;
5180 }
Alexandru Ardeleane5684312019-09-20 12:44:31 +03005181 } else if (edpd_changed) {
5182 struct {
5183 struct ethtool_tunable fld;
5184 u16 msecs;
5185 } cont;
5186
5187 cont.fld.cmd = ETHTOOL_PHY_STUNABLE;
5188 cont.fld.id = ETHTOOL_PHY_EDPD;
5189 cont.fld.type_id = ETHTOOL_TUNABLE_U16;
5190 cont.fld.len = 2;
5191 cont.msecs = edpd_tx_interval;
5192 err = send_ioctl(ctx, &cont.fld);
5193 if (err < 0) {
5194 perror("Cannot Set PHY Energy Detect Power Down");
5195 err = 87;
5196 }
Raju Lakkarajub0fe96d2016-11-24 09:56:51 +01005197 }
5198
5199 return err;
5200}
5201
Dustin Byford8db75d12017-12-18 14:57:41 -08005202static int fecmode_str_to_type(const char *str)
5203{
Edward Creed4b9f3f2018-09-05 18:54:57 +01005204 if (!strcasecmp(str, "auto"))
5205 return ETHTOOL_FEC_AUTO;
5206 if (!strcasecmp(str, "off"))
5207 return ETHTOOL_FEC_OFF;
5208 if (!strcasecmp(str, "rs"))
5209 return ETHTOOL_FEC_RS;
5210 if (!strcasecmp(str, "baser"))
5211 return ETHTOOL_FEC_BASER;
5212
5213 return 0;
5214}
5215
Dustin Byford8db75d12017-12-18 14:57:41 -08005216static int do_gfec(struct cmd_context *ctx)
5217{
5218 struct ethtool_fecparam feccmd = { 0 };
5219 int rv;
5220
5221 if (ctx->argc != 0)
5222 exit_bad_args();
5223
5224 feccmd.cmd = ETHTOOL_GFECPARAM;
5225 rv = send_ioctl(ctx, &feccmd);
5226 if (rv != 0) {
5227 perror("Cannot get FEC settings");
5228 return rv;
5229 }
5230
5231 fprintf(stdout, "FEC parameters for %s:\n", ctx->devname);
5232 fprintf(stdout, "Configured FEC encodings:");
5233 dump_fec(feccmd.fec);
5234 fprintf(stdout, "\n");
5235
5236 fprintf(stdout, "Active FEC encoding:");
5237 dump_fec(feccmd.active_fec);
5238 fprintf(stdout, "\n");
5239
5240 return 0;
5241}
5242
5243static int do_sfec(struct cmd_context *ctx)
5244{
Edward Cree98c148e2018-09-19 17:06:25 +01005245 enum { ARG_NONE, ARG_ENCODING } state = ARG_NONE;
Dustin Byford8db75d12017-12-18 14:57:41 -08005246 struct ethtool_fecparam feccmd;
Edward Cree98c148e2018-09-19 17:06:25 +01005247 int fecmode = 0, newmode;
5248 int rv, i;
Dustin Byford8db75d12017-12-18 14:57:41 -08005249
Edward Cree98c148e2018-09-19 17:06:25 +01005250 for (i = 0; i < ctx->argc; i++) {
5251 if (!strcmp(ctx->argp[i], "encoding")) {
5252 state = ARG_ENCODING;
5253 continue;
5254 }
5255 if (state == ARG_ENCODING) {
5256 newmode = fecmode_str_to_type(ctx->argp[i]);
5257 if (!newmode)
5258 exit_bad_args();
5259 fecmode |= newmode;
5260 continue;
5261 }
Dustin Byford8db75d12017-12-18 14:57:41 -08005262 exit_bad_args();
Edward Cree98c148e2018-09-19 17:06:25 +01005263 }
Dustin Byford8db75d12017-12-18 14:57:41 -08005264
Dustin Byford8db75d12017-12-18 14:57:41 -08005265 if (!fecmode)
5266 exit_bad_args();
5267
5268 feccmd.cmd = ETHTOOL_SFECPARAM;
5269 feccmd.fec = fecmode;
5270 rv = send_ioctl(ctx, &feccmd);
5271 if (rv != 0) {
5272 perror("Cannot set FEC settings");
5273 return rv;
5274 }
5275
5276 return 0;
5277}
5278
Nicholas Nunley9ecd5422019-03-01 00:15:29 -08005279static int do_perqueue(struct cmd_context *ctx);
5280
Ben Hutchingsdfacc4a2011-10-31 18:29:35 +00005281#ifndef TEST_ETHTOOL
Ben Hutchings37897ca2011-10-29 02:33:30 +01005282int send_ioctl(struct cmd_context *ctx, void *cmd)
Jeff Garzika97a2ec2009-03-06 06:12:13 -05005283{
Ben Hutchings37897ca2011-10-29 02:33:30 +01005284 ctx->ifr.ifr_data = cmd;
5285 return ioctl(ctx->fd, SIOCETHTOOL, &ctx->ifr);
Jeff Garzika97a2ec2009-03-06 06:12:13 -05005286}
Ben Hutchingsdfacc4a2011-10-31 18:29:35 +00005287#endif
Jeff Garzika97a2ec2009-03-06 06:12:13 -05005288
Ben Hutchings56b11482011-10-31 23:44:42 +00005289static int show_usage(struct cmd_context *ctx);
5290
5291static const struct option {
5292 const char *opts;
5293 int want_device;
5294 int (*func)(struct cmd_context *);
5295 char *help;
5296 char *opthelp;
5297} args[] = {
5298 { "-s|--change", 1, do_sset, "Change generic options",
5299 " [ speed %d ]\n"
5300 " [ duplex half|full ]\n"
5301 " [ port tp|aui|bnc|mii|fibre ]\n"
Jesse Brandeburg75e67912012-08-21 01:37:16 -07005302 " [ mdix auto|on|off ]\n"
Ben Hutchings56b11482011-10-31 23:44:42 +00005303 " [ autoneg on|off ]\n"
5304 " [ advertise %x ]\n"
5305 " [ phyad %d ]\n"
5306 " [ xcvr internal|external ]\n"
Michal Kubecekb3086af2018-08-17 15:21:07 +02005307 " [ wol p|u|m|b|a|g|s|f|d... ]\n"
Ben Hutchings56b11482011-10-31 23:44:42 +00005308 " [ sopass %x:%x:%x:%x:%x:%x ]\n"
5309 " [ msglvl %d | msglvl type on|off ... ]\n" },
5310 { "-a|--show-pause", 1, do_gpause, "Show pause options" },
5311 { "-A|--pause", 1, do_spause, "Set pause options",
5312 " [ autoneg on|off ]\n"
5313 " [ rx on|off ]\n"
5314 " [ tx on|off ]\n" },
5315 { "-c|--show-coalesce", 1, do_gcoalesce, "Show coalesce options" },
5316 { "-C|--coalesce", 1, do_scoalesce, "Set coalesce options",
5317 " [adaptive-rx on|off]\n"
5318 " [adaptive-tx on|off]\n"
5319 " [rx-usecs N]\n"
5320 " [rx-frames N]\n"
5321 " [rx-usecs-irq N]\n"
5322 " [rx-frames-irq N]\n"
5323 " [tx-usecs N]\n"
5324 " [tx-frames N]\n"
5325 " [tx-usecs-irq N]\n"
5326 " [tx-frames-irq N]\n"
5327 " [stats-block-usecs N]\n"
5328 " [pkt-rate-low N]\n"
5329 " [rx-usecs-low N]\n"
5330 " [rx-frames-low N]\n"
5331 " [tx-usecs-low N]\n"
5332 " [tx-frames-low N]\n"
5333 " [pkt-rate-high N]\n"
5334 " [rx-usecs-high N]\n"
5335 " [rx-frames-high N]\n"
5336 " [tx-usecs-high N]\n"
5337 " [tx-frames-high N]\n"
Scott Brandenc0b078c2017-12-12 12:20:01 -08005338 " [sample-interval N]\n" },
Ben Hutchings56b11482011-10-31 23:44:42 +00005339 { "-g|--show-ring", 1, do_gring, "Query RX/TX ring parameters" },
5340 { "-G|--set-ring", 1, do_sring, "Set RX/TX ring parameters",
5341 " [ rx N ]\n"
5342 " [ rx-mini N ]\n"
5343 " [ rx-jumbo N ]\n"
5344 " [ tx N ]\n" },
Ben Hutchings60428042012-06-01 23:08:32 +01005345 { "-k|--show-features|--show-offload", 1, do_gfeatures,
5346 "Get state of protocol offload and other features" },
5347 { "-K|--features|--offload", 1, do_sfeatures,
5348 "Set protocol offload and other features",
5349 " FEATURE on|off ...\n" },
Ben Hutchings56b11482011-10-31 23:44:42 +00005350 { "-i|--driver", 1, do_gdrv, "Show driver information" },
5351 { "-d|--register-dump", 1, do_gregs, "Do a register dump",
5352 " [ raw on|off ]\n"
5353 " [ file FILENAME ]\n" },
5354 { "-e|--eeprom-dump", 1, do_geeprom, "Do a EEPROM dump",
5355 " [ raw on|off ]\n"
5356 " [ offset N ]\n"
5357 " [ length N ]\n" },
5358 { "-E|--change-eeprom", 1, do_seeprom,
5359 "Change bytes in device EEPROM",
5360 " [ magic N ]\n"
5361 " [ offset N ]\n"
5362 " [ length N ]\n"
5363 " [ value N ]\n" },
5364 { "-r|--negotiate", 1, do_nway_rst, "Restart N-WAY negotiation" },
5365 { "-p|--identify", 1, do_phys_id,
5366 "Show visible port identification (e.g. blinking)",
5367 " [ TIME-IN-SECONDS ]\n" },
5368 { "-t|--test", 1, do_test, "Execute adapter self test",
5369 " [ online | offline | external_lb ]\n" },
Ben Hutchings395d8302016-03-13 15:56:41 +00005370 { "-S|--statistics", 1, do_gnicstats, "Show adapter statistics" },
Ben Hutchings0fd19512016-03-13 15:51:58 +00005371 { "--phy-statistics", 1, do_gphystats,
Andrew Lunn8b4b8232015-12-23 12:58:31 +01005372 "Show phy statistics" },
Ben Hutchings52e837f2012-01-21 00:35:55 +00005373 { "-n|-u|--show-nfc|--show-ntuple", 1, do_grxclass,
5374 "Show Rx network flow classification options or rules",
Ben Hutchings56b11482011-10-31 23:44:42 +00005375 " [ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
Edward Creef5d55b92018-03-09 15:04:12 +00005376 "tcp6|udp6|ah6|esp6|sctp6 [context %d] |\n"
Ben Hutchings52e837f2012-01-21 00:35:55 +00005377 " rule %d ]\n" },
5378 { "-N|-U|--config-nfc|--config-ntuple", 1, do_srxclass,
5379 "Configure Rx network flow classification options or rules",
5380 " rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
Edward Creef5d55b92018-03-09 15:04:12 +00005381 "tcp6|udp6|ah6|esp6|sctp6 m|v|t|s|d|f|n|r... [context %d] |\n"
Edward Cree0c4866c2016-03-17 19:17:32 +00005382 " flow-type ether|ip4|tcp4|udp4|sctp4|ah4|esp4|"
5383 "ip6|tcp6|udp6|ah6|esp6|sctp6\n"
Ben Hutchings56b11482011-10-31 23:44:42 +00005384 " [ src %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
5385 " [ dst %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
5386 " [ proto %d [m %x] ]\n"
Ben Hutchings7d429052016-06-26 00:58:10 +02005387 " [ src-ip IP-ADDRESS [m IP-ADDRESS] ]\n"
5388 " [ dst-ip IP-ADDRESS [m IP-ADDRESS] ]\n"
Ben Hutchings56b11482011-10-31 23:44:42 +00005389 " [ tos %d [m %x] ]\n"
Edward Cree0c4866c2016-03-17 19:17:32 +00005390 " [ tclass %d [m %x] ]\n"
Ben Hutchings56b11482011-10-31 23:44:42 +00005391 " [ l4proto %d [m %x] ]\n"
5392 " [ src-port %d [m %x] ]\n"
5393 " [ dst-port %d [m %x] ]\n"
5394 " [ spi %d [m %x] ]\n"
5395 " [ vlan-etype %x [m %x] ]\n"
5396 " [ vlan %x [m %x] ]\n"
5397 " [ user-def %x [m %x] ]\n"
Yan Burmanb29aa902012-12-11 14:03:56 +02005398 " [ dst-mac %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
Jacob Kellerc837bea2018-02-26 10:49:55 -08005399 " [ action %d ] | [ vf %d queue %d ]\n"
Edward Creef5d55b92018-03-09 15:04:12 +00005400 " [ context %d ]\n"
Ben Hutchings52e837f2012-01-21 00:35:55 +00005401 " [ loc %d]] |\n"
5402 " delete %d\n" },
Richard Cochran0fdcc8c2012-04-03 19:58:23 +02005403 { "-T|--show-time-stamping", 1, do_tsinfo,
5404 "Show time stamping capabilities" },
Venkat Duvvuru86c03262014-07-22 17:51:07 +05305405 { "-x|--show-rxfh-indir|--show-rxfh", 1, do_grxfh,
Edward Creef5d55b92018-03-09 15:04:12 +00005406 "Show Rx flow hash indirection table and/or RSS hash key",
5407 " [ context %d ]\n" },
Venkat Duvvuru86c03262014-07-22 17:51:07 +05305408 { "-X|--set-rxfh-indir|--rxfh", 1, do_srxfh,
Ivan Vecera23efab92017-02-20 15:13:52 +01005409 "Set Rx flow hash indirection table and/or RSS hash key",
Edward Creef5d55b92018-03-09 15:04:12 +00005410 " [ context %d|new ]\n"
Ivan Vecera23efab92017-02-20 15:13:52 +01005411 " [ equal N | weight W0 W1 ... | default ]\n"
Gal Pressmanb888f352017-03-08 16:03:51 +02005412 " [ hkey %x:%x:%x:%x:%x:.... ]\n"
Edward Creef5d55b92018-03-09 15:04:12 +00005413 " [ hfunc FUNC ]\n"
5414 " [ delete ]\n" },
Ben Hutchings52e837f2012-01-21 00:35:55 +00005415 { "-f|--flash", 1, do_flash,
5416 "Flash firmware image from the specified file to a region on the device",
5417 " FILENAME [ REGION-NUMBER-TO-FLASH ]\n" },
Ben Hutchings56b11482011-10-31 23:44:42 +00005418 { "-P|--show-permaddr", 1, do_permaddr,
5419 "Show permanent hardware address" },
5420 { "-w|--get-dump", 1, do_getfwdump,
5421 "Get dump flag, data",
5422 " [ data FILENAME ]\n" },
5423 { "-W|--set-dump", 1, do_setfwdump,
5424 "Set dump flag of the device",
5425 " N\n"},
5426 { "-l|--show-channels", 1, do_gchannels, "Query Channels" },
5427 { "-L|--set-channels", 1, do_schannels, "Set Channels",
5428 " [ rx N ]\n"
5429 " [ tx N ]\n"
5430 " [ other N ]\n"
5431 " [ combined N ]\n" },
Gal Pressman5a20e542017-10-26 17:44:43 +03005432 { "--show-priv-flags", 1, do_gprivflags, "Query private flags" },
Ben Hutchingse1ee5962011-11-30 02:29:21 +00005433 { "--set-priv-flags", 1, do_sprivflags, "Set private flags",
5434 " FLAG on|off ...\n" },
Aurelien Guillaume749f3872012-12-02 21:21:01 +01005435 { "-m|--dump-module-eeprom|--module-info", 1, do_getmodule,
5436 "Query/Decode Module EEPROM information and optical diagnostics if available",
Stuart Hodgson2edf5672012-05-18 15:58:45 +01005437 " [ raw on|off ]\n"
5438 " [ hex on|off ]\n"
5439 " [ offset N ]\n"
5440 " [ length N ]\n" },
Yuval Mintza9fc8272012-06-10 11:48:08 +03005441 { "--show-eee", 1, do_geee, "Show EEE settings"},
5442 { "--set-eee", 1, do_seee, "Set EEE settings",
5443 " [ eee on|off ]\n"
5444 " [ advertise %x ]\n"
5445 " [ tx-lpi on|off ]\n"
5446 " [ tx-timer %d ]\n"},
Raju Lakkarajub0fe96d2016-11-24 09:56:51 +01005447 { "--set-phy-tunable", 1, do_set_phy_tunable, "Set PHY tunable",
Heiner Kallweit27c7bb12019-03-29 20:15:54 +01005448 " [ downshift on|off [count N] ]\n"
Alexandru Ardeleane5684312019-09-20 12:44:31 +03005449 " [ fast-link-down on|off [msecs N] ]\n"
5450 " [ energy-detect-power-down on|off [msecs N] ]\n"},
Raju Lakkarajub0fe96d2016-11-24 09:56:51 +01005451 { "--get-phy-tunable", 1, do_get_phy_tunable, "Get PHY tunable",
Heiner Kallweit27c7bb12019-03-29 20:15:54 +01005452 " [ downshift ]\n"
Alexandru Ardeleane5684312019-09-20 12:44:31 +03005453 " [ fast-link-down ]\n"
5454 " [ energy-detect-power-down ]\n"},
Scott Branden1d3761c2017-12-12 12:20:03 -08005455 { "--reset", 1, do_reset, "Reset components",
5456 " [ flags %x ]\n"
5457 " [ mgmt ]\n"
5458 " [ mgmt-shared ]\n"
5459 " [ irq ]\n"
5460 " [ irq-shared ]\n"
5461 " [ dma ]\n"
5462 " [ dma-shared ]\n"
5463 " [ filter ]\n"
5464 " [ filter-shared ]\n"
5465 " [ offload ]\n"
5466 " [ offload-shared ]\n"
5467 " [ mac ]\n"
5468 " [ mac-shared ]\n"
5469 " [ phy ]\n"
5470 " [ phy-shared ]\n"
5471 " [ ram ]\n"
5472 " [ ram-shared ]\n"
5473 " [ ap ]\n"
5474 " [ ap-shared ]\n"
5475 " [ dedicated ]\n"
5476 " [ all ]\n"},
Dustin Byford8db75d12017-12-18 14:57:41 -08005477 { "--show-fec", 1, do_gfec, "Show FEC settings"},
5478 { "--set-fec", 1, do_sfec, "Set FEC settings",
Edward Cree98c148e2018-09-19 17:06:25 +01005479 " [ encoding auto|off|rs|baser [...]]\n"},
Nicholas Nunley52ecd6e2019-03-01 00:15:30 -08005480 { "-Q|--per-queue", 1, do_perqueue, "Apply per-queue command."
Nicholas Nunley759d6952019-03-01 00:15:31 -08005481 "The supported sub commands include --show-coalesce, --coalesce",
Nicholas Nunley9ecd5422019-03-01 00:15:29 -08005482 " [queue_mask %x] SUB_COMMAND\n"},
Ben Hutchings56b11482011-10-31 23:44:42 +00005483 { "-h|--help", 0, show_usage, "Show this help" },
5484 { "--version", 0, do_version, "Show version number" },
5485 {}
5486};
5487
Maciej Żenczykowskid5432a92019-10-17 11:20:50 -07005488static int show_usage(struct cmd_context *ctx maybe_unused)
Ben Hutchings56b11482011-10-31 23:44:42 +00005489{
5490 int i;
5491
5492 /* ethtool -h */
5493 fprintf(stdout, PACKAGE " version " VERSION "\n");
5494 fprintf(stdout,
5495 "Usage:\n"
5496 " ethtool DEVNAME\t"
5497 "Display standard information about device\n");
5498 for (i = 0; args[i].opts; i++) {
5499 fputs(" ethtool ", stdout);
5500 fprintf(stdout, "%s %s\t%s\n",
5501 args[i].opts,
5502 args[i].want_device ? "DEVNAME" : "\t",
5503 args[i].help);
5504 if (args[i].opthelp)
5505 fputs(args[i].opthelp, stdout);
5506 }
5507
5508 return 0;
5509}
5510
Maciej Żenczykowski2054a8c2019-10-17 11:20:51 -07005511static int find_option(char *arg)
Nicholas Nunley37abfb62019-03-01 00:15:27 -08005512{
5513 const char *opt;
5514 size_t len;
5515 int k;
5516
5517 for (k = 0; args[k].opts; k++) {
5518 opt = args[k].opts;
5519 for (;;) {
5520 len = strcspn(opt, "|");
Maciej Żenczykowski2054a8c2019-10-17 11:20:51 -07005521 if (strncmp(arg, opt, len) == 0 && arg[len] == 0)
Nicholas Nunley37abfb62019-03-01 00:15:27 -08005522 return k;
5523
5524 if (opt[len] == 0)
5525 break;
5526 opt += len + 1;
5527 }
5528 }
5529
5530 return -1;
5531}
5532
Nicholas Nunley9ecd5422019-03-01 00:15:29 -08005533#define MAX(x, y) (x > y ? x : y)
5534
5535static int find_max_num_queues(struct cmd_context *ctx)
5536{
5537 struct ethtool_channels echannels;
5538
5539 echannels.cmd = ETHTOOL_GCHANNELS;
5540 if (send_ioctl(ctx, &echannels))
5541 return -1;
5542
5543 return MAX(echannels.rx_count, echannels.tx_count) +
5544 echannels.combined_count;
5545}
5546
Nicholas Nunley52ecd6e2019-03-01 00:15:30 -08005547static struct ethtool_per_queue_op *
5548get_per_queue_coalesce(struct cmd_context *ctx, __u32 *queue_mask, int n_queues)
5549{
5550 struct ethtool_per_queue_op *per_queue_opt;
5551
5552 per_queue_opt = malloc(sizeof(*per_queue_opt) + n_queues *
5553 sizeof(struct ethtool_coalesce));
5554 if (!per_queue_opt)
5555 return NULL;
5556
5557 memcpy(per_queue_opt->queue_mask, queue_mask,
5558 __KERNEL_DIV_ROUND_UP(MAX_NUM_QUEUE, 32) * sizeof(__u32));
5559 per_queue_opt->cmd = ETHTOOL_PERQUEUE;
5560 per_queue_opt->sub_command = ETHTOOL_GCOALESCE;
5561 if (send_ioctl(ctx, per_queue_opt)) {
5562 free(per_queue_opt);
5563 perror("Cannot get device per queue parameters");
5564 return NULL;
5565 }
5566
5567 return per_queue_opt;
5568}
5569
Nicholas Nunley759d6952019-03-01 00:15:31 -08005570static void set_per_queue_coalesce(struct cmd_context *ctx,
5571 struct ethtool_per_queue_op *per_queue_opt,
5572 int n_queues)
5573{
5574 struct ethtool_coalesce ecoal;
5575 DECLARE_COALESCE_OPTION_VARS();
5576 struct cmdline_info cmdline_coalesce[] = COALESCE_CMDLINE_INFO(ecoal);
5577 __u32 *queue_mask = per_queue_opt->queue_mask;
5578 struct ethtool_coalesce *ecoal_q;
5579 int gcoalesce_changed = 0;
5580 int i, idx = 0;
5581
5582 parse_generic_cmdline(ctx, &gcoalesce_changed,
5583 cmdline_coalesce, ARRAY_SIZE(cmdline_coalesce));
5584
5585 ecoal_q = (struct ethtool_coalesce *)(per_queue_opt + 1);
5586 for (i = 0; i < __KERNEL_DIV_ROUND_UP(MAX_NUM_QUEUE, 32); i++) {
5587 int queue = i * 32;
5588 __u32 mask = queue_mask[i];
5589
5590 while (mask > 0) {
5591 if (mask & 0x1) {
5592 int changed = 0;
5593
5594 memcpy(&ecoal, ecoal_q + idx,
5595 sizeof(struct ethtool_coalesce));
5596 do_generic_set(cmdline_coalesce,
5597 ARRAY_SIZE(cmdline_coalesce),
5598 &changed);
5599 if (!changed)
5600 fprintf(stderr,
5601 "Queue %d, no coalesce parameters changed\n",
5602 queue);
5603 memcpy(ecoal_q + idx, &ecoal,
5604 sizeof(struct ethtool_coalesce));
5605 idx++;
5606 }
5607 mask = mask >> 1;
5608 queue++;
5609 }
5610 if (idx == n_queues)
5611 break;
5612 }
5613
5614 per_queue_opt->cmd = ETHTOOL_PERQUEUE;
5615 per_queue_opt->sub_command = ETHTOOL_SCOALESCE;
5616
5617 if (send_ioctl(ctx, per_queue_opt))
5618 perror("Cannot set device per queue parameters");
5619}
5620
Nicholas Nunley9ecd5422019-03-01 00:15:29 -08005621static int do_perqueue(struct cmd_context *ctx)
5622{
Nicholas Nunley52ecd6e2019-03-01 00:15:30 -08005623 struct ethtool_per_queue_op *per_queue_opt;
Nicholas Nunley9ecd5422019-03-01 00:15:29 -08005624 __u32 queue_mask[__KERNEL_DIV_ROUND_UP(MAX_NUM_QUEUE, 32)] = {0};
5625 int i, n_queues = 0;
5626
5627 if (ctx->argc == 0)
5628 exit_bad_args();
5629
5630 /*
5631 * The sub commands will be applied to
5632 * all queues if no queue_mask set
5633 */
5634 if (strncmp(*ctx->argp, "queue_mask", 11)) {
5635 n_queues = find_max_num_queues(ctx);
5636 if (n_queues < 0) {
5637 perror("Cannot get number of queues");
5638 return -EFAULT;
5639 } else if (n_queues > MAX_NUM_QUEUE) {
5640 n_queues = MAX_NUM_QUEUE;
5641 }
5642 for (i = 0; i < n_queues / 32; i++)
5643 queue_mask[i] = ~0;
5644 if (n_queues % 32)
5645 queue_mask[i] = (1 << (n_queues - i * 32)) - 1;
5646 fprintf(stdout,
5647 "The sub commands will be applied to all %d queues\n",
5648 n_queues);
5649 } else {
5650 ctx->argc--;
5651 ctx->argp++;
5652 if (parse_hex_u32_bitmap(*ctx->argp, MAX_NUM_QUEUE,
5653 queue_mask)) {
5654 fprintf(stdout, "Invalid queue mask\n");
5655 return -1;
5656 }
5657 for (i = 0; i < __KERNEL_DIV_ROUND_UP(MAX_NUM_QUEUE, 32); i++) {
5658 __u32 mask = queue_mask[i];
5659
5660 while (mask > 0) {
5661 if (mask & 0x1)
5662 n_queues++;
5663 mask = mask >> 1;
5664 }
5665 }
5666 ctx->argc--;
5667 ctx->argp++;
5668 }
5669
Maciej Żenczykowski2054a8c2019-10-17 11:20:51 -07005670 i = find_option(ctx->argp[0]);
Nicholas Nunley9ecd5422019-03-01 00:15:29 -08005671 if (i < 0)
5672 exit_bad_args();
5673
Nicholas Nunley52ecd6e2019-03-01 00:15:30 -08005674 if (strstr(args[i].opts, "--show-coalesce") != NULL) {
5675 per_queue_opt = get_per_queue_coalesce(ctx, queue_mask,
5676 n_queues);
5677 if (per_queue_opt == NULL) {
5678 perror("Cannot get device per queue parameters");
5679 return -EFAULT;
5680 }
5681 dump_per_queue_coalesce(per_queue_opt, queue_mask, n_queues);
5682 free(per_queue_opt);
Nicholas Nunley759d6952019-03-01 00:15:31 -08005683 } else if (strstr(args[i].opts, "--coalesce") != NULL) {
5684 ctx->argc--;
5685 ctx->argp++;
5686 per_queue_opt = get_per_queue_coalesce(ctx, queue_mask,
5687 n_queues);
5688 if (per_queue_opt == NULL) {
5689 perror("Cannot get device per queue parameters");
5690 return -EFAULT;
5691 }
5692 set_per_queue_coalesce(ctx, per_queue_opt, n_queues);
5693 free(per_queue_opt);
Nicholas Nunley52ecd6e2019-03-01 00:15:30 -08005694 } else {
5695 perror("The subcommand is not supported yet");
5696 return -EOPNOTSUPP;
5697 }
Nicholas Nunley9ecd5422019-03-01 00:15:29 -08005698
Nicholas Nunley52ecd6e2019-03-01 00:15:30 -08005699 return 0;
Nicholas Nunley9ecd5422019-03-01 00:15:29 -08005700}
5701
Ben Hutchingsdfacc4a2011-10-31 18:29:35 +00005702int main(int argc, char **argp)
Jeff Garzik32c80372005-10-25 01:56:48 -04005703{
Ben Hutchingsc62ebdd2011-10-27 20:14:19 +01005704 int (*func)(struct cmd_context *);
5705 int want_device;
Ben Hutchings127f8062011-10-29 01:15:34 +01005706 struct cmd_context ctx;
5707 int k;
5708
David Decotigny33133ab2016-03-25 09:21:01 -07005709 init_global_link_mode_masks();
5710
Ben Hutchings127f8062011-10-29 01:15:34 +01005711 /* Skip command name */
5712 argp++;
5713 argc--;
5714
5715 /* First argument must be either a valid option or a device
5716 * name to get settings for (which we don't expect to begin
5717 * with '-').
5718 */
5719 if (argc == 0)
5720 exit_bad_args();
Nicholas Nunley37abfb62019-03-01 00:15:27 -08005721
Maciej Żenczykowski2054a8c2019-10-17 11:20:51 -07005722 k = find_option(*argp);
Nicholas Nunley37abfb62019-03-01 00:15:27 -08005723 if (k >= 0) {
5724 argp++;
5725 argc--;
5726 func = args[k].func;
5727 want_device = args[k].want_device;
5728 goto opt_found;
Ben Hutchings127f8062011-10-29 01:15:34 +01005729 }
Ben Hutchingsc62ebdd2011-10-27 20:14:19 +01005730 if ((*argp)[0] == '-')
5731 exit_bad_args();
5732 func = do_gset;
5733 want_device = 1;
Ben Hutchings127f8062011-10-29 01:15:34 +01005734
Ben Hutchingsc62ebdd2011-10-27 20:14:19 +01005735opt_found:
Ben Hutchings127f8062011-10-29 01:15:34 +01005736 if (want_device) {
Ben Hutchings743eb0b2011-10-29 02:36:48 +01005737 ctx.devname = *argp++;
Ben Hutchings127f8062011-10-29 01:15:34 +01005738 argc--;
5739
Ben Hutchings743eb0b2011-10-29 02:36:48 +01005740 if (ctx.devname == NULL)
Ben Hutchings127f8062011-10-29 01:15:34 +01005741 exit_bad_args();
Ben Hutchings743eb0b2011-10-29 02:36:48 +01005742 if (strlen(ctx.devname) >= IFNAMSIZ)
Ben Hutchings127f8062011-10-29 01:15:34 +01005743 exit_bad_args();
5744
5745 /* Setup our control structures. */
5746 memset(&ctx.ifr, 0, sizeof(ctx.ifr));
Ben Hutchings743eb0b2011-10-29 02:36:48 +01005747 strcpy(ctx.ifr.ifr_name, ctx.devname);
Ben Hutchings127f8062011-10-29 01:15:34 +01005748
5749 /* Open control socket. */
5750 ctx.fd = socket(AF_INET, SOCK_DGRAM, 0);
David Decotigny225fdc62016-06-26 10:52:59 +02005751 if (ctx.fd < 0)
5752 ctx.fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
Ben Hutchings127f8062011-10-29 01:15:34 +01005753 if (ctx.fd < 0) {
5754 perror("Cannot get control socket");
5755 return 70;
5756 }
5757 } else {
5758 ctx.fd = -1;
5759 }
5760
5761 ctx.argc = argc;
5762 ctx.argp = argp;
5763
5764 return func(&ctx);
Jeff Garzik32c80372005-10-25 01:56:48 -04005765}