Commit 8d545385 authored by Yinjun Zhang's avatar Yinjun Zhang Committed by Jakub Kicinski

nfp: add support for link auto negotiation

Report the auto negotiation capability if it's supported
in management firmware, and advertise it if it's enabled.
Changing port speed is not allowed when autoneg is enabled.

The ethtool <intf> command displays the auto-neg capability:

  # ethtool enp1s0np0
  Settings for enp1s0np0:
          Supported ports: [ FIBRE ]
          Supported link modes:   Not reported
          Supported pause frame use: Symmetric
          Supports auto-negotiation: Yes
          Supported FEC modes: None        RS      BASER
          Advertised link modes:  Not reported
          Advertised pause frame use: Symmetric
          Advertised auto-negotiation: Yes
          Advertised FEC modes: None       RS      BASER
          Speed: 25000Mb/s
          Duplex: Full
          Auto-negotiation: on
          Port: FIBRE
          PHYAD: 0
          Transceiver: internal
          Link detected: yes
Signed-off-by: default avatarYinjun Zhang <yinjun.zhang@corigine.com>
Signed-off-by: default avatarSimon Horman <simon.horman@corigine.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent b1e4f11e
...@@ -729,8 +729,15 @@ static int nfp_pf_cfg_hwinfo(struct nfp_pf *pf, bool sp_indiff) ...@@ -729,8 +729,15 @@ static int nfp_pf_cfg_hwinfo(struct nfp_pf *pf, bool sp_indiff)
snprintf(hwinfo, sizeof(hwinfo), "sp_indiff=%d", sp_indiff); snprintf(hwinfo, sizeof(hwinfo), "sp_indiff=%d", sp_indiff);
err = nfp_nsp_hwinfo_set(nsp, hwinfo, sizeof(hwinfo)); err = nfp_nsp_hwinfo_set(nsp, hwinfo, sizeof(hwinfo));
/* Not a fatal error, no need to return error to stop driver from loading */ /* Not a fatal error, no need to return error to stop driver from loading */
if (err) if (err) {
nfp_warn(pf->cpp, "HWinfo(sp_indiff=%d) set failed: %d\n", sp_indiff, err); nfp_warn(pf->cpp, "HWinfo(sp_indiff=%d) set failed: %d\n", sp_indiff, err);
} else {
/* Need reinit eth_tbl since the eth table state may change
* after sp_indiff is configured.
*/
kfree(pf->eth_tbl);
pf->eth_tbl = __nfp_eth_read_ports(pf->cpp, nsp);
}
nfp_nsp_close(nsp); nfp_nsp_close(nsp);
return 0; return 0;
......
...@@ -290,8 +290,13 @@ nfp_net_get_link_ksettings(struct net_device *netdev, ...@@ -290,8 +290,13 @@ nfp_net_get_link_ksettings(struct net_device *netdev,
if (eth_port) { if (eth_port) {
ethtool_link_ksettings_add_link_mode(cmd, supported, Pause); ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);
ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause); ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause);
cmd->base.autoneg = eth_port->aneg != NFP_ANEG_DISABLED ? if (eth_port->supp_aneg) {
AUTONEG_ENABLE : AUTONEG_DISABLE; ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
if (eth_port->aneg == NFP_ANEG_AUTO) {
ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);
cmd->base.autoneg = AUTONEG_ENABLE;
}
}
nfp_net_set_fec_link_mode(eth_port, cmd); nfp_net_set_fec_link_mode(eth_port, cmd);
} }
...@@ -327,6 +332,7 @@ static int ...@@ -327,6 +332,7 @@ static int
nfp_net_set_link_ksettings(struct net_device *netdev, nfp_net_set_link_ksettings(struct net_device *netdev,
const struct ethtool_link_ksettings *cmd) const struct ethtool_link_ksettings *cmd)
{ {
bool req_aneg = (cmd->base.autoneg == AUTONEG_ENABLE);
struct nfp_eth_table_port *eth_port; struct nfp_eth_table_port *eth_port;
struct nfp_port *port; struct nfp_port *port;
struct nfp_nsp *nsp; struct nfp_nsp *nsp;
...@@ -346,13 +352,25 @@ nfp_net_set_link_ksettings(struct net_device *netdev, ...@@ -346,13 +352,25 @@ nfp_net_set_link_ksettings(struct net_device *netdev,
if (IS_ERR(nsp)) if (IS_ERR(nsp))
return PTR_ERR(nsp); return PTR_ERR(nsp);
err = __nfp_eth_set_aneg(nsp, cmd->base.autoneg == AUTONEG_ENABLE ? if (req_aneg && !eth_port->supp_aneg) {
NFP_ANEG_AUTO : NFP_ANEG_DISABLED); netdev_warn(netdev, "Autoneg is not supported.\n");
err = -EOPNOTSUPP;
goto err_bad_set;
}
err = __nfp_eth_set_aneg(nsp, req_aneg ? NFP_ANEG_AUTO : NFP_ANEG_DISABLED);
if (err) if (err)
goto err_bad_set; goto err_bad_set;
if (cmd->base.speed != SPEED_UNKNOWN) { if (cmd->base.speed != SPEED_UNKNOWN) {
u32 speed = cmd->base.speed / eth_port->lanes; u32 speed = cmd->base.speed / eth_port->lanes;
if (req_aneg) {
netdev_err(netdev, "Speed changing is not allowed when working on autoneg mode.\n");
err = -EINVAL;
goto err_bad_set;
}
err = __nfp_eth_set_speed(nsp, speed); err = __nfp_eth_set_speed(nsp, speed);
if (err) if (err)
goto err_bad_set; goto err_bad_set;
......
...@@ -174,6 +174,7 @@ struct nfp_eth_table { ...@@ -174,6 +174,7 @@ struct nfp_eth_table {
bool enabled; bool enabled;
bool tx_enabled; bool tx_enabled;
bool rx_enabled; bool rx_enabled;
bool supp_aneg;
bool override_changed; bool override_changed;
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#define NSP_ETH_PORT_PHYLABEL GENMASK_ULL(59, 54) #define NSP_ETH_PORT_PHYLABEL GENMASK_ULL(59, 54)
#define NSP_ETH_PORT_FEC_SUPP_BASER BIT_ULL(60) #define NSP_ETH_PORT_FEC_SUPP_BASER BIT_ULL(60)
#define NSP_ETH_PORT_FEC_SUPP_RS BIT_ULL(61) #define NSP_ETH_PORT_FEC_SUPP_RS BIT_ULL(61)
#define NSP_ETH_PORT_SUPP_ANEG BIT_ULL(63)
#define NSP_ETH_PORT_LANES_MASK cpu_to_le64(NSP_ETH_PORT_LANES) #define NSP_ETH_PORT_LANES_MASK cpu_to_le64(NSP_ETH_PORT_LANES)
...@@ -178,6 +179,7 @@ nfp_eth_port_translate(struct nfp_nsp *nsp, const union eth_table_entry *src, ...@@ -178,6 +179,7 @@ nfp_eth_port_translate(struct nfp_nsp *nsp, const union eth_table_entry *src,
return; return;
dst->act_fec = FIELD_GET(NSP_ETH_STATE_ACT_FEC, state); dst->act_fec = FIELD_GET(NSP_ETH_STATE_ACT_FEC, state);
dst->supp_aneg = FIELD_GET(NSP_ETH_PORT_SUPP_ANEG, port);
} }
static void static void
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment