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

Merge tag 'mlx5-updates-2020-03-09' of git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux



Saeed Mahameed says:

====================
mlx5-updates-2020-03-09

This series provides updates to mlx5 driver:

1) Use vport metadata matching only when mandatory
2) Introduce root flow table and ethtool steering for uplink representors
3) Expose port speed via FW when link modes are not available
3) Misc cleanups
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 119959a0 b63293e7
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -204,7 +204,7 @@ struct mlx5e_tx_wqe {

struct mlx5e_rx_wqe_ll {
	struct mlx5_wqe_srq_next_seg  next;
	struct mlx5_wqe_data_seg      data[0];
	struct mlx5_wqe_data_seg      data[];
};

struct mlx5e_rx_wqe_cyc {
@@ -1169,6 +1169,12 @@ int mlx5e_ethtool_get_link_ksettings(struct mlx5e_priv *priv,
				     struct ethtool_link_ksettings *link_ksettings);
int mlx5e_ethtool_set_link_ksettings(struct mlx5e_priv *priv,
				     const struct ethtool_link_ksettings *link_ksettings);
int mlx5e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, u8 *hfunc);
int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key,
		   const u8 hfunc);
int mlx5e_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
		    u32 *rule_locs);
int mlx5e_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd);
u32 mlx5e_ethtool_get_rxfh_key_size(struct mlx5e_priv *priv);
u32 mlx5e_ethtool_get_rxfh_indir_size(struct mlx5e_priv *priv);
int mlx5e_ethtool_get_ts_info(struct mlx5e_priv *priv,
+22 −15
Original line number Diff line number Diff line
@@ -773,6 +773,7 @@ static void ptys2ethtool_supported_advertised_port(struct ethtool_link_ksettings

static void get_speed_duplex(struct net_device *netdev,
			     u32 eth_proto_oper, bool force_legacy,
			     u16 data_rate_oper,
			     struct ethtool_link_ksettings *link_ksettings)
{
	struct mlx5e_priv *priv = netdev_priv(netdev);
@@ -784,6 +785,9 @@ static void get_speed_duplex(struct net_device *netdev,

	speed = mlx5e_port_ptys2speed(priv->mdev, eth_proto_oper, force_legacy);
	if (!speed) {
		if (data_rate_oper)
			speed = 100 * data_rate_oper;
		else
			speed = SPEED_UNKNOWN;
		goto out;
	}
@@ -873,17 +877,18 @@ int mlx5e_ethtool_get_link_ksettings(struct mlx5e_priv *priv,
				     struct ethtool_link_ksettings *link_ksettings)
{
	struct mlx5_core_dev *mdev = priv->mdev;
	u32 out[MLX5_ST_SZ_DW(ptys_reg)] = {0};
	u32 rx_pause = 0;
	u32 tx_pause = 0;
	u32 eth_proto_cap;
	u32 out[MLX5_ST_SZ_DW(ptys_reg)] = {};
	u32 eth_proto_admin;
	u32 eth_proto_lp;
	u32 eth_proto_oper;
	u8 an_disable_admin;
	u8 an_status;
	u16 data_rate_oper;
	u32 eth_proto_oper;
	u32 eth_proto_cap;
	u8 connector_type;
	u32 rx_pause = 0;
	u32 tx_pause = 0;
	u32 eth_proto_lp;
	bool admin_ext;
	u8 an_status;
	bool ext;
	int err;

@@ -917,6 +922,7 @@ int mlx5e_ethtool_get_link_ksettings(struct mlx5e_priv *priv,
	an_disable_admin    = MLX5_GET(ptys_reg, out, an_disable_admin);
	an_status	    = MLX5_GET(ptys_reg, out, an_status);
	connector_type	    = MLX5_GET(ptys_reg, out, connector_type);
	data_rate_oper	    = MLX5_GET(ptys_reg, out, data_rate_oper);

	mlx5_query_port_pause(mdev, &rx_pause, &tx_pause);

@@ -927,7 +933,7 @@ int mlx5e_ethtool_get_link_ksettings(struct mlx5e_priv *priv,
	get_advertising(eth_proto_admin, tx_pause, rx_pause, link_ksettings,
			admin_ext);
	get_speed_duplex(priv->netdev, eth_proto_oper, !admin_ext,
			 link_ksettings);
			 data_rate_oper, link_ksettings);

	eth_proto_oper = eth_proto_oper ? eth_proto_oper : eth_proto_cap;

@@ -1126,7 +1132,7 @@ static u32 mlx5e_get_rxfh_indir_size(struct net_device *netdev)
	return mlx5e_ethtool_get_rxfh_indir_size(priv);
}

static int mlx5e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
int mlx5e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
		   u8 *hfunc)
{
	struct mlx5e_priv *priv = netdev_priv(netdev);
@@ -1146,7 +1152,7 @@ static int mlx5e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
	return 0;
}

static int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir,
int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir,
		   const u8 *key, const u8 hfunc)
{
	struct mlx5e_priv *priv = netdev_priv(dev);
@@ -1942,7 +1948,8 @@ static u32 mlx5e_get_priv_flags(struct net_device *netdev)
	return priv->channels.params.pflags;
}

static int mlx5e_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, u32 *rule_locs)
int mlx5e_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
		    u32 *rule_locs)
{
	struct mlx5e_priv *priv = netdev_priv(dev);

@@ -1959,7 +1966,7 @@ static int mlx5e_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, u
	return mlx5e_ethtool_get_rxnfc(dev, info, rule_locs);
}

static int mlx5e_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
int mlx5e_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
{
	return mlx5e_ethtool_set_rxnfc(dev, cmd);
}
+71 −51
Original line number Diff line number Diff line
@@ -253,25 +253,6 @@ static int mlx5e_rep_set_ringparam(struct net_device *dev,
	return mlx5e_ethtool_set_ringparam(priv, param);
}

static int mlx5e_replace_rep_vport_rx_rule(struct mlx5e_priv *priv,
					   struct mlx5_flow_destination *dest)
{
	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
	struct mlx5e_rep_priv *rpriv = priv->ppriv;
	struct mlx5_eswitch_rep *rep = rpriv->rep;
	struct mlx5_flow_handle *flow_rule;

	flow_rule = mlx5_eswitch_create_vport_rx_rule(esw,
						      rep->vport,
						      dest);
	if (IS_ERR(flow_rule))
		return PTR_ERR(flow_rule);

	mlx5_del_flow_rules(rpriv->vport_rx_rule);
	rpriv->vport_rx_rule = flow_rule;
	return 0;
}

static void mlx5e_rep_get_channels(struct net_device *dev,
				   struct ethtool_channels *ch)
{
@@ -284,33 +265,8 @@ static int mlx5e_rep_set_channels(struct net_device *dev,
				  struct ethtool_channels *ch)
{
	struct mlx5e_priv *priv = netdev_priv(dev);
	u16 curr_channels_amount = priv->channels.params.num_channels;
	u32 new_channels_amount = ch->combined_count;
	struct mlx5_flow_destination new_dest;
	int err = 0;

	err = mlx5e_ethtool_set_channels(priv, ch);
	if (err)
		return err;

	if (curr_channels_amount == 1 && new_channels_amount > 1) {
		new_dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
		new_dest.ft = priv->fs.ttc.ft.t;
	} else if (new_channels_amount == 1 && curr_channels_amount > 1) {
		new_dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR;
		new_dest.tir_num = priv->direct_tir[0].tirn;
	} else {
		return 0;
	}

	err = mlx5e_replace_rep_vport_rx_rule(priv, &new_dest);
	if (err) {
		netdev_warn(priv->netdev, "Failed to update vport rx rule, when going from (%d) channels to (%d) channels\n",
			    curr_channels_amount, new_channels_amount);
		return err;
	}

	return 0;
	return mlx5e_ethtool_set_channels(priv, ch);
}

static int mlx5e_rep_get_coalesce(struct net_device *netdev,
@@ -413,6 +369,10 @@ static const struct ethtool_ops mlx5e_uplink_rep_ethtool_ops = {
	.set_link_ksettings = mlx5e_uplink_rep_set_link_ksettings,
	.get_rxfh_key_size   = mlx5e_rep_get_rxfh_key_size,
	.get_rxfh_indir_size = mlx5e_rep_get_rxfh_indir_size,
	.get_rxfh          = mlx5e_get_rxfh,
	.set_rxfh          = mlx5e_set_rxfh,
	.get_rxnfc         = mlx5e_get_rxnfc,
	.set_rxnfc         = mlx5e_set_rxnfc,
	.get_pauseparam    = mlx5e_uplink_rep_get_pauseparam,
	.set_pauseparam    = mlx5e_uplink_rep_set_pauseparam,
};
@@ -1596,6 +1556,8 @@ static void mlx5e_cleanup_rep(struct mlx5e_priv *priv)

static int mlx5e_create_rep_ttc_table(struct mlx5e_priv *priv)
{
	struct mlx5e_rep_priv *rpriv = priv->ppriv;
	struct mlx5_eswitch_rep *rep = rpriv->rep;
	struct ttc_params ttc_params = {};
	int tt, err;

@@ -1605,6 +1567,11 @@ static int mlx5e_create_rep_ttc_table(struct mlx5e_priv *priv)
	/* The inner_ttc in the ttc params is intentionally not set */
	ttc_params.any_tt_tirn = priv->direct_tir[0].tirn;
	mlx5e_set_ttc_ft_params(&ttc_params);

	if (rep->vport != MLX5_VPORT_UPLINK)
		/* To give uplik rep TTC a lower level for chaining from root ft */
		ttc_params.ft_attr.level = MLX5E_TTC_FT_LEVEL + 1;

	for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++)
		ttc_params.indir_tirn[tt] = priv->indir_tir[tt].tirn;

@@ -1616,6 +1583,51 @@ static int mlx5e_create_rep_ttc_table(struct mlx5e_priv *priv)
	return 0;
}

static int mlx5e_create_rep_root_ft(struct mlx5e_priv *priv)
{
	struct mlx5e_rep_priv *rpriv = priv->ppriv;
	struct mlx5_eswitch_rep *rep = rpriv->rep;
	struct mlx5_flow_table_attr ft_attr = {};
	struct mlx5_flow_namespace *ns;
	int err = 0;

	if (rep->vport != MLX5_VPORT_UPLINK) {
		/* non uplik reps will skip any bypass tables and go directly to
		 * their own ttc
		 */
		rpriv->root_ft = priv->fs.ttc.ft.t;
		return 0;
	}

	/* uplink root ft will be used to auto chain, to ethtool or ttc tables */
	ns = mlx5_get_flow_namespace(priv->mdev, MLX5_FLOW_NAMESPACE_OFFLOADS);
	if (!ns) {
		netdev_err(priv->netdev, "Failed to get reps offloads namespace\n");
		return -EOPNOTSUPP;
	}

	ft_attr.max_fte = 0; /* Empty table, miss rule will always point to next table */
	ft_attr.level = 1;

	rpriv->root_ft = mlx5_create_flow_table(ns, &ft_attr);
	if (IS_ERR(rpriv->root_ft)) {
		err = PTR_ERR(rpriv->root_ft);
		rpriv->root_ft = NULL;
	}

	return err;
}

static void mlx5e_destroy_rep_root_ft(struct mlx5e_priv *priv)
{
	struct mlx5e_rep_priv *rpriv = priv->ppriv;
	struct mlx5_eswitch_rep *rep = rpriv->rep;

	if (rep->vport != MLX5_VPORT_UPLINK)
		return;
	mlx5_destroy_flow_table(rpriv->root_ft);
}

static int mlx5e_create_rep_vport_rx_rule(struct mlx5e_priv *priv)
{
	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
@@ -1624,11 +1636,10 @@ static int mlx5e_create_rep_vport_rx_rule(struct mlx5e_priv *priv)
	struct mlx5_flow_handle *flow_rule;
	struct mlx5_flow_destination dest;

	dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR;
	dest.tir_num = priv->direct_tir[0].tirn;
	flow_rule = mlx5_eswitch_create_vport_rx_rule(esw,
						      rep->vport,
						      &dest);
	dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
	dest.ft = rpriv->root_ft;

	flow_rule = mlx5_eswitch_create_vport_rx_rule(esw, rep->vport, &dest);
	if (IS_ERR(flow_rule))
		return PTR_ERR(flow_rule);
	rpriv->vport_rx_rule = flow_rule;
@@ -1668,12 +1679,20 @@ static int mlx5e_init_rep_rx(struct mlx5e_priv *priv)
	if (err)
		goto err_destroy_direct_tirs;

	err = mlx5e_create_rep_vport_rx_rule(priv);
	err = mlx5e_create_rep_root_ft(priv);
	if (err)
		goto err_destroy_ttc_table;

	err = mlx5e_create_rep_vport_rx_rule(priv);
	if (err)
		goto err_destroy_root_ft;

	mlx5e_ethtool_init_steering(priv);

	return 0;

err_destroy_root_ft:
	mlx5e_destroy_rep_root_ft(priv);
err_destroy_ttc_table:
	mlx5e_destroy_ttc_table(priv, &priv->fs.ttc);
err_destroy_direct_tirs:
@@ -1694,6 +1713,7 @@ static void mlx5e_cleanup_rep_rx(struct mlx5e_priv *priv)
	struct mlx5e_rep_priv *rpriv = priv->ppriv;

	mlx5_del_flow_rules(rpriv->vport_rx_rule);
	mlx5e_destroy_rep_root_ft(priv);
	mlx5e_destroy_ttc_table(priv, &priv->fs.ttc);
	mlx5e_destroy_direct_tirs(priv, priv->direct_tir);
	mlx5e_destroy_indirect_tirs(priv, false);
+1 −0
Original line number Diff line number Diff line
@@ -87,6 +87,7 @@ struct mlx5e_rep_priv {
	struct mlx5_eswitch_rep *rep;
	struct mlx5e_neigh_update_table neigh_update;
	struct net_device      *netdev;
	struct mlx5_flow_table *root_ft;
	struct mlx5_flow_handle *vport_rx_rule;
	struct list_head       vport_sqs_list;
	struct mlx5_rep_uplink_priv uplink_priv; /* valid for uplink rep */
+45 −20
Original line number Diff line number Diff line
@@ -3313,6 +3313,45 @@ static bool is_duplicated_output_device(struct net_device *dev,
	return false;
}

static int mlx5_validate_goto_chain(struct mlx5_eswitch *esw,
				    struct mlx5e_tc_flow *flow,
				    const struct flow_action_entry *act,
				    u32 actions,
				    struct netlink_ext_ack *extack)
{
	u32 max_chain = mlx5_esw_chains_get_chain_range(esw);
	struct mlx5_esw_flow_attr *attr = flow->esw_attr;
	bool ft_flow = mlx5e_is_ft_flow(flow);
	u32 dest_chain = act->chain_index;

	if (ft_flow) {
		NL_SET_ERR_MSG_MOD(extack, "Goto action is not supported");
		return -EOPNOTSUPP;
	}

	if (!mlx5_esw_chains_backwards_supported(esw) &&
	    dest_chain <= attr->chain) {
		NL_SET_ERR_MSG_MOD(extack,
				   "Goto lower numbered chain isn't supported");
		return -EOPNOTSUPP;
	}
	if (dest_chain > max_chain) {
		NL_SET_ERR_MSG_MOD(extack,
				   "Requested destination chain is out of supported range");
		return -EOPNOTSUPP;
	}

	if (actions & (MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT |
		       MLX5_FLOW_CONTEXT_ACTION_DECAP) &&
	    !MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, reformat_and_fwd_to_table)) {
		NL_SET_ERR_MSG_MOD(extack,
				   "Goto chain is not allowed if action has reformat or decap");
		return -EOPNOTSUPP;
	}

	return 0;
}

static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
				struct flow_action *flow_action,
				struct mlx5e_tc_flow *flow,
@@ -3534,29 +3573,15 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
		case FLOW_ACTION_TUNNEL_DECAP:
			action |= MLX5_FLOW_CONTEXT_ACTION_DECAP;
			break;
		case FLOW_ACTION_GOTO: {
			u32 dest_chain = act->chain_index;
			u32 max_chain = mlx5_esw_chains_get_chain_range(esw);
		case FLOW_ACTION_GOTO:
			err = mlx5_validate_goto_chain(esw, flow, act, action,
						       extack);
			if (err)
				return err;

			if (ft_flow) {
				NL_SET_ERR_MSG_MOD(extack, "Goto action is not supported");
				return -EOPNOTSUPP;
			}
			if (!mlx5_esw_chains_backwards_supported(esw) &&
			    dest_chain <= attr->chain) {
				NL_SET_ERR_MSG_MOD(extack,
						   "Goto earlier chain isn't supported");
				return -EOPNOTSUPP;
			}
			if (dest_chain > max_chain) {
				NL_SET_ERR_MSG_MOD(extack,
						   "Requested destination chain is out of supported range");
				return -EOPNOTSUPP;
			}
			action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
			attr->dest_chain = dest_chain;
			attr->dest_chain = act->chain_index;
			break;
			}
		default:
			NL_SET_ERR_MSG_MOD(extack, "The offload action is not supported");
			return -EOPNOTSUPP;
Loading