diff options
author | David S. Miller <davem@davemloft.net> | 2019-02-23 23:12:10 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-02-23 23:12:10 +0100 |
commit | 515d846773b05972b621675bbb344b9f80d47f26 (patch) | |
tree | 1cbcab2e11cdae2a007f5c9cb161dba369bb8a10 /drivers | |
parent | Merge tag 'mlx5-updates-2019-02-21' of git://git.kernel.org/pub/scm/linux/ker... (diff) | |
parent | net: phy: aquantia: use genphy_c45_read_status (diff) | |
download | linux-515d846773b05972b621675bbb344b9f80d47f26.tar.xz linux-515d846773b05972b621675bbb344b9f80d47f26.zip |
Merge branch 'net-phy-aquantia-improve-and-extend-driver'
Heiner Kallweit says:
====================
net: phy: aquantia: improve and extend driver
This series improves and extends the Aquantia PHY driver.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/phy/aquantia.c | 94 | ||||
-rw-r--r-- | drivers/net/phy/phy-c45.c | 35 |
2 files changed, 98 insertions, 31 deletions
diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c index 34be44d00c19..0f0eb568267d 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) @@ -35,6 +39,10 @@ #define MDIO_AN_TX_VEND_INT_MASK2 0xd401 #define MDIO_AN_TX_VEND_INT_MASK2_LINK BIT(0) +#define MDIO_AN_RX_LP_STAT1 0xe820 +#define MDIO_AN_RX_LP_STAT1_1000BASET_FULL BIT(15) +#define MDIO_AN_RX_LP_STAT1_1000BASET_HALF BIT(14) + /* Vendor specific 1, MDIO_MMD_VEND1 */ #define VEND1_GLOBAL_INT_STD_STATUS 0xfc00 #define VEND1_GLOBAL_INT_VEND_STATUS 0xfc01 @@ -64,10 +72,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; + + 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; - return 0; + 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) @@ -120,36 +158,31 @@ static int aqr_ack_interrupt(struct phy_device *phydev) static int aqr_read_status(struct phy_device *phydev) { - int reg; + int val; + + if (phydev->autoneg == AUTONEG_ENABLE) { + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RX_LP_STAT1); + if (val < 0) + return val; - reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); - reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); - if (reg & MDIO_STAT1_LSTATUS) - phydev->link = 1; - else - phydev->link = 0; - - reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_STATUS1); - mdelay(10); - reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_STATUS1); - - switch (reg & MDIO_AN_TX_VEND_STATUS1_RATE_MASK) { - case MDIO_AN_TX_VEND_STATUS1_2500BASET: - phydev->speed = SPEED_2500; - break; - case MDIO_AN_TX_VEND_STATUS1_1000BASET: - phydev->speed = SPEED_1000; - break; - case MDIO_AN_TX_VEND_STATUS1_100BASETX: - phydev->speed = SPEED_100; - break; - default: - phydev->speed = SPEED_10000; - break; + linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + phydev->lp_advertising, + val & MDIO_AN_RX_LP_STAT1_1000BASET_FULL); + linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, + phydev->lp_advertising, + val & MDIO_AN_RX_LP_STAT1_1000BASET_HALF); } - phydev->duplex = DUPLEX_FULL; - return 0; + return genphy_c45_read_status(phydev); +} + +static int aqcs109_config_init(struct phy_device *phydev) +{ + /* AQCS109 belongs to a chip family partially supporting 10G and 5G. + * PMA speed ability bits are the same for all members of the family, + * AQCS109 however supports speeds up to 2.5G only. + */ + return phy_set_max_speed(phydev, SPEED_2500); } static struct phy_driver aqr_driver[] = { @@ -208,6 +241,7 @@ static struct phy_driver aqr_driver[] = { .name = "Aquantia AQCS109", .aneg_done = genphy_c45_aneg_done, .get_features = genphy_c45_pma_read_abilities, + .config_init = aqcs109_config_init, .config_aneg = aqr_config_aneg, .config_intr = aqr_config_intr, .ack_interrupt = aqr_ack_interrupt, diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c index fc3173cc078b..c86bef005ef2 100644 --- a/drivers/net/phy/phy-c45.c +++ b/drivers/net/phy/phy-c45.c @@ -275,7 +275,7 @@ int genphy_c45_read_lpa(struct phy_device *phydev) if (val < 0) return val; - mii_lpa_to_linkmode_lpa_t(phydev->lp_advertising, val); + mii_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, val); phydev->pause = val & LPA_PAUSE_CAP ? 1 : 0; phydev->asym_pause = val & LPA_PAUSE_ASYM ? 1 : 0; @@ -454,6 +454,39 @@ int genphy_c45_pma_read_abilities(struct phy_device *phydev) } EXPORT_SYMBOL_GPL(genphy_c45_pma_read_abilities); +/** + * genphy_c45_read_status - read PHY status + * @phydev: target phy_device struct + * + * Reads status from PHY and sets phy_device members accordingly. + */ +int genphy_c45_read_status(struct phy_device *phydev) +{ + int ret; + + ret = genphy_c45_read_link(phydev); + if (ret) + return ret; + + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; + phydev->pause = 0; + phydev->asym_pause = 0; + + if (phydev->autoneg == AUTONEG_ENABLE) { + ret = genphy_c45_read_lpa(phydev); + if (ret) + return ret; + + phy_resolve_aneg_linkmode(phydev); + } else { + ret = genphy_c45_read_pma(phydev); + } + + return ret; +} +EXPORT_SYMBOL_GPL(genphy_c45_read_status); + /* The gen10g_* functions are the old Clause 45 stub */ int gen10g_config_aneg(struct phy_device *phydev) |