summaryrefslogtreecommitdiff
path: root/ethtool.c
diff options
context:
space:
mode:
Diffstat (limited to 'ethtool.c')
-rw-r--r--ethtool.c265
1 files changed, 175 insertions, 90 deletions
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" },
{}