]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/net/phy/bcm7xxx.c
net: phy: phy drivers should not set SUPPORTED_[Asym_]Pause
[linux.git] / drivers / net / phy / bcm7xxx.c
index 9636da0b6efc449907025b52e5e9cefaa51df198..264b085d796b4f048551fa033b7c28d302675e24 100644 (file)
 #define AFE_VDAC_OTHERS_0              MISC_ADDR(0x39, 3)
 #define AFE_HPF_TRIM_OTHERS            MISC_ADDR(0x3a, 0)
 
+struct bcm7xxx_phy_priv {
+       u64     *stats;
+};
+
 static void r_rc_cal_reset(struct phy_device *phydev)
 {
        /* Reset R_CAL/RC_CAL Engine */
@@ -167,6 +171,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 +204,12 @@ static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
        if (ret)
                return ret;
 
-       ret = bcm_phy_enable_eee(phydev);
+       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,18 +313,91 @@ 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);
+}
+
+static void bcm7xxx_28nm_get_phy_stats(struct phy_device *phydev,
+                                      struct ethtool_stats *stats, u64 *data)
+{
+       struct bcm7xxx_phy_priv *priv = phydev->priv;
+
+       bcm_phy_get_stats(phydev, priv->stats, stats, data);
+}
+
+static int bcm7xxx_28nm_probe(struct phy_device *phydev)
+{
+       struct bcm7xxx_phy_priv *priv;
+
+       priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       phydev->priv = priv;
+
+       priv->stats = devm_kcalloc(&phydev->mdio.dev,
+                                  bcm_phy_get_sset_count(phydev), sizeof(u64),
+                                  GFP_KERNEL);
+       if (!priv->stats)
+               return -ENOMEM;
+
+       return 0;
+}
+
 #define BCM7XXX_28NM_GPHY(_oui, _name)                                 \
 {                                                                      \
        .phy_id         = (_oui),                                       \
        .phy_id_mask    = 0xfffffff0,                                   \
        .name           = _name,                                        \
-       .features       = PHY_GBIT_FEATURES |                           \
-                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,       \
+       .features       = PHY_GBIT_FEATURES,                            \
        .flags          = PHY_IS_INTERNAL,                              \
        .config_init    = bcm7xxx_28nm_config_init,                     \
        .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,                     \
+       .get_sset_count = bcm_phy_get_sset_count,                       \
+       .get_strings    = bcm_phy_get_strings,                          \
+       .get_stats      = bcm7xxx_28nm_get_phy_stats,                   \
+       .probe          = bcm7xxx_28nm_probe,                           \
 }
 
 #define BCM7XXX_40NM_EPHY(_oui, _name)                                 \
@@ -322,8 +405,7 @@ static int bcm7xxx_suspend(struct phy_device *phydev)
        .phy_id         = (_oui),                                       \
        .phy_id_mask    = 0xfffffff0,                                   \
        .name           = _name,                                        \
-       .features       = PHY_BASIC_FEATURES |                          \
-                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,       \
+       .features       = PHY_BASIC_FEATURES,                           \
        .flags          = PHY_IS_INTERNAL,                              \
        .config_init    = bcm7xxx_config_init,                          \
        .config_aneg    = genphy_config_aneg,                           \