From c6365855a6d9aef3b75e301d26872bc51398c2f3 Mon Sep 17 00:00:00 2001 From: Ioana Radulescu Date: Thu, 18 Oct 2018 18:59:41 +0300 Subject: [PATCH] dpaa2-eth: Add autoneg support For MC versions that support it, use the new DPNI link APIs, which allow setting/getting of advertised and supported link modes. A mapping between DPNI link modes and ethtool ones is created to help converting from one to the other. Signed-off-by: Ioana Radulescu Signed-off-by: Valentin Catalin Neacsu --- drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 8 ++- drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h | 3 ++ .../net/ethernet/freescale/dpaa2/dpaa2-ethtool.c | 57 ++++++++++++++++++++-- 3 files changed, 62 insertions(+), 6 deletions(-) --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -1357,7 +1357,13 @@ static int link_state_update(struct dpaa bool tx_pause; int err; - err = dpni_get_link_state(priv->mc_io, 0, priv->mc_token, &state); + if (dpaa2_eth_cmp_dpni_ver(priv, DPNI_LINK_AUTONEG_VER_MAJOR, + DPNI_LINK_AUTONEG_VER_MINOR) < 0) + err = dpni_get_link_state(priv->mc_io, 0, priv->mc_token, + &state); + else + err = dpni_get_link_state_v2(priv->mc_io, 0, priv->mc_token, + &state); if (unlikely(err)) { netdev_err(priv->net_dev, "dpni_get_link_state() failed\n"); --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h @@ -543,6 +543,9 @@ static inline bool dpaa2_eth_rx_pause_en return !!(link_options & DPNI_LINK_OPT_PAUSE); } +#define DPNI_LINK_AUTONEG_VER_MAJOR 7 +#define DPNI_LINK_AUTONEG_VER_MINOR 8 + static inline unsigned int dpaa2_eth_needed_headroom(struct dpaa2_eth_priv *priv, struct sk_buff *skb) --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c @@ -79,6 +79,41 @@ static void dpaa2_eth_get_drvinfo(struct sizeof(drvinfo->bus_info)); } +struct dpaa2_eth_link_mode_map { + u64 dpni_lm; + u64 ethtool_lm; +}; + +static const struct dpaa2_eth_link_mode_map dpaa2_eth_lm_map[] = { + {DPNI_ADVERTISED_10BASET_FULL, ETHTOOL_LINK_MODE_10baseT_Full_BIT}, + {DPNI_ADVERTISED_100BASET_FULL, ETHTOOL_LINK_MODE_100baseT_Full_BIT}, + {DPNI_ADVERTISED_1000BASET_FULL, ETHTOOL_LINK_MODE_1000baseT_Full_BIT}, + {DPNI_ADVERTISED_10000BASET_FULL, ETHTOOL_LINK_MODE_10000baseT_Full_BIT}, + {DPNI_ADVERTISED_2500BASEX_FULL, ETHTOOL_LINK_MODE_2500baseT_Full_BIT}, + {DPNI_ADVERTISED_AUTONEG, ETHTOOL_LINK_MODE_Autoneg_BIT}, +}; + +static void link_mode_dpni2ethtool(u64 dpni_lm, unsigned long *ethtool_lm) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dpaa2_eth_lm_map); i++) { + if (dpni_lm & dpaa2_eth_lm_map[i].dpni_lm) + __set_bit(dpaa2_eth_lm_map[i].ethtool_lm, ethtool_lm); + } +} + +static void link_mode_ethtool2dpni(const unsigned long *ethtool_lm, + u64 *dpni_lm) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dpaa2_eth_lm_map); i++) { + if (test_bit(dpaa2_eth_lm_map[i].ethtool_lm, ethtool_lm)) + *dpni_lm |= dpaa2_eth_lm_map[i].dpni_lm; + } +} + static int dpaa2_eth_get_link_ksettings(struct net_device *net_dev, struct ethtool_link_ksettings *link_settings) @@ -91,6 +126,14 @@ dpaa2_eth_get_link_ksettings(struct net_ link_settings->base.duplex = DUPLEX_FULL; link_settings->base.speed = priv->link_state.rate; + if (dpaa2_eth_cmp_dpni_ver(priv, DPNI_LINK_AUTONEG_VER_MAJOR, + DPNI_LINK_AUTONEG_VER_MINOR) >= 0) { + link_mode_dpni2ethtool(priv->link_state.supported, + link_settings->link_modes.supported); + link_mode_dpni2ethtool(priv->link_state.advertising, + link_settings->link_modes.advertising); + } + return 0; } @@ -127,12 +170,16 @@ dpaa2_eth_set_link_ksettings(struct net_ else cfg.options &= ~DPNI_LINK_OPT_HALF_DUPLEX; - err = dpni_set_link_cfg(priv->mc_io, 0, priv->mc_token, &cfg); + if (dpaa2_eth_cmp_dpni_ver(priv, DPNI_LINK_AUTONEG_VER_MAJOR, + DPNI_LINK_AUTONEG_VER_MINOR) < 0) { + err = dpni_set_link_cfg(priv->mc_io, 0, priv->mc_token, &cfg); + } else { + link_mode_ethtool2dpni(link_settings->link_modes.advertising, + &cfg.advertising); + dpni_set_link_cfg_v2(priv->mc_io, 0, priv->mc_token, &cfg); + } if (err) - /* ethtool will be loud enough if we return an error; no point - * in putting our own error message on the console by default - */ - netdev_dbg(net_dev, "ERROR %d setting link cfg\n", err); + netdev_err(net_dev, "dpni_set_link_cfg failed"); return err; }