Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bfe26ba9 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'nfp-ethtool-and-related-improvements'



Simon Horman says:

====================
nfp: ethtool and related improvements

Dirk van der Merwe says:

This patch series throws a couple of loosely related items into a single
series.

Patch 1: Clang compilation fix reported by
  Matthias Kaehlcke <mka@chromium.org>

Patch 2: Driver can now do MAC reinit on load when there has been a
  media override set in the NSP.

Patch 3: Refactor the nfp_app_reprs_set API.

Patch 4: Similar to vNICs, representors must be able to deal with media
  override changes in the NSP.

Patch 5: Since representors can now handle media overrides, we can
  allocate the get/set link ndo's to them.

Patch 6 & 7: Add support for FEC mode modification.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1f255691 0d087093
Loading
Loading
Loading
Loading
+4 −12
Original line number Diff line number Diff line
@@ -142,8 +142,8 @@ nfp_flower_spawn_vnic_reprs(struct nfp_app *app,
{
	u8 nfp_pcie = nfp_cppcore_pcie_unit(app->pf->cpp);
	struct nfp_flower_priv *priv = app->priv;
	struct nfp_reprs *reprs, *old_reprs;
	enum nfp_port_type port_type;
	struct nfp_reprs *reprs;
	const u8 queue = 0;
	int i, err;

@@ -194,11 +194,7 @@ nfp_flower_spawn_vnic_reprs(struct nfp_app *app,
			 reprs->reprs[i]->name);
	}

	old_reprs = nfp_app_reprs_set(app, repr_type, reprs);
	if (IS_ERR(old_reprs)) {
		err = PTR_ERR(old_reprs);
		goto err_reprs_clean;
	}
	nfp_app_reprs_set(app, repr_type, reprs);

	return 0;
err_reprs_clean:
@@ -222,8 +218,8 @@ static int
nfp_flower_spawn_phy_reprs(struct nfp_app *app, struct nfp_flower_priv *priv)
{
	struct nfp_eth_table *eth_tbl = app->pf->eth_tbl;
	struct nfp_reprs *reprs, *old_reprs;
	struct sk_buff *ctrl_skb;
	struct nfp_reprs *reprs;
	unsigned int i;
	int err;

@@ -280,11 +276,7 @@ nfp_flower_spawn_phy_reprs(struct nfp_app *app, struct nfp_flower_priv *priv)
			 phys_port, reprs->reprs[phys_port]->name);
	}

	old_reprs = nfp_app_reprs_set(app, NFP_REPR_TYPE_PHYS_PORT, reprs);
	if (IS_ERR(old_reprs)) {
		err = PTR_ERR(old_reprs);
		goto err_reprs_clean;
	}
	nfp_app_reprs_set(app, NFP_REPR_TYPE_PHYS_PORT, reprs);

	/* The MAC_REPR control message should be sent after the MAC
	 * representors are registered using nfp_app_reprs_set().  This is
+0 −6
Original line number Diff line number Diff line
@@ -106,14 +106,8 @@ nfp_app_reprs_set(struct nfp_app *app, enum nfp_repr_type type,

	old = rcu_dereference_protected(app->reprs[type],
					lockdep_is_held(&app->pf->lock));
	if (reprs && old) {
		old = ERR_PTR(-EBUSY);
		goto exit_unlock;
	}

	rcu_assign_pointer(app->reprs[type], reprs);

exit_unlock:
	return old;
}

+27 −1
Original line number Diff line number Diff line
@@ -346,6 +346,32 @@ nfp_fw_load(struct pci_dev *pdev, struct nfp_pf *pf, struct nfp_nsp *nsp)
	return err < 0 ? err : 1;
}

static void
nfp_nsp_init_ports(struct pci_dev *pdev, struct nfp_pf *pf,
		   struct nfp_nsp *nsp)
{
	bool needs_reinit = false;
	int i;

	pf->eth_tbl = __nfp_eth_read_ports(pf->cpp, nsp);
	if (!pf->eth_tbl)
		return;

	if (!nfp_nsp_has_mac_reinit(nsp))
		return;

	for (i = 0; i < pf->eth_tbl->count; i++)
		needs_reinit |= pf->eth_tbl->ports[i].override_changed;
	if (!needs_reinit)
		return;

	kfree(pf->eth_tbl);
	if (nfp_nsp_mac_reinit(nsp))
		dev_warn(&pdev->dev, "MAC reinit failed\n");

	pf->eth_tbl = __nfp_eth_read_ports(pf->cpp, nsp);
}

static int nfp_nsp_init(struct pci_dev *pdev, struct nfp_pf *pf)
{
	struct nfp_nsp *nsp;
@@ -366,7 +392,7 @@ static int nfp_nsp_init(struct pci_dev *pdev, struct nfp_pf *pf)
	if (err < 0)
		goto exit_close_nsp;

	pf->eth_tbl = __nfp_eth_read_ports(pf->cpp, nsp);
	nfp_nsp_init_ports(pdev, pf, nsp);

	pf->nspi = __nfp_nsp_identify(nsp);
	if (pf->nspi)
+119 −2
Original line number Diff line number Diff line
@@ -244,6 +244,30 @@ nfp_app_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
	nfp_get_drvinfo(app, app->pdev, "*", drvinfo);
}

static void
nfp_net_set_fec_link_mode(struct nfp_eth_table_port *eth_port,
			  struct ethtool_link_ksettings *c)
{
	unsigned int modes;

	ethtool_link_ksettings_add_link_mode(c, supported, FEC_NONE);
	if (!nfp_eth_can_support_fec(eth_port)) {
		ethtool_link_ksettings_add_link_mode(c, advertising, FEC_NONE);
		return;
	}

	modes = nfp_eth_supported_fec_modes(eth_port);
	if (modes & NFP_FEC_BASER) {
		ethtool_link_ksettings_add_link_mode(c, supported, FEC_BASER);
		ethtool_link_ksettings_add_link_mode(c, advertising, FEC_BASER);
	}

	if (modes & NFP_FEC_REED_SOLOMON) {
		ethtool_link_ksettings_add_link_mode(c, supported, FEC_RS);
		ethtool_link_ksettings_add_link_mode(c, advertising, FEC_RS);
	}
}

/**
 * nfp_net_get_link_ksettings - Get Link Speed settings
 * @netdev:	network interface device structure
@@ -278,9 +302,11 @@ nfp_net_get_link_ksettings(struct net_device *netdev,

	port = nfp_port_from_netdev(netdev);
	eth_port = nfp_port_get_eth_port(port);
	if (eth_port)
	if (eth_port) {
		cmd->base.autoneg = eth_port->aneg != NFP_ANEG_DISABLED ?
			AUTONEG_ENABLE : AUTONEG_DISABLE;
		nfp_net_set_fec_link_mode(eth_port, cmd);
	}

	if (!netif_carrier_ok(netdev))
		return 0;
@@ -328,7 +354,7 @@ nfp_net_set_link_ksettings(struct net_device *netdev,
		return -EOPNOTSUPP;

	if (netif_running(netdev)) {
		netdev_warn(netdev, "Changing settings not allowed on an active interface. It may cause the port to be disabled until reboot.\n");
		netdev_warn(netdev, "Changing settings not allowed on an active interface. It may cause the port to be disabled until driver reload.\n");
		return -EBUSY;
	}

@@ -686,6 +712,91 @@ static int nfp_port_get_sset_count(struct net_device *netdev, int sset)
	}
}

static int nfp_port_fec_ethtool_to_nsp(u32 fec)
{
	switch (fec) {
	case ETHTOOL_FEC_AUTO:
		return NFP_FEC_AUTO_BIT;
	case ETHTOOL_FEC_OFF:
		return NFP_FEC_DISABLED_BIT;
	case ETHTOOL_FEC_RS:
		return NFP_FEC_REED_SOLOMON_BIT;
	case ETHTOOL_FEC_BASER:
		return NFP_FEC_BASER_BIT;
	default:
		/* NSP only supports a single mode at a time */
		return -EOPNOTSUPP;
	}
}

static u32 nfp_port_fec_nsp_to_ethtool(u32 fec)
{
	u32 result = 0;

	if (fec & NFP_FEC_AUTO)
		result |= ETHTOOL_FEC_AUTO;
	if (fec & NFP_FEC_BASER)
		result |= ETHTOOL_FEC_BASER;
	if (fec & NFP_FEC_REED_SOLOMON)
		result |= ETHTOOL_FEC_RS;
	if (fec & NFP_FEC_DISABLED)
		result |= ETHTOOL_FEC_OFF;

	return result ?: ETHTOOL_FEC_NONE;
}

static int
nfp_port_get_fecparam(struct net_device *netdev,
		      struct ethtool_fecparam *param)
{
	struct nfp_eth_table_port *eth_port;
	struct nfp_port *port;

	param->active_fec = ETHTOOL_FEC_NONE_BIT;
	param->fec = ETHTOOL_FEC_NONE_BIT;

	port = nfp_port_from_netdev(netdev);
	eth_port = nfp_port_get_eth_port(port);
	if (!eth_port)
		return -EOPNOTSUPP;

	if (!nfp_eth_can_support_fec(eth_port))
		return 0;

	param->fec = nfp_port_fec_nsp_to_ethtool(eth_port->fec_modes_supported);
	param->active_fec = nfp_port_fec_nsp_to_ethtool(eth_port->fec);

	return 0;
}

static int
nfp_port_set_fecparam(struct net_device *netdev,
		      struct ethtool_fecparam *param)
{
	struct nfp_eth_table_port *eth_port;
	struct nfp_port *port;
	int err, fec;

	port = nfp_port_from_netdev(netdev);
	eth_port = nfp_port_get_eth_port(port);
	if (!eth_port)
		return -EOPNOTSUPP;

	if (!nfp_eth_can_support_fec(eth_port))
		return -EOPNOTSUPP;

	fec = nfp_port_fec_ethtool_to_nsp(param->fec);
	if (fec < 0)
		return fec;

	err = nfp_eth_set_fec(port->app->cpp, eth_port->index, fec);
	if (!err)
		/* Only refresh if we did something */
		nfp_net_refresh_port_table(port);

	return err < 0 ? err : 0;
}

/* RX network flow classification (RSS, filters, etc)
 */
static u32 ethtool_flow_to_nfp_flag(u32 flow_type)
@@ -1144,6 +1255,8 @@ static const struct ethtool_ops nfp_net_ethtool_ops = {
	.set_channels		= nfp_net_set_channels,
	.get_link_ksettings	= nfp_net_get_link_ksettings,
	.set_link_ksettings	= nfp_net_set_link_ksettings,
	.get_fecparam		= nfp_port_get_fecparam,
	.set_fecparam		= nfp_port_set_fecparam,
};

const struct ethtool_ops nfp_port_ethtool_ops = {
@@ -1155,6 +1268,10 @@ const struct ethtool_ops nfp_port_ethtool_ops = {
	.set_dump		= nfp_app_set_dump,
	.get_dump_flag		= nfp_app_get_dump_flag,
	.get_dump_data		= nfp_app_get_dump_data,
	.get_link_ksettings	= nfp_net_get_link_ksettings,
	.set_link_ksettings	= nfp_net_set_link_ksettings,
	.get_fecparam		= nfp_port_get_fecparam,
	.set_fecparam		= nfp_port_set_fecparam,
};

void nfp_net_set_ethtool_ops(struct net_device *netdev)
+7 −1
Original line number Diff line number Diff line
@@ -597,7 +597,7 @@ nfp_net_eth_port_update(struct nfp_cpp *cpp, struct nfp_port *port,
		return -EIO;
	}
	if (eth_port->override_changed) {
		nfp_warn(cpp, "Port #%d config changed, unregistering. Reboot required before port will be operational again.\n", port->eth_id);
		nfp_warn(cpp, "Port #%d config changed, unregistering. Driver reload required before port will be operational again.\n", port->eth_id);
		port->type = NFP_PORT_INVALID;
	}

@@ -611,6 +611,7 @@ int nfp_net_refresh_port_table_sync(struct nfp_pf *pf)
	struct nfp_eth_table *eth_table;
	struct nfp_net *nn, *next;
	struct nfp_port *port;
	int err;

	lockdep_assert_held(&pf->lock);

@@ -640,6 +641,11 @@ int nfp_net_refresh_port_table_sync(struct nfp_pf *pf)

	kfree(eth_table);

	/* Resync repr state. This may cause reprs to be removed. */
	err = nfp_reprs_resync_phys_ports(pf->app);
	if (err)
		return err;

	/* Shoot off the ports which became invalid */
	list_for_each_entry_safe(nn, next, &pf->vnics, vnic_list) {
		if (!nn->port || nn->port->type != NFP_PORT_INVALID)
Loading