diff options
Diffstat (limited to 'drivers/net/phy/qcom/qca83xx.c')
| -rw-r--r-- | drivers/net/phy/qcom/qca83xx.c | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/drivers/net/phy/qcom/qca83xx.c b/drivers/net/phy/qcom/qca83xx.c index bc70ed8efd86..2c4d085bacdb 100644 --- a/drivers/net/phy/qcom/qca83xx.c +++ b/drivers/net/phy/qcom/qca83xx.c @@ -92,6 +92,63 @@ static int qca83xx_probe(struct phy_device *phydev) return 0; } +static int qca8337_read_status(struct phy_device *phydev) +{ + struct at803x_ss_mask ss_mask = { + .speed_mask = AT803X_SS_SPEED_MASK, + .speed_shift = __bf_shf(AT803X_SS_SPEED_MASK), + }; + int ret, old_link = phydev->link; + + ret = genphy_read_status(phydev); + if (ret) + return ret; + + /* Keep the state resolved at link-up while the link stays up */ + if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) + goto out; + + phydev->mdix = ETH_TP_MDI_INVALID; + + /* genphy_read_status() derives speed and duplex from the + * advertisements, which is wrong after a SmartSpeed downshift. + * Use what the PHY resolved instead. + */ + if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete && + phydev->link) { + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; + phydev->pause = false; + phydev->asym_pause = false; + + ret = at803x_read_specific_status(phydev, ss_mask); + if (ret) + return ret; + + /* Report the link down until speed and duplex are resolved, + * so that the next poll reads them again. Also clear what + * genphy_read_status() read for an up link, as the + * PHY_HALTED path of the state machine does. + */ + if (phydev->speed == SPEED_UNKNOWN || + phydev->duplex == DUPLEX_UNKNOWN) { + phydev->link = 0; + phydev->duplex = DUPLEX_UNKNOWN; + phydev->mdix = ETH_TP_MDI_INVALID; + phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; + linkmode_zero(phydev->lp_advertising); + } else { + phy_resolve_aneg_pause(phydev); + } + } + +out: + /* MDI-X configuration is not implemented */ + phydev->mdix_ctrl = ETH_TP_MDI_INVALID; + + return 0; +} + static int qca83xx_config_init(struct phy_device *phydev) { u8 switch_revision; @@ -220,6 +277,7 @@ static struct phy_driver qca83xx_driver[] = { .flags = PHY_IS_INTERNAL, .config_init = qca83xx_config_init, .soft_reset = genphy_soft_reset, + .read_status = qca8337_read_status, .get_sset_count = qca83xx_get_sset_count, .get_strings = qca83xx_get_strings, .get_stats = qca83xx_get_stats, |
