nfp: add support for .set_link_ksettings()
authorJakub Kicinski <jakub.kicinski@netronome.com>
Tue, 4 Apr 2017 23:12:35 +0000 (16:12 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 5 Apr 2017 17:49:12 +0000 (10:49 -0700)
Support setting link speed and autonegotiation through
set_link_ksettings() ethtool op.  If the port is reconfigured
in incompatible way and reboot is required the netdev will get
unregistered and not come back until user reboots the system.

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Simon Horman <simon.horman@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c

index 963d6dd97cec84daaa774525dbe7b456c765e9c5..3328041ec290915866160f90a228b9a33dac0605 100644 (file)
@@ -237,6 +237,51 @@ nfp_net_get_link_ksettings(struct net_device *netdev,
        return 0;
 }
 
+static int
+nfp_net_set_link_ksettings(struct net_device *netdev,
+                          const struct ethtool_link_ksettings *cmd)
+{
+       struct nfp_net *nn = netdev_priv(netdev);
+       struct nfp_nsp *nsp;
+       int err;
+
+       if (!nn->eth_port)
+               return -EOPNOTSUPP;
+
+       if (netif_running(netdev)) {
+               nn_warn(nn, "Changing settings not allowed on an active interface. It may cause the port to be disabled until reboot.\n");
+               return -EBUSY;
+       }
+
+       nsp = nfp_eth_config_start(nn->cpp, nn->eth_port->index);
+       if (IS_ERR(nsp))
+               return PTR_ERR(nsp);
+
+       err = __nfp_eth_set_aneg(nsp, cmd->base.autoneg == AUTONEG_ENABLE ?
+                                NFP_ANEG_AUTO : NFP_ANEG_DISABLED);
+       if (err)
+               goto err_bad_set;
+       if (cmd->base.speed != SPEED_UNKNOWN) {
+               u32 speed = cmd->base.speed / nn->eth_port->lanes;
+
+               err = __nfp_eth_set_speed(nsp, speed);
+               if (err)
+                       goto err_bad_set;
+       }
+
+       err = nfp_eth_config_commit_end(nsp);
+       if (err > 0)
+               return 0; /* no change */
+
+       nfp_net_refresh_port_config(nn);
+
+       return err;
+
+err_bad_set:
+       nfp_eth_config_cleanup_end(nsp);
+       return err;
+}
+
 static void nfp_net_get_ringparam(struct net_device *netdev,
                                  struct ethtool_ringparam *ring)
 {
@@ -879,6 +924,7 @@ static const struct ethtool_ops nfp_net_ethtool_ops = {
        .get_channels           = nfp_net_get_channels,
        .set_channels           = nfp_net_set_channels,
        .get_link_ksettings     = nfp_net_get_link_ksettings,
+       .set_link_ksettings     = nfp_net_set_link_ksettings,
 };
 
 void nfp_net_set_ethtool_ops(struct net_device *netdev)