Commit 8ae6daca authored by David Decotigny's avatar David Decotigny Committed by David S. Miller

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: default avatarDavid Decotigny <decot@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 36504605
...@@ -318,19 +318,15 @@ void __init tx4939_sio_init(unsigned int sclk, unsigned int cts_mask) ...@@ -318,19 +318,15 @@ void __init tx4939_sio_init(unsigned int sclk, unsigned int cts_mask)
} }
#if defined(CONFIG_TC35815) || defined(CONFIG_TC35815_MODULE) #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 }; struct ethtool_cmd cmd;
int speed = 100; /* default 100Mbps */ if (dev_ethtool_get_settings(dev, &cmd))
int err; return 100; /* default 100Mbps */
if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings)
return speed; return ethtool_cmd_speed(&cmd);
err = dev->ethtool_ops->get_settings(dev, &cmd);
if (err < 0)
return speed;
speed = cmd.speed == SPEED_100 ? 100 : 10;
return speed;
} }
static int tx4939_netdev_event(struct notifier_block *this, static int tx4939_netdev_event(struct notifier_block *this,
unsigned long event, unsigned long event,
void *ptr) void *ptr)
...@@ -343,8 +339,7 @@ static int tx4939_netdev_event(struct notifier_block *this, ...@@ -343,8 +339,7 @@ static int tx4939_netdev_event(struct notifier_block *this,
else if (dev->irq == TXX9_IRQ_BASE + TX4939_IR_ETH(1)) else if (dev->irq == TXX9_IRQ_BASE + TX4939_IR_ETH(1))
bit = TX4939_PCFG_SPEED1; bit = TX4939_PCFG_SPEED1;
if (bit) { if (bit) {
int speed = tx4939_get_eth_speed(dev); if (tx4939_get_eth_speed(dev) == 100)
if (speed == 100)
txx9_set64(&tx4939_ccfgptr->pcfg, bit); txx9_set64(&tx4939_ccfgptr->pcfg, bit);
else else
txx9_clear64(&tx4939_ccfgptr->pcfg, bit); txx9_clear64(&tx4939_ccfgptr->pcfg, bit);
......
...@@ -1668,7 +1668,7 @@ static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex) ...@@ -1668,7 +1668,7 @@ static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex)
static void e100_watchdog(unsigned long data) static void e100_watchdog(unsigned long data)
{ {
struct nic *nic = (struct nic *)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, netif_printk(nic, timer, KERN_DEBUG, nic->netdev,
"right now = %ld\n", jiffies); "right now = %ld\n", jiffies);
......
...@@ -176,6 +176,9 @@ static u32 mdio45_get_an(const struct mdio_if_info *mdio, u16 addr) ...@@ -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_adv: Modes currently advertised on next pages
* @npage_lpa: Modes advertised by link partner 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 * Since the CSRs for auto-negotiation using next pages are not fully
* standardised, this function does not attempt to decode them. The * standardised, this function does not attempt to decode them. The
* caller must pass them in. * caller must pass them in.
......
...@@ -58,6 +58,9 @@ static u32 mii_get_an(struct mii_if_info *mii, u16 addr) ...@@ -58,6 +58,9 @@ static u32 mii_get_an(struct mii_if_info *mii, u16 addr)
* @mii: MII interface * @mii: MII interface
* @ecmd: requested ethtool_cmd * @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. * Returns 0 for success, negative on error.
*/ */
int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
......
...@@ -888,12 +888,12 @@ static void pch_gbe_watchdog(unsigned long data) ...@@ -888,12 +888,12 @@ static void pch_gbe_watchdog(unsigned long data)
struct pch_gbe_adapter *adapter = (struct pch_gbe_adapter *)data; struct pch_gbe_adapter *adapter = (struct pch_gbe_adapter *)data;
struct net_device *netdev = adapter->netdev; struct net_device *netdev = adapter->netdev;
struct pch_gbe_hw *hw = &adapter->hw; struct pch_gbe_hw *hw = &adapter->hw;
struct ethtool_cmd cmd;
pr_debug("right now = %ld\n", jiffies); pr_debug("right now = %ld\n", jiffies);
pch_gbe_update_stats(adapter); pch_gbe_update_stats(adapter);
if ((mii_link_ok(&adapter->mii)) && (!netif_carrier_ok(netdev))) { 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; netdev->tx_queue_len = adapter->tx_queue_len;
/* mii library handles link maintenance tasks */ /* mii library handles link maintenance tasks */
if (mii_ethtool_gset(&adapter->mii, &cmd)) { if (mii_ethtool_gset(&adapter->mii, &cmd)) {
...@@ -903,7 +903,7 @@ static void pch_gbe_watchdog(unsigned long data) ...@@ -903,7 +903,7 @@ static void pch_gbe_watchdog(unsigned long data)
PCH_GBE_WATCHDOG_PERIOD)); PCH_GBE_WATCHDOG_PERIOD));
return; return;
} }
hw->mac.link_speed = cmd.speed; hw->mac.link_speed = ethtool_cmd_speed(&cmd);
hw->mac.link_duplex = cmd.duplex; hw->mac.link_duplex = cmd.duplex;
/* Set the RGMII control. */ /* Set the RGMII control. */
pch_gbe_set_rgmii_ctrl(adapter, hw->mac.link_speed, pch_gbe_set_rgmii_ctrl(adapter, hw->mac.link_speed,
...@@ -913,7 +913,7 @@ static void pch_gbe_watchdog(unsigned long data) ...@@ -913,7 +913,7 @@ static void pch_gbe_watchdog(unsigned long data)
hw->mac.link_duplex); hw->mac.link_duplex);
netdev_dbg(netdev, netdev_dbg(netdev,
"Link is Up %d Mbps %s-Duplex\n", "Link is Up %d Mbps %s-Duplex\n",
cmd.speed, hw->mac.link_speed,
cmd.duplex == DUPLEX_FULL ? "Full" : "Half"); cmd.duplex == DUPLEX_FULL ? "Full" : "Half");
netif_carrier_on(netdev); netif_carrier_on(netdev);
netif_wake_queue(netdev); netif_wake_queue(netdev);
......
...@@ -247,7 +247,7 @@ inline void pch_gbe_phy_set_rgmii(struct pch_gbe_hw *hw) ...@@ -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) void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw)
{ {
struct pch_gbe_adapter *adapter; struct pch_gbe_adapter *adapter;
struct ethtool_cmd cmd; struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET };
int ret; int ret;
u16 mii_reg; u16 mii_reg;
......
...@@ -2099,7 +2099,7 @@ static int pcnet32_open(struct net_device *dev) ...@@ -2099,7 +2099,7 @@ static int pcnet32_open(struct net_device *dev)
int first_phy = -1; int first_phy = -1;
u16 bmcr; u16 bmcr;
u32 bcr9; u32 bcr9;
struct ethtool_cmd ecmd; struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
/* /*
* There is really no good other way to handle multiple PHYs * There is really no good other way to handle multiple PHYs
...@@ -2115,9 +2115,9 @@ static int pcnet32_open(struct net_device *dev) ...@@ -2115,9 +2115,9 @@ static int pcnet32_open(struct net_device *dev)
ecmd.port = PORT_MII; ecmd.port = PORT_MII;
ecmd.transceiver = XCVR_INTERNAL; ecmd.transceiver = XCVR_INTERNAL;
ecmd.autoneg = AUTONEG_DISABLE; ecmd.autoneg = AUTONEG_DISABLE;
ecmd.speed = ethtool_cmd_speed_set(&ecmd,
lp-> (lp->options & PCNET32_PORT_100) ?
options & PCNET32_PORT_100 ? SPEED_100 : SPEED_10; SPEED_100 : SPEED_10);
bcr9 = lp->a.read_bcr(ioaddr, 9); bcr9 = lp->a.read_bcr(ioaddr, 9);
if (lp->options & PCNET32_PORT_FD) { if (lp->options & PCNET32_PORT_FD) {
...@@ -2763,11 +2763,11 @@ static void pcnet32_check_media(struct net_device *dev, int verbose) ...@@ -2763,11 +2763,11 @@ static void pcnet32_check_media(struct net_device *dev, int verbose)
netif_carrier_on(dev); netif_carrier_on(dev);
if (lp->mii) { if (lp->mii) {
if (netif_msg_link(lp)) { if (netif_msg_link(lp)) {
struct ethtool_cmd ecmd; struct ethtool_cmd ecmd = {
.cmd = ETHTOOL_GSET };
mii_ethtool_gset(&lp->mii_if, &ecmd); mii_ethtool_gset(&lp->mii_if, &ecmd);
netdev_info(dev, "link up, %sMbps, %s-duplex\n", netdev_info(dev, "link up, %uMbps, %s-duplex\n",
(ecmd.speed == SPEED_100) ethtool_cmd_speed(&ecmd),
? "100" : "10",
(ecmd.duplex == DUPLEX_FULL) (ecmd.duplex == DUPLEX_FULL)
? "full" : "half"); ? "full" : "half");
} }
......
...@@ -232,12 +232,12 @@ void efx_mdio_set_mmds_lpower(struct efx_nic *efx, ...@@ -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) 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); efx->phy_op->get_settings(efx, &prev);
if (ecmd->advertising == prev.advertising && if (ecmd->advertising == prev.advertising &&
ecmd->speed == prev.speed && ethtool_cmd_speed(ecmd) == ethtool_cmd_speed(&prev) &&
ecmd->duplex == prev.duplex && ecmd->duplex == prev.duplex &&
ecmd->port == prev.port && ecmd->port == prev.port &&
ecmd->autoneg == prev.autoneg) ecmd->autoneg == prev.autoneg)
......
...@@ -237,13 +237,12 @@ stmmac_set_pauseparam(struct net_device *netdev, ...@@ -237,13 +237,12 @@ stmmac_set_pauseparam(struct net_device *netdev,
if (phy->autoneg) { if (phy->autoneg) {
if (netif_running(netdev)) { if (netif_running(netdev)) {
struct ethtool_cmd cmd; struct ethtool_cmd cmd = { .cmd = ETHTOOL_SSET };
/* auto-negotiation automatically restarted */ /* auto-negotiation automatically restarted */
cmd.cmd = ETHTOOL_NWAY_RST;
cmd.supported = phy->supported; cmd.supported = phy->supported;
cmd.advertising = phy->advertising; cmd.advertising = phy->advertising;
cmd.autoneg = phy->autoneg; cmd.autoneg = phy->autoneg;
cmd.speed = phy->speed; ethtool_cmd_speed_set(&cmd, phy->speed);
cmd.duplex = phy->duplex; cmd.duplex = phy->duplex;
cmd.phy_address = phy->addr; cmd.phy_address = phy->addr;
ret = phy_ethtool_sset(phy, &cmd); ret = phy_ethtool_sset(phy, &cmd);
......
...@@ -847,7 +847,7 @@ static void ax88172_set_multicast(struct net_device *net) ...@@ -847,7 +847,7 @@ static void ax88172_set_multicast(struct net_device *net)
static int ax88172_link_reset(struct usbnet *dev) static int ax88172_link_reset(struct usbnet *dev)
{ {
u8 mode; u8 mode;
struct ethtool_cmd ecmd; struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
mii_check_media(&dev->mii, 1, 1); mii_check_media(&dev->mii, 1, 1);
mii_ethtool_gset(&dev->mii, &ecmd); mii_ethtool_gset(&dev->mii, &ecmd);
...@@ -856,8 +856,8 @@ static int ax88172_link_reset(struct usbnet *dev) ...@@ -856,8 +856,8 @@ static int ax88172_link_reset(struct usbnet *dev)
if (ecmd.duplex != DUPLEX_FULL) if (ecmd.duplex != DUPLEX_FULL)
mode |= ~AX88172_MEDIUM_FD; mode |= ~AX88172_MEDIUM_FD;
netdev_dbg(dev->net, "ax88172_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n", netdev_dbg(dev->net, "ax88172_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
ecmd.speed, ecmd.duplex, mode); ethtool_cmd_speed(&ecmd), ecmd.duplex, mode);
asix_write_medium_mode(dev, mode); asix_write_medium_mode(dev, mode);
...@@ -947,20 +947,20 @@ static const struct ethtool_ops ax88772_ethtool_ops = { ...@@ -947,20 +947,20 @@ static const struct ethtool_ops ax88772_ethtool_ops = {
static int ax88772_link_reset(struct usbnet *dev) static int ax88772_link_reset(struct usbnet *dev)
{ {
u16 mode; u16 mode;
struct ethtool_cmd ecmd; struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
mii_check_media(&dev->mii, 1, 1); mii_check_media(&dev->mii, 1, 1);
mii_ethtool_gset(&dev->mii, &ecmd); mii_ethtool_gset(&dev->mii, &ecmd);
mode = AX88772_MEDIUM_DEFAULT; mode = AX88772_MEDIUM_DEFAULT;
if (ecmd.speed != SPEED_100) if (ethtool_cmd_speed(&ecmd) != SPEED_100)
mode &= ~AX_MEDIUM_PS; mode &= ~AX_MEDIUM_PS;
if (ecmd.duplex != DUPLEX_FULL) if (ecmd.duplex != DUPLEX_FULL)
mode &= ~AX_MEDIUM_FD; mode &= ~AX_MEDIUM_FD;
netdev_dbg(dev->net, "ax88772_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n", netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
ecmd.speed, ecmd.duplex, mode); ethtool_cmd_speed(&ecmd), ecmd.duplex, mode);
asix_write_medium_mode(dev, mode); asix_write_medium_mode(dev, mode);
...@@ -1173,18 +1173,20 @@ static int marvell_led_status(struct usbnet *dev, u16 speed) ...@@ -1173,18 +1173,20 @@ static int marvell_led_status(struct usbnet *dev, u16 speed)
static int ax88178_link_reset(struct usbnet *dev) static int ax88178_link_reset(struct usbnet *dev)
{ {
u16 mode; u16 mode;
struct ethtool_cmd ecmd; struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
struct asix_data *data = (struct asix_data *)&dev->data; struct asix_data *data = (struct asix_data *)&dev->data;
u32 speed;
netdev_dbg(dev->net, "ax88178_link_reset()\n"); netdev_dbg(dev->net, "ax88178_link_reset()\n");
mii_check_media(&dev->mii, 1, 1); mii_check_media(&dev->mii, 1, 1);
mii_ethtool_gset(&dev->mii, &ecmd); mii_ethtool_gset(&dev->mii, &ecmd);
mode = AX88178_MEDIUM_DEFAULT; mode = AX88178_MEDIUM_DEFAULT;
speed = ethtool_cmd_speed(&ecmd);
if (ecmd.speed == SPEED_1000) if (speed == SPEED_1000)
mode |= AX_MEDIUM_GM; mode |= AX_MEDIUM_GM;
else if (ecmd.speed == SPEED_100) else if (speed == SPEED_100)
mode |= AX_MEDIUM_PS; mode |= AX_MEDIUM_PS;
else else
mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM); mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM);
...@@ -1196,13 +1198,13 @@ static int ax88178_link_reset(struct usbnet *dev) ...@@ -1196,13 +1198,13 @@ static int ax88178_link_reset(struct usbnet *dev)
else else
mode &= ~AX_MEDIUM_FD; mode &= ~AX_MEDIUM_FD;
netdev_dbg(dev->net, "ax88178_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n", netdev_dbg(dev->net, "ax88178_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
ecmd.speed, ecmd.duplex, mode); speed, ecmd.duplex, mode);
asix_write_medium_mode(dev, mode); asix_write_medium_mode(dev, mode);
if (data->phymode == PHY_MODE_MARVELL && data->ledmode) if (data->phymode == PHY_MODE_MARVELL && data->ledmode)
marvell_led_status(dev, ecmd.speed); marvell_led_status(dev, speed);
return 0; return 0;
} }
......
...@@ -599,13 +599,13 @@ static void dm9601_status(struct usbnet *dev, struct urb *urb) ...@@ -599,13 +599,13 @@ static void dm9601_status(struct usbnet *dev, struct urb *urb)
static int dm9601_link_reset(struct usbnet *dev) 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_check_media(&dev->mii, 1, 1);
mii_ethtool_gset(&dev->mii, &ecmd); mii_ethtool_gset(&dev->mii, &ecmd);
netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n", netdev_dbg(dev->net, "link_reset() speed: %u duplex: %d\n",
ecmd.speed, ecmd.duplex); ethtool_cmd_speed(&ecmd), ecmd.duplex);
return 0; return 0;
} }
......
...@@ -503,7 +503,7 @@ static int smsc75xx_update_flowcontrol(struct usbnet *dev, u8 duplex, ...@@ -503,7 +503,7 @@ static int smsc75xx_update_flowcontrol(struct usbnet *dev, u8 duplex,
static int smsc75xx_link_reset(struct usbnet *dev) static int smsc75xx_link_reset(struct usbnet *dev)
{ {
struct mii_if_info *mii = &dev->mii; struct mii_if_info *mii = &dev->mii;
struct ethtool_cmd ecmd; struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
u16 lcladv, rmtadv; u16 lcladv, rmtadv;
int ret; int ret;
...@@ -519,8 +519,9 @@ static int smsc75xx_link_reset(struct usbnet *dev) ...@@ -519,8 +519,9 @@ static int smsc75xx_link_reset(struct usbnet *dev)
lcladv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); lcladv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE);
rmtadv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_LPA); rmtadv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_LPA);
netif_dbg(dev, link, dev->net, "speed: %d duplex: %d lcladv: %04x" netif_dbg(dev, link, dev->net, "speed: %u duplex: %d lcladv: %04x"
" rmtadv: %04x", ecmd.speed, ecmd.duplex, lcladv, rmtadv); " rmtadv: %04x", ethtool_cmd_speed(&ecmd),
ecmd.duplex, lcladv, rmtadv);
return smsc75xx_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv); return smsc75xx_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv);
} }
......
...@@ -457,7 +457,7 @@ static int smsc95xx_link_reset(struct usbnet *dev) ...@@ -457,7 +457,7 @@ static int smsc95xx_link_reset(struct usbnet *dev)
{ {
struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
struct mii_if_info *mii = &dev->mii; struct mii_if_info *mii = &dev->mii;
struct ethtool_cmd ecmd; struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
unsigned long flags; unsigned long flags;
u16 lcladv, rmtadv; u16 lcladv, rmtadv;
u32 intdata; u32 intdata;
...@@ -472,8 +472,9 @@ static int smsc95xx_link_reset(struct usbnet *dev) ...@@ -472,8 +472,9 @@ static int smsc95xx_link_reset(struct usbnet *dev)
lcladv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); lcladv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE);
rmtadv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_LPA); 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", netif_dbg(dev, link, dev->net,
ecmd.speed, ecmd.duplex, lcladv, rmtadv); "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); spin_lock_irqsave(&pdata->mac_cr_lock, flags);
if (ecmd.duplex != DUPLEX_FULL) { if (ecmd.duplex != DUPLEX_FULL) {
......
...@@ -664,7 +664,7 @@ static void bnx2fc_link_speed_update(struct fc_lport *lport) ...@@ -664,7 +664,7 @@ static void bnx2fc_link_speed_update(struct fc_lport *lport)
struct fcoe_port *port = lport_priv(lport); struct fcoe_port *port = lport_priv(lport);
struct bnx2fc_hba *hba = port->priv; struct bnx2fc_hba *hba = port->priv;
struct net_device *netdev = hba->netdev; struct net_device *netdev = hba->netdev;
struct ethtool_cmd ecmd = { ETHTOOL_GSET }; struct ethtool_cmd ecmd;
if (!dev_ethtool_get_settings(netdev, &ecmd)) { if (!dev_ethtool_get_settings(netdev, &ecmd)) {
lport->link_supported_speeds &= lport->link_supported_speeds &=
...@@ -675,12 +675,15 @@ static void bnx2fc_link_speed_update(struct fc_lport *lport) ...@@ -675,12 +675,15 @@ static void bnx2fc_link_speed_update(struct fc_lport *lport)
if (ecmd.supported & SUPPORTED_10000baseT_Full) if (ecmd.supported & SUPPORTED_10000baseT_Full)
lport->link_supported_speeds |= FC_PORTSPEED_10GBIT; 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; lport->link_speed = FC_PORTSPEED_1GBIT;
if (ecmd.speed == SPEED_10000) break;
case SPEED_10000:
lport->link_speed = FC_PORTSPEED_10GBIT; lport->link_speed = FC_PORTSPEED_10GBIT;
break;
}
} }
return;
} }
static int bnx2fc_link_ok(struct fc_lport *lport) static int bnx2fc_link_ok(struct fc_lport *lport)
{ {
......
...@@ -2026,7 +2026,7 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) ...@@ -2026,7 +2026,7 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode)
int fcoe_link_speed_update(struct fc_lport *lport) int fcoe_link_speed_update(struct fc_lport *lport)
{ {
struct net_device *netdev = fcoe_netdev(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)) { if (!dev_ethtool_get_settings(netdev, &ecmd)) {
lport->link_supported_speeds &= lport->link_supported_speeds &=
...@@ -2037,11 +2037,14 @@ int fcoe_link_speed_update(struct fc_lport *lport) ...@@ -2037,11 +2037,14 @@ int fcoe_link_speed_update(struct fc_lport *lport)
if (ecmd.supported & SUPPORTED_10000baseT_Full) if (ecmd.supported & SUPPORTED_10000baseT_Full)
lport->link_supported_speeds |= lport->link_supported_speeds |=
FC_PORTSPEED_10GBIT; FC_PORTSPEED_10GBIT;
if (ecmd.speed == SPEED_1000) switch (ethtool_cmd_speed(&ecmd)) {
case SPEED_1000:
lport->link_speed = FC_PORTSPEED_1GBIT; lport->link_speed = FC_PORTSPEED_1GBIT;
if (ecmd.speed == SPEED_10000) break;
case SPEED_10000:
lport->link_speed = FC_PORTSPEED_10GBIT; lport->link_speed = FC_PORTSPEED_10GBIT;
break;
}
return 0; return 0;
} }
return -1; return -1;
......
...@@ -744,7 +744,9 @@ bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported); ...@@ -744,7 +744,9 @@ bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported);
/** /**
* struct ethtool_ops - optional netdev operations * struct ethtool_ops - optional netdev operations
* @get_settings: Get various device settings including Ethernet link * @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 * @set_settings: Set various device settings including Ethernet link
* settings. Returns a negative error code or zero. * settings. Returns a negative error code or zero.
* @get_drvinfo: Report driver/device information. Should only set the * @get_drvinfo: Report driver/device information. Should only set the
......
...@@ -2597,13 +2597,8 @@ static inline int netif_is_bond_slave(struct net_device *dev) ...@@ -2597,13 +2597,8 @@ static inline int netif_is_bond_slave(struct net_device *dev)
extern struct pernet_operations __net_initdata loopback_net_ops; extern struct pernet_operations __net_initdata loopback_net_ops;
static inline int dev_ethtool_get_settings(struct net_device *dev, int dev_ethtool_get_settings(struct net_device *dev,
struct ethtool_cmd *cmd) struct ethtool_cmd *cmd);
{
if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings)
return -EOPNOTSUPP;
return dev->ethtool_ops->get_settings(dev, cmd);
}
static inline u32 dev_ethtool_get_rx_csum(struct net_device *dev) static inline u32 dev_ethtool_get_rx_csum(struct net_device *dev)
{ {
......
...@@ -217,18 +217,19 @@ static inline enum ib_mtu iboe_get_mtu(int mtu) ...@@ -217,18 +217,19 @@ static inline enum ib_mtu iboe_get_mtu(int mtu)
static inline int iboe_get_rate(struct net_device *dev) static inline int iboe_get_rate(struct net_device *dev)
{ {
struct ethtool_cmd cmd; struct ethtool_cmd cmd;
u32 speed;
if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings || if (dev_ethtool_get_settings(dev, &cmd))
dev->ethtool_ops->get_settings(dev, &cmd))
return IB_RATE_PORT_CURRENT; return IB_RATE_PORT_CURRENT;
if (cmd.speed >= 40000) speed = ethtool_cmd_speed(&cmd);
if (speed >= 40000)
return IB_RATE_40_GBPS; return IB_RATE_40_GBPS;
else if (cmd.speed >= 30000) else if (speed >= 30000)
return IB_RATE_30_GBPS; return IB_RATE_30_GBPS;
else if (cmd.speed >= 20000) else if (speed >= 20000)
return IB_RATE_20_GBPS; return IB_RATE_20_GBPS;
else if (cmd.speed >= 10000) else if (speed >= 10000)
return IB_RATE_10_GBPS; return IB_RATE_10_GBPS;
else else
return IB_RATE_PORT_CURRENT; return IB_RATE_PORT_CURRENT;
......
...@@ -4495,6 +4495,30 @@ void dev_set_rx_mode(struct net_device *dev) ...@@ -4495,6 +4495,30 @@ void dev_set_rx_mode(struct net_device *dev)
netif_addr_unlock_bh(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_get_flags - get flags reported to userspace
* @dev: device * @dev: device
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
static const char fmt_hex[] = "%#x\n"; static const char fmt_hex[] = "%#x\n";
static const char fmt_long_hex[] = "%#lx\n"; static const char fmt_long_hex[] = "%#lx\n";
static const char fmt_dec[] = "%d\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_ulong[] = "%lu\n";
static const char fmt_u64[] = "%llu\n"; static const char fmt_u64[] = "%llu\n";
...@@ -145,13 +146,10 @@ static ssize_t show_speed(struct device *dev, ...@@ -145,13 +146,10 @@ static ssize_t show_speed(struct device *dev,
if (!rtnl_trylock()) if (!rtnl_trylock())
return restart_syscall(); return restart_syscall();
if (netif_running(netdev) && if (netif_running(netdev)) {
netdev->ethtool_ops && struct ethtool_cmd cmd;
netdev->ethtool_ops->get_settings) { if (!dev_ethtool_get_settings(netdev, &cmd))
struct ethtool_cmd cmd = { ETHTOOL_GSET }; ret = sprintf(buf, fmt_udec, ethtool_cmd_speed(&cmd));
if (!netdev->ethtool_ops->get_settings(netdev, &cmd))
ret = sprintf(buf, fmt_dec, ethtool_cmd_speed(&cmd));
} }
rtnl_unlock(); rtnl_unlock();
return ret; return ret;
...@@ -166,13 +164,11 @@ static ssize_t show_duplex(struct device *dev, ...@@ -166,13 +164,11 @@ static ssize_t show_duplex(struct device *dev,
if (!rtnl_trylock()) if (!rtnl_trylock())
return restart_syscall(); return restart_syscall();
if (netif_running(netdev) && if (netif_running(netdev)) {
netdev->ethtool_ops && struct ethtool_cmd cmd;
netdev->ethtool_ops->get_settings) { if (!dev_ethtool_get_settings(netdev, &cmd))
struct ethtool_cmd cmd = { ETHTOOL_GSET }; ret = sprintf(buf, "%s\n",
cmd.duplex ? "full" : "half");
if (!netdev->ethtool_ops->get_settings(netdev, &cmd))
ret = sprintf(buf, "%s\n", cmd.duplex ? "full" : "half");
} }
rtnl_unlock(); rtnl_unlock();
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment