diff options
-rw-r--r-- | ethtool-copy.h | 46 | ||||
-rw-r--r-- | ethtool.8.in | 32 | ||||
-rw-r--r-- | ethtool.c | 265 | ||||
-rw-r--r-- | test-cmdline.c | 15 |
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 @@ -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" }, |