From 75e6791c0d2d60705932ea5aa8ced5596cb85da4 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Tue, 21 Aug 2012 01:37:16 -0700 Subject: ethtool: allow setting MDI-X state A bit ago ethtool 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 when multiple ethtool -r ethX are required before link is achieved. This patch allows the user to override the normal "auto" setting and force the crossover state to on or off. The set will fail if the driver doesn't support the get, as suggested by Ben Hutchings. setting MDI not supported In addition the do_gset output was changed slightly to report the value set by the user (when the driver supports the set) old: MDI-X: on new: MDI-X: on (auto) or MDI-X: on (forced) usage is ethtool -s eth0 mdix [auto|on|off] Signed-off-by: Jesse Brandeburg CC: Ben Hutchings Tested-by: Aaron Brown aaron.f.brown@intel.com Signed-off-by: Jeff Kirsher Signed-off-by: Ben Hutchings --- ethtool.c | 55 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 10 deletions(-) (limited to 'ethtool.c') diff --git a/ethtool.c b/ethtool.c index e573357..e21b7cb 100644 --- a/ethtool.c +++ b/ethtool.c @@ -18,6 +18,8 @@ * Rx Network Flow Control configuration support * Various features by Ben Hutchings ; * Copyright 2009, 2010 Solarflare Communications + * MDI-X set support by Jesse Brandeburg + * Copyright 2012 Intel Corporation * * TODO: * * show settings for all devices @@ -602,16 +604,25 @@ static int dump_ecmd(struct ethtool_cmd *ep) if (ep->port == PORT_TP) { fprintf(stdout, " MDI-X: "); - switch (ep->eth_tp_mdix) { - case ETH_TP_MDI: - fprintf(stdout, "off\n"); - break; - case ETH_TP_MDI_X: - fprintf(stdout, "on\n"); - break; - default: - fprintf(stdout, "Unknown\n"); - break; + if (ep->eth_tp_mdix_ctrl == ETH_TP_MDI) { + fprintf(stdout, "off (forced)\n"); + } else if (ep->eth_tp_mdix_ctrl == ETH_TP_MDI_X) { + fprintf(stdout, "on (forced)\n"); + } else { + switch (ep->eth_tp_mdix) { + case ETH_TP_MDI: + fprintf(stdout, "off"); + break; + case ETH_TP_MDI_X: + fprintf(stdout, "on"); + break; + default: + fprintf(stdout, "Unknown"); + break; + } + if (ep->eth_tp_mdix_ctrl == ETH_TP_MDI_AUTO) + fprintf(stdout, " (auto)"); + fprintf(stdout, "\n"); } } @@ -2199,6 +2210,7 @@ static int do_sset(struct cmd_context *ctx) int speed_wanted = -1; int duplex_wanted = -1; int port_wanted = -1; + int mdix_wanted = -1; int autoneg_wanted = -1; int phyad_wanted = -1; int xcvr_wanted = -1; @@ -2259,6 +2271,19 @@ static int do_sset(struct cmd_context *ctx) port_wanted = PORT_FIBRE; else exit_bad_args(); + } else if (!strcmp(argp[i], "mdix")) { + gset_changed = 1; + i += 1; + if (i >= argc) + exit_bad_args(); + if (!strcmp(argp[i], "auto")) + mdix_wanted = ETH_TP_MDI_AUTO; + else if (!strcmp(argp[i], "on")) + mdix_wanted = ETH_TP_MDI_X; + else if (!strcmp(argp[i], "off")) + mdix_wanted = ETH_TP_MDI; + else + exit_bad_args(); } else if (!strcmp(argp[i], "autoneg")) { i += 1; if (i >= argc) @@ -2380,6 +2405,13 @@ static int do_sset(struct cmd_context *ctx) ecmd.duplex = duplex_wanted; if (port_wanted != -1) ecmd.port = port_wanted; + if (mdix_wanted != -1) { + /* check driver supports MDI-X */ + if (ecmd.eth_tp_mdix_ctrl != ETH_TP_MDI_INVALID) + ecmd.eth_tp_mdix_ctrl = mdix_wanted; + else + fprintf(stderr, "setting MDI not supported\n"); + } if (autoneg_wanted != -1) ecmd.autoneg = autoneg_wanted; if (phyad_wanted != -1) @@ -2439,6 +2471,8 @@ static int do_sset(struct cmd_context *ctx) 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"); } } @@ -3604,6 +3638,7 @@ static const 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" -- cgit v1.2.1