diff mbox

[RFC] ethtool: allow setting MDI-X state

Message ID 20101117231655.30673.37157.stgit@jbrandeb-ich9b.jf.intel.com
State RFC, archived
Delegated to: David Miller
Headers show

Commit Message

Jesse Brandeburg Nov. 17, 2010, 11:16 p.m. UTC
ethtool recently added support for reading MDI-X state, this
patch finishes the implementation, adding the complementary write
command.

Add support to ethtool for controlling the MDI-X (crossover)
state of a network port.  Most adapters correctly negotiate
MDI-X, but some ill-behaved switches have trouble and end up
picking the wrong MDI setting, which results in complete loss of
link.  Usually this error condition can be observed with multiple
ethtool -r ethX required before link is achieved.

usage is ethtool -s eth0 mdix [auto|on|off]

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
---

 ethtool.8 |    8 ++++++++
 ethtool.c |   34 ++++++++++++++++++++++++++++++++++
 2 files changed, 42 insertions(+), 0 deletions(-)


--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/ethtool.8 b/ethtool.8
index 1760924..c96e35d 100644
--- a/ethtool.8
+++ b/ethtool.8
@@ -196,6 +196,7 @@  ethtool \- Display or change ethernet card settings
 .BI speed \ N
 .B2 duplex half full
 .B4 port tp aui bnc mii fibre
+.B3 mdix auto on off
 .B2 autoneg on off
 .RB [ advertise
 .IR N ]
@@ -452,6 +453,13 @@  Sets full or half duplex mode.
 .A4 port tp aui bnc mii fibre
 Selects device port.
 .TP
+.A3 mdix auto on off
+Selects MDI-X mode for port. May be used to override the automatic detection
+feature of most adapters.  Auto means automatic detection of MDI status, on
+forces MDI-X (crossover) mode, while off means MDI (straight through) mode.
+Depending on implementation an ethtool -r ethX command may be necessary to
+cause the change to take effect.
+.TP
 .A2 autoneg on off
 Specifies whether autonegotiation should be enabled. Autonegotiation 
 is enabled by deafult, but in some network devices may have trouble
diff --git a/ethtool.c b/ethtool.c
index 239912b..fcc7998 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -157,6 +157,7 @@  static struct option {
 		"		[ speed %d ]\n"
 		"		[ duplex half|full ]\n"
 		"		[ port tp|aui|bnc|mii|fibre ]\n"
+		"		[ mdix auto|on|off ]\n"
 		"		[ autoneg on|off ]\n"
 		"		[ advertise %x ]\n"
 		"		[ phyad %d ]\n"
@@ -353,6 +354,7 @@  static s32 coal_tx_frames_high_wanted = -1;
 static int speed_wanted = -1;
 static int duplex_wanted = -1;
 static int port_wanted = -1;
+static int mdix_wanted = -1;
 static int autoneg_wanted = -1;
 static int phyad_wanted = -1;
 static int xcvr_wanted = -1;
@@ -1048,6 +1050,20 @@  static void parse_cmdline(int argc, char **argp)
 				else
 					show_usage(1);
 				break;
+			} else if (!strcmp(argp[i], "mdix")) {
+				gset_changed = 1;
+				i += 1;
+				if (i >= argc)
+					show_usage(1);
+				if (!strcmp(argp[i], "auto"))
+					mdix_wanted = ETH_TP_MDI_INVALID;
+				else if (!strcmp(argp[i], "on"))
+					mdix_wanted = ETH_TP_MDI_X;
+				else if (!strcmp(argp[i], "off"))
+					mdix_wanted = ETH_TP_MDI;
+				else
+					show_usage(1);
+				break;
 			} else if (!strcmp(argp[i], "autoneg")) {
 				i += 1;
 				if (i >= argc)
@@ -1124,6 +1140,20 @@  static void parse_cmdline(int argc, char **argp)
 					i = argc;
 				}
 				break;
+			} else if (!strcmp(argp[i], "mdix")) {
+				gset_changed = 1;
+				i += 1;
+				if (i >= argc)
+					show_usage(1);
+				if (!strcmp(argp[i], "auto"))
+					mdix_wanted = ETH_TP_MDI_INVALID;
+				else if (!strcmp(argp[i], "on"))
+					mdix_wanted = ETH_TP_MDI_X;
+				else if (!strcmp(argp[i], "off"))
+					mdix_wanted = ETH_TP_MDI;
+				else
+					show_usage(1);
+				break;
 			}
 			show_usage(1);
 		}
@@ -2525,6 +2555,8 @@  static int do_sset(int fd, struct ifreq *ifr)
 				ecmd.duplex = duplex_wanted;
 			if (port_wanted != -1)
 				ecmd.port = port_wanted;
+			if (mdix_wanted != -1)
+				ecmd.eth_tp_mdix = mdix_wanted;
 			if (autoneg_wanted != -1)
 				ecmd.autoneg = autoneg_wanted;
 			if (phyad_wanted != -1)
@@ -2566,6 +2598,8 @@  static int do_sset(int fd, struct ifreq *ifr)
 				fprintf(stderr, "  not setting phy_address\n");
 			if (xcvr_wanted != -1)
 				fprintf(stderr, "  not setting transceiver\n");
+			if (mdix_wanted != -1)
+				fprintf(stderr, "  not setting mdix\n");
 		}
 	}