ethtool: Call ethtool's get/set_settings callbacks with cleaned data
authorDavid Decotigny <decot@google.com>
Wed, 27 Apr 2011 18:32:38 +0000 (18:32 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 29 Apr 2011 21:01:30 +0000 (14:01 -0700)
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>
20 files changed:
arch/mips/txx9/generic/setup_tx4939.c
drivers/net/e100.c
drivers/net/mdio.c
drivers/net/mii.c
drivers/net/pch_gbe/pch_gbe_main.c
drivers/net/pch_gbe/pch_gbe_phy.c
drivers/net/pcnet32.c
drivers/net/sfc/mdio_10g.c
drivers/net/stmmac/stmmac_ethtool.c
drivers/net/usb/asix.c
drivers/net/usb/dm9601.c
drivers/net/usb/smsc75xx.c
drivers/net/usb/smsc95xx.c
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
drivers/scsi/fcoe/fcoe.c
include/linux/ethtool.h
include/linux/netdevice.h
include/rdma/ib_addr.h
net/core/dev.c
net/core/net-sysfs.c

index 3dc19f4829592b1986433ef3f43f777effcea3fb..e9f95dcde3790b630d1d3a9c1be0d4adab623b10 100644 (file)
@@ -318,19 +318,15 @@ void __init tx4939_sio_init(unsigned int sclk, unsigned int cts_mask)
 }
 
 #if defined(CONFIG_TC35815) || defined(CONFIG_TC35815_MODULE)
-static int tx4939_get_eth_speed(struct net_device *dev)
+static u32 tx4939_get_eth_speed(struct net_device *dev)
 {
-       struct ethtool_cmd cmd = { ETHTOOL_GSET };
-       int speed = 100;        /* default 100Mbps */
-       int err;
-       if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings)
-               return speed;
-       err = dev->ethtool_ops->get_settings(dev, &cmd);
-       if (err < 0)
-               return speed;
-       speed = cmd.speed == SPEED_100 ? 100 : 10;
-       return speed;
+       struct ethtool_cmd cmd;
+       if (dev_ethtool_get_settings(dev, &cmd))
+               return 100;     /* default 100Mbps */
+
+       return ethtool_cmd_speed(&cmd);
 }
+
 static int tx4939_netdev_event(struct notifier_block *this,
                               unsigned long event,
                               void *ptr)
@@ -343,8 +339,7 @@ static int tx4939_netdev_event(struct notifier_block *this,
                else if (dev->irq == TXX9_IRQ_BASE + TX4939_IR_ETH(1))
                        bit = TX4939_PCFG_SPEED1;
                if (bit) {
-                       int speed = tx4939_get_eth_speed(dev);
-                       if (speed == 100)
+                       if (tx4939_get_eth_speed(dev) == 100)
                                txx9_set64(&tx4939_ccfgptr->pcfg, bit);
                        else
                                txx9_clear64(&tx4939_ccfgptr->pcfg, bit);
index b0aa9e68990a70e783118ca78c39f969f56098d0..66ba596a4d3791c061520722322ae23c4624bd52 100644 (file)
@@ -1668,7 +1668,7 @@ static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex)
 static void e100_watchdog(unsigned long data)
 {
        struct nic *nic = (struct nic *)data;
-       struct ethtool_cmd cmd;
+       struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET };
 
        netif_printk(nic, timer, KERN_DEBUG, nic->netdev,
                     "right now = %ld\n", jiffies);
index e85bf04cf813c608d80a247f2f3d144fbc7cc6a5..f2d10abd04035a7b4f05580ff363607396f8cc06 100644 (file)
@@ -176,6 +176,9 @@ static u32 mdio45_get_an(const struct mdio_if_info *mdio, u16 addr)
  * @npage_adv: Modes currently advertised on next pages
  * @npage_lpa: Modes advertised by link partner on next pages
  *
+ * The @ecmd parameter is expected to have been cleared before calling
+ * mdio45_ethtool_gset_npage().
+ *
  * Since the CSRs for auto-negotiation using next pages are not fully
  * standardised, this function does not attempt to decode them.  The
  * caller must pass them in.
index 0a6c6a2e7550f17235827811be88140ba891a0f6..05acca78f63a9a6ce294c49a902a65485b7aed71 100644 (file)
@@ -58,6 +58,9 @@ static u32 mii_get_an(struct mii_if_info *mii, u16 addr)
  * @mii: MII interface
  * @ecmd: requested ethtool_cmd
  *
+ * The @ecmd parameter is expected to have been cleared before calling
+ * mii_ethtool_gset().
+ *
  * Returns 0 for success, negative on error.
  */
 int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
index 4cc9872f5ec4d7dde7af29ad7c2a6189c061965e..f3e4b0adae93b462274dd7e26e3de06f86dfaf50 100644 (file)
@@ -888,12 +888,12 @@ static void pch_gbe_watchdog(unsigned long data)
        struct pch_gbe_adapter *adapter = (struct pch_gbe_adapter *)data;
        struct net_device *netdev = adapter->netdev;
        struct pch_gbe_hw *hw = &adapter->hw;
-       struct ethtool_cmd cmd;
 
        pr_debug("right now = %ld\n", jiffies);
 
        pch_gbe_update_stats(adapter);
        if ((mii_link_ok(&adapter->mii)) && (!netif_carrier_ok(netdev))) {
+               struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET };
                netdev->tx_queue_len = adapter->tx_queue_len;
                /* mii library handles link maintenance tasks */
                if (mii_ethtool_gset(&adapter->mii, &cmd)) {
@@ -903,7 +903,7 @@ static void pch_gbe_watchdog(unsigned long data)
                                                PCH_GBE_WATCHDOG_PERIOD));
                        return;
                }
-               hw->mac.link_speed = cmd.speed;
+               hw->mac.link_speed = ethtool_cmd_speed(&cmd);
                hw->mac.link_duplex = cmd.duplex;
                /* Set the RGMII control. */
                pch_gbe_set_rgmii_ctrl(adapter, hw->mac.link_speed,
@@ -913,7 +913,7 @@ static void pch_gbe_watchdog(unsigned long data)
                                 hw->mac.link_duplex);
                netdev_dbg(netdev,
                           "Link is Up %d Mbps %s-Duplex\n",
-                          cmd.speed,
+                          hw->mac.link_speed,
                           cmd.duplex == DUPLEX_FULL ? "Full" : "Half");
                netif_carrier_on(netdev);
                netif_wake_queue(netdev);
index 923a687acd30461ab536e351353d0a227765c3e1..9a8207f686fd41cc289dca79b0a6545f36b756b0 100644 (file)
@@ -247,7 +247,7 @@ inline void pch_gbe_phy_set_rgmii(struct pch_gbe_hw *hw)
 void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw)
 {
        struct pch_gbe_adapter *adapter;
-       struct ethtool_cmd     cmd;
+       struct ethtool_cmd     cmd = { .cmd = ETHTOOL_GSET };
        int ret;
        u16 mii_reg;
 
index 0a1efbae1bc0577c9774d3fe577d46ad3244e5cb..b48aba9e42274de4609d3920d133021a11de4b6b 100644 (file)
@@ -2099,7 +2099,7 @@ static int pcnet32_open(struct net_device *dev)
                int first_phy = -1;
                u16 bmcr;
                u32 bcr9;
-               struct ethtool_cmd ecmd;
+               struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
 
                /*
                 * There is really no good other way to handle multiple PHYs
@@ -2115,9 +2115,9 @@ static int pcnet32_open(struct net_device *dev)
                        ecmd.port = PORT_MII;
                        ecmd.transceiver = XCVR_INTERNAL;
                        ecmd.autoneg = AUTONEG_DISABLE;
-                       ecmd.speed =
-                           lp->
-                           options & PCNET32_PORT_100 ? SPEED_100 : SPEED_10;
+                       ethtool_cmd_speed_set(&ecmd,
+                                             (lp->options & PCNET32_PORT_100) ?
+                                             SPEED_100 : SPEED_10);
                        bcr9 = lp->a.read_bcr(ioaddr, 9);
 
                        if (lp->options & PCNET32_PORT_FD) {
@@ -2763,11 +2763,11 @@ static void pcnet32_check_media(struct net_device *dev, int verbose)
                netif_carrier_on(dev);
                if (lp->mii) {
                        if (netif_msg_link(lp)) {
-                               struct ethtool_cmd ecmd;
+                               struct ethtool_cmd ecmd = {
+                                       .cmd = ETHTOOL_GSET };
                                mii_ethtool_gset(&lp->mii_if, &ecmd);
-                               netdev_info(dev, "link up, %sMbps, %s-duplex\n",
-                                           (ecmd.speed == SPEED_100)
-                                           ? "100" : "10",
+                               netdev_info(dev, "link up, %uMbps, %s-duplex\n",
+                                           ethtool_cmd_speed(&ecmd),
                                            (ecmd.duplex == DUPLEX_FULL)
                                            ? "full" : "half");
                        }
index 19e68c26d1030a64bda6acec5486e363763b47b9..71159145b4bf7cd2c33605a161472cef28514507 100644 (file)
@@ -232,12 +232,12 @@ void efx_mdio_set_mmds_lpower(struct efx_nic *efx,
  */
 int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
 {
-       struct ethtool_cmd prev;
+       struct ethtool_cmd prev = { .cmd = ETHTOOL_GSET };
 
        efx->phy_op->get_settings(efx, &prev);
 
        if (ecmd->advertising == prev.advertising &&
-           ecmd->speed == prev.speed &&
+           ethtool_cmd_speed(ecmd) == ethtool_cmd_speed(&prev) &&
            ecmd->duplex == prev.duplex &&
            ecmd->port == prev.port &&
            ecmd->autoneg == prev.autoneg)
index 0e61ac8707cbef1d5c75f82258f65d3d4cb14094..6f5aaeb986ffa7e731d77580bbcd94458d87ffb9 100644 (file)
@@ -237,13 +237,12 @@ stmmac_set_pauseparam(struct net_device *netdev,
 
        if (phy->autoneg) {
                if (netif_running(netdev)) {
-                       struct ethtool_cmd cmd;
+                       struct ethtool_cmd cmd = { .cmd = ETHTOOL_SSET };
                        /* auto-negotiation automatically restarted */
-                       cmd.cmd = ETHTOOL_NWAY_RST;
                        cmd.supported = phy->supported;
                        cmd.advertising = phy->advertising;
                        cmd.autoneg = phy->autoneg;
-                       cmd.speed = phy->speed;
+                       ethtool_cmd_speed_set(&cmd, phy->speed);
                        cmd.duplex = phy->duplex;
                        cmd.phy_address = phy->addr;
                        ret = phy_ethtool_sset(phy, &cmd);
index 6140b56cce53d2205638803ce13702bcbfeb8910..6998aa6b7bb7449daff10095d5150963a154153a 100644 (file)
@@ -847,7 +847,7 @@ static void ax88172_set_multicast(struct net_device *net)
 static int ax88172_link_reset(struct usbnet *dev)
 {
        u8 mode;
-       struct ethtool_cmd ecmd;
+       struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
 
        mii_check_media(&dev->mii, 1, 1);
        mii_ethtool_gset(&dev->mii, &ecmd);
@@ -856,8 +856,8 @@ static int ax88172_link_reset(struct usbnet *dev)
        if (ecmd.duplex != DUPLEX_FULL)
                mode |= ~AX88172_MEDIUM_FD;
 
-       netdev_dbg(dev->net, "ax88172_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n",
-                  ecmd.speed, ecmd.duplex, mode);
+       netdev_dbg(dev->net, "ax88172_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
+                  ethtool_cmd_speed(&ecmd), ecmd.duplex, mode);
 
        asix_write_medium_mode(dev, mode);
 
@@ -947,20 +947,20 @@ static const struct ethtool_ops ax88772_ethtool_ops = {
 static int ax88772_link_reset(struct usbnet *dev)
 {
        u16 mode;
-       struct ethtool_cmd ecmd;
+       struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
 
        mii_check_media(&dev->mii, 1, 1);
        mii_ethtool_gset(&dev->mii, &ecmd);
        mode = AX88772_MEDIUM_DEFAULT;
 
-       if (ecmd.speed != SPEED_100)
+       if (ethtool_cmd_speed(&ecmd) != SPEED_100)
                mode &= ~AX_MEDIUM_PS;
 
        if (ecmd.duplex != DUPLEX_FULL)
                mode &= ~AX_MEDIUM_FD;
 
-       netdev_dbg(dev->net, "ax88772_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n",
-                  ecmd.speed, ecmd.duplex, mode);
+       netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
+                  ethtool_cmd_speed(&ecmd), ecmd.duplex, mode);
 
        asix_write_medium_mode(dev, mode);
 
@@ -1173,18 +1173,20 @@ static int marvell_led_status(struct usbnet *dev, u16 speed)
 static int ax88178_link_reset(struct usbnet *dev)
 {
        u16 mode;
-       struct ethtool_cmd ecmd;
+       struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
        struct asix_data *data = (struct asix_data *)&dev->data;
+       u32 speed;
 
        netdev_dbg(dev->net, "ax88178_link_reset()\n");
 
        mii_check_media(&dev->mii, 1, 1);
        mii_ethtool_gset(&dev->mii, &ecmd);
        mode = AX88178_MEDIUM_DEFAULT;
+       speed = ethtool_cmd_speed(&ecmd);
 
-       if (ecmd.speed == SPEED_1000)
+       if (speed == SPEED_1000)
                mode |= AX_MEDIUM_GM;
-       else if (ecmd.speed == SPEED_100)
+       else if (speed == SPEED_100)
                mode |= AX_MEDIUM_PS;
        else
                mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM);
@@ -1196,13 +1198,13 @@ static int ax88178_link_reset(struct usbnet *dev)
        else
                mode &= ~AX_MEDIUM_FD;
 
-       netdev_dbg(dev->net, "ax88178_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n",
-                  ecmd.speed, ecmd.duplex, mode);
+       netdev_dbg(dev->net, "ax88178_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
+                  speed, ecmd.duplex, mode);
 
        asix_write_medium_mode(dev, mode);
 
        if (data->phymode == PHY_MODE_MARVELL && data->ledmode)
-               marvell_led_status(dev, ecmd.speed);
+               marvell_led_status(dev, speed);
 
        return 0;
 }
index 5002f5be47be7dcbd95e0fd9cee2a80910046a81..1d93133e9b744529cb1d72328846be6589417275 100644 (file)
@@ -599,13 +599,13 @@ static void dm9601_status(struct usbnet *dev, struct urb *urb)
 
 static int dm9601_link_reset(struct usbnet *dev)
 {
-       struct ethtool_cmd ecmd;
+       struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
 
        mii_check_media(&dev->mii, 1, 1);
        mii_ethtool_gset(&dev->mii, &ecmd);
 
-       netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n",
-                  ecmd.speed, ecmd.duplex);
+       netdev_dbg(dev->net, "link_reset() speed: %u duplex: %d\n",
+                  ethtool_cmd_speed(&ecmd), ecmd.duplex);
 
        return 0;
 }
index 860a20c938b4fc8b92de71afd8c9e86f51b8f4a7..15b3d6888ae9b1997d3c4f09b8968baacef782cc 100644 (file)
@@ -503,7 +503,7 @@ static int smsc75xx_update_flowcontrol(struct usbnet *dev, u8 duplex,
 static int smsc75xx_link_reset(struct usbnet *dev)
 {
        struct mii_if_info *mii = &dev->mii;
-       struct ethtool_cmd ecmd;
+       struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
        u16 lcladv, rmtadv;
        int ret;
 
@@ -519,8 +519,9 @@ static int smsc75xx_link_reset(struct usbnet *dev)
        lcladv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE);
        rmtadv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_LPA);
 
-       netif_dbg(dev, link, dev->net, "speed: %d duplex: %d lcladv: %04x"
-               " rmtadv: %04x", ecmd.speed, ecmd.duplex, lcladv, rmtadv);
+       netif_dbg(dev, link, dev->net, "speed: %u duplex: %d lcladv: %04x"
+                 " rmtadv: %04x", ethtool_cmd_speed(&ecmd),
+                 ecmd.duplex, lcladv, rmtadv);
 
        return smsc75xx_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv);
 }
index 24f4b3739dd2a897b1929d05978046083a2e3799..b374a9997908bd7f2667629a0d9784e25753140f 100644 (file)
@@ -457,7 +457,7 @@ static int smsc95xx_link_reset(struct usbnet *dev)
 {
        struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
        struct mii_if_info *mii = &dev->mii;
-       struct ethtool_cmd ecmd;
+       struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
        unsigned long flags;
        u16 lcladv, rmtadv;
        u32 intdata;
@@ -472,8 +472,9 @@ static int smsc95xx_link_reset(struct usbnet *dev)
        lcladv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE);
        rmtadv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_LPA);
 
-       netif_dbg(dev, link, dev->net, "speed: %d duplex: %d lcladv: %04x rmtadv: %04x\n",
-                 ecmd.speed, ecmd.duplex, lcladv, rmtadv);
+       netif_dbg(dev, link, dev->net,
+                 "speed: %u duplex: %d lcladv: %04x rmtadv: %04x\n",
+                 ethtool_cmd_speed(&ecmd), ecmd.duplex, lcladv, rmtadv);
 
        spin_lock_irqsave(&pdata->mac_cr_lock, flags);
        if (ecmd.duplex != DUPLEX_FULL) {
index e2e647509a7349113ff4606d6be2ea92b3b796a3..cd050196a1631f4cc86c72f9457abad7961882d0 100644 (file)
@@ -664,7 +664,7 @@ static void bnx2fc_link_speed_update(struct fc_lport *lport)
        struct fcoe_port *port = lport_priv(lport);
        struct bnx2fc_hba *hba = port->priv;
        struct net_device *netdev = hba->netdev;
-       struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+       struct ethtool_cmd ecmd;
 
        if (!dev_ethtool_get_settings(netdev, &ecmd)) {
                lport->link_supported_speeds &=
@@ -675,12 +675,15 @@ static void bnx2fc_link_speed_update(struct fc_lport *lport)
                if (ecmd.supported & SUPPORTED_10000baseT_Full)
                        lport->link_supported_speeds |= FC_PORTSPEED_10GBIT;
 
-               if (ecmd.speed == SPEED_1000)
+               switch (ethtool_cmd_speed(&ecmd)) {
+               case SPEED_1000:
                        lport->link_speed = FC_PORTSPEED_1GBIT;
-               if (ecmd.speed == SPEED_10000)
+                       break;
+               case SPEED_10000:
                        lport->link_speed = FC_PORTSPEED_10GBIT;
+                       break;
+               }
        }
-       return;
 }
 static int bnx2fc_link_ok(struct fc_lport *lport)
 {
index bde6ee5333eba62f7ac5a87c566c58c1dc31075b..04f346b562da797cc02cc12e9c74dea56d59a546 100644 (file)
@@ -2026,7 +2026,7 @@ out_nodev:
 int fcoe_link_speed_update(struct fc_lport *lport)
 {
        struct net_device *netdev = fcoe_netdev(lport);
-       struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+       struct ethtool_cmd ecmd;
 
        if (!dev_ethtool_get_settings(netdev, &ecmd)) {
                lport->link_supported_speeds &=
@@ -2037,11 +2037,14 @@ int fcoe_link_speed_update(struct fc_lport *lport)
                if (ecmd.supported & SUPPORTED_10000baseT_Full)
                        lport->link_supported_speeds |=
                                FC_PORTSPEED_10GBIT;
-               if (ecmd.speed == SPEED_1000)
+               switch (ethtool_cmd_speed(&ecmd)) {
+               case SPEED_1000:
                        lport->link_speed = FC_PORTSPEED_1GBIT;
-               if (ecmd.speed == SPEED_10000)
+                       break;
+               case SPEED_10000:
                        lport->link_speed = FC_PORTSPEED_10GBIT;
-
+                       break;
+               }
                return 0;
        }
        return -1;
index 7e6e0a89ca26b89d51f6f64fc080b710ca0d1be3..4194a2067a1475dcb85d786be94cd1bf578312c4 100644 (file)
@@ -744,7 +744,9 @@ bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported);
 /**
  * struct ethtool_ops - optional netdev operations
  * @get_settings: Get various device settings including Ethernet link
- *     settings.  Returns a negative error code or zero.
+ *     settings. The @cmd parameter is expected to have been cleared
+ *     before get_settings is called. Returns a negative error code or
+ *     zero.
  * @set_settings: Set various device settings including Ethernet link
  *     settings.  Returns a negative error code or zero.
  * @get_drvinfo: Report driver/device information.  Should only set the
index e03af35843bc249a621a905622f7f8ac440fd72b..d5de66af46f9b93d6ac84dcd7c3162dc1e0e433b 100644 (file)
@@ -2597,13 +2597,8 @@ static inline int netif_is_bond_slave(struct net_device *dev)
 
 extern struct pernet_operations __net_initdata loopback_net_ops;
 
-static inline int dev_ethtool_get_settings(struct net_device *dev,
-                                          struct ethtool_cmd *cmd)
-{
-       if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings)
-               return -EOPNOTSUPP;
-       return dev->ethtool_ops->get_settings(dev, cmd);
-}
+int dev_ethtool_get_settings(struct net_device *dev,
+                            struct ethtool_cmd *cmd);
 
 static inline u32 dev_ethtool_get_rx_csum(struct net_device *dev)
 {
index b5fc9f39122b65ab7a7fbd4911dd9e4ab6c98d8e..ae8c68f30f1bc36c3ffa1c7095e85125f85f6ae7 100644 (file)
@@ -217,18 +217,19 @@ static inline enum ib_mtu iboe_get_mtu(int mtu)
 static inline int iboe_get_rate(struct net_device *dev)
 {
        struct ethtool_cmd cmd;
+       u32 speed;
 
-       if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings ||
-           dev->ethtool_ops->get_settings(dev, &cmd))
+       if (dev_ethtool_get_settings(dev, &cmd))
                return IB_RATE_PORT_CURRENT;
 
-       if (cmd.speed >= 40000)
+       speed = ethtool_cmd_speed(&cmd);
+       if (speed >= 40000)
                return IB_RATE_40_GBPS;
-       else if (cmd.speed >= 30000)
+       else if (speed >= 30000)
                return IB_RATE_30_GBPS;
-       else if (cmd.speed >= 20000)
+       else if (speed >= 20000)
                return IB_RATE_20_GBPS;
-       else if (cmd.speed >= 10000)
+       else if (speed >= 10000)
                return IB_RATE_10_GBPS;
        else
                return IB_RATE_PORT_CURRENT;
index 7db99b52679f09ee83d4cedae34faecb5fb3f6b2..e95dc30110ebec687c6a3a4b968143fbfeb11a01 100644 (file)
@@ -4495,6 +4495,30 @@ void dev_set_rx_mode(struct net_device *dev)
        netif_addr_unlock_bh(dev);
 }
 
+/**
+ *     dev_ethtool_get_settings - call device's ethtool_ops::get_settings()
+ *     @dev: device
+ *     @cmd: memory area for ethtool_ops::get_settings() result
+ *
+ *      The cmd arg is initialized properly (cleared and
+ *      ethtool_cmd::cmd field set to ETHTOOL_GSET).
+ *
+ *     Return device's ethtool_ops::get_settings() result value or
+ *     -EOPNOTSUPP when device doesn't expose
+ *     ethtool_ops::get_settings() operation.
+ */
+int dev_ethtool_get_settings(struct net_device *dev,
+                            struct ethtool_cmd *cmd)
+{
+       if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings)
+               return -EOPNOTSUPP;
+
+       memset(cmd, 0, sizeof(struct ethtool_cmd));
+       cmd->cmd = ETHTOOL_GSET;
+       return dev->ethtool_ops->get_settings(dev, cmd);
+}
+EXPORT_SYMBOL(dev_ethtool_get_settings);
+
 /**
  *     dev_get_flags - get flags reported to userspace
  *     @dev: device
index 5ceb257e860c18cbabe352f67cb8760d95bcba84..381813eae46c6af9cda9a7776b47e0e3d27e7322 100644 (file)
@@ -28,6 +28,7 @@
 static const char fmt_hex[] = "%#x\n";
 static const char fmt_long_hex[] = "%#lx\n";
 static const char fmt_dec[] = "%d\n";
+static const char fmt_udec[] = "%u\n";
 static const char fmt_ulong[] = "%lu\n";
 static const char fmt_u64[] = "%llu\n";
 
@@ -145,13 +146,10 @@ static ssize_t show_speed(struct device *dev,
        if (!rtnl_trylock())
                return restart_syscall();
 
-       if (netif_running(netdev) &&
-           netdev->ethtool_ops &&
-           netdev->ethtool_ops->get_settings) {
-               struct ethtool_cmd cmd = { ETHTOOL_GSET };
-
-               if (!netdev->ethtool_ops->get_settings(netdev, &cmd))
-                       ret = sprintf(buf, fmt_dec, ethtool_cmd_speed(&cmd));
+       if (netif_running(netdev)) {
+               struct ethtool_cmd cmd;
+               if (!dev_ethtool_get_settings(netdev, &cmd))
+                       ret = sprintf(buf, fmt_udec, ethtool_cmd_speed(&cmd));
        }
        rtnl_unlock();
        return ret;
@@ -166,13 +164,11 @@ static ssize_t show_duplex(struct device *dev,
        if (!rtnl_trylock())
                return restart_syscall();
 
-       if (netif_running(netdev) &&
-           netdev->ethtool_ops &&
-           netdev->ethtool_ops->get_settings) {
-               struct ethtool_cmd cmd = { ETHTOOL_GSET };
-
-               if (!netdev->ethtool_ops->get_settings(netdev, &cmd))
-                       ret = sprintf(buf, "%s\n", cmd.duplex ? "full" : "half");
+       if (netif_running(netdev)) {
+               struct ethtool_cmd cmd;
+               if (!dev_ethtool_get_settings(netdev, &cmd))
+                       ret = sprintf(buf, "%s\n",
+                                     cmd.duplex ? "full" : "half");
        }
        rtnl_unlock();
        return ret;