From: Francois Romieu ethtool get_settings() for r8169 (Andy Lutomirski ). rtl8169_ethtool_ops.get_drvinfo() is set as well. The locking does not need to be specially clever. --- 25-akpm/drivers/net/r8169.c | 57 ++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 57 insertions(+) diff -puN drivers/net/r8169.c~266-mm2-r8169-ethtool-get_settings drivers/net/r8169.c --- 25/drivers/net/r8169.c~266-mm2-r8169-ethtool-get_settings 2004-05-15 23:35:04.155207216 -0700 +++ 25-akpm/drivers/net/r8169.c 2004-05-15 23:35:04.159206608 -0700 @@ -336,6 +336,8 @@ struct rtl8169_private { unsigned long phy_link_down_cnt; u16 cp_cmd; u16 intr_mask; + int phy_auto_nego_reg; + int phy_1000_ctrl_reg; }; MODULE_AUTHOR("Realtek"); @@ -451,6 +453,9 @@ static void rtl8169_set_speed(struct net auto_nego &= ~(PHY_Cap_10_Full | PHY_Cap_100_Full); } + tp->phy_auto_nego_reg = auto_nego; + tp->phy_1000_ctrl_reg = giga_ctrl; + if (!(status & TBI_Enable)) { mdio_write(ioaddr, PHY_AUTO_NEGO_REG, auto_nego); mdio_write(ioaddr, PHY_1000_CTRL_REG, giga_ctrl); @@ -460,6 +465,56 @@ static void rtl8169_set_speed(struct net PHY_Enable_Auto_Nego | PHY_Restart_Auto_Nego); } +static int rtl8169_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + unsigned long flags; + u8 status; + + spin_lock_irqsave(&tp->lock, flags); + + status = RTL_R8(PHYstatus); + cmd->supported = SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg | + SUPPORTED_TP; + + cmd->autoneg = 1; + cmd->advertising = ADVERTISED_TP | ADVERTISED_Autoneg; + /* + * FIXME: the driver should retrieve the values from the registers + * of the rtl8169. + */ + if (tp->phy_auto_nego_reg & PHY_Cap_10_Half) + cmd->advertising |= ADVERTISED_10baseT_Half; + if (tp->phy_auto_nego_reg & PHY_Cap_10_Full) + cmd->advertising |= ADVERTISED_10baseT_Full; + if (tp->phy_auto_nego_reg & PHY_Cap_100_Half) + cmd->advertising |= ADVERTISED_100baseT_Half; + if (tp->phy_auto_nego_reg & PHY_Cap_100_Full) + cmd->advertising |= ADVERTISED_100baseT_Full; + if (tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full) + cmd->advertising |= ADVERTISED_1000baseT_Full; + + if (status & _1000bpsF) + cmd->speed = SPEED_1000; + else if (status & _100bps) + cmd->speed = SPEED_100; + else if (status & _10bps) + cmd->speed = SPEED_10; + + cmd->duplex = ((status & _1000bpsF) || (status & FullDup)) ? + DUPLEX_FULL : DUPLEX_HALF; + + spin_unlock_irqrestore(&tp->lock, flags); + + return 0; +} + static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct rtl8169_private *tp = netdev_priv(dev); @@ -474,6 +529,8 @@ static int rtl8169_set_settings(struct n static struct ethtool_ops rtl8169_ethtool_ops = { .get_drvinfo = rtl8169_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_settings = rtl8169_get_settings, .set_settings = rtl8169_set_settings, }; _