summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Fainelli <f.fainelli@gmail.com>2016-01-13 16:59:31 +0300
committerJoe Hershberger <joe.hershberger@ni.com>2016-01-28 12:31:30 -0600
commitbbdcaff12ad8c32100b5e1fdf9b9ae6931c3ba0d (patch)
tree8a75d5cd1a92cc571c54f351bdfec4bac2a94118
parentafe6462da9f68e872a9aeae1dc5389184819c1cf (diff)
net: phy: ensure Gigabit features are masked off if requested
When a Gigabit PHY device is connected to a 10/100Mbits capable Ethernet MAC, the driver will restrict the phydev->supported modes to mask off Gigabit. If the Gigabit PHY comes out of reset with the Gigabit features set by default in MII_CTRL1000, it will keep advertising these feature, so by the time we call genphy_config_advert(), the condition on phydev->supported having the Gigabit features on is false, and we do not update MII_CTRL1000 with updated values, and we keep advertising Gigabit features, eventually configuring the PHY for Gigabit whilst the Ethernet MAC does not support that. This patches fixes the problem by ensuring that the Gigabit feature bits are always cleared in MII_CTRL1000, if the PHY happens to be a Gigabit PHY, and then, if Gigabit features are supported, setting those and updating MII_CTRL1000 accordingly. This is a copy of patch from Linux kernel, see http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=5273e3a5ca94fbeb8e07d31203069220d5e682aa Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com> Cc: Joe Hershberger <joe.hershberger@ni.com> Acked-by: Joe Hershberger <joe.hershberger@ni.com>
-rw-r--r--drivers/net/phy/phy.c47
1 files changed, 29 insertions, 18 deletions
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index ef9f13bd46..aac9aa33f8 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -38,16 +38,16 @@ DECLARE_GLOBAL_DATA_PTR;
static int genphy_config_advert(struct phy_device *phydev)
{
u32 advertise;
- int oldadv, adv;
+ int oldadv, adv, bmsr;
int err, changed = 0;
- /* Only allow advertising what
- * this PHY supports */
+ /* Only allow advertising what this PHY supports */
phydev->advertising &= phydev->supported;
advertise = phydev->advertising;
/* Setup standard advertisement */
- oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
+ adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
+ oldadv = adv;
if (adv < 0)
return adv;
@@ -79,29 +79,40 @@ static int genphy_config_advert(struct phy_device *phydev)
changed = 1;
}
+ bmsr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+ if (bmsr < 0)
+ return bmsr;
+
+ /* Per 802.3-2008, Section 22.2.4.2.16 Extended status all
+ * 1000Mbits/sec capable PHYs shall have the BMSR_ESTATEN bit set to a
+ * logical 1.
+ */
+ if (!(bmsr & BMSR_ESTATEN))
+ return changed;
+
/* Configure gigabit if it's supported */
- if (phydev->supported & (SUPPORTED_1000baseT_Half |
- SUPPORTED_1000baseT_Full)) {
- oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
+ adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
+ oldadv = adv;
+
+ if (adv < 0)
+ return adv;
- if (adv < 0)
- return adv;
+ adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
- adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+ if (phydev->supported & (SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full)) {
if (advertise & SUPPORTED_1000baseT_Half)
adv |= ADVERTISE_1000HALF;
if (advertise & SUPPORTED_1000baseT_Full)
adv |= ADVERTISE_1000FULL;
+ }
- if (adv != oldadv) {
- err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000,
- adv);
+ if (adv != oldadv)
+ changed = 1;
- if (err < 0)
- return err;
- changed = 1;
- }
- }
+ err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, adv);
+ if (err < 0)
+ return err;
return changed;
}