net: phy: bcm7xxx: Add support for downshift/Wirespeed
authorFlorian Fainelli <f.fainelli@gmail.com>
Tue, 22 Nov 2016 19:40:57 +0000 (11:40 -0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 24 Nov 2016 20:45:53 +0000 (15:45 -0500)
Add support for configuring the downshift/Wirespeed enable/disable
toggles and specify a link retry value ranging from 1 to 9. Since the
integrated BCM7xxx have issues when wirespeed is enabled and EEE is also
enabled, we do disable EEE if wirespeed is enabled.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/phy/bcm7xxx.c

index b7789e8796704f9adae600173540466018440ce8..5b3be4c67be8ae0c628f4501754e37620eaaa98c 100644 (file)
@@ -167,6 +167,7 @@ static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
 {
        u8 rev = PHY_BRCM_7XXX_REV(phydev->dev_flags);
        u8 patch = PHY_BRCM_7XXX_PATCH(phydev->dev_flags);
+       u8 count;
        int ret = 0;
 
        pr_info_once("%s: %s PHY revision: 0x%02x, patch: %d\n",
@@ -199,7 +200,12 @@ static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
        if (ret)
                return ret;
 
-       ret = bcm_phy_set_eee(phydev, true);
+       ret = bcm_phy_downshift_get(phydev, &count);
+       if (ret)
+               return ret;
+
+       /* Only enable EEE if Wirespeed/downshift is disabled */
+       ret = bcm_phy_set_eee(phydev, count == DOWNSHIFT_DEV_DISABLE);
        if (ret)
                return ret;
 
@@ -303,6 +309,47 @@ static int bcm7xxx_suspend(struct phy_device *phydev)
        return 0;
 }
 
+static int bcm7xxx_28nm_get_tunable(struct phy_device *phydev,
+                                   struct ethtool_tunable *tuna,
+                                   void *data)
+{
+       switch (tuna->id) {
+       case ETHTOOL_PHY_DOWNSHIFT:
+               return bcm_phy_downshift_get(phydev, (u8 *)data);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static int bcm7xxx_28nm_set_tunable(struct phy_device *phydev,
+                                   struct ethtool_tunable *tuna,
+                                   const void *data)
+{
+       u8 count = *(u8 *)data;
+       int ret;
+
+       switch (tuna->id) {
+       case ETHTOOL_PHY_DOWNSHIFT:
+               ret = bcm_phy_downshift_set(phydev, count);
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       if (ret)
+               return ret;
+
+       /* Disable EEE advertisment since this prevents the PHY
+        * from successfully linking up, trigger auto-negotiation restart
+        * to let the MAC decide what to do.
+        */
+       ret = bcm_phy_set_eee(phydev, count == DOWNSHIFT_DEV_DISABLE);
+       if (ret)
+               return ret;
+
+       return genphy_restart_aneg(phydev);
+}
+
 #define BCM7XXX_28NM_GPHY(_oui, _name)                                 \
 {                                                                      \
        .phy_id         = (_oui),                                       \
@@ -315,6 +362,8 @@ static int bcm7xxx_suspend(struct phy_device *phydev)
        .config_aneg    = genphy_config_aneg,                           \
        .read_status    = genphy_read_status,                           \
        .resume         = bcm7xxx_28nm_resume,                          \
+       .get_tunable    = bcm7xxx_28nm_get_tunable,                     \
+       .set_tunable    = bcm7xxx_28nm_set_tunable,                     \
 }
 
 #define BCM7XXX_40NM_EPHY(_oui, _name)                                 \