summaryrefslogtreecommitdiff
path: root/ethtool.c
diff options
context:
space:
mode:
authorJohan Gunnarsson <johan.gunnarsson@axis.com>2012-08-24 13:32:45 +0200
committerBen Hutchings <bhutchings@solarflare.com>2012-09-06 19:34:37 +0100
commit517f88b51e1814c4904ecbad82c18e1b68a99f40 (patch)
tree26d49969199f664aa0247ec05de16170acc74116 /ethtool.c
parent0a74e37f7052bde56f52eae84b7f15df408fbc05 (diff)
downloadethtool-517f88b51e1814c4904ecbad82c18e1b68a99f40.tar.gz
ethtool: don't overwrite useful bits in advertising bitfield
There are bits in this bitfield that we want to leave untouched (PAUSE and ASYM_PAUSE bits) when changing other bits (speed and duplex bits.) Previously, these were always overwritten to zero when running commands like "ethtool -s eth0 speed 10 duplex full autoneg off". Signed-off-by: Johan Gunnarsson <johangu@axis.com> [bwh: Fixed spelling and formatting] Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Diffstat (limited to 'ethtool.c')
-rw-r--r--ethtool.c91
1 files changed, 77 insertions, 14 deletions
diff --git a/ethtool.c b/ethtool.c
index e21b7cb..25ba51f 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -48,6 +48,53 @@
#define MAX_ADDR_LEN 32
#endif
+#define ALL_ADVERTISED_MODES \
+ (ADVERTISED_10baseT_Half | \
+ ADVERTISED_10baseT_Full | \
+ ADVERTISED_100baseT_Half | \
+ ADVERTISED_100baseT_Full | \
+ ADVERTISED_1000baseT_Half | \
+ ADVERTISED_1000baseT_Full | \
+ ADVERTISED_2500baseX_Full | \
+ ADVERTISED_10000baseKX4_Full | \
+ ADVERTISED_10000baseKR_Full | \
+ ADVERTISED_10000baseR_FEC | \
+ ADVERTISED_20000baseMLD2_Full | \
+ ADVERTISED_20000baseKR2_Full | \
+ ADVERTISED_40000baseKR4_Full | \
+ ADVERTISED_40000baseCR4_Full | \
+ ADVERTISED_40000baseSR4_Full | \
+ ADVERTISED_40000baseLR4_Full)
+
+#define ALL_ADVERTISED_FLAGS \
+ (ADVERTISED_10baseT_Half | \
+ ADVERTISED_10baseT_Full | \
+ ADVERTISED_100baseT_Half | \
+ ADVERTISED_100baseT_Full | \
+ ADVERTISED_1000baseT_Half | \
+ ADVERTISED_1000baseT_Full | \
+ ADVERTISED_Autoneg | \
+ ADVERTISED_TP | \
+ ADVERTISED_AUI | \
+ ADVERTISED_MII | \
+ ADVERTISED_FIBRE | \
+ ADVERTISED_BNC | \
+ ADVERTISED_10000baseT_Full | \
+ ADVERTISED_Pause | \
+ ADVERTISED_Asym_Pause | \
+ ADVERTISED_2500baseX_Full | \
+ ADVERTISED_Backplane | \
+ ADVERTISED_1000baseKX_Full | \
+ ADVERTISED_10000baseKX4_Full | \
+ ADVERTISED_10000baseKR_Full | \
+ ADVERTISED_10000baseR_FEC | \
+ ADVERTISED_20000baseMLD2_Full | \
+ ADVERTISED_20000baseKR2_Full | \
+ ADVERTISED_40000baseKR4_Full | \
+ ADVERTISED_40000baseCR4_Full | \
+ ADVERTISED_40000baseSR4_Full | \
+ ADVERTISED_40000baseLR4_Full)
+
#ifndef HAVE_NETIF_MSG
enum {
NETIF_MSG_DRV = 0x0001,
@@ -2214,6 +2261,7 @@ static int do_sset(struct cmd_context *ctx)
int autoneg_wanted = -1;
int phyad_wanted = -1;
int xcvr_wanted = -1;
+ int full_advertising_wanted = -1;
int advertising_wanted = -1;
int gset_changed = 0; /* did anything in GSET change? */
u32 wol_wanted = 0;
@@ -2302,7 +2350,7 @@ static int do_sset(struct cmd_context *ctx)
i += 1;
if (i >= argc)
exit_bad_args();
- advertising_wanted = get_int(argp[i], 16);
+ full_advertising_wanted = get_int(argp[i], 16);
} else if (!strcmp(argp[i], "phyad")) {
gset_changed = 1;
i += 1;
@@ -2359,7 +2407,10 @@ static int do_sset(struct cmd_context *ctx)
}
}
- if (advertising_wanted < 0) {
+ if (full_advertising_wanted < 0) {
+ /* User didn't supply a full advertisement bitfield:
+ * construct one from the specified speed and duplex.
+ */
if (speed_wanted == SPEED_10 && duplex_wanted == DUPLEX_HALF)
advertising_wanted = ADVERTISED_10baseT_Half;
else if (speed_wanted == SPEED_10 &&
@@ -2437,19 +2488,31 @@ static int do_sset(struct cmd_context *ctx)
}
if (autoneg_wanted == AUTONEG_ENABLE &&
advertising_wanted == 0) {
- ecmd.advertising = ecmd.supported &
- (ADVERTISED_10baseT_Half |
- ADVERTISED_10baseT_Full |
- ADVERTISED_100baseT_Half |
- ADVERTISED_100baseT_Full |
- ADVERTISED_1000baseT_Half |
- ADVERTISED_1000baseT_Full |
- ADVERTISED_2500baseX_Full |
- ADVERTISED_10000baseT_Full |
- ADVERTISED_20000baseMLD2_Full |
- ADVERTISED_20000baseKR2_Full);
+ /* Auto negotiation enabled, but with
+ * unspecified speed and duplex: enable all
+ * supported speeds and duplexes.
+ */
+ ecmd.advertising =
+ (ecmd.advertising &
+ ~ALL_ADVERTISED_MODES) |
+ (ALL_ADVERTISED_MODES & ecmd.supported);
+
+ /* If driver supports unknown flags, we cannot
+ * be sure that we enable all link modes.
+ */
+ if ((ecmd.supported & ALL_ADVERTISED_FLAGS) !=
+ ecmd.supported) {
+ fprintf(stderr, "Driver supports one "
+ "or more unknown flags\n");
+ }
} else if (advertising_wanted > 0) {
- ecmd.advertising = advertising_wanted;
+ /* Enable all requested modes */
+ ecmd.advertising =
+ (ecmd.advertising &
+ ~ALL_ADVERTISED_MODES) |
+ advertising_wanted;
+ } else if (full_advertising_wanted > 0) {
+ ecmd.advertising = full_advertising_wanted;
}
/* Try to perform the update. */