See also ticket 17800
With kernel>=3.14 autonegotiation is disabled at least for AR8327 based
switches. Reason is that with 3.14 an additional phy reset was
introduced in phy_init_hw in drivers/net/phy/phy_device.c
This reset clears BMCR_ANENABLE.
After the reset phy_init_hw calls the driver's config_init callback
which however for ar8327/8337 does nothing.
Fix the issue by extending ar8xxx_phy_config_init to check for
BMCR_ANENABLE being set in case of ar8327/ar8337.
If needed set the flag and restart autonegotiation.

For kernel>=3.16 the phy reset in phy_init_hw can be overwritten by
a soft_reset callback provided by the phy driver.
ar8216 driver takes care of resetting the switch properly for all
supported switch types anyway, therefore provide a dummy soft_reset
callback to disable the unneeded additional phy reset.

Signed-off-by: Heiner Kallweit <hkallwe...@gmail.com>
---
 .../linux/generic/files/drivers/net/phy/ar8216.c   | 34 ++++++++++++++++++++--
 1 file changed, 32 insertions(+), 2 deletions(-)

diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.c 
b/target/linux/generic/files/drivers/net/phy/ar8216.c
index 4410fbb..03de384 100644
--- a/target/linux/generic/files/drivers/net/phy/ar8216.c
+++ b/target/linux/generic/files/drivers/net/phy/ar8216.c
@@ -36,6 +36,7 @@
 #include <linux/of_device.h>
 #include <linux/leds.h>
 #include <linux/gpio.h>
+#include <linux/version.h>
 
 #include "ar8216.h"
 
@@ -2765,8 +2766,24 @@ ar8xxx_phy_config_init(struct phy_device *phydev)
        if (WARN_ON(!priv))
                return -ENODEV;
 
-       if (chip_is_ar8327(priv) || chip_is_ar8337(priv))
-               return 0;
+       if (chip_is_ar8327(priv) || chip_is_ar8337(priv)) {
+               if (AUTONEG_ENABLE != phydev->autoneg)
+                       return 0;
+               /*
+                * BMCR_ANENABLE might have been cleared
+                * by phy_init_hw in certain kernel versions
+                * therefore check for it
+                */
+               ret = phy_read(phydev, MII_BMCR);
+               if (ret < 0)
+                       return ret;
+               if (ret & BMCR_ANENABLE)
+                       return 0;
+
+               dev_info(&phydev->dev, "ANEG disabled, re-enabling ..\n");
+               ret |= BMCR_ANENABLE | BMCR_ANRESTART;
+               return phy_write(phydev, MII_BMCR, ret);
+       }
 
        priv->phy = phydev;
 
@@ -3011,6 +3028,15 @@ ar8xxx_phy_remove(struct phy_device *phydev)
        ar8xxx_free(priv);
 }
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0)
+static int
+ar8xxx_phy_soft_reset(struct phy_device *phydev)
+{
+       /* we don't need an extra reset */
+       return 0;
+}
+#endif
+
 static struct phy_driver ar8xxx_phy_driver = {
        .phy_id         = 0x004d0000,
        .name           = "Atheros AR8216/AR8236/AR8316",
@@ -3022,6 +3048,10 @@ static struct phy_driver ar8xxx_phy_driver = {
        .config_init    = ar8xxx_phy_config_init,
        .config_aneg    = ar8xxx_phy_config_aneg,
        .read_status    = ar8xxx_phy_read_status,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0)
+       .soft_reset     = ar8xxx_phy_soft_reset,
+#endif
+
        .driver         = { .owner = THIS_MODULE },
 };
 
-- 
2.1.3
_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel

Reply via email to