diff options
author | Andrew Lunn <andrew@lunn.ch> | 2019-02-22 23:49:54 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-02-23 14:12:09 -0800 |
commit | 09c4c57f7bc4150cfe516126d921ae15c32750e7 (patch) | |
tree | 4628c59b4446f5a1967b2b0e8cdad2c93eba5f50 | |
parent | 0974f1f03b07543f3225414118e6e7ff205da96e (diff) | |
download | linux-09c4c57f7bc4150cfe516126d921ae15c32750e7.tar.bz2 |
net: phy: aquantia: add support for auto-negotiation configuration
Make use of the generic c45 code, plus code specific to the Aquantia
phy for 1000BaseT negotiation.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/phy/aquantia.c | 40 |
1 files changed, 37 insertions, 3 deletions
diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c index 9661ef4b40b0..a1846daa3388 100644 --- a/drivers/net/phy/aquantia.c +++ b/drivers/net/phy/aquantia.c @@ -20,6 +20,10 @@ #define PHY_ID_AQCS109 0x03a1b5c2 #define PHY_ID_AQR405 0x03a1b4b0 +#define MDIO_AN_VEND_PROV 0xc400 +#define MDIO_AN_VEND_PROV_1000BASET_FULL BIT(15) +#define MDIO_AN_VEND_PROV_1000BASET_HALF BIT(14) + #define MDIO_AN_TX_VEND_STATUS1 0xc800 #define MDIO_AN_TX_VEND_STATUS1_10BASET (0x0 << 1) #define MDIO_AN_TX_VEND_STATUS1_100BASETX (0x1 << 1) @@ -64,10 +68,40 @@ static int aqr_config_aneg(struct phy_device *phydev) { - linkmode_copy(phydev->supported, phy_10gbit_features); - linkmode_copy(phydev->advertising, phydev->supported); + bool changed = false; + u16 reg; + int ret; - return 0; + if (phydev->autoneg == AUTONEG_DISABLE) + return genphy_c45_pma_setup_forced(phydev); + + ret = genphy_c45_an_config_aneg(phydev); + if (ret < 0) + return ret; + if (ret > 0) + changed = true; + + /* Clause 45 has no standardized support for 1000BaseT, therefore + * use vendor registers for this mode. + */ + reg = 0; + if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + phydev->advertising)) + reg |= MDIO_AN_VEND_PROV_1000BASET_FULL; + + if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, + phydev->advertising)) + reg |= MDIO_AN_VEND_PROV_1000BASET_HALF; + + ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_VEND_PROV, + MDIO_AN_VEND_PROV_1000BASET_HALF | + MDIO_AN_VEND_PROV_1000BASET_FULL, reg); + if (ret < 0) + return ret; + if (ret > 0) + changed = true; + + return genphy_c45_check_and_restart_aneg(phydev, changed); } static int aqr_config_intr(struct phy_device *phydev) |