Commit 62fad9e6 authored by Yinjun Zhang's avatar Yinjun Zhang Committed by Paolo Abeni
Browse files

nfp: propagate port speed from management firmware



In future releases the NIC application firmware may be indifferent to port
speeds - not built for specific port speeds - and consequently it will not
be able to report VF port speeds to the driver without first learning them.
With this change, the driver will pass the speed of physical ports from
management firmware to application firmware, and the latter will copy the
speed of port 0 to all the active VFs. So that the driver can get VF port
speed as before.

The port speed of a VF may be requested from userspace using:

  ethtool <vf-intf>

Signed-off-by: default avatarYinjun Zhang <yinjun.zhang@corigine.com>
Reviewed-by: default avatarLouis Peens <louis.peens@corigine.com>
Signed-off-by: default avatarSimon Horman <simon.horman@corigine.com>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent f97e971d
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -190,4 +190,7 @@ int nfp_shared_buf_pool_set(struct nfp_pf *pf, unsigned int sb,

int nfp_devlink_params_register(struct nfp_pf *pf);
void nfp_devlink_params_unregister(struct nfp_pf *pf);

unsigned int nfp_net_lr2speed(unsigned int linkrate);
unsigned int nfp_net_speed2lr(unsigned int speed);
#endif /* NFP_MAIN_H */
+6 −3
Original line number Diff line number Diff line
@@ -474,19 +474,22 @@ static void nfp_net_read_link_status(struct nfp_net *nn)
{
	unsigned long flags;
	bool link_up;
	u32 sts;
	u16 sts;

	spin_lock_irqsave(&nn->link_status_lock, flags);

	sts = nn_readl(nn, NFP_NET_CFG_STS);
	sts = nn_readw(nn, NFP_NET_CFG_STS);
	link_up = !!(sts & NFP_NET_CFG_STS_LINK);

	if (nn->link_up == link_up)
		goto out;

	nn->link_up = link_up;
	if (nn->port)
	if (nn->port) {
		set_bit(NFP_PORT_CHANGED, &nn->port->flags);
		if (nn->port->link_cb)
			nn->port->link_cb(nn->port);
	}

	if (nn->link_up) {
		netif_carrier_on(nn->dp.netdev);
+4 −0
Original line number Diff line number Diff line
@@ -193,6 +193,10 @@
#define   NFP_NET_CFG_STS_LINK_RATE_40G		  5
#define   NFP_NET_CFG_STS_LINK_RATE_50G		  6
#define   NFP_NET_CFG_STS_LINK_RATE_100G	  7
/* NSP Link rate is a 16-bit word. It's determined by NSP and
 * written to CFG BAR by NFP driver.
 */
#define NFP_NET_CFG_STS_NSP_LINK_RATE	0x0036
#define NFP_NET_CFG_CAP			0x0038
#define NFP_NET_CFG_MAX_TXRINGS		0x003c
#define NFP_NET_CFG_MAX_RXRINGS		0x0040
+9 −21
Original line number Diff line number Diff line
@@ -273,20 +273,11 @@ static int
nfp_net_get_link_ksettings(struct net_device *netdev,
			   struct ethtool_link_ksettings *cmd)
{
	static const u32 ls_to_ethtool[] = {
		[NFP_NET_CFG_STS_LINK_RATE_UNSUPPORTED]	= 0,
		[NFP_NET_CFG_STS_LINK_RATE_UNKNOWN]	= SPEED_UNKNOWN,
		[NFP_NET_CFG_STS_LINK_RATE_1G]		= SPEED_1000,
		[NFP_NET_CFG_STS_LINK_RATE_10G]		= SPEED_10000,
		[NFP_NET_CFG_STS_LINK_RATE_25G]		= SPEED_25000,
		[NFP_NET_CFG_STS_LINK_RATE_40G]		= SPEED_40000,
		[NFP_NET_CFG_STS_LINK_RATE_50G]		= SPEED_50000,
		[NFP_NET_CFG_STS_LINK_RATE_100G]	= SPEED_100000,
	};
	struct nfp_eth_table_port *eth_port;
	struct nfp_port *port;
	struct nfp_net *nn;
	u32 sts, ls;
	unsigned int speed;
	u16 sts;

	/* Init to unknowns */
	ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
@@ -319,18 +310,15 @@ nfp_net_get_link_ksettings(struct net_device *netdev,
		return -EOPNOTSUPP;
	nn = netdev_priv(netdev);

	sts = nn_readl(nn, NFP_NET_CFG_STS);

	ls = FIELD_GET(NFP_NET_CFG_STS_LINK_RATE, sts);
	if (ls == NFP_NET_CFG_STS_LINK_RATE_UNSUPPORTED)
	sts = nn_readw(nn, NFP_NET_CFG_STS);
	speed = nfp_net_lr2speed(FIELD_GET(NFP_NET_CFG_STS_LINK_RATE, sts));
	if (!speed)
		return -EOPNOTSUPP;

	if (ls == NFP_NET_CFG_STS_LINK_RATE_UNKNOWN ||
	    ls >= ARRAY_SIZE(ls_to_ethtool))
		return 0;

	cmd->base.speed = ls_to_ethtool[ls];
	if (speed != SPEED_UNKNOWN) {
		cmd->base.speed = speed;
		cmd->base.duplex = DUPLEX_FULL;
	}

	return 0;
}
+55 −0
Original line number Diff line number Diff line
@@ -202,6 +202,9 @@ nfp_net_pf_alloc_vnics(struct nfp_pf *pf, void __iomem *ctrl_bar,
			goto err_free_prev;
		}

		if (nn->port)
			nn->port->link_cb = nfp_net_refresh_port_table;

		ctrl_bar += NFP_PF_CSR_SLICE_SIZE;

		/* Kill the vNIC if app init marked it as invalid */
@@ -523,6 +526,57 @@ static int nfp_net_pci_map_mem(struct nfp_pf *pf)
	return err;
}

static const unsigned int lr_to_speed[] = {
	[NFP_NET_CFG_STS_LINK_RATE_UNSUPPORTED]	= 0,
	[NFP_NET_CFG_STS_LINK_RATE_UNKNOWN]	= SPEED_UNKNOWN,
	[NFP_NET_CFG_STS_LINK_RATE_1G]		= SPEED_1000,
	[NFP_NET_CFG_STS_LINK_RATE_10G]		= SPEED_10000,
	[NFP_NET_CFG_STS_LINK_RATE_25G]		= SPEED_25000,
	[NFP_NET_CFG_STS_LINK_RATE_40G]		= SPEED_40000,
	[NFP_NET_CFG_STS_LINK_RATE_50G]		= SPEED_50000,
	[NFP_NET_CFG_STS_LINK_RATE_100G]	= SPEED_100000,
};

unsigned int nfp_net_lr2speed(unsigned int linkrate)
{
	if (linkrate < ARRAY_SIZE(lr_to_speed))
		return lr_to_speed[linkrate];

	return SPEED_UNKNOWN;
}

unsigned int nfp_net_speed2lr(unsigned int speed)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(lr_to_speed); i++) {
		if (speed == lr_to_speed[i])
			return i;
	}

	return NFP_NET_CFG_STS_LINK_RATE_UNKNOWN;
}

static void nfp_net_notify_port_speed(struct nfp_port *port)
{
	struct net_device *netdev = port->netdev;
	struct nfp_net *nn;
	u16 sts;

	if (!nfp_netdev_is_nfp_net(netdev))
		return;

	nn = netdev_priv(netdev);
	sts = nn_readw(nn, NFP_NET_CFG_STS);

	if (!(sts & NFP_NET_CFG_STS_LINK)) {
		nn_writew(nn, NFP_NET_CFG_STS_NSP_LINK_RATE, NFP_NET_CFG_STS_LINK_RATE_UNKNOWN);
		return;
	}

	nn_writew(nn, NFP_NET_CFG_STS_NSP_LINK_RATE, nfp_net_speed2lr(port->eth_port->speed));
}

static int
nfp_net_eth_port_update(struct nfp_cpp *cpp, struct nfp_port *port,
			struct nfp_eth_table *eth_table)
@@ -544,6 +598,7 @@ nfp_net_eth_port_update(struct nfp_cpp *cpp, struct nfp_port *port,
	}

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

	return 0;
}
Loading