summaryrefslogtreecommitdiff
path: root/ethtool.c
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2011-10-27 14:17:59 +0100
committerBen Hutchings <bhutchings@solarflare.com>2012-06-02 01:31:10 +0100
commit5bebf1ee71990a00fb7973702e3ed19b3fa71027 (patch)
treecd0bd6148b9b486df12ffc0248dd757e87bd4a31 /ethtool.c
parente5c984ac501788d668e8aed1f7b1fd79ce1d93c5 (diff)
downloadethtool-5bebf1ee71990a00fb7973702e3ed19b3fa71027.tar.gz
Report when offload feature changes are not exactly as requested
When an offload feature is enabled or disabled, this can change the state of other features that depend on it, or may itself be deferred if it depends on a feature that is disabled. Report when this happens, and fail if no offload features could be changed. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Diffstat (limited to 'ethtool.c')
-rw-r--r--ethtool.c65
1 files changed, 45 insertions, 20 deletions
diff --git a/ethtool.c b/ethtool.c
index 34d8b90..1cb708f 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -1069,13 +1069,15 @@ static int dump_coalesce(const struct ethtool_coalesce *ecoal)
return 0;
}
-static int dump_offload(u32 active)
+static int dump_offload(u32 active, u32 mask)
{
u32 value;
int i;
for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
value = off_flag_def[i].value;
+ if (!(mask & value))
+ continue;
printf("%s: %s\n",
off_flag_def[i].long_name,
(active & value) ? "on" : "off");
@@ -1647,17 +1649,14 @@ static int do_scoalesce(struct cmd_context *ctx)
return 0;
}
-static int do_goffload(struct cmd_context *ctx)
+static int get_offload(struct cmd_context *ctx, u32 *flags)
{
struct ethtool_value eval;
int err, allfail = 1;
- u32 flags = 0, value;
+ u32 value;
int i;
- if (ctx->argc != 0)
- exit_bad_args();
-
- fprintf(stdout, "Offload parameters for %s:\n", ctx->devname);
+ *flags = 0;
for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
value = off_flag_def[i].value;
@@ -1671,7 +1670,7 @@ static int do_goffload(struct cmd_context *ctx)
off_flag_def[i].long_name);
} else {
if (eval.data)
- flags |= value;
+ *flags |= value;
allfail = 0;
}
}
@@ -1681,16 +1680,28 @@ static int do_goffload(struct cmd_context *ctx)
if (err) {
perror("Cannot get device flags");
} else {
- flags |= eval.data & ETH_FLAG_EXT_MASK;
+ *flags |= eval.data & ETH_FLAG_EXT_MASK;
allfail = 0;
}
- if (allfail) {
+ return allfail;
+}
+
+static int do_goffload(struct cmd_context *ctx)
+{
+ u32 flags;
+
+ if (ctx->argc != 0)
+ exit_bad_args();
+
+ fprintf(stdout, "Offload parameters for %s:\n", ctx->devname);
+
+ if (get_offload(ctx, &flags)) {
fprintf(stdout, "no offload info available\n");
return 83;
}
- return dump_offload(flags);
+ return dump_offload(flags, ~(u32)0);
}
static int do_soffload(struct cmd_context *ctx)
@@ -1699,6 +1710,7 @@ static int do_soffload(struct cmd_context *ctx)
u32 off_flags_wanted = 0;
u32 off_flags_mask = 0;
struct cmdline_info cmdline_offload[ARRAY_SIZE(off_flag_def)];
+ u32 old_flags, new_flags, diff;
struct ethtool_value eval;
int err;
int i;
@@ -1712,6 +1724,11 @@ static int do_soffload(struct cmd_context *ctx)
parse_generic_cmdline(ctx, &goffload_changed,
cmdline_offload, ARRAY_SIZE(cmdline_offload));
+ if (get_offload(ctx, &old_flags)) {
+ fprintf(stderr, "no offload info available\n");
+ return 1;
+ }
+
for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
if (!off_flag_def[i].set_cmd)
continue;
@@ -1729,16 +1746,8 @@ static int do_soffload(struct cmd_context *ctx)
}
}
if (off_flags_mask & ETH_FLAG_EXT_MASK) {
- eval.cmd = ETHTOOL_GFLAGS;
- eval.data = 0;
- err = send_ioctl(ctx, &eval);
- if (err) {
- perror("Cannot get device flag settings");
- return 91;
- }
-
eval.cmd = ETHTOOL_SFLAGS;
- eval.data &= ~(off_flags_mask & ETH_FLAG_EXT_MASK);
+ eval.data = old_flags & ~off_flags_mask & ETH_FLAG_EXT_MASK;
eval.data |= off_flags_wanted & ETH_FLAG_EXT_MASK;
err = send_ioctl(ctx, &eval);
@@ -1750,6 +1759,22 @@ static int do_soffload(struct cmd_context *ctx)
if (off_flags_mask == 0) {
fprintf(stdout, "no offload settings changed\n");
+ return 0;
+ }
+
+ /* Compare new state with requested state */
+ if (get_offload(ctx, &new_flags)) {
+ fprintf(stderr, "no offload info available\n");
+ return 1;
+ }
+ if (new_flags != ((old_flags & ~off_flags_mask) | off_flags_wanted)) {
+ if (new_flags == old_flags) {
+ fprintf(stderr,
+ "Could not change any device offload settings\n");
+ return 1;
+ }
+ printf("Actual changes:\n");
+ dump_offload(new_flags, new_flags ^ old_flags);
}
return 0;