Currently, aqr_gen2_fill_interface_modes() reads VEND1_GLOBAL_CFG_* registers to populate phydev->supported_interfaces. But this is not the only place which needs to read these registers. There is also aqr107_read_rate(). Based on the premise that these values are statically set by firmware and the driver only needs to read them, the proposal is to read them only once, at config_init() time, and use the cached values also in aqr107_read_rate(). This patch only refactors the aqr_gen2_fill_interface_modes() code to save the registers to driver memory, and to populate supported_interfaces based on that. Signed-off-by: Vladimir Oltean --- drivers/net/phy/aquantia/aquantia.h | 27 +++++++ drivers/net/phy/aquantia/aquantia_main.c | 91 ++++++++++++++++-------- 2 files changed, 87 insertions(+), 31 deletions(-) diff --git a/drivers/net/phy/aquantia/aquantia.h b/drivers/net/phy/aquantia/aquantia.h index 67ec6f7484af..492052cf1e6e 100644 --- a/drivers/net/phy/aquantia/aquantia.h +++ b/drivers/net/phy/aquantia/aquantia.h @@ -174,11 +174,38 @@ static const struct aqr107_hw_stat aqr107_hw_stats[] = { #define AQR107_SGMII_STAT_SZ ARRAY_SIZE(aqr107_hw_stats) +static const struct { + int speed; + u16 reg; +} aqr_global_cfg_regs[] = { + { SPEED_10, VEND1_GLOBAL_CFG_10M, }, + { SPEED_100, VEND1_GLOBAL_CFG_100M, }, + { SPEED_1000, VEND1_GLOBAL_CFG_1G, }, + { SPEED_2500, VEND1_GLOBAL_CFG_2_5G, }, + { SPEED_5000, VEND1_GLOBAL_CFG_5G, }, + { SPEED_10000, VEND1_GLOBAL_CFG_10G, }, +}; + +#define AQR_NUM_GLOBAL_CFG ARRAY_SIZE(aqr_global_cfg_regs) + +enum aqr_rate_adaptation { + AQR_RATE_ADAPT_NONE, + AQR_RATE_ADAPT_USX, + AQR_RATE_ADAPT_PAUSE, +}; + +struct aqr_global_syscfg { + int speed; + phy_interface_t interface; + enum aqr_rate_adaptation rate_adapt; +}; + struct aqr107_priv { u64 sgmii_stats[AQR107_SGMII_STAT_SZ]; unsigned long leds_active_low; unsigned long leds_active_high; bool wait_on_global_cfg; + struct aqr_global_syscfg global_cfg[AQR_NUM_GLOBAL_CFG]; }; #if IS_REACHABLE(CONFIG_HWMON) diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c index 21fdbda2a0e0..9d704b7e3dc8 100644 --- a/drivers/net/phy/aquantia/aquantia_main.c +++ b/drivers/net/phy/aquantia/aquantia_main.c @@ -860,44 +860,24 @@ static int aqr_gen1_config_init(struct phy_device *phydev) return 0; } -static const u16 aqr_global_cfg_regs[] = { - VEND1_GLOBAL_CFG_10M, - VEND1_GLOBAL_CFG_100M, - VEND1_GLOBAL_CFG_1G, - VEND1_GLOBAL_CFG_2_5G, - VEND1_GLOBAL_CFG_5G, - VEND1_GLOBAL_CFG_10G, -}; - -static int aqr_gen2_fill_interface_modes(struct phy_device *phydev) +/* Walk the media-speed configuration registers to determine which + * host-side serdes modes may be used by the PHY depending on the + * negotiated media speed. + */ +static int aqr_gen2_read_global_syscfg(struct phy_device *phydev) { - unsigned long *possible = phydev->possible_interfaces; struct aqr107_priv *priv = phydev->priv; unsigned int serdes_mode, rate_adapt; phy_interface_t interface; - int i, val, ret; + int i, val; - /* It's been observed on some models that - when coming out of suspend - * - the FW signals that the PHY is ready but the GLOBAL_CFG registers - * continue on returning zeroes for some time. Let's poll the 100M - * register until it returns a real value as both 113c and 115c support - * this mode. - */ - if (priv->wait_on_global_cfg) { - ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, - VEND1_GLOBAL_CFG_100M, val, - val != 0, 1000, 100000, false); - if (ret) - return ret; - } + for (i = 0; i < AQR_NUM_GLOBAL_CFG; i++) { + struct aqr_global_syscfg *syscfg = &priv->global_cfg[i]; + + syscfg->speed = aqr_global_cfg_regs[i].speed; - /* Walk the media-speed configuration registers to determine which - * host-side serdes modes may be used by the PHY depending on the - * negotiated media speed. - */ - for (i = 0; i < ARRAY_SIZE(aqr_global_cfg_regs); i++) { val = phy_read_mmd(phydev, MDIO_MMD_VEND1, - aqr_global_cfg_regs[i]); + aqr_global_cfg_regs[i].reg); if (val < 0) return val; @@ -931,6 +911,55 @@ static int aqr_gen2_fill_interface_modes(struct phy_device *phydev) break; } + syscfg->interface = interface; + + switch (rate_adapt) { + case VEND1_GLOBAL_CFG_RATE_ADAPT_NONE: + syscfg->rate_adapt = AQR_RATE_ADAPT_NONE; + break; + case VEND1_GLOBAL_CFG_RATE_ADAPT_USX: + syscfg->rate_adapt = AQR_RATE_ADAPT_USX; + break; + case VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE: + syscfg->rate_adapt = AQR_RATE_ADAPT_PAUSE; + break; + default: + phydev_warn(phydev, "unrecognized rate adapt mode %u\n", + rate_adapt); + break; + } + } + + return 0; +} + +static int aqr_gen2_fill_interface_modes(struct phy_device *phydev) +{ + unsigned long *possible = phydev->possible_interfaces; + struct aqr107_priv *priv = phydev->priv; + phy_interface_t interface; + int i, val, ret; + + /* It's been observed on some models that - when coming out of suspend + * - the FW signals that the PHY is ready but the GLOBAL_CFG registers + * continue on returning zeroes for some time. Let's poll the 100M + * register until it returns a real value as both 113c and 115c support + * this mode. + */ + if (priv->wait_on_global_cfg) { + ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, + VEND1_GLOBAL_CFG_100M, val, + val != 0, 1000, 100000, false); + if (ret) + return ret; + } + + ret = aqr_gen2_read_global_syscfg(phydev); + if (ret) + return ret; + + for (i = 0; i < AQR_NUM_GLOBAL_CFG; i++) { + interface = priv->global_cfg[i].interface; if (interface != PHY_INTERFACE_MODE_NA) __set_bit(interface, possible); } -- 2.34.1