summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ethtool-copy.h46
-rw-r--r--ethtool.8.in32
-rw-r--r--ethtool.c265
-rw-r--r--test-cmdline.c15
4 files changed, 267 insertions, 91 deletions
diff --git a/ethtool-copy.h b/ethtool-copy.h
index 9e26a76..0e90e9b 100644
--- a/ethtool-copy.h
+++ b/ethtool-copy.h
@@ -134,6 +134,35 @@ struct ethtool_eeprom {
};
/**
+ * struct ethtool_eee - Energy Efficient Ethernet information
+ * @cmd: ETHTOOL_{G,S}EEE
+ * @supported: Mask of %SUPPORTED_* flags for the speed/duplex combinations
+ * for which there is EEE support.
+ * @advertised: Mask of %ADVERTISED_* flags for the speed/duplex combinations
+ * advertised as eee capable.
+ * @lp_advertised: Mask of %ADVERTISED_* flags for the speed/duplex
+ * combinations advertised by the link partner as eee capable.
+ * @eee_active: Result of the eee auto negotiation.
+ * @eee_enabled: EEE configured mode (enabled/disabled).
+ * @tx_lpi_enabled: Whether the interface should assert its tx lpi, given
+ * that eee was negotiated.
+ * @tx_lpi_timer: Time in microseconds the interface delays prior to asserting
+ * its tx lpi (after reaching 'idle' state). Effective only when eee
+ * was negotiated and tx_lpi_enabled was set.
+ */
+struct ethtool_eee {
+ __u32 cmd;
+ __u32 supported;
+ __u32 advertised;
+ __u32 lp_advertised;
+ __u32 eee_active;
+ __u32 eee_enabled;
+ __u32 tx_lpi_enabled;
+ __u32 tx_lpi_timer;
+ __u32 reserved[2];
+};
+
+/**
* struct ethtool_modinfo - plugin module eeprom information
* @cmd: %ETHTOOL_GMODULEINFO
* @type: Standard the module information conforms to %ETH_MODULE_SFF_xxxx
@@ -651,12 +680,17 @@ struct ethtool_flash {
* %ETHTOOL_SET_DUMP
* @version: FW version of the dump, filled in by driver
* @flag: driver dependent flag for dump setting, filled in by driver during
- * get and filled in by ethtool for set operation
+ * get and filled in by ethtool for set operation.
+ * flag must be initialized by macro ETH_FW_DUMP_DISABLE value when
+ * firmware dump is disabled.
* @len: length of dump data, used as the length of the user buffer on entry to
* %ETHTOOL_GET_DUMP_DATA and this is returned as dump length by driver
* for %ETHTOOL_GET_DUMP_FLAG command
* @data: data collected for get dump data operation
*/
+
+#define ETH_FW_DUMP_DISABLE 0
+
struct ethtool_dump {
__u32 cmd;
__u32 version;
@@ -848,6 +882,8 @@ enum ethtool_sfeatures_retval_bits {
#define ETHTOOL_GET_TS_INFO 0x00000041 /* Get time stamping and PHC info */
#define ETHTOOL_GMODULEINFO 0x00000042 /* Get plug-in module information */
#define ETHTOOL_GMODULEEEPROM 0x00000043 /* Get plug-in module eeprom */
+#define ETHTOOL_GEEE 0x00000044 /* Get EEE settings */
+#define ETHTOOL_SEEE 0x00000045 /* Set EEE settings */
/* compatibility with older code */
#define SPARC_ETH_GSET ETHTOOL_GSET
@@ -877,6 +913,10 @@ enum ethtool_sfeatures_retval_bits {
#define SUPPORTED_10000baseR_FEC (1 << 20)
#define SUPPORTED_20000baseMLD2_Full (1 << 21)
#define SUPPORTED_20000baseKR2_Full (1 << 22)
+#define SUPPORTED_40000baseKR4_Full (1 << 23)
+#define SUPPORTED_40000baseCR4_Full (1 << 24)
+#define SUPPORTED_40000baseSR4_Full (1 << 25)
+#define SUPPORTED_40000baseLR4_Full (1 << 26)
/* Indicates what features are advertised by the interface. */
#define ADVERTISED_10baseT_Half (1 << 0)
@@ -902,6 +942,10 @@ enum ethtool_sfeatures_retval_bits {
#define ADVERTISED_10000baseR_FEC (1 << 20)
#define ADVERTISED_20000baseMLD2_Full (1 << 21)
#define ADVERTISED_20000baseKR2_Full (1 << 22)
+#define ADVERTISED_40000baseKR4_Full (1 << 23)
+#define ADVERTISED_40000baseCR4_Full (1 << 24)
+#define ADVERTISED_40000baseSR4_Full (1 << 25)
+#define ADVERTISED_40000baseLR4_Full (1 << 26)
/* The following are all involved in forcing a particular link
* mode for the device for setting things. When getting the
diff --git a/ethtool.8.in b/ethtool.8.in
index cf2a09c..ff3255b 100644
--- a/ethtool.8.in
+++ b/ethtool.8.in
@@ -325,6 +325,16 @@ ethtool \- query or control network driver and hardware settings
.I devname flag
.A1 on off
.RB ...
+.HP
+.B ethtool \-\-show\-eee
+.I devname
+.HP
+.B ethtool \-\-set\-eee
+.I devname
+.B2 eee on off
+.B2 tx-lpi on off
+.BN tx-timer
+.BN advertise
.
.\" Adjust lines (i.e. full justification) and hyphenate.
.ad
@@ -810,6 +820,28 @@ Sets the device's private flags as specified.
.I flag
.A1 on off
Sets the state of the named private flag.
+.TP
+.B \-\-show\-eee
+Queries the specified network device for its support of Efficient Energy
+Ethernet (according to the IEEE 802.3az specifications)
+.TP
+.B \-\-set\-eee
+Sets the device EEE behaviour.
+.TP
+.A2 eee on off
+Enables/disables the device support of EEE.
+.TP
+.A2 tx-lpi on off
+Determines whether the device should assert its Tx LPI.
+.TP
+.BI advertise \ N
+Sets the speeds for which the device should advertise EEE capabiliities.
+Values are as for
+.B \-\-change advertise
+.TP
+.BI tx-timer \ N
+Sets the amount of time the device should stay in idle mode prior to asserting
+its Tx LPI (in microseconds). This has meaning only when Tx LPI is enabled.
.SH BUGS
Not supported (in part or whole) on all network drivers.
.SH AUTHOR
diff --git a/ethtool.c b/ethtool.c
index 9991ce2..e573357 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -418,7 +418,8 @@ static int do_version(struct cmd_context *ctx)
return 0;
}
-static void dump_link_caps(const char *prefix, const char *an_prefix, u32 mask);
+static void dump_link_caps(const char *prefix, const char *an_prefix, u32 mask,
+ int link_mode_only);
static void dump_supported(struct ethtool_cmd *ep)
{
@@ -437,17 +438,39 @@ static void dump_supported(struct ethtool_cmd *ep)
fprintf(stdout, "FIBRE ");
fprintf(stdout, "]\n");
- dump_link_caps("Supported", "Supports", mask);
+ dump_link_caps("Supported", "Supports", mask, 0);
}
/* Print link capability flags (supported, advertised or lp_advertised).
* Assumes that the corresponding SUPPORTED and ADVERTISED flags are equal.
*/
static void
-dump_link_caps(const char *prefix, const char *an_prefix, u32 mask)
-{
+dump_link_caps(const char *prefix, const char *an_prefix, u32 mask,
+ int link_mode_only)
+{
+ static const struct {
+ int same_line; /* print on same line as previous */
+ u32 value;
+ const char *name;
+ } mode_defs[] = {
+ { 0, ADVERTISED_10baseT_Half, "10baseT/Half" },
+ { 1, ADVERTISED_10baseT_Full, "10baseT/Full" },
+ { 0, ADVERTISED_100baseT_Half, "100baseT/Half" },
+ { 1, ADVERTISED_100baseT_Full, "100baseT/Full" },
+ { 0, ADVERTISED_1000baseT_Half, "1000baseT/Half" },
+ { 1, ADVERTISED_1000baseT_Full, "1000baseT/Full" },
+ { 0, ADVERTISED_1000baseKX_Full, "1000baseKX/Full" },
+ { 0, ADVERTISED_2500baseX_Full, "2500baseX/Full" },
+ { 0, ADVERTISED_10000baseT_Full, "10000baseT/Full" },
+ { 0, ADVERTISED_10000baseKX4_Full, "10000baseKX4/Full" },
+ { 0, ADVERTISED_20000baseMLD2_Full, "20000baseMLD2/Full" },
+ { 0, ADVERTISED_40000baseKR4_Full, "40000baseKR4/Full" },
+ { 0, ADVERTISED_40000baseCR4_Full, "40000baseCR4/Full" },
+ { 0, ADVERTISED_40000baseSR4_Full, "40000baseSR4/Full" },
+ { 0, ADVERTISED_40000baseLR4_Full, "40000baseLR4/Full" },
+ };
int indent;
- int did1;
+ int did1, new_line_pend, i;
/* Indent just like the separate functions used to */
indent = strlen(prefix) + 14;
@@ -457,82 +480,44 @@ dump_link_caps(const char *prefix, const char *an_prefix, u32 mask)
fprintf(stdout, " %s link modes:%*s", prefix,
indent - (int)strlen(prefix) - 12, "");
did1 = 0;
- if (mask & ADVERTISED_10baseT_Half) {
- did1++; fprintf(stdout, "10baseT/Half ");
- }
- if (mask & ADVERTISED_10baseT_Full) {
- did1++; fprintf(stdout, "10baseT/Full ");
- }
- if (did1 && (mask & (ADVERTISED_100baseT_Half|ADVERTISED_100baseT_Full))) {
- fprintf(stdout, "\n");
- fprintf(stdout, " %*s", indent, "");
- }
- if (mask & ADVERTISED_100baseT_Half) {
- did1++; fprintf(stdout, "100baseT/Half ");
- }
- if (mask & ADVERTISED_100baseT_Full) {
- did1++; fprintf(stdout, "100baseT/Full ");
- }
- if (did1 && (mask & (ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full))) {
- fprintf(stdout, "\n");
- fprintf(stdout, " %*s", indent, "");
- }
- if (mask & ADVERTISED_1000baseT_Half) {
- did1++; fprintf(stdout, "1000baseT/Half ");
- }
- if (mask & ADVERTISED_1000baseT_Full) {
- did1++; fprintf(stdout, "1000baseT/Full ");
- }
- if (did1 && (mask & ADVERTISED_2500baseX_Full)) {
- fprintf(stdout, "\n");
- fprintf(stdout, " %*s", indent, "");
- }
- if (mask & ADVERTISED_2500baseX_Full) {
- did1++; fprintf(stdout, "2500baseX/Full ");
- }
- if (did1 && (mask & ADVERTISED_10000baseT_Full)) {
- fprintf(stdout, "\n");
- fprintf(stdout, " %*s", indent, "");
- }
- if (mask & ADVERTISED_10000baseT_Full) {
- did1++; fprintf(stdout, "10000baseT/Full ");
- }
- if (did1 && (mask & ADVERTISED_20000baseMLD2_Full)) {
- fprintf(stdout, "\n");
- fprintf(stdout, " %*s", indent, "");
- }
- if (mask & ADVERTISED_20000baseMLD2_Full) {
- did1++; fprintf(stdout, "20000baseMLD2/Full ");
- }
- if (did1 && (mask & ADVERTISED_20000baseKR2_Full)) {
- fprintf(stdout, "\n");
- fprintf(stdout, " %*s", indent, "");
- }
- if (mask & ADVERTISED_20000baseKR2_Full) {
- did1++; fprintf(stdout, "20000baseKR2/Full ");
+ new_line_pend = 0;
+ for (i = 0; i < ARRAY_SIZE(mode_defs); i++) {
+ if (did1 && !mode_defs[i].same_line)
+ new_line_pend = 1;
+ if (mask & mode_defs[i].value) {
+ if (new_line_pend) {
+ fprintf(stdout, "\n");
+ fprintf(stdout, " %*s", indent, "");
+ new_line_pend = 0;
+ }
+ did1++;
+ fprintf(stdout, "%s ", mode_defs[i].name);
+ }
}
if (did1 == 0)
fprintf(stdout, "Not reported");
fprintf(stdout, "\n");
- fprintf(stdout, " %s pause frame use: ", prefix);
- if (mask & ADVERTISED_Pause) {
- fprintf(stdout, "Symmetric");
- if (mask & ADVERTISED_Asym_Pause)
- fprintf(stdout, " Receive-only");
- fprintf(stdout, "\n");
- } else {
- if (mask & ADVERTISED_Asym_Pause)
- fprintf(stdout, "Transmit-only\n");
+ if (!link_mode_only) {
+ fprintf(stdout, " %s pause frame use: ", prefix);
+ if (mask & ADVERTISED_Pause) {
+ fprintf(stdout, "Symmetric");
+ if (mask & ADVERTISED_Asym_Pause)
+ fprintf(stdout, " Receive-only");
+ fprintf(stdout, "\n");
+ } else {
+ if (mask & ADVERTISED_Asym_Pause)
+ fprintf(stdout, "Transmit-only\n");
+ else
+ fprintf(stdout, "No\n");
+ }
+
+ fprintf(stdout, " %s auto-negotiation: ", an_prefix);
+ if (mask & ADVERTISED_Autoneg)
+ fprintf(stdout, "Yes\n");
else
fprintf(stdout, "No\n");
}
-
- fprintf(stdout, " %s auto-negotiation: ", an_prefix);
- if (mask & ADVERTISED_Autoneg)
- fprintf(stdout, "Yes\n");
- else
- fprintf(stdout, "No\n");
}
static int dump_ecmd(struct ethtool_cmd *ep)
@@ -540,10 +525,11 @@ static int dump_ecmd(struct ethtool_cmd *ep)
u32 speed;
dump_supported(ep);
- dump_link_caps("Advertised", "Advertised", ep->advertising);
+ dump_link_caps("Advertised", "Advertised", ep->advertising, 0);
if (ep->lp_advertising)
dump_link_caps("Link partner advertised",
- "Link partner advertised", ep->lp_advertising);
+ "Link partner advertised", ep->lp_advertising,
+ 0);
fprintf(stdout, " Speed: ");
speed = ethtool_cmd_speed(ep);
@@ -635,19 +621,19 @@ static int dump_ecmd(struct ethtool_cmd *ep)
static int dump_drvinfo(struct ethtool_drvinfo *info)
{
fprintf(stdout,
- "driver: %s\n"
- "version: %s\n"
- "firmware-version: %s\n"
- "bus-info: %s\n"
+ "driver: %.*s\n"
+ "version: %.*s\n"
+ "firmware-version: %.*s\n"
+ "bus-info: %.*s\n"
"supports-statistics: %s\n"
"supports-test: %s\n"
"supports-eeprom-access: %s\n"
"supports-register-dump: %s\n"
"supports-priv-flags: %s\n",
- info->driver,
- info->version,
- info->fw_version,
- info->bus_info,
+ (int)sizeof(info->driver), info->driver,
+ (int)sizeof(info->version), info->version,
+ (int)sizeof(info->fw_version), info->fw_version,
+ (int)sizeof(info->bus_info), info->bus_info,
info->n_stats ? "yes" : "no",
info->testinfo_len ? "yes" : "no",
info->eedump_len ? "yes" : "no",
@@ -1222,6 +1208,34 @@ static int dump_rxfhash(int fhash, u64 val)
return 0;
}
+static void dump_eeecmd(struct ethtool_eee *ep)
+{
+
+ fprintf(stdout, " EEE status: ");
+ if (!ep->supported) {
+ fprintf(stdout, "not supported\n");
+ return;
+ } else if (!ep->eee_enabled) {
+ fprintf(stdout, "disabled\n");
+ } else {
+ fprintf(stdout, "enabled - ");
+ if (ep->eee_active)
+ fprintf(stdout, "active\n");
+ else
+ fprintf(stdout, "inactive\n");
+ }
+
+ fprintf(stdout, " Tx LPI:");
+ if (ep->tx_lpi_enabled)
+ fprintf(stdout, " %d (us)\n", ep->tx_lpi_timer);
+ else
+ fprintf(stdout, " disabled\n");
+
+ dump_link_caps("Supported EEE", "", ep->supported, 1);
+ dump_link_caps("Advertised EEE", "", ep->advertised, 1);
+ dump_link_caps("Link partner advertised EEE", "", ep->lp_advertised, 1);
+}
+
#define N_SOTS 7
static char *so_timestamping_labels[N_SOTS] = {
@@ -1309,14 +1323,14 @@ static int dump_tsinfo(const struct ethtool_ts_info *info)
static struct ethtool_gstrings *
get_stringset(struct cmd_context *ctx, enum ethtool_stringset set_id,
- ptrdiff_t drvinfo_offset)
+ ptrdiff_t drvinfo_offset, int null_terminate)
{
struct {
struct ethtool_sset_info hdr;
u32 buf[1];
} sset_info;
struct ethtool_drvinfo drvinfo;
- u32 len;
+ u32 len, i;
struct ethtool_gstrings *strings;
sset_info.hdr.cmd = ETHTOOL_GSSET_INFO;
@@ -1346,6 +1360,10 @@ get_stringset(struct cmd_context *ctx, enum ethtool_stringset set_id,
return NULL;
}
+ if (null_terminate)
+ for (i = 0; i < len; i++)
+ strings->data[(i + 1) * ETH_GSTRING_LEN - 1] = 0;
+
return strings;
}
@@ -1356,7 +1374,7 @@ static struct feature_defs *get_feature_defs(struct cmd_context *ctx)
u32 n_features;
int i, j;
- names = get_stringset(ctx, ETH_SS_FEATURES, 0);
+ names = get_stringset(ctx, ETH_SS_FEATURES, 0, 1);
if (names) {
n_features = names->len;
} else if (errno == EOPNOTSUPP || errno == EINVAL) {
@@ -2685,7 +2703,8 @@ static int do_test(struct cmd_context *ctx)
}
strings = get_stringset(ctx, ETH_SS_TEST,
- offsetof(struct ethtool_drvinfo, testinfo_len));
+ offsetof(struct ethtool_drvinfo, testinfo_len),
+ 1);
if (!strings) {
perror("Cannot get strings");
return 74;
@@ -2754,7 +2773,8 @@ static int do_gstats(struct cmd_context *ctx)
exit_bad_args();
strings = get_stringset(ctx, ETH_SS_STATS,
- offsetof(struct ethtool_drvinfo, n_stats));
+ offsetof(struct ethtool_drvinfo, n_stats),
+ 0);
if (!strings) {
perror("Cannot get stats strings information");
return 96;
@@ -3319,7 +3339,8 @@ static int do_gprivflags(struct cmd_context *ctx)
exit_bad_args();
strings = get_stringset(ctx, ETH_SS_PRIV_FLAGS,
- offsetof(struct ethtool_drvinfo, n_priv_flags));
+ offsetof(struct ethtool_drvinfo, n_priv_flags),
+ 1);
if (!strings) {
perror("Cannot get private flag names");
return 1;
@@ -3359,7 +3380,8 @@ static int do_sprivflags(struct cmd_context *ctx)
unsigned int i;
strings = get_stringset(ctx, ETH_SS_PRIV_FLAGS,
- offsetof(struct ethtool_drvinfo, n_priv_flags));
+ offsetof(struct ethtool_drvinfo, n_priv_flags),
+ 1);
if (!strings) {
perror("Cannot get private flag names");
return 1;
@@ -3504,6 +3526,63 @@ static int do_getmodule(struct cmd_context *ctx)
return 0;
}
+static int do_geee(struct cmd_context *ctx)
+{
+ struct ethtool_eee eeecmd;
+
+ if (ctx->argc != 0)
+ exit_bad_args();
+
+ eeecmd.cmd = ETHTOOL_GEEE;
+ if (send_ioctl(ctx, &eeecmd)) {
+ perror("Cannot get EEE settings");
+ return 1;
+ }
+
+ fprintf(stdout, "EEE Settings for %s:\n", ctx->devname);
+ dump_eeecmd(&eeecmd);
+
+ return 0;
+}
+
+static int do_seee(struct cmd_context *ctx)
+{
+ int adv_c = -1, lpi_c = -1, lpi_time_c = -1, eee_c = -1;
+ int change = -1, change2 = -1;
+ struct ethtool_eee eeecmd;
+ struct cmdline_info cmdline_eee[] = {
+ { "advertise", CMDL_U32, &adv_c, &eeecmd.advertised },
+ { "tx-lpi", CMDL_BOOL, &lpi_c, &eeecmd.tx_lpi_enabled },
+ { "tx-timer", CMDL_U32, &lpi_time_c, &eeecmd.tx_lpi_timer},
+ { "eee", CMDL_BOOL, &eee_c, &eeecmd.eee_enabled},
+ };
+
+ if (ctx->argc == 0)
+ exit_bad_args();
+
+ parse_generic_cmdline(ctx, &change, cmdline_eee,
+ ARRAY_SIZE(cmdline_eee));
+
+ eeecmd.cmd = ETHTOOL_GEEE;
+ if (send_ioctl(ctx, &eeecmd)) {
+ perror("Cannot get EEE settings");
+ return 1;
+ }
+
+ do_generic_set(cmdline_eee, ARRAY_SIZE(cmdline_eee), &change2);
+
+ if (change2) {
+
+ eeecmd.cmd = ETHTOOL_SEEE;
+ if (send_ioctl(ctx, &eeecmd)) {
+ perror("Cannot set EEE settings");
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
#ifndef TEST_ETHTOOL
int send_ioctl(struct cmd_context *ctx, void *cmd)
{
@@ -3652,6 +3731,12 @@ static const struct option {
" [ hex on|off ]\n"
" [ offset N ]\n"
" [ length N ]\n" },
+ { "--show-eee", 1, do_geee, "Show EEE settings"},
+ { "--set-eee", 1, do_seee, "Set EEE settings",
+ " [ eee on|off ]\n"
+ " [ advertise %x ]\n"
+ " [ tx-lpi on|off ]\n"
+ " [ tx-timer %d ]\n"},
{ "-h|--help", 0, show_usage, "Show this help" },
{ "--version", 0, do_version, "Show version number" },
{}
diff --git a/test-cmdline.c b/test-cmdline.c
index 978c312..6a60ed4 100644
--- a/test-cmdline.c
+++ b/test-cmdline.c
@@ -217,6 +217,21 @@ static struct test_case {
{ 0, "-m devname hex off" },
{ 1, "-m devname hex on raw on" },
{ 0, "-m devname offset 4 length 6" },
+ { 1, "--show-eee" },
+ { 0, "--show-eee devname" },
+ { 1, "--show-eee devname foo" },
+ { 1, "--set-eee" },
+ { 1, "--set-eee devname" },
+ { 1, "--set-eee devname foo" },
+ { 0, "--set-eee devname eee on" },
+ { 0, "--set-eee devname eee off" },
+ { 1, "--set-eee devname eee foo" },
+ { 0, "--set-eee devname tx-lpi on" },
+ { 0, "--set-eee devname tx-lpi off" },
+ { 1, "--set-eee devname tx-lpi foo" },
+ { 0, "--set-eee devname tx-timer 42 advertise 0x4321" },
+ { 1, "--set-eee devname tx-timer foo" },
+ { 1, "--set-eee devname advertise foo" },
/* can't test --set-priv-flags yet */
{ 0, "-h" },
{ 0, "--help" },