lkml.org 
[lkml]   [2023]   [Feb]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH net-next v5 11/23] net: phy: at803x: implement ethtool access to SmartEEE functionality
    Date
    If AR8035 PHY is used with a MAC without EEE support
    (iMX6, etc), then we need to process ethtool_eee::tx_lpi_timer and
    tx_lpi_enabled by the PHY driver. So, add get/set_eee support for this
    functionality.

    Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
    ---
    drivers/net/phy/at803x.c | 109 +++++++++++++++++++++++++++++++++++++--
    1 file changed, 104 insertions(+), 5 deletions(-)

    diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
    index 22f4458274aa..9eb4439b0afc 100644
    --- a/drivers/net/phy/at803x.c
    +++ b/drivers/net/phy/at803x.c
    @@ -166,8 +166,18 @@

    #define AT803X_MMD3_SMARTEEE_CTL1 0x805b
    #define AT803X_MMD3_SMARTEEE_CTL2 0x805c
    +#define AT803X_MMD3_SMARTEEE_LPI_TIME_LOW GENMASK(15, 0)
    +#define AT803X_MMD3_SMARTEEE_LPI_TIME_15_0 GENMASK(15, 0)
    #define AT803X_MMD3_SMARTEEE_CTL3 0x805d
    #define AT803X_MMD3_SMARTEEE_CTL3_LPI_EN BIT(8)
    +#define AT803X_MMD3_SMARTEEE_LPI_TIME_HIGH GENMASK(7, 0)
    +#define AT803X_MMD3_SMARTEEE_LPI_TIME_23_16 GENMASK(23, 16)
    +/* Tx LPI timer resolution */
    +#define AT803X_MMD3_SMARTEEE_LPI_TIME_RESOL_NS 163840
    +#define AT803X_MMD3_SMARTEEE_LPI_TIME_MAX_US \
    + ((GENMASK(23, 0) * AT803X_MMD3_SMARTEEE_LPI_TIME_RESOL_NS) / \
    + NSEC_PER_USEC)
    +#define AT803X_MMD3_SMARTEEE_LPI_TIME_DEF_US 335544

    #define ATH9331_PHY_ID 0x004dd041
    #define ATH8030_PHY_ID 0x004dd076
    @@ -951,17 +961,26 @@ static int at803x_get_features(struct phy_device *phydev)
    return 0;
    }

    -static int at803x_smarteee_config(struct phy_device *phydev)
    +static int at803x_smarteee_config(struct phy_device *phydev, bool enable,
    + u32 tx_lpi_timer_us)
    {
    struct at803x_priv *priv = phydev->priv;
    + u64 tx_lpi_timer_raw;
    + u64 tx_lpi_timer_ns;
    u16 mask = 0, val = 0;
    int ret;

    - if (priv->flags & AT803X_DISABLE_SMARTEEE)
    + if (priv->flags & AT803X_DISABLE_SMARTEEE || !enable)
    return phy_modify_mmd(phydev, MDIO_MMD_PCS,
    AT803X_MMD3_SMARTEEE_CTL3,
    AT803X_MMD3_SMARTEEE_CTL3_LPI_EN, 0);

    + if (tx_lpi_timer_us > AT803X_MMD3_SMARTEEE_LPI_TIME_MAX_US) {
    + phydev_err(phydev, "Max LPI timer is %lu microsecs\n",
    + AT803X_MMD3_SMARTEEE_LPI_TIME_MAX_US);
    + return -EINVAL;
    + }
    +
    if (priv->smarteee_lpi_tw_1g) {
    mask |= 0xff00;
    val |= priv->smarteee_lpi_tw_1g << 8;
    @@ -978,9 +997,27 @@ static int at803x_smarteee_config(struct phy_device *phydev)
    if (ret)
    return ret;

    + tx_lpi_timer_ns = tx_lpi_timer_us * NSEC_PER_USEC;
    + tx_lpi_timer_raw =
    + DIV_ROUND_CLOSEST_ULL(tx_lpi_timer_ns,
    + AT803X_MMD3_SMARTEEE_LPI_TIME_RESOL_NS);
    + val = FIELD_PREP(AT803X_MMD3_SMARTEEE_LPI_TIME_LOW,
    + FIELD_GET(AT803X_MMD3_SMARTEEE_LPI_TIME_15_0,
    + tx_lpi_timer_raw));
    +
    + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, AT803X_MMD3_SMARTEEE_CTL2,
    + val);
    + if (ret)
    + return ret;
    +
    + val = AT803X_MMD3_SMARTEEE_CTL3_LPI_EN |
    + FIELD_PREP(AT803X_MMD3_SMARTEEE_LPI_TIME_HIGH,
    + FIELD_GET(AT803X_MMD3_SMARTEEE_LPI_TIME_23_16,
    + tx_lpi_timer_raw));
    +
    return phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_MMD3_SMARTEEE_CTL3,
    - AT803X_MMD3_SMARTEEE_CTL3_LPI_EN,
    - AT803X_MMD3_SMARTEEE_CTL3_LPI_EN);
    + AT803X_MMD3_SMARTEEE_CTL3_LPI_EN |
    + AT803X_MMD3_SMARTEEE_LPI_TIME_HIGH, val);
    }

    static int at803x_clk_out_config(struct phy_device *phydev)
    @@ -1067,7 +1104,8 @@ static int at803x_config_init(struct phy_device *phydev)
    if (ret < 0)
    return ret;

    - ret = at803x_smarteee_config(phydev);
    + ret = at803x_smarteee_config(phydev, true,
    + AT803X_MMD3_SMARTEEE_LPI_TIME_DEF_US);
    if (ret < 0)
    return ret;

    @@ -1612,6 +1650,65 @@ static int at803x_cable_test_start(struct phy_device *phydev)
    return 0;
    }

    +static int at803x_get_eee(struct phy_device *phydev, struct ethtool_eee *data)
    +{
    + struct at803x_priv *priv = phydev->priv;
    + u32 tx_timer_raw;
    + u64 tx_timer_ns;
    + int ret;
    +
    + /* If SmartEEE is not enabled, it is expected that tx_lpi_* fields
    + * are processed by the MAC driver.
    + */
    + if (priv->flags & AT803X_DISABLE_SMARTEEE)
    + return genphy_c45_ethtool_get_eee(phydev, data);
    +
    + ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
    + AT803X_MMD3_SMARTEEE_CTL2);
    + tx_timer_raw = FIELD_PREP(AT803X_MMD3_SMARTEEE_LPI_TIME_15_0,
    + FIELD_GET(AT803X_MMD3_SMARTEEE_LPI_TIME_LOW,
    + ret));
    + if (ret < 0)
    + return ret;
    +
    + ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
    + AT803X_MMD3_SMARTEEE_CTL3);
    + if (ret < 0)
    + return ret;
    +
    + tx_timer_raw |= FIELD_PREP(AT803X_MMD3_SMARTEEE_LPI_TIME_23_16,
    + FIELD_GET(AT803X_MMD3_SMARTEEE_LPI_TIME_HIGH,
    + ret));
    + tx_timer_ns = tx_timer_raw * AT803X_MMD3_SMARTEEE_LPI_TIME_RESOL_NS;
    + data->tx_lpi_timer = DIV_ROUND_CLOSEST_ULL(tx_timer_ns, NSEC_PER_USEC);
    +
    + data->tx_lpi_enabled = !!(ret & AT803X_MMD3_SMARTEEE_CTL3_LPI_EN);
    +
    + return genphy_c45_ethtool_get_eee(phydev, data);
    +}
    +
    +static int at803x_set_eee(struct phy_device *phydev, struct ethtool_eee *data)
    +{
    + struct at803x_priv *priv = phydev->priv;
    + int ret;
    +
    + /* If SmartEEE is not enabled, it is expected that tx_lpi_* fields
    + * are processed by the MAC driver.
    + */
    + if (priv->flags & AT803X_DISABLE_SMARTEEE)
    + return genphy_c45_ethtool_set_eee(phydev, data);
    +
    + /* Changing Tx LPI on/off or Tx LPI timer settings
    + * do not require link reset.
    + */
    + ret = at803x_smarteee_config(phydev, data->tx_lpi_enabled,
    + data->tx_lpi_timer);
    + if (ret)
    + return ret;
    +
    + return genphy_c45_ethtool_set_eee(phydev, data);
    +}
    +
    static int qca83xx_config_init(struct phy_device *phydev)
    {
    u8 switch_revision;
    @@ -2038,6 +2135,8 @@ static struct phy_driver at803x_driver[] = {
    .set_tunable = at803x_set_tunable,
    .cable_test_start = at803x_cable_test_start,
    .cable_test_get_status = at803x_cable_test_get_status,
    + .get_eee = at803x_get_eee,
    + .set_eee = at803x_set_eee,
    }, {
    /* Qualcomm Atheros AR8030 */
    .phy_id = ATH8030_PHY_ID,
    --
    2.30.2
    \
     
     \ /
      Last update: 2023-03-27 00:11    [W:4.044 / U:0.912 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site