ethtool reporting wrong speed and duplex when link partner is forced
From: <hidden>
Date: 2008-01-03 07:17:59
Hello,
In drivers/net/mii.c, is there a reason why mii_nway_result is used to
find the speed and duplex settings when autonegation is on? This
gives wrong result when autoneg is on, but we are making link to a
host which is forced. In this case the variable lpa is 0, and
mii_nway_result(advert & lpa) gives LPA_10HALF, which is wrong.
The real speed can be found from the BMCR register.
This is how it looks like with ethtool:
# ethtool eth1
...
Advertised auto-negotiation: Yes
Speed: 10Mb/s
Duplex: Half
Auto-negotiation: on
Link detected: yes
# ethtool -d eth1
...
0x62: MII Basic Mode Control Register 0x3000
0x68: MII Link Partner Ability 0x0000
And looking at mii.h we see that this implies BMCR_SPEED100 and
BMCR_ANENABLE, i.e. we are in 100 half duplex, as we should be (link
partner was forced to 100 full duplex).
Below is a quick patch you can comment. I have not yet tested this myself.
Esa-Pekka
--- 1.20/drivers/net/mii.c 2007-04-28 18:01:05 +03:00
+++ 1.21/drivers/net/mii.c 2008-01-03 08:25:42 +02:00@@ -90,31 +90,16 @@ int mii_ethtool_gset(struct mii_if_info if (bmcr & BMCR_ANENABLE) { ecmd->advertising |= ADVERTISED_Autoneg; ecmd->autoneg = AUTONEG_ENABLE; - - nego = mii_nway_result(advert & lpa); - if ((bmcr2 & (ADVERTISE_1000HALF | ADVERTISE_1000FULL)) & - (lpa2 >> 2)) - ecmd->speed = SPEED_1000; - else if (nego == LPA_100FULL || nego == LPA_100HALF) - ecmd->speed = SPEED_100; - else - ecmd->speed = SPEED_10; - if ((lpa2 & LPA_1000FULL) || nego == LPA_100FULL || - nego == LPA_10FULL) { - ecmd->duplex = DUPLEX_FULL; - mii->full_duplex = 1; - } else { - ecmd->duplex = DUPLEX_HALF; - mii->full_duplex = 0; - } } else { ecmd->autoneg = AUTONEG_DISABLE; - - ecmd->speed = ((bmcr & BMCR_SPEED1000 && - (bmcr & BMCR_SPEED100) == 0) ? SPEED_1000 : - (bmcr & BMCR_SPEED100) ? SPEED_100 :
SPEED_10);
- ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL :
DUPLEX_HA\
LF;
}
+
+
+ ecmd->speed = ((bmcr & BMCR_SPEED1000 &&
+ (bmcr & BMCR_SPEED100) == 0) ? SPEED_1000 :
+ (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10);
+ ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
+
/* ignore maxtxpkt, maxrxpkt for now */