aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Decotigny <decot@google.com>2011-04-27 14:32:38 -0400
committerDavid S. Miller <davem@davemloft.net>2011-04-29 17:01:30 -0400
commit8ae6daca85c8bbd6a32c382db5e2a2a989f8bed2 (patch)
tree0c85476c2af6568c3d3a73a960d582d2f91a1256
parent36504605432996590f889e33d47e2d9c581f7569 (diff)
ethtool: Call ethtool's get/set_settings callbacks with cleaned data
This makes sure that when a driver calls the ethtool's get/set_settings() callback of another driver, the data passed to it is clean. This guarantees that speed_hi will be zeroed correctly if the called callback doesn't explicitely set it: we are sure we don't get a corrupted speed from the underlying driver. We also take care of setting the cmd field appropriately (ETHTOOL_GSET/SSET). This applies to dev_ethtool_get_settings(), which now makes sure it sets up that ethtool command parameter correctly before passing it to drivers. This also means that whoever calls dev_ethtool_get_settings() does not have to clean the ethtool command parameter. This function also becomes an exported symbol instead of an inline. All drivers visible to make allyesconfig under x86_64 have been updated. Signed-off-by: David Decotigny <decot@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/mips/txx9/generic/setup_tx4939.c21
-rw-r--r--drivers/net/e100.c2
-rw-r--r--drivers/net/mdio.c3
-rw-r--r--drivers/net/mii.c3
-rw-r--r--drivers/net/pch_gbe/pch_gbe_main.c6
-rw-r--r--drivers/net/pch_gbe/pch_gbe_phy.c2
-rw-r--r--drivers/net/pcnet32.c16
-rw-r--r--drivers/net/sfc/mdio_10g.c4
-rw-r--r--drivers/net/stmmac/stmmac_ethtool.c5
-rw-r--r--drivers/net/usb/asix.c28
-rw-r--r--drivers/net/usb/dm9601.c6
-rw-r--r--drivers/net/usb/smsc75xx.c7
-rw-r--r--drivers/net/usb/smsc95xx.c7
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_fcoe.c11
-rw-r--r--drivers/scsi/fcoe/fcoe.c11
-rw-r--r--include/linux/ethtool.h4
-rw-r--r--include/linux/netdevice.h9
-rw-r--r--include/rdma/ib_addr.h13
-rw-r--r--net/core/dev.c24
-rw-r--r--net/core/net-sysfs.c24
20 files changed, 117 insertions, 89 deletions
diff --git a/arch/mips/txx9/generic/setup_tx4939.c b/arch/mips/txx9/generic/setup_tx4939.c
index 3dc19f482959..e9f95dcde379 100644
--- a/arch/mips/txx9/generic/setup_tx4939.c
+++ b/arch/mips/txx9/generic/setup_tx4939.c
@@ -318,19 +318,15 @@ void __init tx4939_sio_init(unsigned int sclk, unsigned int cts_mask)
318} 318}
319 319
320#if defined(CONFIG_TC35815) || defined(CONFIG_TC35815_MODULE) 320#if defined(CONFIG_TC35815) || defined(CONFIG_TC35815_MODULE)
321static int tx4939_get_eth_speed(struct net_device *dev) 321static u32 tx4939_get_eth_speed(struct net_device *dev)
322{ 322{
323 struct ethtool_cmd cmd = { ETHTOOL_GSET }; 323 struct ethtool_cmd cmd;
324 int speed = 100; /* default 100Mbps */ 324 if (dev_ethtool_get_settings(dev, &cmd))
325 int err; 325 return 100; /* default 100Mbps */
326 if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings) 326
327 return speed; 327 return ethtool_cmd_speed(&cmd);
328 err = dev->ethtool_ops->get_settings(dev, &cmd);
329 if (err < 0)
330 return speed;
331 speed = cmd.speed == SPEED_100 ? 100 : 10;
332 return speed;
333} 328}
329
334static int tx4939_netdev_event(struct notifier_block *this, 330static int tx4939_netdev_event(struct notifier_block *this,
335 unsigned long event, 331 unsigned long event,
336 void *ptr) 332 void *ptr)
@@ -343,8 +339,7 @@ static int tx4939_netdev_event(struct notifier_block *this,
343 else if (dev->irq == TXX9_IRQ_BASE + TX4939_IR_ETH(1)) 339 else if (dev->irq == TXX9_IRQ_BASE + TX4939_IR_ETH(1))
344 bit = TX4939_PCFG_SPEED1; 340 bit = TX4939_PCFG_SPEED1;
345 if (bit) { 341 if (bit) {
346 int speed = tx4939_get_eth_speed(dev); 342 if (tx4939_get_eth_speed(dev) == 100)
347 if (speed == 100)
348 txx9_set64(&tx4939_ccfgptr->pcfg, bit); 343 txx9_set64(&tx4939_ccfgptr->pcfg, bit);
349 else 344 else
350 txx9_clear64(&tx4939_ccfgptr->pcfg, bit); 345 txx9_clear64(&tx4939_ccfgptr->pcfg, bit);
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index b0aa9e68990a..66ba596a4d37 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -1668,7 +1668,7 @@ static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex)
1668static void e100_watchdog(unsigned long data) 1668static void e100_watchdog(unsigned long data)
1669{ 1669{
1670 struct nic *nic = (struct nic *)data; 1670 struct nic *nic = (struct nic *)data;
1671 struct ethtool_cmd cmd; 1671 struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET };
1672 1672
1673 netif_printk(nic, timer, KERN_DEBUG, nic->netdev, 1673 netif_printk(nic, timer, KERN_DEBUG, nic->netdev,
1674 "right now = %ld\n", jiffies); 1674 "right now = %ld\n", jiffies);
diff --git a/drivers/net/mdio.c b/drivers/net/mdio.c
index e85bf04cf813..f2d10abd0403 100644
--- a/drivers/net/mdio.c
+++ b/drivers/net/mdio.c
@@ -176,6 +176,9 @@ static u32 mdio45_get_an(const struct mdio_if_info *mdio, u16 addr)
176 * @npage_adv: Modes currently advertised on next pages 176 * @npage_adv: Modes currently advertised on next pages
177 * @npage_lpa: Modes advertised by link partner on next pages 177 * @npage_lpa: Modes advertised by link partner on next pages
178 * 178 *
179 * The @ecmd parameter is expected to have been cleared before calling
180 * mdio45_ethtool_gset_npage().
181 *
179 * Since the CSRs for auto-negotiation using next pages are not fully 182 * Since the CSRs for auto-negotiation using next pages are not fully
180 * standardised, this function does not attempt to decode them. The 183 * standardised, this function does not attempt to decode them. The
181 * caller must pass them in. 184 * caller must pass them in.
diff --git a/drivers/net/mii.c b/drivers/net/mii.c
index 0a6c6a2e7550..05acca78f63a 100644
--- a/drivers/net/mii.c
+++ b/drivers/net/mii.c
@@ -58,6 +58,9 @@ static u32 mii_get_an(struct mii_if_info *mii, u16 addr)
58 * @mii: MII interface 58 * @mii: MII interface
59 * @ecmd: requested ethtool_cmd 59 * @ecmd: requested ethtool_cmd
60 * 60 *
61 * The @ecmd parameter is expected to have been cleared before calling
62 * mii_ethtool_gset().
63 *
61 * Returns 0 for success, negative on error. 64 * Returns 0 for success, negative on error.
62 */ 65 */
63int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) 66int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c
index 4cc9872f5ec4..f3e4b0adae93 100644
--- a/drivers/net/pch_gbe/pch_gbe_main.c
+++ b/drivers/net/pch_gbe/pch_gbe_main.c
@@ -888,12 +888,12 @@ static void pch_gbe_watchdog(unsigned long data)
888 struct pch_gbe_adapter *adapter = (struct pch_gbe_adapter *)data; 888 struct pch_gbe_adapter *adapter = (struct pch_gbe_adapter *)data;
889 struct net_device *netdev = adapter->netdev; 889 struct net_device *netdev = adapter->netdev;
890 struct pch_gbe_hw *hw = &adapter->hw; 890 struct pch_gbe_hw *hw = &adapter->hw;
891 struct ethtool_cmd cmd;
892 891
893 pr_debug("right now = %ld\n", jiffies); 892 pr_debug("right now = %ld\n", jiffies);
894 893
895 pch_gbe_update_stats(adapter); 894 pch_gbe_update_stats(adapter);
896 if ((mii_link_ok(&adapter->mii)) && (!netif_carrier_ok(netdev))) { 895 if ((mii_link_ok(&adapter->mii)) && (!netif_carrier_ok(netdev))) {
896 struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET };
897 netdev->tx_queue_len = adapter->tx_queue_len; 897 netdev->tx_queue_len = adapter->tx_queue_len;
898 /* mii library handles link maintenance tasks */ 898 /* mii library handles link maintenance tasks */
899 if (mii_ethtool_gset(&adapter->mii, &cmd)) { 899 if (mii_ethtool_gset(&adapter->mii, &cmd)) {
@@ -903,7 +903,7 @@ static void pch_gbe_watchdog(unsigned long data)
903 PCH_GBE_WATCHDOG_PERIOD)); 903 PCH_GBE_WATCHDOG_PERIOD));
904 return; 904 return;
905 } 905 }
906 hw->mac.link_speed = cmd.speed; 906 hw->mac.link_speed = ethtool_cmd_speed(&cmd);
907 hw->mac.link_duplex = cmd.duplex; 907 hw->mac.link_duplex = cmd.duplex;
908 /* Set the RGMII control. */ 908 /* Set the RGMII control. */
909 pch_gbe_set_rgmii_ctrl(adapter, hw->mac.link_speed, 909 pch_gbe_set_rgmii_ctrl(adapter, hw->mac.link_speed,
@@ -913,7 +913,7 @@ static void pch_gbe_watchdog(unsigned long data)
913 hw->mac.link_duplex); 913 hw->mac.link_duplex);
914 netdev_dbg(netdev, 914 netdev_dbg(netdev,
915 "Link is Up %d Mbps %s-Duplex\n", 915 "Link is Up %d Mbps %s-Duplex\n",
916 cmd.speed, 916 hw->mac.link_speed,
917 cmd.duplex == DUPLEX_FULL ? "Full" : "Half"); 917 cmd.duplex == DUPLEX_FULL ? "Full" : "Half");
918 netif_carrier_on(netdev); 918 netif_carrier_on(netdev);
919 netif_wake_queue(netdev); 919 netif_wake_queue(netdev);
diff --git a/drivers/net/pch_gbe/pch_gbe_phy.c b/drivers/net/pch_gbe/pch_gbe_phy.c
index 923a687acd30..9a8207f686fd 100644
--- a/drivers/net/pch_gbe/pch_gbe_phy.c
+++ b/drivers/net/pch_gbe/pch_gbe_phy.c
@@ -247,7 +247,7 @@ inline void pch_gbe_phy_set_rgmii(struct pch_gbe_hw *hw)
247void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw) 247void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw)
248{ 248{
249 struct pch_gbe_adapter *adapter; 249 struct pch_gbe_adapter *adapter;
250 struct ethtool_cmd cmd; 250 struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET };
251 int ret; 251 int ret;
252 u16 mii_reg; 252 u16 mii_reg;
253 253
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 0a1efbae1bc0..b48aba9e4227 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -2099,7 +2099,7 @@ static int pcnet32_open(struct net_device *dev)
2099 int first_phy = -1; 2099 int first_phy = -1;
2100 u16 bmcr; 2100 u16 bmcr;
2101 u32 bcr9; 2101 u32 bcr9;
2102 struct ethtool_cmd ecmd; 2102 struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
2103 2103
2104 /* 2104 /*
2105 * There is really no good other way to handle multiple PHYs 2105 * There is really no good other way to handle multiple PHYs
@@ -2115,9 +2115,9 @@ static int pcnet32_open(struct net_device *dev)
2115 ecmd.port = PORT_MII; 2115 ecmd.port = PORT_MII;
2116 ecmd.transceiver = XCVR_INTERNAL; 2116 ecmd.transceiver = XCVR_INTERNAL;
2117 ecmd.autoneg = AUTONEG_DISABLE; 2117 ecmd.autoneg = AUTONEG_DISABLE;
2118 ecmd.speed = 2118 ethtool_cmd_speed_set(&ecmd,
2119 lp-> 2119 (lp->options & PCNET32_PORT_100) ?
2120 options & PCNET32_PORT_100 ? SPEED_100 : SPEED_10; 2120 SPEED_100 : SPEED_10);
2121 bcr9 = lp->a.read_bcr(ioaddr, 9); 2121 bcr9 = lp->a.read_bcr(ioaddr, 9);
2122 2122
2123 if (lp->options & PCNET32_PORT_FD) { 2123 if (lp->options & PCNET32_PORT_FD) {
@@ -2763,11 +2763,11 @@ static void pcnet32_check_media(struct net_device *dev, int verbose)
2763 netif_carrier_on(dev); 2763 netif_carrier_on(dev);
2764 if (lp->mii) { 2764 if (lp->mii) {
2765 if (netif_msg_link(lp)) { 2765 if (netif_msg_link(lp)) {
2766 struct ethtool_cmd ecmd; 2766 struct ethtool_cmd ecmd = {
2767 .cmd = ETHTOOL_GSET };
2767 mii_ethtool_gset(&lp->mii_if, &ecmd); 2768 mii_ethtool_gset(&lp->mii_if, &ecmd);
2768 netdev_info(dev, "link up, %sMbps, %s-duplex\n", 2769 netdev_info(dev, "link up, %uMbps, %s-duplex\n",
2769 (ecmd.speed == SPEED_100) 2770 ethtool_cmd_speed(&ecmd),
2770 ? "100" : "10",
2771 (ecmd.duplex == DUPLEX_FULL) 2771 (ecmd.duplex == DUPLEX_FULL)
2772 ? "full" : "half"); 2772 ? "full" : "half");
2773 } 2773 }
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c
index 19e68c26d103..71159145b4bf 100644
--- a/drivers/net/sfc/mdio_10g.c
+++ b/drivers/net/sfc/mdio_10g.c
@@ -232,12 +232,12 @@ void efx_mdio_set_mmds_lpower(struct efx_nic *efx,
232 */ 232 */
233int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) 233int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
234{ 234{
235 struct ethtool_cmd prev; 235 struct ethtool_cmd prev = { .cmd = ETHTOOL_GSET };
236 236
237 efx->phy_op->get_settings(efx, &prev); 237 efx->phy_op->get_settings(efx, &prev);
238 238
239 if (ecmd->advertising == prev.advertising && 239 if (ecmd->advertising == prev.advertising &&
240 ecmd->speed == prev.speed && 240 ethtool_cmd_speed(ecmd) == ethtool_cmd_speed(&prev) &&
241 ecmd->duplex == prev.duplex && 241 ecmd->duplex == prev.duplex &&
242 ecmd->port == prev.port && 242 ecmd->port == prev.port &&
243 ecmd->autoneg == prev.autoneg) 243 ecmd->autoneg == prev.autoneg)
diff --git a/drivers/net/stmmac/stmmac_ethtool.c b/drivers/net/stmmac/stmmac_ethtool.c
index 0e61ac8707cb..6f5aaeb986ff 100644
--- a/drivers/net/stmmac/stmmac_ethtool.c
+++ b/drivers/net/stmmac/stmmac_ethtool.c
@@ -237,13 +237,12 @@ stmmac_set_pauseparam(struct net_device *netdev,
237 237
238 if (phy->autoneg) { 238 if (phy->autoneg) {
239 if (netif_running(netdev)) { 239 if (netif_running(netdev)) {
240 struct ethtool_cmd cmd; 240 struct ethtool_cmd cmd = { .cmd = ETHTOOL_SSET };
241 /* auto-negotiation automatically restarted */ 241 /* auto-negotiation automatically restarted */
242 cmd.cmd = ETHTOOL_NWAY_RST;
243 cmd.supported = phy->supported; 242 cmd.supported = phy->supported;
244 cmd.advertising = phy->advertising; 243 cmd.advertising = phy->advertising;
245 cmd.autoneg = phy->autoneg; 244 cmd.autoneg = phy->autoneg;
246 cmd.speed = phy->speed; 245 ethtool_cmd_speed_set(&cmd, phy->speed);
247 cmd.duplex = phy->duplex; 246 cmd.duplex = phy->duplex;
248 cmd.phy_address = phy->addr; 247 cmd.phy_address = phy->addr;
249 ret = phy_ethtool_sset(phy, &cmd); 248 ret = phy_ethtool_sset(phy, &cmd);
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index 6140b56cce53..6998aa6b7bb7 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -847,7 +847,7 @@ static void ax88172_set_multicast(struct net_device *net)
847static int ax88172_link_reset(struct usbnet *dev) 847static int ax88172_link_reset(struct usbnet *dev)
848{ 848{
849 u8 mode; 849 u8 mode;
850 struct ethtool_cmd ecmd; 850 struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
851 851
852 mii_check_media(&dev->mii, 1, 1); 852 mii_check_media(&dev->mii, 1, 1);
853 mii_ethtool_gset(&dev->mii, &ecmd); 853 mii_ethtool_gset(&dev->mii, &ecmd);
@@ -856,8 +856,8 @@ static int ax88172_link_reset(struct usbnet *dev)
856 if (ecmd.duplex != DUPLEX_FULL) 856 if (ecmd.duplex != DUPLEX_FULL)
857 mode |= ~AX88172_MEDIUM_FD; 857 mode |= ~AX88172_MEDIUM_FD;
858 858
859 netdev_dbg(dev->net, "ax88172_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n", 859 netdev_dbg(dev->net, "ax88172_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
860 ecmd.speed, ecmd.duplex, mode); 860 ethtool_cmd_speed(&ecmd), ecmd.duplex, mode);
861 861
862 asix_write_medium_mode(dev, mode); 862 asix_write_medium_mode(dev, mode);
863 863
@@ -947,20 +947,20 @@ static const struct ethtool_ops ax88772_ethtool_ops = {
947static int ax88772_link_reset(struct usbnet *dev) 947static int ax88772_link_reset(struct usbnet *dev)
948{ 948{
949 u16 mode; 949 u16 mode;
950 struct ethtool_cmd ecmd; 950 struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
951 951
952 mii_check_media(&dev->mii, 1, 1); 952 mii_check_media(&dev->mii, 1, 1);
953 mii_ethtool_gset(&dev->mii, &ecmd); 953 mii_ethtool_gset(&dev->mii, &ecmd);
954 mode = AX88772_MEDIUM_DEFAULT; 954 mode = AX88772_MEDIUM_DEFAULT;
955 955
956 if (ecmd.speed != SPEED_100) 956 if (ethtool_cmd_speed(&ecmd) != SPEED_100)
957 mode &= ~AX_MEDIUM_PS; 957 mode &= ~AX_MEDIUM_PS;
958 958
959 if (ecmd.duplex != DUPLEX_FULL) 959 if (ecmd.duplex != DUPLEX_FULL)
960 mode &= ~AX_MEDIUM_FD; 960 mode &= ~AX_MEDIUM_FD;
961 961
962 netdev_dbg(dev->net, "ax88772_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n", 962 netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
963 ecmd.speed, ecmd.duplex, mode); 963 ethtool_cmd_speed(&ecmd), ecmd.duplex, mode);
964 964
965 asix_write_medium_mode(dev, mode); 965 asix_write_medium_mode(dev, mode);
966 966
@@ -1173,18 +1173,20 @@ static int marvell_led_status(struct usbnet *dev, u16 speed)
1173static int ax88178_link_reset(struct usbnet *dev) 1173static int ax88178_link_reset(struct usbnet *dev)
1174{ 1174{
1175 u16 mode; 1175 u16 mode;
1176 struct ethtool_cmd ecmd; 1176 struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
1177 struct asix_data *data = (struct asix_data *)&dev->data; 1177 struct asix_data *data = (struct asix_data *)&dev->data;
1178 u32 speed;
1178 1179
1179 netdev_dbg(dev->net, "ax88178_link_reset()\n"); 1180 netdev_dbg(dev->net, "ax88178_link_reset()\n");
1180 1181
1181 mii_check_media(&dev->mii, 1, 1); 1182 mii_check_media(&dev->mii, 1, 1);
1182 mii_ethtool_gset(&dev->mii, &ecmd); 1183 mii_ethtool_gset(&dev->mii, &ecmd);
1183 mode = AX88178_MEDIUM_DEFAULT; 1184 mode = AX88178_MEDIUM_DEFAULT;
1185 speed = ethtool_cmd_speed(&ecmd);
1184 1186
1185 if (ecmd.speed == SPEED_1000) 1187 if (speed == SPEED_1000)
1186 mode |= AX_MEDIUM_GM; 1188 mode |= AX_MEDIUM_GM;
1187 else if (ecmd.speed == SPEED_100) 1189 else if (speed == SPEED_100)
1188 mode |= AX_MEDIUM_PS; 1190 mode |= AX_MEDIUM_PS;
1189 else 1191 else
1190 mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM); 1192 mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM);
@@ -1196,13 +1198,13 @@ static int ax88178_link_reset(struct usbnet *dev)
1196 else 1198 else
1197 mode &= ~AX_MEDIUM_FD; 1199 mode &= ~AX_MEDIUM_FD;
1198 1200
1199 netdev_dbg(dev->net, "ax88178_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n", 1201 netdev_dbg(dev->net, "ax88178_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
1200 ecmd.speed, ecmd.duplex, mode); 1202 speed, ecmd.duplex, mode);
1201 1203
1202 asix_write_medium_mode(dev, mode); 1204 asix_write_medium_mode(dev, mode);
1203 1205
1204 if (data->phymode == PHY_MODE_MARVELL && data->ledmode) 1206 if (data->phymode == PHY_MODE_MARVELL && data->ledmode)
1205 marvell_led_status(dev, ecmd.speed); 1207 marvell_led_status(dev, speed);
1206 1208
1207 return 0; 1209 return 0;
1208} 1210}
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
index 5002f5be47be..1d93133e9b74 100644
--- a/drivers/net/usb/dm9601.c
+++ b/drivers/net/usb/dm9601.c
@@ -599,13 +599,13 @@ static void dm9601_status(struct usbnet *dev, struct urb *urb)
599 599
600static int dm9601_link_reset(struct usbnet *dev) 600static int dm9601_link_reset(struct usbnet *dev)
601{ 601{
602 struct ethtool_cmd ecmd; 602 struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
603 603
604 mii_check_media(&dev->mii, 1, 1); 604 mii_check_media(&dev->mii, 1, 1);
605 mii_ethtool_gset(&dev->mii, &ecmd); 605 mii_ethtool_gset(&dev->mii, &ecmd);
606 606
607 netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n", 607 netdev_dbg(dev->net, "link_reset() speed: %u duplex: %d\n",
608 ecmd.speed, ecmd.duplex); 608 ethtool_cmd_speed(&ecmd), ecmd.duplex);
609 609
610 return 0; 610 return 0;
611} 611}
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index 860a20c938b4..15b3d6888ae9 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -503,7 +503,7 @@ static int smsc75xx_update_flowcontrol(struct usbnet *dev, u8 duplex,
503static int smsc75xx_link_reset(struct usbnet *dev) 503static int smsc75xx_link_reset(struct usbnet *dev)
504{ 504{
505 struct mii_if_info *mii = &dev->mii; 505 struct mii_if_info *mii = &dev->mii;
506 struct ethtool_cmd ecmd; 506 struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
507 u16 lcladv, rmtadv; 507 u16 lcladv, rmtadv;
508 int ret; 508 int ret;
509 509
@@ -519,8 +519,9 @@ static int smsc75xx_link_reset(struct usbnet *dev)
519 lcladv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); 519 lcladv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE);
520 rmtadv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_LPA); 520 rmtadv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_LPA);
521 521
522 netif_dbg(dev, link, dev->net, "speed: %d duplex: %d lcladv: %04x" 522 netif_dbg(dev, link, dev->net, "speed: %u duplex: %d lcladv: %04x"
523 " rmtadv: %04x", ecmd.speed, ecmd.duplex, lcladv, rmtadv); 523 " rmtadv: %04x", ethtool_cmd_speed(&ecmd),
524 ecmd.duplex, lcladv, rmtadv);
524 525
525 return smsc75xx_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv); 526 return smsc75xx_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv);
526} 527}
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 24f4b3739dd2..b374a9997908 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -457,7 +457,7 @@ static int smsc95xx_link_reset(struct usbnet *dev)
457{ 457{
458 struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); 458 struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
459 struct mii_if_info *mii = &dev->mii; 459 struct mii_if_info *mii = &dev->mii;
460 struct ethtool_cmd ecmd; 460 struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
461 unsigned long flags; 461 unsigned long flags;
462 u16 lcladv, rmtadv; 462 u16 lcladv, rmtadv;
463 u32 intdata; 463 u32 intdata;
@@ -472,8 +472,9 @@ static int smsc95xx_link_reset(struct usbnet *dev)
472 lcladv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); 472 lcladv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE);
473 rmtadv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_LPA); 473 rmtadv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_LPA);
474 474
475 netif_dbg(dev, link, dev->net, "speed: %d duplex: %d lcladv: %04x rmtadv: %04x\n", 475 netif_dbg(dev, link, dev->net,
476 ecmd.speed, ecmd.duplex, lcladv, rmtadv); 476 "speed: %u duplex: %d lcladv: %04x rmtadv: %04x\n",
477 ethtool_cmd_speed(&ecmd), ecmd.duplex, lcladv, rmtadv);
477 478
478 spin_lock_irqsave(&pdata->mac_cr_lock, flags); 479 spin_lock_irqsave(&pdata->mac_cr_lock, flags);
479 if (ecmd.duplex != DUPLEX_FULL) { 480 if (ecmd.duplex != DUPLEX_FULL) {
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index e2e647509a73..cd050196a163 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -664,7 +664,7 @@ static void bnx2fc_link_speed_update(struct fc_lport *lport)
664 struct fcoe_port *port = lport_priv(lport); 664 struct fcoe_port *port = lport_priv(lport);
665 struct bnx2fc_hba *hba = port->priv; 665 struct bnx2fc_hba *hba = port->priv;
666 struct net_device *netdev = hba->netdev; 666 struct net_device *netdev = hba->netdev;
667 struct ethtool_cmd ecmd = { ETHTOOL_GSET }; 667 struct ethtool_cmd ecmd;
668 668
669 if (!dev_ethtool_get_settings(netdev, &ecmd)) { 669 if (!dev_ethtool_get_settings(netdev, &ecmd)) {
670 lport->link_supported_speeds &= 670 lport->link_supported_speeds &=
@@ -675,12 +675,15 @@ static void bnx2fc_link_speed_update(struct fc_lport *lport)
675 if (ecmd.supported & SUPPORTED_10000baseT_Full) 675 if (ecmd.supported & SUPPORTED_10000baseT_Full)
676 lport->link_supported_speeds |= FC_PORTSPEED_10GBIT; 676 lport->link_supported_speeds |= FC_PORTSPEED_10GBIT;
677 677
678 if (ecmd.speed == SPEED_1000) 678 switch (ethtool_cmd_speed(&ecmd)) {
679 case SPEED_1000:
679 lport->link_speed = FC_PORTSPEED_1GBIT; 680 lport->link_speed = FC_PORTSPEED_1GBIT;
680 if (ecmd.speed == SPEED_10000) 681 break;
682 case SPEED_10000:
681 lport->link_speed = FC_PORTSPEED_10GBIT; 683 lport->link_speed = FC_PORTSPEED_10GBIT;
684 break;
685 }
682 } 686 }
683 return;
684} 687}
685static int bnx2fc_link_ok(struct fc_lport *lport) 688static int bnx2fc_link_ok(struct fc_lport *lport)
686{ 689{
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index bde6ee5333eb..04f346b562da 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -2026,7 +2026,7 @@ out_nodev:
2026int fcoe_link_speed_update(struct fc_lport *lport) 2026int fcoe_link_speed_update(struct fc_lport *lport)
2027{ 2027{
2028 struct net_device *netdev = fcoe_netdev(lport); 2028 struct net_device *netdev = fcoe_netdev(lport);
2029 struct ethtool_cmd ecmd = { ETHTOOL_GSET }; 2029 struct ethtool_cmd ecmd;
2030 2030
2031 if (!dev_ethtool_get_settings(netdev, &ecmd)) { 2031 if (!dev_ethtool_get_settings(netdev, &ecmd)) {
2032 lport->link_supported_speeds &= 2032 lport->link_supported_speeds &=
@@ -2037,11 +2037,14 @@ int fcoe_link_speed_update(struct fc_lport *lport)
2037 if (ecmd.supported & SUPPORTED_10000baseT_Full) 2037 if (ecmd.supported & SUPPORTED_10000baseT_Full)
2038 lport->link_supported_speeds |= 2038 lport->link_supported_speeds |=
2039 FC_PORTSPEED_10GBIT; 2039 FC_PORTSPEED_10GBIT;
2040 if (ecmd.speed == SPEED_1000) 2040 switch (ethtool_cmd_speed(&ecmd)) {
2041 case SPEED_1000:
2041 lport->link_speed = FC_PORTSPEED_1GBIT; 2042 lport->link_speed = FC_PORTSPEED_1GBIT;
2042 if (ecmd.speed == SPEED_10000) 2043 break;
2044 case SPEED_10000:
2043 lport->link_speed = FC_PORTSPEED_10GBIT; 2045 lport->link_speed = FC_PORTSPEED_10GBIT;
2044 2046 break;
2047 }
2045 return 0; 2048 return 0;
2046 } 2049 }
2047 return -1; 2050 return -1;
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 7e6e0a89ca26..4194a2067a14 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -744,7 +744,9 @@ bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported);
744/** 744/**
745 * struct ethtool_ops - optional netdev operations 745 * struct ethtool_ops - optional netdev operations
746 * @get_settings: Get various device settings including Ethernet link 746 * @get_settings: Get various device settings including Ethernet link
747 * settings. Returns a negative error code or zero. 747 * settings. The @cmd parameter is expected to have been cleared
748 * before get_settings is called. Returns a negative error code or
749 * zero.
748 * @set_settings: Set various device settings including Ethernet link 750 * @set_settings: Set various device settings including Ethernet link
749 * settings. Returns a negative error code or zero. 751 * settings. Returns a negative error code or zero.
750 * @get_drvinfo: Report driver/device information. Should only set the 752 * @get_drvinfo: Report driver/device information. Should only set the
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index e03af35843bc..d5de66af46f9 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2597,13 +2597,8 @@ static inline int netif_is_bond_slave(struct net_device *dev)
2597 2597
2598extern struct pernet_operations __net_initdata loopback_net_ops; 2598extern struct pernet_operations __net_initdata loopback_net_ops;
2599 2599
2600static inline int dev_ethtool_get_settings(struct net_device *dev, 2600int dev_ethtool_get_settings(struct net_device *dev,
2601 struct ethtool_cmd *cmd) 2601 struct ethtool_cmd *cmd);
2602{
2603 if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings)
2604 return -EOPNOTSUPP;
2605 return dev->ethtool_ops->get_settings(dev, cmd);
2606}
2607 2602
2608static inline u32 dev_ethtool_get_rx_csum(struct net_device *dev) 2603static inline u32 dev_ethtool_get_rx_csum(struct net_device *dev)
2609{ 2604{
diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h
index b5fc9f39122b..ae8c68f30f1b 100644
--- a/include/rdma/ib_addr.h
+++ b/include/rdma/ib_addr.h
@@ -217,18 +217,19 @@ static inline enum ib_mtu iboe_get_mtu(int mtu)
217static inline int iboe_get_rate(struct net_device *dev) 217static inline int iboe_get_rate(struct net_device *dev)
218{ 218{
219 struct ethtool_cmd cmd; 219 struct ethtool_cmd cmd;
220 u32 speed;
220 221
221 if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings || 222 if (dev_ethtool_get_settings(dev, &cmd))
222 dev->ethtool_ops->get_settings(dev, &cmd))
223 return IB_RATE_PORT_CURRENT; 223 return IB_RATE_PORT_CURRENT;
224 224
225 if (cmd.speed >= 40000) 225 speed = ethtool_cmd_speed(&cmd);
226 if (speed >= 40000)
226 return IB_RATE_40_GBPS; 227 return IB_RATE_40_GBPS;
227 else if (cmd.speed >= 30000) 228 else if (speed >= 30000)
228 return IB_RATE_30_GBPS; 229 return IB_RATE_30_GBPS;
229 else if (cmd.speed >= 20000) 230 else if (speed >= 20000)
230 return IB_RATE_20_GBPS; 231 return IB_RATE_20_GBPS;
231 else if (cmd.speed >= 10000) 232 else if (speed >= 10000)
232 return IB_RATE_10_GBPS; 233 return IB_RATE_10_GBPS;
233 else 234 else
234 return IB_RATE_PORT_CURRENT; 235 return IB_RATE_PORT_CURRENT;
diff --git a/net/core/dev.c b/net/core/dev.c
index 7db99b52679f..e95dc30110eb 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4496,6 +4496,30 @@ void dev_set_rx_mode(struct net_device *dev)
4496} 4496}
4497 4497
4498/** 4498/**
4499 * dev_ethtool_get_settings - call device's ethtool_ops::get_settings()
4500 * @dev: device
4501 * @cmd: memory area for ethtool_ops::get_settings() result
4502 *
4503 * The cmd arg is initialized properly (cleared and
4504 * ethtool_cmd::cmd field set to ETHTOOL_GSET).
4505 *
4506 * Return device's ethtool_ops::get_settings() result value or
4507 * -EOPNOTSUPP when device doesn't expose
4508 * ethtool_ops::get_settings() operation.
4509 */
4510int dev_ethtool_get_settings(struct net_device *dev,
4511 struct ethtool_cmd *cmd)
4512{
4513 if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings)
4514 return -EOPNOTSUPP;
4515
4516 memset(cmd, 0, sizeof(struct ethtool_cmd));
4517 cmd->cmd = ETHTOOL_GSET;
4518 return dev->ethtool_ops->get_settings(dev, cmd);
4519}
4520EXPORT_SYMBOL(dev_ethtool_get_settings);
4521
4522/**
4499 * dev_get_flags - get flags reported to userspace 4523 * dev_get_flags - get flags reported to userspace
4500 * @dev: device 4524 * @dev: device
4501 * 4525 *
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 5ceb257e860c..381813eae46c 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -28,6 +28,7 @@
28static const char fmt_hex[] = "%#x\n"; 28static const char fmt_hex[] = "%#x\n";
29static const char fmt_long_hex[] = "%#lx\n"; 29static const char fmt_long_hex[] = "%#lx\n";
30static const char fmt_dec[] = "%d\n"; 30static const char fmt_dec[] = "%d\n";
31static const char fmt_udec[] = "%u\n";
31static const char fmt_ulong[] = "%lu\n"; 32static const char fmt_ulong[] = "%lu\n";
32static const char fmt_u64[] = "%llu\n"; 33static const char fmt_u64[] = "%llu\n";
33 34
@@ -145,13 +146,10 @@ static ssize_t show_speed(struct device *dev,
145 if (!rtnl_trylock()) 146 if (!rtnl_trylock())
146 return restart_syscall(); 147 return restart_syscall();
147 148
148 if (netif_running(netdev) && 149 if (netif_running(netdev)) {
149 netdev->ethtool_ops && 150 struct ethtool_cmd cmd;
150 netdev->ethtool_ops->get_settings) { 151 if (!dev_ethtool_get_settings(netdev, &cmd))
151 struct ethtool_cmd cmd = { ETHTOOL_GSET }; 152 ret = sprintf(buf, fmt_udec, ethtool_cmd_speed(&cmd));
152
153 if (!netdev->ethtool_ops->get_settings(netdev, &cmd))
154 ret = sprintf(buf, fmt_dec, ethtool_cmd_speed(&cmd));
155 } 153 }
156 rtnl_unlock(); 154 rtnl_unlock();
157 return ret; 155 return ret;
@@ -166,13 +164,11 @@ static ssize_t show_duplex(struct device *dev,
166 if (!rtnl_trylock()) 164 if (!rtnl_trylock())
167 return restart_syscall(); 165 return restart_syscall();
168 166
169 if (netif_running(netdev) && 167 if (netif_running(netdev)) {
170 netdev->ethtool_ops && 168 struct ethtool_cmd cmd;
171 netdev->ethtool_ops->get_settings) { 169 if (!dev_ethtool_get_settings(netdev, &cmd))
172 struct ethtool_cmd cmd = { ETHTOOL_GSET }; 170 ret = sprintf(buf, "%s\n",
173 171 cmd.duplex ? "full" : "half");
174 if (!netdev->ethtool_ops->get_settings(netdev, &cmd))
175 ret = sprintf(buf, "%s\n", cmd.duplex ? "full" : "half");
176 } 172 }
177 rtnl_unlock(); 173 rtnl_unlock();
178 return ret; 174 return ret;