From: Francois Romieu ethtool set_settings support (Andy Lutomirski ). --- 25-akpm/drivers/net/r8169.c | 60 ++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 60 insertions(+) diff -puN drivers/net/r8169.c~266-mm2-r8169-ethtool-set_settings drivers/net/r8169.c --- 25/drivers/net/r8169.c~266-mm2-r8169-ethtool-set_settings 2004-05-15 23:35:03.074371528 -0700 +++ 25-akpm/drivers/net/r8169.c 2004-05-15 23:35:03.103367120 -0700 @@ -413,8 +413,68 @@ static void rtl8169_get_drvinfo(struct n strcpy(info->bus_info, pci_name(tp->pci_dev)); } +static void rtl8169_set_speed(struct net_device *dev, + u8 autoneg, u16 speed, u8 duplex) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + int auto_nego, giga_ctrl; + u8 status; + + status = RTL_R8(PHYstatus); + if ((status & TBI_Enable) && (autoneg == AUTONEG_DISABLE)) { + autoneg = AUTONEG_ENABLE; + printk(KERN_WARNING PFX + "%s: ignoring request to force speed in TBI mode\n", + dev->name); + } + + auto_nego = mdio_read(ioaddr, PHY_AUTO_NEGO_REG); + auto_nego &= ~(PHY_Cap_10_Half | PHY_Cap_10_Full | + PHY_Cap_100_Half | PHY_Cap_100_Full); + giga_ctrl = mdio_read(ioaddr, PHY_1000_CTRL_REG); + giga_ctrl &= ~(PHY_Cap_1000_Full | PHY_Cap_Null); + + if (autoneg == AUTONEG_ENABLE) { + auto_nego |= (PHY_Cap_10_Half | PHY_Cap_10_Full | + PHY_Cap_100_Half | PHY_Cap_100_Full); + giga_ctrl |= PHY_Cap_1000_Full; + } else { + if (speed == SPEED_10) + auto_nego |= PHY_Cap_10_Half | PHY_Cap_10_Full; + else if (speed == SPEED_100) + auto_nego |= PHY_Cap_100_Half | PHY_Cap_100_Full; + else if (speed == SPEED_1000) + giga_ctrl |= PHY_Cap_1000_Full; + + if (duplex == DUPLEX_HALF) + auto_nego &= ~(PHY_Cap_10_Full | PHY_Cap_100_Full); + } + + if (!(status & TBI_Enable)) { + mdio_write(ioaddr, PHY_AUTO_NEGO_REG, auto_nego); + mdio_write(ioaddr, PHY_1000_CTRL_REG, giga_ctrl); + } + + mdio_write(ioaddr, PHY_CTRL_REG, + PHY_Enable_Auto_Nego | PHY_Restart_Auto_Nego); +} + +static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct rtl8169_private *tp = netdev_priv(dev); + unsigned long flags; + + spin_lock_irqsave(&tp->lock, flags); + rtl8169_set_speed(dev, cmd->autoneg, cmd->speed, cmd->duplex); + spin_unlock_irqrestore(&tp->lock, flags); + + return 0; +} + static struct ethtool_ops rtl8169_ethtool_ops = { .get_drvinfo = rtl8169_get_drvinfo, + .set_settings = rtl8169_set_settings, }; static void rtl8169_write_gmii_reg_bit(void *ioaddr, int reg, int bitnum, _