netdev
[Top] [All Lists]

[PATCH] r8169: support restricting speed+duplex in autonegotiation

To: Francois Romieu <romieu@xxxxxxxxxxxxx>
Subject: [PATCH] r8169: support restricting speed+duplex in autonegotiation
From: Richard Dawe <rich@xxxxxxxxxxxxxxxxxxxx>
Date: Fri, 27 May 2005 23:36:39 +0100
Cc: Linux netdev <netdev@xxxxxxxxxxx>
Sender: netdev-bounce@xxxxxxxxxxx
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050513 Fedora/1.7.8-1.3.1
Hello.

Attached is a patch for drivers/net/r8169.c against Linux 2.6.11 that allows adjustment of the speed and duplex advertised via autonegotiation. Example usage:

  ethtool -s eth0 autoneg on speed 10 duplex half

Also attached is a test script which tries various combinations of autoneg, speed and duplex. There is also a log of the test run attache.d While the test ran I had an ssh session running "while true; do sleep 1; date; done". The ssh session did not drop. Note that I don't have GigE, so that part of the test was bogus.

I also tried various speed tests, to check that the speed and duplex were actually changed. They were.

Bye, Rich

r8169: Allow adjustment of speed and duplex advertised via autonegotiation

Signed-off-by: Richard Dawe <rich@xxxxxxxxxxxxxxxxxxxx>
--- r8169.c.orig        2005-05-27 21:12:21.000000000 +0100
+++ r8169.c     2005-05-27 22:14:59.000000000 +0100
@@ -407,7 +407,9 @@ struct rtl8169_private {
 #ifdef CONFIG_R8169_VLAN
        struct vlan_group *vlgrp;
 #endif
-       int (*set_speed)(struct net_device *, u8 autoneg, u16 speed, u8 duplex);
+       int (*set_speed)(struct net_device *,
+                        u8 autoneg, u16 speed, u8 duplex,
+                        u32 advertising);
        void (*get_settings)(struct net_device *, struct ethtool_cmd *);
        void (*phy_reset_enable)(void __iomem *);
        unsigned int (*phy_reset_pending)(void __iomem *);
@@ -549,7 +551,9 @@ static void rtl8169_check_link_status(st
        spin_unlock_irqrestore(&tp->lock, flags);
 }
 
-static void rtl8169_link_option(int idx, u8 *autoneg, u16 *speed, u8 *duplex)
+static void rtl8169_link_option(int idx,
+                               u8 *autoneg, u16 *speed, u8 *duplex,
+                               u32 *advertising)
 {
        struct {
                u16 speed;
@@ -579,6 +583,23 @@ static void rtl8169_link_option(int idx,
        *autoneg = p->autoneg;
        *speed = p->speed;
        *duplex = p->duplex;
+
+       if (p->media == _10_Half)
+               *advertising = ADVERTISED_10baseT_Half;
+       if (p->media == _10_Full)
+               *advertising = ADVERTISED_10baseT_Full;
+       if (p->media == _100_Half)
+               *advertising = ADVERTISED_100baseT_Half;
+       if (p->media == _100_Full)
+               *advertising = ADVERTISED_100baseT_Full;
+       if (p->media == _1000_Full)
+               *advertising = ADVERTISED_1000baseT_Full;
+       if (p->media == 0xff)
+               *advertising = ADVERTISED_10baseT_Half |
+                              ADVERTISED_10baseT_Full |
+                              ADVERTISED_100baseT_Half |
+                              ADVERTISED_100baseT_Full |
+                              ADVERTISED_1000baseT_Full;
 }
 
 static void rtl8169_get_drvinfo(struct net_device *dev,
@@ -597,7 +618,8 @@ static int rtl8169_get_regs_len(struct n
 }
 
 static int rtl8169_set_speed_tbi(struct net_device *dev,
-                                u8 autoneg, u16 speed, u8 duplex)
+                                u8 autoneg, u16 speed, u8 duplex,
+                                u32 advertising)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->mmio_addr;
@@ -608,7 +630,8 @@ static int rtl8169_set_speed_tbi(struct 
        if ((autoneg == AUTONEG_DISABLE) && (speed == SPEED_1000) &&
            (duplex == DUPLEX_FULL)) {
                RTL_W32(TBICSR, reg & ~(TBINwEnable | TBINwRestart));
-       } else if (autoneg == AUTONEG_ENABLE)
+       } else if ((autoneg == AUTONEG_ENABLE) &&
+                  (advertising & ADVERTISED_1000baseT_Full))
                RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart);
        else {
                printk(KERN_WARNING PFX
@@ -621,11 +644,13 @@ static int rtl8169_set_speed_tbi(struct 
 }
 
 static int rtl8169_set_speed_xmii(struct net_device *dev,
-                                 u8 autoneg, u16 speed, u8 duplex)
+                                 u8 autoneg, u16 speed, u8 duplex,
+                                 u32 advertising)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->mmio_addr;
        int auto_nego, giga_ctrl;
+       int ret = 0;
 
        auto_nego = mdio_read(ioaddr, PHY_AUTO_NEGO_REG);
        auto_nego &= ~(PHY_Cap_10_Half | PHY_Cap_10_Full |
@@ -634,9 +659,16 @@ static int rtl8169_set_speed_xmii(struct
        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;
+               if (advertising & ADVERTISED_10baseT_Half)
+                       auto_nego |= PHY_Cap_10_Half;
+               if (advertising & ADVERTISED_10baseT_Full)
+                       auto_nego |= PHY_Cap_10_Full;
+               if (advertising & ADVERTISED_100baseT_Half)
+                       auto_nego |= PHY_Cap_100_Half;
+               if (advertising & ADVERTISED_100baseT_Full)
+                       auto_nego |= PHY_Cap_100_Full;
+               if (advertising & ADVERTISED_1000baseT_Full)
+                       giga_ctrl |= PHY_Cap_1000_Full;
        } else {
                if (speed == SPEED_10)
                        auto_nego |= PHY_Cap_10_Half | PHY_Cap_10_Full;
@@ -649,23 +681,28 @@ static int rtl8169_set_speed_xmii(struct
                        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 (ret == 0)
+       {
+               tp->phy_auto_nego_reg = auto_nego;
+               tp->phy_1000_ctrl_reg = giga_ctrl;
+
+               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);
+       }
 
-       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);
-       return 0;
+       return ret;
 }
 
 static int rtl8169_set_speed(struct net_device *dev,
-                            u8 autoneg, u16 speed, u8 duplex)
+                            u8 autoneg, u16 speed, u8 duplex,
+                            u32 advertising)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
        int ret;
 
-       ret = tp->set_speed(dev, autoneg, speed, duplex);
+       ret = tp->set_speed(dev, autoneg, speed, duplex, advertising);
 
        if (netif_running(dev) && (tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full))
                mod_timer(&tp->timer, jiffies + RTL8169_PHY_TIMEOUT);
@@ -680,7 +717,9 @@ static int rtl8169_set_settings(struct n
        int ret;
 
        spin_lock_irqsave(&tp->lock, flags);
-       ret = rtl8169_set_speed(dev, cmd->autoneg, cmd->speed, cmd->duplex);
+       ret = rtl8169_set_speed(dev,
+                               cmd->autoneg, cmd->speed, cmd->duplex,
+                               cmd->advertising);
        spin_unlock_irqrestore(&tp->lock, flags);
        
        return ret;
@@ -1311,6 +1350,7 @@ rtl8169_init_one(struct pci_dev *pdev, c
        static int printed_version = 0;
        u8 autoneg, duplex;
        u16 speed;
+       u32 advertising;
        int i, rc;
 
        assert(pdev != NULL);
@@ -1423,9 +1463,9 @@ rtl8169_init_one(struct pci_dev *pdev, c
                mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0
        }
 
-       rtl8169_link_option(board_idx, &autoneg, &speed, &duplex);
+       rtl8169_link_option(board_idx, &autoneg, &speed, &duplex, &advertising);
 
-       rtl8169_set_speed(dev, autoneg, speed, duplex);
+       rtl8169_set_speed(dev, autoneg, speed, duplex, advertising);
        
        if (RTL_R8(PHYstatus) & TBI_Enable)
                printk(KERN_INFO PFX "%s: TBI auto-negotiating\n", dev->name);

Attachment: test.sh
Description: Bourne shell script

+ for i in on off
+ ethtool -s eth0 autoneg on speed 10 duplex half
+ sleep 10
+ ethtool eth0
Settings for eth0:
        Supported ports: [ TP ]
        Supported link modes:   10baseT/Half 10baseT/Full 
                                100baseT/Half 100baseT/Full 
                                1000baseT/Full 
        Supports auto-negotiation: Yes
        Advertised link modes:  10baseT/Half 
        Advertised auto-negotiation: Yes
        Speed: 10Mb/s
        Duplex: Half
        Port: Twisted Pair
        PHYAD: 0
        Transceiver: internal
        Auto-negotiation: on
        Link detected: yes
+ sleep 10
+ ethtool -s eth0 autoneg on speed 10 duplex full
+ sleep 10
+ ethtool eth0
Settings for eth0:
        Supported ports: [ TP ]
        Supported link modes:   10baseT/Half 10baseT/Full 
                                100baseT/Half 100baseT/Full 
                                1000baseT/Full 
        Supports auto-negotiation: Yes
        Advertised link modes:  10baseT/Full 
        Advertised auto-negotiation: Yes
        Speed: 10Mb/s
        Duplex: Full
        Port: Twisted Pair
        PHYAD: 0
        Transceiver: internal
        Auto-negotiation: on
        Link detected: yes
+ sleep 10
+ ethtool -s eth0 autoneg on speed 100 duplex half
+ sleep 10
+ ethtool eth0
Settings for eth0:
        Supported ports: [ TP ]
        Supported link modes:   10baseT/Half 10baseT/Full 
                                100baseT/Half 100baseT/Full 
                                1000baseT/Full 
        Supports auto-negotiation: Yes
        Advertised link modes:  100baseT/Half 
        Advertised auto-negotiation: Yes
        Speed: 100Mb/s
        Duplex: Half
        Port: Twisted Pair
        PHYAD: 0
        Transceiver: internal
        Auto-negotiation: on
        Link detected: yes
+ sleep 10
+ ethtool -s eth0 autoneg on speed 100 duplex full
+ sleep 10
+ ethtool eth0
Settings for eth0:
        Supported ports: [ TP ]
        Supported link modes:   10baseT/Half 10baseT/Full 
                                100baseT/Half 100baseT/Full 
                                1000baseT/Full 
        Supports auto-negotiation: Yes
        Advertised link modes:  100baseT/Full 
        Advertised auto-negotiation: Yes
        Speed: 100Mb/s
        Duplex: Full
        Port: Twisted Pair
        PHYAD: 0
        Transceiver: internal
        Auto-negotiation: on
        Link detected: yes
+ sleep 10
+ ethtool -s eth0 autoneg on speed 1000 duplex full
+ sleep 10
+ ethtool eth0
Settings for eth0:
        Supported ports: [ TP ]
        Supported link modes:   10baseT/Half 10baseT/Full 
                                100baseT/Half 100baseT/Full 
                                1000baseT/Full 
        Supports auto-negotiation: Yes
        Advertised link modes:  1000baseT/Full 
        Advertised auto-negotiation: Yes
        Speed: 100Mb/s
        Duplex: Half
        Port: Twisted Pair
        PHYAD: 0
        Transceiver: internal
        Auto-negotiation: on
        Link detected: no
+ sleep 10
+ ethtool -s eth0 autoneg on
+ sleep 10
+ ethtool eth0
Settings for eth0:
        Supported ports: [ TP ]
        Supported link modes:   10baseT/Half 10baseT/Full 
                                100baseT/Half 100baseT/Full 
                                1000baseT/Full 
        Supports auto-negotiation: Yes
        Advertised link modes:  10baseT/Half 10baseT/Full 
                                100baseT/Half 100baseT/Full 
                                1000baseT/Full 
        Advertised auto-negotiation: Yes
        Speed: 100Mb/s
        Duplex: Full
        Port: Twisted Pair
        PHYAD: 0
        Transceiver: internal
        Auto-negotiation: on
        Link detected: yes
+ sleep 10
+ for i in on off
+ ethtool -s eth0 autoneg off speed 10 duplex half
+ sleep 10
+ ethtool eth0
Settings for eth0:
        Supported ports: [ TP ]
        Supported link modes:   10baseT/Half 10baseT/Full 
                                100baseT/Half 100baseT/Full 
                                1000baseT/Full 
        Supports auto-negotiation: Yes
        Advertised link modes:  10baseT/Half 
        Advertised auto-negotiation: Yes
        Speed: 10Mb/s
        Duplex: Half
        Port: Twisted Pair
        PHYAD: 0
        Transceiver: internal
        Auto-negotiation: on
        Link detected: yes
+ sleep 10
+ ethtool -s eth0 autoneg off speed 10 duplex full
+ sleep 10
+ ethtool eth0
Settings for eth0:
        Supported ports: [ TP ]
        Supported link modes:   10baseT/Half 10baseT/Full 
                                100baseT/Half 100baseT/Full 
                                1000baseT/Full 
        Supports auto-negotiation: Yes
        Advertised link modes:  10baseT/Half 10baseT/Full 
        Advertised auto-negotiation: Yes
        Speed: 10Mb/s
        Duplex: Full
        Port: Twisted Pair
        PHYAD: 0
        Transceiver: internal
        Auto-negotiation: on
        Link detected: yes
+ sleep 10
+ ethtool -s eth0 autoneg off speed 100 duplex half
+ sleep 10
+ ethtool eth0
Settings for eth0:
        Supported ports: [ TP ]
        Supported link modes:   10baseT/Half 10baseT/Full 
                                100baseT/Half 100baseT/Full 
                                1000baseT/Full 
        Supports auto-negotiation: Yes
        Advertised link modes:  100baseT/Half 
        Advertised auto-negotiation: Yes
        Speed: 100Mb/s
        Duplex: Half
        Port: Twisted Pair
        PHYAD: 0
        Transceiver: internal
        Auto-negotiation: on
        Link detected: yes
+ sleep 10
+ ethtool -s eth0 autoneg off speed 100 duplex full
+ sleep 10
+ ethtool eth0
Settings for eth0:
        Supported ports: [ TP ]
        Supported link modes:   10baseT/Half 10baseT/Full 
                                100baseT/Half 100baseT/Full 
                                1000baseT/Full 
        Supports auto-negotiation: Yes
        Advertised link modes:  100baseT/Half 100baseT/Full 
        Advertised auto-negotiation: Yes
        Speed: 100Mb/s
        Duplex: Full
        Port: Twisted Pair
        PHYAD: 0
        Transceiver: internal
        Auto-negotiation: on
        Link detected: yes
+ sleep 10
+ ethtool -s eth0 autoneg off speed 1000 duplex full
+ sleep 10
+ ethtool eth0
Settings for eth0:
        Supported ports: [ TP ]
        Supported link modes:   10baseT/Half 10baseT/Full 
                                100baseT/Half 100baseT/Full 
                                1000baseT/Full 
        Supports auto-negotiation: Yes
        Advertised link modes:  1000baseT/Full 
        Advertised auto-negotiation: Yes
        Speed: 100Mb/s
        Duplex: Half
        Port: Twisted Pair
        PHYAD: 0
        Transceiver: internal
        Auto-negotiation: on
        Link detected: no
+ sleep 10
+ ethtool -s eth0 autoneg on
+ sleep 10
+ ethtool eth0
Settings for eth0:
        Supported ports: [ TP ]
        Supported link modes:   10baseT/Half 10baseT/Full 
                                100baseT/Half 100baseT/Full 
                                1000baseT/Full 
        Supports auto-negotiation: Yes
        Advertised link modes:  10baseT/Half 10baseT/Full 
                                100baseT/Half 100baseT/Full 
                                1000baseT/Full 
        Advertised auto-negotiation: Yes
        Speed: 100Mb/s
        Duplex: Full
        Port: Twisted Pair
        PHYAD: 0
        Transceiver: internal
        Auto-negotiation: on
        Link detected: yes
+ sleep 10
<Prev in Thread] Current Thread [Next in Thread>