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

Commit eb488c26 authored by Jakub Kicinski's avatar Jakub Kicinski Committed by David S. Miller
Browse files

nfp: introduce nfp_port



Encapsulate port information into struct nfp_port.  nfp_port will
soon be extended to contain devlink_port information.  It also makes
it easier to reuse port-related code between vNICs and representors.

Signed-off-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: default avatarSimon Horman <simon.horman@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d88b0a23
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -20,7 +20,8 @@ nfp-objs := \
	    nfp_net_ethtool.o \
	    nfp_net_offload.o \
	    nfp_net_main.o \
	    nfp_netvf_main.o
	    nfp_netvf_main.o \
	    nfp_port.o

ifeq ($(CONFIG_BPF_SYSCALL),y)
nfp-objs += \
+10 −4
Original line number Diff line number Diff line
@@ -116,6 +116,7 @@ struct nfp_cpp;
struct nfp_eth_table_port;
struct nfp_net;
struct nfp_net_r_vector;
struct nfp_port;

/* Convenience macro for wrapping descriptor index on ring size */
#define D_IDX(ring, idx)	((idx) & ((ring)->cnt - 1))
@@ -558,7 +559,7 @@ struct nfp_net_dp {
 * @vnic_list:		Entry on device vNIC list
 * @pdev:		Backpointer to PCI device
 * @app:		APP handle if available
 * @eth_port:		Translated ETH Table port entry
 * @port:		Pointer to nfp_port structure if vNIC is a port
 */
struct nfp_net {
	struct nfp_net_dp dp;
@@ -630,7 +631,7 @@ struct nfp_net {
	struct pci_dev *pdev;
	struct nfp_app *app;

	struct nfp_eth_table_port *eth_port;
	struct nfp_port *port;
};

/* Functions to read/write from/to a BAR
@@ -802,6 +803,13 @@ static inline u32 nfp_qcp_wr_ptr_read(u8 __iomem *q)
/* Globals */
extern const char nfp_driver_version[];

extern const struct net_device_ops nfp_net_netdev_ops;

static inline bool nfp_netdev_is_nfp_net(struct net_device *netdev)
{
	return netdev->netdev_ops == &nfp_net_netdev_ops;
}

/* Prototypes */
void nfp_net_get_fw_version(struct nfp_net_fw_version *fw_ver,
			    void __iomem *ctrl_bar);
@@ -835,8 +843,6 @@ int nfp_net_ring_reconfig(struct nfp_net *nn, struct nfp_net_dp *new,
			  struct netlink_ext_ack *extack);

bool nfp_net_link_changed_read_clear(struct nfp_net *nn);
int nfp_net_refresh_eth_port(struct nfp_net *nn);
void nfp_net_refresh_port_table(struct nfp_net *nn);

#ifdef CONFIG_NFP_DEBUG
void nfp_net_debugfs_create(void);
+3 −22
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@
#include "nfpcore/nfp_nsp.h"
#include "nfp_net_ctrl.h"
#include "nfp_net.h"
#include "nfp_port.h"

/**
 * nfp_net_get_fw_version() - Read and parse the FW version
@@ -2846,26 +2847,6 @@ nfp_net_features_check(struct sk_buff *skb, struct net_device *dev,
	return features;
}

static int
nfp_net_get_phys_port_name(struct net_device *netdev, char *name, size_t len)
{
	struct nfp_net *nn = netdev_priv(netdev);
	int err;

	if (!nn->eth_port)
		return -EOPNOTSUPP;

	if (!nn->eth_port->is_split)
		err = snprintf(name, len, "p%d", nn->eth_port->label_port);
	else
		err = snprintf(name, len, "p%ds%d", nn->eth_port->label_port,
			       nn->eth_port->label_subport);
	if (err >= len)
		return -EINVAL;

	return 0;
}

/**
 * nfp_net_set_vxlan_port() - set vxlan port in SW and reconfigure HW
 * @nn:   NFP Net device to reconfigure
@@ -3028,7 +3009,7 @@ static int nfp_net_xdp(struct net_device *netdev, struct netdev_xdp *xdp)
	}
}

static const struct net_device_ops nfp_net_netdev_ops = {
const struct net_device_ops nfp_net_netdev_ops = {
	.ndo_open		= nfp_net_netdev_open,
	.ndo_stop		= nfp_net_netdev_close,
	.ndo_start_xmit		= nfp_net_tx,
@@ -3040,7 +3021,7 @@ static const struct net_device_ops nfp_net_netdev_ops = {
	.ndo_set_mac_address	= eth_mac_addr,
	.ndo_set_features	= nfp_net_set_features,
	.ndo_features_check	= nfp_net_features_check,
	.ndo_get_phys_port_name	= nfp_net_get_phys_port_name,
	.ndo_get_phys_port_name	= nfp_port_get_phys_port_name,
	.ndo_udp_tunnel_add	= nfp_net_add_vxlan_port,
	.ndo_udp_tunnel_del	= nfp_net_del_vxlan_port,
	.ndo_xdp		= nfp_net_xdp,
+26 −13
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@
#include "nfp_app.h"
#include "nfp_net_ctrl.h"
#include "nfp_net.h"
#include "nfp_port.h"

enum nfp_dump_diag {
	NFP_DUMP_NSP_DIAG = 0,
@@ -196,33 +197,42 @@ nfp_net_get_link_ksettings(struct net_device *netdev,
		[NFP_NET_CFG_STS_LINK_RATE_50G]		= SPEED_50000,
		[NFP_NET_CFG_STS_LINK_RATE_100G]	= SPEED_100000,
	};
	struct nfp_net *nn = netdev_priv(netdev);
	struct nfp_eth_table_port *eth_port;
	struct nfp_port *port;
	struct nfp_net *nn;
	u32 sts, ls;

	/* Init to unknowns */
	ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
	cmd->base.port = PORT_OTHER;
	cmd->base.speed = SPEED_UNKNOWN;
	cmd->base.duplex = DUPLEX_UNKNOWN;

	if (nn->eth_port)
		cmd->base.autoneg = nn->eth_port->aneg != NFP_ANEG_DISABLED ?
	port = nfp_port_from_netdev(netdev);
	eth_port = __nfp_port_get_eth_port(port);
	if (eth_port)
		cmd->base.autoneg = eth_port->aneg != NFP_ANEG_DISABLED ?
			AUTONEG_ENABLE : AUTONEG_DISABLE;

	if (!netif_carrier_ok(netdev))
		return 0;

	if (!nfp_netdev_is_nfp_net(netdev))
		return -EOPNOTSUPP;
	nn = netdev_priv(netdev);

	/* Use link speed from ETH table if available, otherwise try the BAR */
	if (nn->eth_port) {
	if (eth_port) {
		int err;

		if (nfp_net_link_changed_read_clear(nn)) {
			err = nfp_net_refresh_eth_port(nn);
			err = nfp_net_refresh_eth_port(port);
			if (err)
				return err;
		}

		cmd->base.port = nn->eth_port->port_type;
		cmd->base.speed = nn->eth_port->speed;
		cmd->base.port = eth_port->port_type;
		cmd->base.speed = eth_port->speed;
		cmd->base.duplex = DUPLEX_FULL;
		return 0;
	}
@@ -247,19 +257,22 @@ 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_eth_table_port *eth_port;
	struct nfp_port *port;
	struct nfp_nsp *nsp;
	int err;

	if (!nn->eth_port)
	port = nfp_port_from_netdev(netdev);
	eth_port = __nfp_port_get_eth_port(port);
	if (!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");
		netdev_warn(netdev, "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->app->cpp, nn->eth_port->index);
	nsp = nfp_eth_config_start(port->app->cpp, eth_port->index);
	if (IS_ERR(nsp))
		return PTR_ERR(nsp);

@@ -268,7 +281,7 @@ nfp_net_set_link_ksettings(struct net_device *netdev,
	if (err)
		goto err_bad_set;
	if (cmd->base.speed != SPEED_UNKNOWN) {
		u32 speed = cmd->base.speed / nn->eth_port->lanes;
		u32 speed = cmd->base.speed / eth_port->lanes;

		err = __nfp_eth_set_speed(nsp, speed);
		if (err)
@@ -279,7 +292,7 @@ nfp_net_set_link_ksettings(struct net_device *netdev,
	if (err > 0)
		return 0; /* no change */

	nfp_net_refresh_port_table(nn);
	nfp_net_refresh_port_table(port);

	return err;

+45 −23
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@
#include "nfp_net_ctrl.h"
#include "nfp_net.h"
#include "nfp_main.h"
#include "nfp_port.h"

#define NFP_PF_CSR_SLICE_SIZE	(32 * 1024)

@@ -142,14 +143,16 @@ static u8 __iomem *nfp_net_map_area(struct nfp_cpp *cpp,
static void
nfp_net_get_mac_addr(struct nfp_net *nn, struct nfp_cpp *cpp, unsigned int id)
{
	struct nfp_eth_table_port *eth_port;
	struct nfp_net_dp *dp = &nn->dp;
	u8 mac_addr[ETH_ALEN];
	const char *mac_str;
	char name[32];

	if (nn->eth_port) {
		ether_addr_copy(dp->netdev->dev_addr, nn->eth_port->mac_addr);
		ether_addr_copy(dp->netdev->perm_addr, nn->eth_port->mac_addr);
	eth_port = __nfp_port_get_eth_port(nn->port);
	if (eth_port) {
		ether_addr_copy(dp->netdev->dev_addr, eth_port->mac_addr);
		ether_addr_copy(dp->netdev->perm_addr, eth_port->mac_addr);
		return;
	}

@@ -270,6 +273,7 @@ static u8 __iomem *nfp_net_pf_map_ctrl_bar(struct nfp_pf *pf)

static void nfp_net_pf_free_vnic(struct nfp_pf *pf, struct nfp_net *nn)
{
	nfp_port_free(nn->port);
	list_del(&nn->vnic_list);
	pf->num_vnics--;
	nfp_net_free(nn);
@@ -291,6 +295,7 @@ nfp_net_pf_alloc_vnic(struct nfp_pf *pf, void __iomem *ctrl_bar,
		      int stride, struct nfp_net_fw_version *fw_ver,
		      unsigned int eth_id)
{
	struct nfp_eth_table_port *eth_port;
	u32 n_tx_rings, n_rx_rings;
	struct nfp_net *nn;

@@ -310,7 +315,18 @@ nfp_net_pf_alloc_vnic(struct nfp_pf *pf, void __iomem *ctrl_bar,
	nn->dp.is_vf = 0;
	nn->stride_rx = stride;
	nn->stride_tx = stride;
	nn->eth_port = nfp_net_find_port(pf->eth_tbl, eth_id);

	eth_port = nfp_net_find_port(pf->eth_tbl, eth_id);
	if (eth_port) {
		nn->port = nfp_port_alloc(pf->app, NFP_PORT_PHYS_PORT,
					  nn->dp.netdev);
		if (IS_ERR(nn->port)) {
			nfp_net_free(nn);
			return ERR_CAST(nn->port);
		}
		nn->port->eth_id = eth_id;
		nn->port->eth_port = eth_port;
	}

	pf->num_vnics++;
	list_add_tail(&nn->vnic_list, &pf->vnics);
@@ -380,12 +396,12 @@ nfp_net_pf_alloc_vnics(struct nfp_pf *pf, void __iomem *ctrl_bar,
		ctrl_bar += NFP_PF_CSR_SLICE_SIZE;

		/* Check if vNIC has external port associated and cfg is OK */
		if (pf->eth_tbl && !nn->eth_port) {
		if (pf->eth_tbl && !nn->port) {
			nfp_err(pf->cpp, "NSP port entries don't match vNICs (no entry for port #%d)\n", i);
			err = -EINVAL;
			goto err_free_prev;
		}
		if (nn->eth_port && nn->eth_port->override_changed) {
		if (nn->port && nn->port->eth_port->override_changed) {
			nfp_warn(pf->cpp, "Config changed for port #%d, reboot required before port will be operational\n", i);
			nfp_net_pf_free_vnic(pf, nn);
			continue;
@@ -526,13 +542,20 @@ static void nfp_net_refresh_vnics(struct work_struct *work)

	rtnl_lock();
	list_for_each_entry(nn, &pf->vnics, vnic_list) {
		if (!nn->eth_port)
		if (!__nfp_port_get_eth_port(nn->port))
			continue;
		nn->port->eth_port = nfp_net_find_port(eth_table,
						       nn->port->eth_id);
		if (!nn->port->eth_port) {
			nfp_warn(pf->cpp, "Warning: port #%d not present after reconfig\n",
				 nn->port->eth_id);
			continue;
		}
		if (nn->port->eth_port->override_changed) {
			nfp_warn(pf->cpp, "Port config changed, unregistering. Reboot required before port will be operational again.\n");
			nn->port->type = NFP_PORT_INVALID;
			continue;
		nn->eth_port = nfp_net_find_port(eth_table,
						 nn->eth_port->eth_index);
		if (!nn->eth_port)
			nfp_err(pf->cpp,
				"Warning: port disappeared after reconfig\n");
		}
	}
	rtnl_unlock();

@@ -540,11 +563,9 @@ static void nfp_net_refresh_vnics(struct work_struct *work)
	pf->eth_tbl = eth_table;

	list_for_each_entry_safe(nn, next, &pf->vnics, vnic_list) {
		if (nn->eth_port && !nn->eth_port->override_changed)
		if (!nn->port || nn->port->type != NFP_PORT_INVALID)
			continue;

		nn_warn(nn, "Port config changed, unregistering. Reboot required before port will be operational again.\n");

		nfp_net_debugfs_dir_clean(&nn->debugfs_dir);
		nfp_net_clean(nn);

@@ -557,32 +578,33 @@ static void nfp_net_refresh_vnics(struct work_struct *work)
	mutex_unlock(&pf->lock);
}

void nfp_net_refresh_port_table(struct nfp_net *nn)
void nfp_net_refresh_port_table(struct nfp_port *port)
{
	struct nfp_pf *pf = pci_get_drvdata(nn->pdev);
	struct nfp_pf *pf = port->app->pf;

	schedule_work(&pf->port_refresh_work);
}

int nfp_net_refresh_eth_port(struct nfp_net *nn)
int nfp_net_refresh_eth_port(struct nfp_port *port)
{
	struct nfp_cpp *cpp = port->app->cpp;
	struct nfp_eth_table_port *eth_port;
	struct nfp_eth_table *eth_table;

	eth_table = nfp_eth_read_ports(nn->app->cpp);
	eth_table = nfp_eth_read_ports(cpp);
	if (!eth_table) {
		nn_err(nn, "Error refreshing port state table!\n");
		nfp_err(cpp, "Error refreshing port state table!\n");
		return -EIO;
	}

	eth_port = nfp_net_find_port(eth_table, nn->eth_port->eth_index);
	eth_port = nfp_net_find_port(eth_table, port->eth_id);
	if (!eth_port) {
		nn_err(nn, "Error finding state of the port!\n");
		nfp_err(cpp, "Error finding state of the port!\n");
		kfree(eth_table);
		return -EIO;
	}

	memcpy(nn->eth_port, eth_port, sizeof(*eth_port));
	memcpy(port->eth_port, eth_port, sizeof(*eth_port));

	kfree(eth_table);

Loading