diff options
Diffstat (limited to 'ethtool.c')
-rw-r--r-- | ethtool.c | 265 |
1 files changed, 175 insertions, 90 deletions
@@ -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" }, {} |