From 8b8bc13d89a7d23d14b0e041c73f037c9db997b1 Mon Sep 17 00:00:00 2001 From: Luo Jie Date: Sun, 16 Jul 2023 16:49:19 +0800 Subject: [PATCH 1/6] net: phy: at803x: support qca8081 genphy_c45_pma_read_abilities qca8081 PHY supports to use genphy_c45_pma_read_abilities for getting the PHY features supported except for the autoneg ability but autoneg ability exists in MDIO_STAT1 instead of MMD7.1, add it manually after calling genphy_c45_pma_read_abilities. Signed-off-by: Luo Jie Reviewed-by: Russell King (Oracle) Signed-off-by: David S. Miller --- drivers/net/phy/at803x.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index c1f307d90518b..11388ef3f7ef6 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -897,15 +897,6 @@ static int at803x_get_features(struct phy_device *phydev) if (err) return err; - if (phydev->drv->phy_id == QCA8081_PHY_ID) { - err = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_NG_EXTABLE); - if (err < 0) - return err; - - linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported, - err & MDIO_PMA_NG_EXTABLE_2_5GBT); - } - if (phydev->drv->phy_id != ATH8031_PHY_ID) return 0; @@ -1991,6 +1982,23 @@ static int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finish return 0; } +static int qca808x_get_features(struct phy_device *phydev) +{ + int ret; + + ret = genphy_c45_pma_read_abilities(phydev); + if (ret) + return ret; + + /* The autoneg ability is not existed in bit3 of MMD7.1, + * but it is supported by qca808x PHY, so we add it here + * manually. + */ + linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported); + + return 0; +} + static struct phy_driver at803x_driver[] = { { /* Qualcomm Atheros AR8035 */ @@ -2160,7 +2168,7 @@ static struct phy_driver at803x_driver[] = { .set_tunable = at803x_set_tunable, .set_wol = at803x_set_wol, .get_wol = at803x_get_wol, - .get_features = at803x_get_features, + .get_features = qca808x_get_features, .config_aneg = at803x_config_aneg, .suspend = genphy_suspend, .resume = genphy_resume, From f3db55ae860a82e1224a909072783ef850e5d228 Mon Sep 17 00:00:00 2001 From: Luo Jie Date: Sun, 16 Jul 2023 16:49:20 +0800 Subject: [PATCH 2/6] net: phy: at803x: merge qca8081 slave seed function merge the seed enablement and seed value configuration into one function, since the random seed value is needed to be configured when the seed is enabled. Signed-off-by: Luo Jie Reviewed-by: Russell King (Oracle) Signed-off-by: David S. Miller --- drivers/net/phy/at803x.c | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index 11388ef3f7ef6..1d4aef60d51a9 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -1725,24 +1725,19 @@ static int qca808x_phy_fast_retrain_config(struct phy_device *phydev) return 0; } -static int qca808x_phy_ms_random_seed_set(struct phy_device *phydev) -{ - u16 seed_value = get_random_u32_below(QCA808X_MASTER_SLAVE_SEED_RANGE); - - return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED, - QCA808X_MASTER_SLAVE_SEED_CFG, - FIELD_PREP(QCA808X_MASTER_SLAVE_SEED_CFG, seed_value)); -} - static int qca808x_phy_ms_seed_enable(struct phy_device *phydev, bool enable) { - u16 seed_enable = 0; + u16 seed_value; - if (enable) - seed_enable = QCA808X_MASTER_SLAVE_SEED_ENABLE; + if (!enable) + return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED, + QCA808X_MASTER_SLAVE_SEED_ENABLE, 0); + seed_value = get_random_u32_below(QCA808X_MASTER_SLAVE_SEED_RANGE); return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED, - QCA808X_MASTER_SLAVE_SEED_ENABLE, seed_enable); + QCA808X_MASTER_SLAVE_SEED_CFG | QCA808X_MASTER_SLAVE_SEED_ENABLE, + FIELD_PREP(QCA808X_MASTER_SLAVE_SEED_CFG, seed_value) | + QCA808X_MASTER_SLAVE_SEED_ENABLE); } static int qca808x_config_init(struct phy_device *phydev) @@ -1766,12 +1761,7 @@ static int qca808x_config_init(struct phy_device *phydev) if (ret) return ret; - /* Configure lower ramdom seed to make phy linked as slave mode */ - ret = qca808x_phy_ms_random_seed_set(phydev); - if (ret) - return ret; - - /* Enable seed */ + /* Enable seed and configure lower ramdom seed to make phy linked as slave mode */ ret = qca808x_phy_ms_seed_enable(phydev, true); if (ret) return ret; @@ -1816,7 +1806,6 @@ static int qca808x_read_status(struct phy_device *phydev) if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR) { qca808x_phy_ms_seed_enable(phydev, false); } else { - qca808x_phy_ms_random_seed_set(phydev); qca808x_phy_ms_seed_enable(phydev, true); } } From 7cc3209558002d95c0d45a1276ba4f5f741eec42 Mon Sep 17 00:00:00 2001 From: Luo Jie Date: Sun, 16 Jul 2023 16:49:21 +0800 Subject: [PATCH 3/6] net: phy: at803x: enable qca8081 slave seed conditionally qca8081 is the single port PHY, the slave prefer mode is used by default. if the phy master perfer mode is configured, the slave seed configuration should not be enabled, since the slave seed enablement is for making PHY linked as slave mode easily. disable slave seed if the master mode is preferred. Signed-off-by: Luo Jie Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/at803x.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index 1d4aef60d51a9..6cdc1b8f8c4d8 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -1740,6 +1740,12 @@ static int qca808x_phy_ms_seed_enable(struct phy_device *phydev, bool enable) QCA808X_MASTER_SLAVE_SEED_ENABLE); } +static bool qca808x_is_prefer_master(struct phy_device *phydev) +{ + return (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_FORCE) || + (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_PREFERRED); +} + static int qca808x_config_init(struct phy_device *phydev) { int ret; @@ -1761,11 +1767,17 @@ static int qca808x_config_init(struct phy_device *phydev) if (ret) return ret; - /* Enable seed and configure lower ramdom seed to make phy linked as slave mode */ - ret = qca808x_phy_ms_seed_enable(phydev, true); - if (ret) + ret = genphy_read_master_slave(phydev); + if (ret < 0) return ret; + if (!qca808x_is_prefer_master(phydev)) { + /* Enable seed and configure lower ramdom seed to make phy linked as slave mode */ + ret = qca808x_phy_ms_seed_enable(phydev, true); + if (ret) + return ret; + } + /* Configure adc threshold as 100mv for the link 10M */ return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD, QCA808X_ADC_THRESHOLD_MASK, QCA808X_ADC_THRESHOLD_100MV); @@ -1797,13 +1809,16 @@ static int qca808x_read_status(struct phy_device *phydev) phydev->interface = PHY_INTERFACE_MODE_SGMII; } else { /* generate seed as a lower random value to make PHY linked as SLAVE easily, - * except for master/slave configuration fault detected. + * except for master/slave configuration fault detected or the master mode + * preferred. + * * the reason for not putting this code into the function link_change_notify is * the corner case where the link partner is also the qca8081 PHY and the seed * value is configured as the same value, the link can't be up and no link change * occurs. */ - if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR) { + if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR || + qca808x_is_prefer_master(phydev)) { qca808x_phy_ms_seed_enable(phydev, false); } else { qca808x_phy_ms_seed_enable(phydev, true); From fea7cfb83d1a2782e39cd101dd44ed2548539de5 Mon Sep 17 00:00:00 2001 From: Luo Jie Date: Sun, 16 Jul 2023 16:49:22 +0800 Subject: [PATCH 4/6] net: phy: at803x: support qca8081 1G chip type The qca8081 1G chip version does not support 2.5 capability, which is distinguished from qca8081 2.5G chip according to the bit0 of register mmd7.0x901d, the 1G version chip also has the same PHY ID as the normal qca8081 2.5G chip. Signed-off-by: Luo Jie Reviewed-by: Russell King (Oracle) Signed-off-by: David S. Miller --- drivers/net/phy/at803x.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index 6cdc1b8f8c4d8..cb4c45c81a853 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -272,6 +272,10 @@ #define QCA808X_CDT_STATUS_STAT_OPEN 2 #define QCA808X_CDT_STATUS_STAT_SHORT 3 +/* QCA808X 1G chip type */ +#define QCA808X_PHY_MMD7_CHIP_TYPE 0x901d +#define QCA808X_PHY_CHIP_TYPE_1G BIT(0) + MODULE_DESCRIPTION("Qualcomm Atheros AR803x and QCA808X PHY driver"); MODULE_AUTHOR("Matus Ujhelyi"); MODULE_LICENSE("GPL"); @@ -2000,6 +2004,17 @@ static int qca808x_get_features(struct phy_device *phydev) */ linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported); + /* As for the qca8081 1G version chip, the 2500baseT ability is also + * existed in the bit0 of MMD1.21, we need to remove it manually if + * it is the qca8081 1G chip according to the bit0 of MMD7.0x901d. + */ + ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_CHIP_TYPE); + if (ret < 0) + return ret; + + if (QCA808X_PHY_CHIP_TYPE_1G & ret) + linkmode_clear_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported); + return 0; } From df9401ff3e6eeaa42bfb06761967f1b71f5afce7 Mon Sep 17 00:00:00 2001 From: Luo Jie Date: Sun, 16 Jul 2023 16:49:23 +0800 Subject: [PATCH 5/6] net: phy: at803x: remove qca8081 1G fast retrain and slave seed config The fast retrain and slave seed configs are only applicable when the 2.5G ability is supported. Signed-off-by: Luo Jie Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/at803x.c | 50 +++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index cb4c45c81a853..a141f133b8aa1 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -1750,6 +1750,11 @@ static bool qca808x_is_prefer_master(struct phy_device *phydev) (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_PREFERRED); } +static bool qca808x_has_fast_retrain_or_slave_seed(struct phy_device *phydev) +{ + return linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported); +} + static int qca808x_config_init(struct phy_device *phydev) { int ret; @@ -1766,20 +1771,24 @@ static int qca808x_config_init(struct phy_device *phydev) if (ret) return ret; - /* Config the fast retrain for the link 2500M */ - ret = qca808x_phy_fast_retrain_config(phydev); - if (ret) - return ret; - - ret = genphy_read_master_slave(phydev); - if (ret < 0) - return ret; - - if (!qca808x_is_prefer_master(phydev)) { - /* Enable seed and configure lower ramdom seed to make phy linked as slave mode */ - ret = qca808x_phy_ms_seed_enable(phydev, true); + if (qca808x_has_fast_retrain_or_slave_seed(phydev)) { + /* Config the fast retrain for the link 2500M */ + ret = qca808x_phy_fast_retrain_config(phydev); if (ret) return ret; + + ret = genphy_read_master_slave(phydev); + if (ret < 0) + return ret; + + if (!qca808x_is_prefer_master(phydev)) { + /* Enable seed and configure lower ramdom seed to make phy + * linked as slave mode. + */ + ret = qca808x_phy_ms_seed_enable(phydev, true); + if (ret) + return ret; + } } /* Configure adc threshold as 100mv for the link 10M */ @@ -1821,11 +1830,13 @@ static int qca808x_read_status(struct phy_device *phydev) * value is configured as the same value, the link can't be up and no link change * occurs. */ - if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR || - qca808x_is_prefer_master(phydev)) { - qca808x_phy_ms_seed_enable(phydev, false); - } else { - qca808x_phy_ms_seed_enable(phydev, true); + if (qca808x_has_fast_retrain_or_slave_seed(phydev)) { + if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR || + qca808x_is_prefer_master(phydev)) { + qca808x_phy_ms_seed_enable(phydev, false); + } else { + qca808x_phy_ms_seed_enable(phydev, true); + } } } @@ -1840,7 +1851,10 @@ static int qca808x_soft_reset(struct phy_device *phydev) if (ret < 0) return ret; - return qca808x_phy_ms_seed_enable(phydev, true); + if (qca808x_has_fast_retrain_or_slave_seed(phydev)) + ret = qca808x_phy_ms_seed_enable(phydev, true); + + return ret; } static bool qca808x_cdt_fault_length_valid(int cdt_code) From 723970affdd8766fa0d91cd34bf2ffc861538b5f Mon Sep 17 00:00:00 2001 From: Luo Jie Date: Sun, 16 Jul 2023 16:49:24 +0800 Subject: [PATCH 6/6] net: phy: at803x: add qca8081 fifo reset on the link changed The qca8081 sgmii fifo needs to be reset on link down and released on the link up in case of any abnormal issue such as the packet blocked on the PHY. Signed-off-by: Luo Jie Reviewed-by: Andrew Lunn Reviewed-by: Russell King (Oracle) Signed-off-by: David S. Miller --- drivers/net/phy/at803x.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index a141f133b8aa1..13c4121fa3092 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -276,6 +276,9 @@ #define QCA808X_PHY_MMD7_CHIP_TYPE 0x901d #define QCA808X_PHY_CHIP_TYPE_1G BIT(0) +#define QCA8081_PHY_SERDES_MMD1_FIFO_CTRL 0x9072 +#define QCA8081_PHY_FIFO_RSTN BIT(11) + MODULE_DESCRIPTION("Qualcomm Atheros AR803x and QCA808X PHY driver"); MODULE_AUTHOR("Matus Ujhelyi"); MODULE_LICENSE("GPL"); @@ -2032,6 +2035,16 @@ static int qca808x_get_features(struct phy_device *phydev) return 0; } +static void qca808x_link_change_notify(struct phy_device *phydev) +{ + /* Assert interface sgmii fifo on link down, deassert it on link up, + * the interface device address is always phy address added by 1. + */ + mdiobus_c45_modify_changed(phydev->mdio.bus, phydev->mdio.addr + 1, + MDIO_MMD_PMAPMD, QCA8081_PHY_SERDES_MMD1_FIFO_CTRL, + QCA8081_PHY_FIFO_RSTN, phydev->link ? QCA8081_PHY_FIFO_RSTN : 0); +} + static struct phy_driver at803x_driver[] = { { /* Qualcomm Atheros AR8035 */ @@ -2210,6 +2223,7 @@ static struct phy_driver at803x_driver[] = { .soft_reset = qca808x_soft_reset, .cable_test_start = qca808x_cable_test_start, .cable_test_get_status = qca808x_cable_test_get_status, + .link_change_notify = qca808x_link_change_notify, }, }; module_phy_driver(at803x_driver);