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