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

Merge tag 'mlx5-updates-2018-10-18' of git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux



Saeed Mahameed says:

====================
mlx5-updates-2018-10-18

This series provides misc updates to mlx5 core and netdevice driver.

1) From Tariq Toukan: Refactor fragmented buffer struct fields and init flow.

2) From Vlad Buslov, Flow counters cache improvements and fixes follow up.
as a follow up work for the previous series of the mlx5 flow counters,
Vlad provides two fixes:
  2.1) Take fs_counters dellist before addlist
Fixes: 6e5e2283 ("net/mlx5: Add new list to store deleted flow counters")
  2.2) Remove counter from idr after removing it from list
Fixes: 12d6066c ("net/mlx5: Add flow counters idr")

From Shay Agroskin,
3) Add FEC set/get FW commands and FEC ethtool callbacks support
4) Add new ethtool statistics to cover errors on rx, such as FEC errors.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 79861919 4cb4e98e
Loading
Loading
Loading
Loading
+13 −18
Original line number Diff line number Diff line
@@ -393,7 +393,7 @@ static void handle_atomics(struct mlx5_ib_qp *qp, struct mlx5_cqe64 *cqe64,

static void free_cq_buf(struct mlx5_ib_dev *dev, struct mlx5_ib_cq_buf *buf)
{
	mlx5_frag_buf_free(dev->mdev, &buf->fbc.frag_buf);
	mlx5_frag_buf_free(dev->mdev, &buf->frag_buf);
}

static void get_sig_err_item(struct mlx5_sig_err_cqe *cqe,
@@ -728,16 +728,11 @@ static int alloc_cq_frag_buf(struct mlx5_ib_dev *dev,
			     int nent,
			     int cqe_size)
{
	struct mlx5_frag_buf_ctrl *c = &buf->fbc;
	struct mlx5_frag_buf *frag_buf = &c->frag_buf;
	u32 cqc_buff[MLX5_ST_SZ_DW(cqc)] = {0};
	struct mlx5_frag_buf *frag_buf = &buf->frag_buf;
	u8 log_wq_stride = 6 + (cqe_size == 128 ? 1 : 0);
	u8 log_wq_sz     = ilog2(cqe_size);
	int err;

	MLX5_SET(cqc, cqc_buff, log_cq_size, ilog2(cqe_size));
	MLX5_SET(cqc, cqc_buff, cqe_sz, (cqe_size == 128) ? 1 : 0);

	mlx5_core_init_cq_frag_buf(&buf->fbc, cqc_buff);

	err = mlx5_frag_buf_alloc_node(dev->mdev,
				       nent * cqe_size,
				       frag_buf,
@@ -745,6 +740,8 @@ static int alloc_cq_frag_buf(struct mlx5_ib_dev *dev,
	if (err)
		return err;

	mlx5_init_fbc(frag_buf->frags, log_wq_stride, log_wq_sz, &buf->fbc);

	buf->cqe_size = cqe_size;
	buf->nent = nent;

@@ -934,7 +931,7 @@ static int create_cq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq,

	*inlen = MLX5_ST_SZ_BYTES(create_cq_in) +
		 MLX5_FLD_SZ_BYTES(create_cq_in, pas[0]) *
		 cq->buf.fbc.frag_buf.npages;
		 cq->buf.frag_buf.npages;
	*cqb = kvzalloc(*inlen, GFP_KERNEL);
	if (!*cqb) {
		err = -ENOMEM;
@@ -942,11 +939,11 @@ static int create_cq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq,
	}

	pas = (__be64 *)MLX5_ADDR_OF(create_cq_in, *cqb, pas);
	mlx5_fill_page_frag_array(&cq->buf.fbc.frag_buf, pas);
	mlx5_fill_page_frag_array(&cq->buf.frag_buf, pas);

	cqc = MLX5_ADDR_OF(create_cq_in, *cqb, cq_context);
	MLX5_SET(cqc, cqc, log_page_size,
		 cq->buf.fbc.frag_buf.page_shift -
		 cq->buf.frag_buf.page_shift -
		 MLX5_ADAPTER_PAGE_SHIFT);

	*index = dev->mdev->priv.uar->index;
@@ -1365,11 +1362,10 @@ int mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
		cqe_size = 64;
		err = resize_kernel(dev, cq, entries, cqe_size);
		if (!err) {
			struct mlx5_frag_buf_ctrl *c;
			struct mlx5_frag_buf *frag_buf = &cq->resize_buf->frag_buf;

			c = &cq->resize_buf->fbc;
			npas = c->frag_buf.npages;
			page_shift = c->frag_buf.page_shift;
			npas = frag_buf->npages;
			page_shift = frag_buf->page_shift;
		}
	}

@@ -1390,8 +1386,7 @@ int mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
		mlx5_ib_populate_pas(dev, cq->resize_umem, page_shift,
				     pas, 0);
	else
		mlx5_fill_page_frag_array(&cq->resize_buf->fbc.frag_buf,
					  pas);
		mlx5_fill_page_frag_array(&cq->resize_buf->frag_buf, pas);

	MLX5_SET(modify_cq_in, in,
		 modify_field_select_resize_field_select.resize_field_select.resize_field_select,
+1 −0
Original line number Diff line number Diff line
@@ -435,6 +435,7 @@ struct mlx5_ib_qp {

struct mlx5_ib_cq_buf {
	struct mlx5_frag_buf_ctrl fbc;
	struct mlx5_frag_buf    frag_buf;
	struct ib_umem		*umem;
	int			cqe_size;
	int			nent;
+208 −0
Original line number Diff line number Diff line
@@ -235,3 +235,211 @@ out:
	kfree(out);
	return err;
}

static u32 fec_supported_speeds[] = {
	10000,
	40000,
	25000,
	50000,
	56000,
	100000
};

#define MLX5E_FEC_SUPPORTED_SPEEDS ARRAY_SIZE(fec_supported_speeds)

/* get/set FEC admin field for a given speed */
static int mlx5e_fec_admin_field(u32 *pplm,
				 u8 *fec_policy,
				 bool write,
				 u32 speed)
{
	switch (speed) {
	case 10000:
	case 40000:
		if (!write)
			*fec_policy = MLX5_GET(pplm_reg, pplm,
					       fec_override_cap_10g_40g);
		else
			MLX5_SET(pplm_reg, pplm,
				 fec_override_admin_10g_40g, *fec_policy);
		break;
	case 25000:
		if (!write)
			*fec_policy = MLX5_GET(pplm_reg, pplm,
					       fec_override_admin_25g);
		else
			MLX5_SET(pplm_reg, pplm,
				 fec_override_admin_25g, *fec_policy);
		break;
	case 50000:
		if (!write)
			*fec_policy = MLX5_GET(pplm_reg, pplm,
					       fec_override_admin_50g);
		else
			MLX5_SET(pplm_reg, pplm,
				 fec_override_admin_50g, *fec_policy);
		break;
	case 56000:
		if (!write)
			*fec_policy = MLX5_GET(pplm_reg, pplm,
					       fec_override_admin_56g);
		else
			MLX5_SET(pplm_reg, pplm,
				 fec_override_admin_56g, *fec_policy);
		break;
	case 100000:
		if (!write)
			*fec_policy = MLX5_GET(pplm_reg, pplm,
					       fec_override_admin_100g);
		else
			MLX5_SET(pplm_reg, pplm,
				 fec_override_admin_100g, *fec_policy);
		break;
	default:
		return -EINVAL;
	}
	return 0;
}

/* returns FEC capabilities for a given speed */
static int mlx5e_get_fec_cap_field(u32 *pplm,
				   u8 *fec_cap,
				   u32 speed)
{
	switch (speed) {
	case 10000:
	case 40000:
		*fec_cap = MLX5_GET(pplm_reg, pplm,
				    fec_override_admin_10g_40g);
		break;
	case 25000:
		*fec_cap = MLX5_GET(pplm_reg, pplm,
				    fec_override_cap_25g);
		break;
	case 50000:
		*fec_cap = MLX5_GET(pplm_reg, pplm,
				    fec_override_cap_50g);
		break;
	case 56000:
		*fec_cap = MLX5_GET(pplm_reg, pplm,
				    fec_override_cap_56g);
		break;
	case 100000:
		*fec_cap = MLX5_GET(pplm_reg, pplm,
				    fec_override_cap_100g);
		break;
	default:
		return -EINVAL;
	}
	return 0;
}

int mlx5e_get_fec_caps(struct mlx5_core_dev *dev, u8 *fec_caps)
{
	u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
	u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
	int sz = MLX5_ST_SZ_BYTES(pplm_reg);
	u32 current_fec_speed;
	int err;

	if (!MLX5_CAP_GEN(dev, pcam_reg))
		return -EOPNOTSUPP;

	if (!MLX5_CAP_PCAM_REG(dev, pplm))
		return -EOPNOTSUPP;

	MLX5_SET(pplm_reg, in, local_port, 1);
	err =  mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
	if (err)
		return err;

	err = mlx5e_port_linkspeed(dev, &current_fec_speed);
	if (err)
		return err;

	return mlx5e_get_fec_cap_field(out, fec_caps, current_fec_speed);
}

int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active,
		       u8 *fec_configured_mode)
{
	u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
	u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
	int sz = MLX5_ST_SZ_BYTES(pplm_reg);
	u32 link_speed;
	int err;

	if (!MLX5_CAP_GEN(dev, pcam_reg))
		return -EOPNOTSUPP;

	if (!MLX5_CAP_PCAM_REG(dev, pplm))
		return -EOPNOTSUPP;

	MLX5_SET(pplm_reg, in, local_port, 1);
	err =  mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
	if (err)
		return err;

	*fec_mode_active = MLX5_GET(pplm_reg, out, fec_mode_active);

	if (!fec_configured_mode)
		return 0;

	err = mlx5e_port_linkspeed(dev, &link_speed);
	if (err)
		return err;

	return mlx5e_fec_admin_field(out, fec_configured_mode, 0, link_speed);
}

int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy)
{
	bool fec_mode_not_supp_in_speed = false;
	u8 no_fec_policy = BIT(MLX5E_FEC_NOFEC);
	u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
	u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
	int sz = MLX5_ST_SZ_BYTES(pplm_reg);
	u32 current_fec_speed;
	u8 fec_caps = 0;
	int err;
	int i;

	if (!MLX5_CAP_GEN(dev, pcam_reg))
		return -EOPNOTSUPP;

	if (!MLX5_CAP_PCAM_REG(dev, pplm))
		return -EOPNOTSUPP;

	MLX5_SET(pplm_reg, in, local_port, 1);
	err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
	if (err)
		return err;

	err = mlx5e_port_linkspeed(dev, &current_fec_speed);
	if (err)
		return err;

	memset(in, 0, sz);
	MLX5_SET(pplm_reg, in, local_port, 1);
	for (i = 0; i < MLX5E_FEC_SUPPORTED_SPEEDS && !!fec_policy; i++) {
		mlx5e_get_fec_cap_field(out, &fec_caps, fec_supported_speeds[i]);
		/* policy supported for link speed */
		if (!!(fec_caps & fec_policy)) {
			mlx5e_fec_admin_field(in, &fec_policy, 1,
					      fec_supported_speeds[i]);
		} else {
			if (fec_supported_speeds[i] == current_fec_speed)
				return -EOPNOTSUPP;
			mlx5e_fec_admin_field(in, &no_fec_policy, 1,
					      fec_supported_speeds[i]);
			fec_mode_not_supp_in_speed = true;
		}
	}

	if (fec_mode_not_supp_in_speed)
		mlx5_core_dbg(dev,
			      "FEC policy 0x%x is not supported for some speeds",
			      fec_policy);

	return mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 1);
}
+12 −0
Original line number Diff line number Diff line
@@ -45,4 +45,16 @@ int mlx5e_port_query_pbmc(struct mlx5_core_dev *mdev, void *out);
int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in);
int mlx5e_port_query_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer);
int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer);

int mlx5e_get_fec_caps(struct mlx5_core_dev *dev, u8 *fec_caps);
int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active,
		       u8 *fec_configured_mode);
int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy);

enum {
	MLX5E_FEC_NOFEC,
	MLX5E_FEC_FIRECODE,
	MLX5E_FEC_RS_528_514,
};

#endif
+126 −2
Original line number Diff line number Diff line
@@ -547,6 +547,70 @@ static void ptys2ethtool_adver_link(unsigned long *advertising_modes,
			  __ETHTOOL_LINK_MODE_MASK_NBITS);
}

static const u32 pplm_fec_2_ethtool[] = {
	[MLX5E_FEC_NOFEC] = ETHTOOL_FEC_OFF,
	[MLX5E_FEC_FIRECODE] = ETHTOOL_FEC_BASER,
	[MLX5E_FEC_RS_528_514] = ETHTOOL_FEC_RS,
};

static u32 pplm2ethtool_fec(u_long fec_mode, unsigned long size)
{
	int mode = 0;

	if (!fec_mode)
		return ETHTOOL_FEC_AUTO;

	mode = find_first_bit(&fec_mode, size);

	if (mode < ARRAY_SIZE(pplm_fec_2_ethtool))
		return pplm_fec_2_ethtool[mode];

	return 0;
}

/* we use ETHTOOL_FEC_* offset and apply it to ETHTOOL_LINK_MODE_FEC_*_BIT */
static u32 ethtool_fec2ethtool_caps(u_long ethtool_fec_code)
{
	u32 offset;

	offset = find_first_bit(&ethtool_fec_code, sizeof(u32));
	offset -= ETHTOOL_FEC_OFF_BIT;
	offset += ETHTOOL_LINK_MODE_FEC_NONE_BIT;

	return offset;
}

static int get_fec_supported_advertised(struct mlx5_core_dev *dev,
					struct ethtool_link_ksettings *link_ksettings)
{
	u_long fec_caps = 0;
	u32 active_fec = 0;
	u32 offset;
	u32 bitn;
	int err;

	err = mlx5e_get_fec_caps(dev, (u8 *)&fec_caps);
	if (err)
		return (err == -EOPNOTSUPP) ? 0 : err;

	err = mlx5e_get_fec_mode(dev, &active_fec, NULL);
	if (err)
		return err;

	for_each_set_bit(bitn, &fec_caps, ARRAY_SIZE(pplm_fec_2_ethtool)) {
		u_long ethtool_bitmask = pplm_fec_2_ethtool[bitn];

		offset = ethtool_fec2ethtool_caps(ethtool_bitmask);
		__set_bit(offset, link_ksettings->link_modes.supported);
	}

	active_fec = pplm2ethtool_fec(active_fec, sizeof(u32) * BITS_PER_BYTE);
	offset = ethtool_fec2ethtool_caps(active_fec);
	__set_bit(offset, link_ksettings->link_modes.advertising);

	return 0;
}

static void ptys2ethtool_supported_advertised_port(struct ethtool_link_ksettings *link_ksettings,
						   u32 eth_proto_cap,
						   u8 connector_type)
@@ -742,7 +806,7 @@ static int mlx5e_get_link_ksettings(struct net_device *netdev,
	if (err) {
		netdev_err(netdev, "%s: query port ptys failed: %d\n",
			   __func__, err);
		goto err_query_ptys;
		goto err_query_regs;
	}

	eth_proto_cap    = MLX5_GET(ptys_reg, out, eth_proto_capability);
@@ -778,11 +842,17 @@ static int mlx5e_get_link_ksettings(struct net_device *netdev,
							  AUTONEG_ENABLE;
	ethtool_link_ksettings_add_link_mode(link_ksettings, supported,
					     Autoneg);

	err = get_fec_supported_advertised(mdev, link_ksettings);
	if (err)
		netdev_dbg(netdev, "%s: FEC caps query failed: %d\n",
			   __func__, err);

	if (!an_disable_admin)
		ethtool_link_ksettings_add_link_mode(link_ksettings,
						     advertising, Autoneg);

err_query_ptys:
err_query_regs:
	return err;
}

@@ -1277,6 +1347,58 @@ static int mlx5e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
	return mlx5_set_port_wol(mdev, mlx5_wol_mode);
}

static int mlx5e_get_fecparam(struct net_device *netdev,
			      struct ethtool_fecparam *fecparam)
{
	struct mlx5e_priv *priv = netdev_priv(netdev);
	struct mlx5_core_dev *mdev = priv->mdev;
	u8 fec_configured = 0;
	u32 fec_active = 0;
	int err;

	err = mlx5e_get_fec_mode(mdev, &fec_active, &fec_configured);

	if (err)
		return err;

	fecparam->active_fec = pplm2ethtool_fec((u_long)fec_active,
						sizeof(u32) * BITS_PER_BYTE);

	if (!fecparam->active_fec)
		return -EOPNOTSUPP;

	fecparam->fec = pplm2ethtool_fec((u_long)fec_configured,
					 sizeof(u8) * BITS_PER_BYTE);

	return 0;
}

static int mlx5e_set_fecparam(struct net_device *netdev,
			      struct ethtool_fecparam *fecparam)
{
	struct mlx5e_priv *priv = netdev_priv(netdev);
	struct mlx5_core_dev *mdev = priv->mdev;
	u8 fec_policy = 0;
	int mode;
	int err;

	for (mode = 0; mode < ARRAY_SIZE(pplm_fec_2_ethtool); mode++) {
		if (!(pplm_fec_2_ethtool[mode] & fecparam->fec))
			continue;
		fec_policy |= (1 << mode);
		break;
	}

	err = mlx5e_set_fec_mode(mdev, fec_policy);

	if (err)
		return err;

	mlx5_toggle_port_link(mdev);

	return 0;
}

static u32 mlx5e_get_msglevel(struct net_device *dev)
{
	return ((struct mlx5e_priv *)netdev_priv(dev))->msglevel;
@@ -1699,4 +1821,6 @@ const struct ethtool_ops mlx5e_ethtool_ops = {
	.self_test         = mlx5e_self_test,
	.get_msglevel      = mlx5e_get_msglevel,
	.set_msglevel      = mlx5e_set_msglevel,
	.get_fecparam      = mlx5e_get_fecparam,
	.set_fecparam      = mlx5e_set_fecparam,
};
Loading