Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

David Decotigny and committed by
David S. Miller
8ae6daca 36504605

+117 -89
+8 -13
arch/mips/txx9/generic/setup_tx4939.c
··· 318 318 } 319 319 320 320 #if defined(CONFIG_TC35815) || defined(CONFIG_TC35815_MODULE) 321 - static int tx4939_get_eth_speed(struct net_device *dev) 321 + static u32 tx4939_get_eth_speed(struct net_device *dev) 322 322 { 323 - struct ethtool_cmd cmd = { ETHTOOL_GSET }; 324 - int speed = 100; /* default 100Mbps */ 325 - int err; 326 - if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings) 327 - return speed; 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; 323 + struct ethtool_cmd cmd; 324 + if (dev_ethtool_get_settings(dev, &cmd)) 325 + return 100; /* default 100Mbps */ 326 + 327 + return ethtool_cmd_speed(&cmd); 333 328 } 329 + 334 330 static int tx4939_netdev_event(struct notifier_block *this, 335 331 unsigned long event, 336 332 void *ptr) ··· 339 343 else if (dev->irq == TXX9_IRQ_BASE + TX4939_IR_ETH(1)) 340 344 bit = TX4939_PCFG_SPEED1; 341 345 if (bit) { 342 - int speed = tx4939_get_eth_speed(dev); 343 - if (speed == 100) 346 + if (tx4939_get_eth_speed(dev) == 100) 344 347 txx9_set64(&tx4939_ccfgptr->pcfg, bit); 345 348 else 346 349 txx9_clear64(&tx4939_ccfgptr->pcfg, bit);
+1 -1
drivers/net/e100.c
··· 1668 1668 static void e100_watchdog(unsigned long data) 1669 1669 { 1670 1670 struct nic *nic = (struct nic *)data; 1671 - struct ethtool_cmd cmd; 1671 + struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET }; 1672 1672 1673 1673 netif_printk(nic, timer, KERN_DEBUG, nic->netdev, 1674 1674 "right now = %ld\n", jiffies);
+3
drivers/net/mdio.c
··· 176 176 * @npage_adv: Modes currently advertised on next pages 177 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 182 * Since the CSRs for auto-negotiation using next pages are not fully 180 183 * standardised, this function does not attempt to decode them. The 181 184 * caller must pass them in.
+3
drivers/net/mii.c
··· 58 58 * @mii: MII interface 59 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 64 * Returns 0 for success, negative on error. 62 65 */ 63 66 int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
+3 -3
drivers/net/pch_gbe/pch_gbe_main.c
··· 888 888 struct pch_gbe_adapter *adapter = (struct pch_gbe_adapter *)data; 889 889 struct net_device *netdev = adapter->netdev; 890 890 struct pch_gbe_hw *hw = &adapter->hw; 891 - struct ethtool_cmd cmd; 892 891 893 892 pr_debug("right now = %ld\n", jiffies); 894 893 895 894 pch_gbe_update_stats(adapter); 896 895 if ((mii_link_ok(&adapter->mii)) && (!netif_carrier_ok(netdev))) { 896 + struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET }; 897 897 netdev->tx_queue_len = adapter->tx_queue_len; 898 898 /* mii library handles link maintenance tasks */ 899 899 if (mii_ethtool_gset(&adapter->mii, &cmd)) { ··· 903 903 PCH_GBE_WATCHDOG_PERIOD)); 904 904 return; 905 905 } 906 - hw->mac.link_speed = cmd.speed; 906 + hw->mac.link_speed = ethtool_cmd_speed(&cmd); 907 907 hw->mac.link_duplex = cmd.duplex; 908 908 /* Set the RGMII control. */ 909 909 pch_gbe_set_rgmii_ctrl(adapter, hw->mac.link_speed, ··· 913 913 hw->mac.link_duplex); 914 914 netdev_dbg(netdev, 915 915 "Link is Up %d Mbps %s-Duplex\n", 916 - cmd.speed, 916 + hw->mac.link_speed, 917 917 cmd.duplex == DUPLEX_FULL ? "Full" : "Half"); 918 918 netif_carrier_on(netdev); 919 919 netif_wake_queue(netdev);
+1 -1
drivers/net/pch_gbe/pch_gbe_phy.c
··· 247 247 void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw) 248 248 { 249 249 struct pch_gbe_adapter *adapter; 250 - struct ethtool_cmd cmd; 250 + struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET }; 251 251 int ret; 252 252 u16 mii_reg; 253 253
+8 -8
drivers/net/pcnet32.c
··· 2099 2099 int first_phy = -1; 2100 2100 u16 bmcr; 2101 2101 u32 bcr9; 2102 - struct ethtool_cmd ecmd; 2102 + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; 2103 2103 2104 2104 /* 2105 2105 * There is really no good other way to handle multiple PHYs ··· 2115 2115 ecmd.port = PORT_MII; 2116 2116 ecmd.transceiver = XCVR_INTERNAL; 2117 2117 ecmd.autoneg = AUTONEG_DISABLE; 2118 - ecmd.speed = 2119 - lp-> 2120 - options & PCNET32_PORT_100 ? SPEED_100 : SPEED_10; 2118 + ethtool_cmd_speed_set(&ecmd, 2119 + (lp->options & PCNET32_PORT_100) ? 2120 + SPEED_100 : SPEED_10); 2121 2121 bcr9 = lp->a.read_bcr(ioaddr, 9); 2122 2122 2123 2123 if (lp->options & PCNET32_PORT_FD) { ··· 2763 2763 netif_carrier_on(dev); 2764 2764 if (lp->mii) { 2765 2765 if (netif_msg_link(lp)) { 2766 - struct ethtool_cmd ecmd; 2766 + struct ethtool_cmd ecmd = { 2767 + .cmd = ETHTOOL_GSET }; 2767 2768 mii_ethtool_gset(&lp->mii_if, &ecmd); 2768 - netdev_info(dev, "link up, %sMbps, %s-duplex\n", 2769 - (ecmd.speed == SPEED_100) 2770 - ? "100" : "10", 2769 + netdev_info(dev, "link up, %uMbps, %s-duplex\n", 2770 + ethtool_cmd_speed(&ecmd), 2771 2771 (ecmd.duplex == DUPLEX_FULL) 2772 2772 ? "full" : "half"); 2773 2773 }
+2 -2
drivers/net/sfc/mdio_10g.c
··· 232 232 */ 233 233 int 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 237 efx->phy_op->get_settings(efx, &prev); 238 238 239 239 if (ecmd->advertising == prev.advertising && 240 - ecmd->speed == prev.speed && 240 + ethtool_cmd_speed(ecmd) == ethtool_cmd_speed(&prev) && 241 241 ecmd->duplex == prev.duplex && 242 242 ecmd->port == prev.port && 243 243 ecmd->autoneg == prev.autoneg)
+2 -3
drivers/net/stmmac/stmmac_ethtool.c
··· 237 237 238 238 if (phy->autoneg) { 239 239 if (netif_running(netdev)) { 240 - struct ethtool_cmd cmd; 240 + struct ethtool_cmd cmd = { .cmd = ETHTOOL_SSET }; 241 241 /* auto-negotiation automatically restarted */ 242 - cmd.cmd = ETHTOOL_NWAY_RST; 243 242 cmd.supported = phy->supported; 244 243 cmd.advertising = phy->advertising; 245 244 cmd.autoneg = phy->autoneg; 246 - cmd.speed = phy->speed; 245 + ethtool_cmd_speed_set(&cmd, phy->speed); 247 246 cmd.duplex = phy->duplex; 248 247 cmd.phy_address = phy->addr; 249 248 ret = phy_ethtool_sset(phy, &cmd);
+15 -13
drivers/net/usb/asix.c
··· 847 847 static int ax88172_link_reset(struct usbnet *dev) 848 848 { 849 849 u8 mode; 850 - struct ethtool_cmd ecmd; 850 + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; 851 851 852 852 mii_check_media(&dev->mii, 1, 1); 853 853 mii_ethtool_gset(&dev->mii, &ecmd); ··· 856 856 if (ecmd.duplex != DUPLEX_FULL) 857 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", 860 - ecmd.speed, ecmd.duplex, mode); 859 + netdev_dbg(dev->net, "ax88172_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", 860 + ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); 861 861 862 862 asix_write_medium_mode(dev, mode); 863 863 ··· 947 947 static int ax88772_link_reset(struct usbnet *dev) 948 948 { 949 949 u16 mode; 950 - struct ethtool_cmd ecmd; 950 + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; 951 951 952 952 mii_check_media(&dev->mii, 1, 1); 953 953 mii_ethtool_gset(&dev->mii, &ecmd); 954 954 mode = AX88772_MEDIUM_DEFAULT; 955 955 956 - if (ecmd.speed != SPEED_100) 956 + if (ethtool_cmd_speed(&ecmd) != SPEED_100) 957 957 mode &= ~AX_MEDIUM_PS; 958 958 959 959 if (ecmd.duplex != DUPLEX_FULL) 960 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", 963 - ecmd.speed, ecmd.duplex, mode); 962 + netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", 963 + ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); 964 964 965 965 asix_write_medium_mode(dev, mode); 966 966 ··· 1173 1173 static int ax88178_link_reset(struct usbnet *dev) 1174 1174 { 1175 1175 u16 mode; 1176 - struct ethtool_cmd ecmd; 1176 + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; 1177 1177 struct asix_data *data = (struct asix_data *)&dev->data; 1178 + u32 speed; 1178 1179 1179 1180 netdev_dbg(dev->net, "ax88178_link_reset()\n"); 1180 1181 1181 1182 mii_check_media(&dev->mii, 1, 1); 1182 1183 mii_ethtool_gset(&dev->mii, &ecmd); 1183 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 1188 mode |= AX_MEDIUM_GM; 1187 - else if (ecmd.speed == SPEED_100) 1189 + else if (speed == SPEED_100) 1188 1190 mode |= AX_MEDIUM_PS; 1189 1191 else 1190 1192 mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM); ··· 1198 1196 else 1199 1197 mode &= ~AX_MEDIUM_FD; 1200 1198 1201 - netdev_dbg(dev->net, "ax88178_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n", 1202 - ecmd.speed, ecmd.duplex, mode); 1199 + netdev_dbg(dev->net, "ax88178_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", 1200 + speed, ecmd.duplex, mode); 1203 1201 1204 1202 asix_write_medium_mode(dev, mode); 1205 1203 1206 1204 if (data->phymode == PHY_MODE_MARVELL && data->ledmode) 1207 - marvell_led_status(dev, ecmd.speed); 1205 + marvell_led_status(dev, speed); 1208 1206 1209 1207 return 0; 1210 1208 }
+3 -3
drivers/net/usb/dm9601.c
··· 599 599 600 600 static 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 604 mii_check_media(&dev->mii, 1, 1); 605 605 mii_ethtool_gset(&dev->mii, &ecmd); 606 606 607 - netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n", 608 - ecmd.speed, ecmd.duplex); 607 + netdev_dbg(dev->net, "link_reset() speed: %u duplex: %d\n", 608 + ethtool_cmd_speed(&ecmd), ecmd.duplex); 609 609 610 610 return 0; 611 611 }
+4 -3
drivers/net/usb/smsc75xx.c
··· 503 503 static int smsc75xx_link_reset(struct usbnet *dev) 504 504 { 505 505 struct mii_if_info *mii = &dev->mii; 506 - struct ethtool_cmd ecmd; 506 + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; 507 507 u16 lcladv, rmtadv; 508 508 int ret; 509 509 ··· 519 519 lcladv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); 520 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" 523 - " rmtadv: %04x", ecmd.speed, ecmd.duplex, lcladv, rmtadv); 522 + netif_dbg(dev, link, dev->net, "speed: %u duplex: %d lcladv: %04x" 523 + " rmtadv: %04x", ethtool_cmd_speed(&ecmd), 524 + ecmd.duplex, lcladv, rmtadv); 524 525 525 526 return smsc75xx_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv); 526 527 }
+4 -3
drivers/net/usb/smsc95xx.c
··· 457 457 { 458 458 struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); 459 459 struct mii_if_info *mii = &dev->mii; 460 - struct ethtool_cmd ecmd; 460 + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; 461 461 unsigned long flags; 462 462 u16 lcladv, rmtadv; 463 463 u32 intdata; ··· 472 472 lcladv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); 473 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", 476 - ecmd.speed, ecmd.duplex, lcladv, rmtadv); 475 + netif_dbg(dev, link, dev->net, 476 + "speed: %u duplex: %d lcladv: %04x rmtadv: %04x\n", 477 + ethtool_cmd_speed(&ecmd), ecmd.duplex, lcladv, rmtadv); 477 478 478 479 spin_lock_irqsave(&pdata->mac_cr_lock, flags); 479 480 if (ecmd.duplex != DUPLEX_FULL) {
+7 -4
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
··· 664 664 struct fcoe_port *port = lport_priv(lport); 665 665 struct bnx2fc_hba *hba = port->priv; 666 666 struct net_device *netdev = hba->netdev; 667 - struct ethtool_cmd ecmd = { ETHTOOL_GSET }; 667 + struct ethtool_cmd ecmd; 668 668 669 669 if (!dev_ethtool_get_settings(netdev, &ecmd)) { 670 670 lport->link_supported_speeds &= ··· 675 675 if (ecmd.supported & SUPPORTED_10000baseT_Full) 676 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 680 lport->link_speed = FC_PORTSPEED_1GBIT; 680 - if (ecmd.speed == SPEED_10000) 681 + break; 682 + case SPEED_10000: 681 683 lport->link_speed = FC_PORTSPEED_10GBIT; 684 + break; 685 + } 682 686 } 683 - return; 684 687 } 685 688 static int bnx2fc_link_ok(struct fc_lport *lport) 686 689 {
+7 -4
drivers/scsi/fcoe/fcoe.c
··· 2026 2026 int fcoe_link_speed_update(struct fc_lport *lport) 2027 2027 { 2028 2028 struct net_device *netdev = fcoe_netdev(lport); 2029 - struct ethtool_cmd ecmd = { ETHTOOL_GSET }; 2029 + struct ethtool_cmd ecmd; 2030 2030 2031 2031 if (!dev_ethtool_get_settings(netdev, &ecmd)) { 2032 2032 lport->link_supported_speeds &= ··· 2037 2037 if (ecmd.supported & SUPPORTED_10000baseT_Full) 2038 2038 lport->link_supported_speeds |= 2039 2039 FC_PORTSPEED_10GBIT; 2040 - if (ecmd.speed == SPEED_1000) 2040 + switch (ethtool_cmd_speed(&ecmd)) { 2041 + case SPEED_1000: 2041 2042 lport->link_speed = FC_PORTSPEED_1GBIT; 2042 - if (ecmd.speed == SPEED_10000) 2043 + break; 2044 + case SPEED_10000: 2043 2045 lport->link_speed = FC_PORTSPEED_10GBIT; 2044 - 2046 + break; 2047 + } 2045 2048 return 0; 2046 2049 } 2047 2050 return -1;
+3 -1
include/linux/ethtool.h
··· 744 744 /** 745 745 * struct ethtool_ops - optional netdev operations 746 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 750 * @set_settings: Set various device settings including Ethernet link 749 751 * settings. Returns a negative error code or zero. 750 752 * @get_drvinfo: Report driver/device information. Should only set the
+2 -7
include/linux/netdevice.h
··· 2597 2597 2598 2598 extern struct pernet_operations __net_initdata loopback_net_ops; 2599 2599 2600 - static inline int dev_ethtool_get_settings(struct net_device *dev, 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 - } 2600 + int dev_ethtool_get_settings(struct net_device *dev, 2601 + struct ethtool_cmd *cmd); 2607 2602 2608 2603 static inline u32 dev_ethtool_get_rx_csum(struct net_device *dev) 2609 2604 {
+7 -6
include/rdma/ib_addr.h
··· 217 217 static inline int iboe_get_rate(struct net_device *dev) 218 218 { 219 219 struct ethtool_cmd cmd; 220 + u32 speed; 220 221 221 - if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings || 222 - dev->ethtool_ops->get_settings(dev, &cmd)) 222 + if (dev_ethtool_get_settings(dev, &cmd)) 223 223 return IB_RATE_PORT_CURRENT; 224 224 225 - if (cmd.speed >= 40000) 225 + speed = ethtool_cmd_speed(&cmd); 226 + if (speed >= 40000) 226 227 return IB_RATE_40_GBPS; 227 - else if (cmd.speed >= 30000) 228 + else if (speed >= 30000) 228 229 return IB_RATE_30_GBPS; 229 - else if (cmd.speed >= 20000) 230 + else if (speed >= 20000) 230 231 return IB_RATE_20_GBPS; 231 - else if (cmd.speed >= 10000) 232 + else if (speed >= 10000) 232 233 return IB_RATE_10_GBPS; 233 234 else 234 235 return IB_RATE_PORT_CURRENT;
+24
net/core/dev.c
··· 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 + */ 4510 + int 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 + } 4520 + EXPORT_SYMBOL(dev_ethtool_get_settings); 4521 + 4522 + /** 4499 4523 * dev_get_flags - get flags reported to userspace 4500 4524 * @dev: device 4501 4525 *
+10 -14
net/core/net-sysfs.c
··· 28 28 static const char fmt_hex[] = "%#x\n"; 29 29 static const char fmt_long_hex[] = "%#lx\n"; 30 30 static const char fmt_dec[] = "%d\n"; 31 + static const char fmt_udec[] = "%u\n"; 31 32 static const char fmt_ulong[] = "%lu\n"; 32 33 static const char fmt_u64[] = "%llu\n"; 33 34 ··· 146 145 if (!rtnl_trylock()) 147 146 return restart_syscall(); 148 147 149 - if (netif_running(netdev) && 150 - netdev->ethtool_ops && 151 - netdev->ethtool_ops->get_settings) { 152 - struct ethtool_cmd cmd = { ETHTOOL_GSET }; 153 - 154 - if (!netdev->ethtool_ops->get_settings(netdev, &cmd)) 155 - ret = sprintf(buf, fmt_dec, ethtool_cmd_speed(&cmd)); 148 + if (netif_running(netdev)) { 149 + struct ethtool_cmd cmd; 150 + if (!dev_ethtool_get_settings(netdev, &cmd)) 151 + ret = sprintf(buf, fmt_udec, ethtool_cmd_speed(&cmd)); 156 152 } 157 153 rtnl_unlock(); 158 154 return ret; ··· 164 166 if (!rtnl_trylock()) 165 167 return restart_syscall(); 166 168 167 - if (netif_running(netdev) && 168 - netdev->ethtool_ops && 169 - netdev->ethtool_ops->get_settings) { 170 - struct ethtool_cmd cmd = { ETHTOOL_GSET }; 171 - 172 - if (!netdev->ethtool_ops->get_settings(netdev, &cmd)) 173 - ret = sprintf(buf, "%s\n", cmd.duplex ? "full" : "half"); 169 + if (netif_running(netdev)) { 170 + struct ethtool_cmd cmd; 171 + if (!dev_ethtool_get_settings(netdev, &cmd)) 172 + ret = sprintf(buf, "%s\n", 173 + cmd.duplex ? "full" : "half"); 174 174 } 175 175 rtnl_unlock(); 176 176 return ret;