Commit c67289e0 authored by David S. Miller's avatar David S. Miller

Merge tag 'mlx5-updates-2022-06-29' of git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux

mlx5-updates-2022-06-29

Chris Mi Says:
==============
Remove dependency between sriov and eswitch mode

Currently, there are three eswitch modes, none, legacy and
switchdev. None is the default mode. And when disabling sriov,
current eswitch mode will be changed to none. This patchset
removes eswitch mode none and also removes dependency between
sriov and eswitch mode. With this patchset, there are two
behavior changes:

Original behavior
-----------------
 - When driver is loaded without sriov enabled, none is the default
   mode. But actually eswitch mode should be either legacy or
   switchdev, so devlink will return unsupported when showing
   eswitch mode.
 - When disabling sriov in either legacy or switchdev mode, eswitch
   mode will be changed to none.

New behavior
------------
 - When driver is loaded, legacy will be the default mode.
 - When disabling sriov in either legacy or switchdev mode, eswitch
   mode will not be changed.

Jianbo Liu Says:
================
Add support offloading police action

This patchset supports offloading police action by flow meter ASO
object in hardware.

The first part is to add interfaces to create and destroy flow meter
ASO object, and modify meter parameters by ACCESS_ASO WQE. As multiple
objects are created at a time, and two meters are in one object,
bitmaps are used manage these meters in one creation.

Then the police action can be mapped to a meter by the action index.
After mlx5e tc action refactoring was merged and post_act table was
added, a simple tc flow with one police action is broken down into two
rules in hardware. One rule with the original match in the original
table, which performs a metadata rewrite and do metering, then jumps
to post_meter table. The second rule is placed in the post_act table
with all the actions left.

The rules in post_meter table match on the meter outcome. If the
outcome is GREEN, we merely jump back to the post_act table for
further processing. Otherwise, the outcome is RED, and we drop the
packet.

The last part is to support flow meter ASO object in sw steering.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 8e60a041 a8d52b02
......@@ -17,7 +17,7 @@ mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
fs_counters.o fs_ft_pool.o rl.o lag/debugfs.o lag/lag.o dev.o events.o wq.o lib/gid.o \
lib/devcom.o lib/pci_vsc.o lib/dm.o lib/fs_ttc.o diag/fs_tracepoint.o \
diag/fw_tracer.o diag/crdump.o devlink.o diag/rsc_dump.o \
fw_reset.o qos.o lib/tout.o
fw_reset.o qos.o lib/tout.o lib/aso.o
#
# Netdev basic
......@@ -45,7 +45,8 @@ mlx5_core-$(CONFIG_MLX5_CLS_ACT) += en_tc.o en/rep/tc.o en/rep/neigh.o \
esw/indir_table.o en/tc_tun_encap.o \
en/tc_tun_vxlan.o en/tc_tun_gre.o en/tc_tun_geneve.o \
en/tc_tun_mplsoudp.o diag/en_tc_tracepoint.o \
en/tc/post_act.o en/tc/int_port.o
en/tc/post_act.o en/tc/int_port.o en/tc/meter.o \
en/tc/post_meter.o
mlx5_core-$(CONFIG_MLX5_CLS_ACT) += en/tc/act/act.o en/tc/act/drop.o en/tc/act/trap.o \
en/tc/act/accept.o en/tc/act/mark.o en/tc/act/goto.o \
......@@ -53,7 +54,7 @@ mlx5_core-$(CONFIG_MLX5_CLS_ACT) += en/tc/act/act.o en/tc/act/drop.o en/tc/a
en/tc/act/vlan.o en/tc/act/vlan_mangle.o en/tc/act/mpls.o \
en/tc/act/mirred.o en/tc/act/mirred_nic.o \
en/tc/act/ct.o en/tc/act/sample.o en/tc/act/ptype.o \
en/tc/act/redirect_ingress.o
en/tc/act/redirect_ingress.o en/tc/act/police.o
ifneq ($(CONFIG_MLX5_TC_CT),)
mlx5_core-y += en/tc_ct.o en/tc/ct_fs_dmfs.o
......
......@@ -30,7 +30,7 @@ static struct mlx5e_tc_act *tc_acts_fdb[NUM_FLOW_ACTIONS] = {
NULL, /* FLOW_ACTION_WAKE, */
NULL, /* FLOW_ACTION_QUEUE, */
&mlx5e_tc_act_sample,
NULL, /* FLOW_ACTION_POLICE, */
&mlx5e_tc_act_police,
&mlx5e_tc_act_ct,
NULL, /* FLOW_ACTION_CT_METADATA, */
&mlx5e_tc_act_mpls_push,
......@@ -106,8 +106,8 @@ mlx5e_tc_act_init_parse_state(struct mlx5e_tc_act_parse_state *parse_state,
{
memset(parse_state, 0, sizeof(*parse_state));
parse_state->flow = flow;
parse_state->num_actions = flow_action->num_entries;
parse_state->extack = extack;
parse_state->flow_action = flow_action;
}
void
......
......@@ -13,7 +13,7 @@
struct mlx5_flow_attr;
struct mlx5e_tc_act_parse_state {
unsigned int num_actions;
struct flow_action *flow_action;
struct mlx5e_tc_flow *flow;
struct netlink_ext_ack *extack;
u32 actions;
......@@ -76,6 +76,7 @@ extern struct mlx5e_tc_act mlx5e_tc_act_ct;
extern struct mlx5e_tc_act mlx5e_tc_act_sample;
extern struct mlx5e_tc_act mlx5e_tc_act_ptype;
extern struct mlx5e_tc_act mlx5e_tc_act_redirect_ingress;
extern struct mlx5e_tc_act mlx5e_tc_act_police;
struct mlx5e_tc_act *
mlx5e_tc_act_get(enum flow_action_id act_id,
......
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include "act.h"
#include "en/tc_priv.h"
static bool
tc_act_can_offload_police(struct mlx5e_tc_act_parse_state *parse_state,
const struct flow_action_entry *act,
int act_index,
struct mlx5_flow_attr *attr)
{
if (mlx5e_policer_validate(parse_state->flow_action, act,
parse_state->extack))
return false;
return !!mlx5e_get_flow_meters(parse_state->flow->priv->mdev);
}
static int
tc_act_parse_police(struct mlx5e_tc_act_parse_state *parse_state,
const struct flow_action_entry *act,
struct mlx5e_priv *priv,
struct mlx5_flow_attr *attr)
{
struct mlx5e_flow_meter_params *params;
params = &attr->meter_attr.params;
params->index = act->hw_index;
if (act->police.rate_bytes_ps) {
params->mode = MLX5_RATE_LIMIT_BPS;
/* change rate to bits per second */
params->rate = act->police.rate_bytes_ps << 3;
params->burst = act->police.burst;
} else if (act->police.rate_pkt_ps) {
params->mode = MLX5_RATE_LIMIT_PPS;
params->rate = act->police.rate_pkt_ps;
params->burst = act->police.burst_pkt;
} else {
return -EOPNOTSUPP;
}
attr->action |= MLX5_FLOW_CONTEXT_ACTION_EXECUTE_ASO;
attr->exe_aso_type = MLX5_EXE_ASO_FLOW_METER;
return 0;
}
static bool
tc_act_is_multi_table_act_police(struct mlx5e_priv *priv,
const struct flow_action_entry *act,
struct mlx5_flow_attr *attr)
{
return true;
}
struct mlx5e_tc_act mlx5e_tc_act_police = {
.can_offload = tc_act_can_offload_police,
.parse_action = tc_act_parse_police,
.is_multi_table_act = tc_act_is_multi_table_act_police,
};
......@@ -12,7 +12,7 @@ tc_act_can_offload_trap(struct mlx5e_tc_act_parse_state *parse_state,
{
struct netlink_ext_ack *extack = parse_state->extack;
if (parse_state->num_actions != 1) {
if (parse_state->flow_action->num_entries != 1) {
NL_SET_ERR_MSG_MOD(extack, "action trap is supported as a sole action only");
return false;
}
......
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
/* Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
#ifndef __MLX5_EN_FLOW_METER_H__
#define __MLX5_EN_FLOW_METER_H__
struct mlx5e_flow_meter_aso_obj;
struct mlx5e_flow_meters;
struct mlx5_flow_attr;
enum mlx5e_flow_meter_mode {
MLX5_RATE_LIMIT_BPS,
MLX5_RATE_LIMIT_PPS,
};
struct mlx5e_flow_meter_params {
enum mlx5e_flow_meter_mode mode;
/* police action index */
u32 index;
u64 rate;
u64 burst;
};
struct mlx5e_flow_meter_handle {
struct mlx5e_flow_meters *flow_meters;
struct mlx5e_flow_meter_aso_obj *meters_obj;
u32 obj_id;
u8 idx;
int refcnt;
struct hlist_node hlist;
struct mlx5e_flow_meter_params params;
};
struct mlx5e_meter_attr {
struct mlx5e_flow_meter_params params;
struct mlx5e_flow_meter_handle *meter;
};
int
mlx5e_tc_meter_modify(struct mlx5_core_dev *mdev,
struct mlx5e_flow_meter_handle *meter,
struct mlx5e_flow_meter_params *meter_params);
struct mlx5e_flow_meter_handle *
mlx5e_tc_meter_get(struct mlx5_core_dev *mdev, struct mlx5e_flow_meter_params *params);
void
mlx5e_tc_meter_put(struct mlx5e_flow_meter_handle *meter);
struct mlx5_flow_table *
mlx5e_tc_meter_get_post_meter_ft(struct mlx5e_flow_meters *flow_meters);
struct mlx5e_flow_meters *
mlx5e_flow_meters_init(struct mlx5e_priv *priv,
enum mlx5_flow_namespace_type ns_type,
struct mlx5e_post_act *post_action);
void
mlx5e_flow_meters_cleanup(struct mlx5e_flow_meters *flow_meters);
#endif /* __MLX5_EN_FLOW_METER_H__ */
......@@ -22,9 +22,9 @@ struct mlx5e_post_act_handle {
u32 id;
};
#define MLX5_POST_ACTION_BITS (mlx5e_tc_attr_to_reg_mappings[FTEID_TO_REG].mlen)
#define MLX5_POST_ACTION_MAX GENMASK(MLX5_POST_ACTION_BITS - 1, 0)
#define MLX5_POST_ACTION_MASK MLX5_POST_ACTION_MAX
#define MLX5_POST_ACTION_BITS MLX5_REG_MAPPING_MBITS(FTEID_TO_REG)
#define MLX5_POST_ACTION_MASK MLX5_REG_MAPPING_MASK(FTEID_TO_REG)
#define MLX5_POST_ACTION_MAX MLX5_POST_ACTION_MASK
struct mlx5e_post_act *
mlx5e_tc_post_act_init(struct mlx5e_priv *priv, struct mlx5_fs_chains *chains,
......
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include "en/tc_priv.h"
#include "post_meter.h"
#include "en/tc/post_act.h"
#define MLX5_PACKET_COLOR_BITS MLX5_REG_MAPPING_MBITS(PACKET_COLOR_TO_REG)
#define MLX5_PACKET_COLOR_MASK MLX5_REG_MAPPING_MASK(PACKET_COLOR_TO_REG)
struct mlx5e_post_meter_priv {
struct mlx5_flow_table *ft;
struct mlx5_flow_group *fg;
struct mlx5_flow_handle *fwd_green_rule;
struct mlx5_flow_handle *drop_red_rule;
};
struct mlx5_flow_table *
mlx5e_post_meter_get_ft(struct mlx5e_post_meter_priv *post_meter)
{
return post_meter->ft;
}
static int
mlx5e_post_meter_table_create(struct mlx5e_priv *priv,
enum mlx5_flow_namespace_type ns_type,
struct mlx5e_post_meter_priv *post_meter)
{
struct mlx5_flow_table_attr ft_attr = {};
struct mlx5_flow_namespace *root_ns;
root_ns = mlx5_get_flow_namespace(priv->mdev, ns_type);
if (!root_ns) {
mlx5_core_warn(priv->mdev, "Failed to get namespace for flow meter\n");
return -EOPNOTSUPP;
}
ft_attr.flags = MLX5_FLOW_TABLE_UNMANAGED;
ft_attr.prio = FDB_SLOW_PATH;
ft_attr.max_fte = 2;
ft_attr.level = 1;
post_meter->ft = mlx5_create_flow_table(root_ns, &ft_attr);
if (IS_ERR(post_meter->ft)) {
mlx5_core_warn(priv->mdev, "Failed to create post_meter table\n");
return PTR_ERR(post_meter->ft);
}
return 0;
}
static int
mlx5e_post_meter_fg_create(struct mlx5e_priv *priv,
struct mlx5e_post_meter_priv *post_meter)
{
int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
void *misc2, *match_criteria;
u32 *flow_group_in;
int err = 0;
flow_group_in = kvzalloc(inlen, GFP_KERNEL);
if (!flow_group_in)
return -ENOMEM;
MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
MLX5_MATCH_MISC_PARAMETERS_2);
match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in,
match_criteria);
misc2 = MLX5_ADDR_OF(fte_match_param, match_criteria, misc_parameters_2);
MLX5_SET(fte_match_set_misc2, misc2, metadata_reg_c_5, MLX5_PACKET_COLOR_MASK);
MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 1);
post_meter->fg = mlx5_create_flow_group(post_meter->ft, flow_group_in);
if (IS_ERR(post_meter->fg)) {
mlx5_core_warn(priv->mdev, "Failed to create post_meter flow group\n");
err = PTR_ERR(post_meter->fg);
}
kvfree(flow_group_in);
return err;
}
static int
mlx5e_post_meter_rules_create(struct mlx5e_priv *priv,
struct mlx5e_post_meter_priv *post_meter,
struct mlx5e_post_act *post_act)
{
struct mlx5_flow_destination dest = {};
struct mlx5_flow_act flow_act = {};
struct mlx5_flow_handle *rule;
struct mlx5_flow_spec *spec;
int err;
spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec)
return -ENOMEM;
mlx5e_tc_match_to_reg_match(spec, PACKET_COLOR_TO_REG,
MLX5_FLOW_METER_COLOR_RED, MLX5_PACKET_COLOR_MASK);
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP;
flow_act.flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
rule = mlx5_add_flow_rules(post_meter->ft, spec, &flow_act, NULL, 0);
if (IS_ERR(rule)) {
mlx5_core_warn(priv->mdev, "Failed to create post_meter flow drop rule\n");
err = PTR_ERR(rule);
goto err_red;
}
post_meter->drop_red_rule = rule;
mlx5e_tc_match_to_reg_match(spec, PACKET_COLOR_TO_REG,
MLX5_FLOW_METER_COLOR_GREEN, MLX5_PACKET_COLOR_MASK);
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
dest.ft = mlx5e_tc_post_act_get_ft(post_act);
rule = mlx5_add_flow_rules(post_meter->ft, spec, &flow_act, &dest, 1);
if (IS_ERR(rule)) {
mlx5_core_warn(priv->mdev, "Failed to create post_meter flow fwd rule\n");
err = PTR_ERR(rule);
goto err_green;
}
post_meter->fwd_green_rule = rule;
kvfree(spec);
return 0;
err_green:
mlx5_del_flow_rules(post_meter->drop_red_rule);
err_red:
kvfree(spec);
return err;
}
static void
mlx5e_post_meter_rules_destroy(struct mlx5e_post_meter_priv *post_meter)
{
mlx5_del_flow_rules(post_meter->drop_red_rule);
mlx5_del_flow_rules(post_meter->fwd_green_rule);
}
static void
mlx5e_post_meter_fg_destroy(struct mlx5e_post_meter_priv *post_meter)
{
mlx5_destroy_flow_group(post_meter->fg);
}
static void
mlx5e_post_meter_table_destroy(struct mlx5e_post_meter_priv *post_meter)
{
mlx5_destroy_flow_table(post_meter->ft);
}
struct mlx5e_post_meter_priv *
mlx5e_post_meter_init(struct mlx5e_priv *priv,
enum mlx5_flow_namespace_type ns_type,
struct mlx5e_post_act *post_act)
{
struct mlx5e_post_meter_priv *post_meter;
int err;
post_meter = kzalloc(sizeof(*post_meter), GFP_KERNEL);
if (!post_meter)
return ERR_PTR(-ENOMEM);
err = mlx5e_post_meter_table_create(priv, ns_type, post_meter);
if (err)
goto err_ft;
err = mlx5e_post_meter_fg_create(priv, post_meter);
if (err)
goto err_fg;
err = mlx5e_post_meter_rules_create(priv, post_meter, post_act);
if (err)
goto err_rules;
return post_meter;
err_rules:
mlx5e_post_meter_fg_destroy(post_meter);
err_fg:
mlx5e_post_meter_table_destroy(post_meter);
err_ft:
kfree(post_meter);
return ERR_PTR(err);
}
void
mlx5e_post_meter_cleanup(struct mlx5e_post_meter_priv *post_meter)
{
mlx5e_post_meter_rules_destroy(post_meter);
mlx5e_post_meter_fg_destroy(post_meter);
mlx5e_post_meter_table_destroy(post_meter);
kfree(post_meter);
}
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
/* Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
#ifndef __MLX5_EN_POST_METER_H__
#define __MLX5_EN_POST_METER_H__
#define packet_color_to_reg { \
.mfield = MLX5_ACTION_IN_FIELD_METADATA_REG_C_5, \
.moffset = 0, \
.mlen = 8, \
.soffset = MLX5_BYTE_OFF(fte_match_param, \
misc_parameters_2.metadata_reg_c_5), \
}
struct mlx5e_post_meter_priv;
struct mlx5_flow_table *
mlx5e_post_meter_get_ft(struct mlx5e_post_meter_priv *post_meter);
struct mlx5e_post_meter_priv *
mlx5e_post_meter_init(struct mlx5e_priv *priv,
enum mlx5_flow_namespace_type ns_type,
struct mlx5e_post_act *post_act);
void
mlx5e_post_meter_cleanup(struct mlx5e_post_meter_priv *post_meter);
#endif /* __MLX5_EN_POST_METER_H__ */
......@@ -36,8 +36,8 @@
#define MLX5_CT_STATE_RELATED_BIT BIT(5)
#define MLX5_CT_STATE_INVALID_BIT BIT(6)
#define MLX5_CT_LABELS_BITS (mlx5e_tc_attr_to_reg_mappings[LABELS_TO_REG].mlen)
#define MLX5_CT_LABELS_MASK GENMASK(MLX5_CT_LABELS_BITS - 1, 0)
#define MLX5_CT_LABELS_BITS MLX5_REG_MAPPING_MBITS(LABELS_TO_REG)
#define MLX5_CT_LABELS_MASK MLX5_REG_MAPPING_MASK(LABELS_TO_REG)
/* Statically allocate modify actions for
* ipv6 and port nat (5) + tuple fields (4) + nic mode zone restore (1) = 10.
......
......@@ -62,10 +62,11 @@ struct mlx5_ct_attr {
misc_parameters_2.metadata_reg_c_4),\
}
/* 8 LSB of metadata C5 are reserved for packet color */
#define fteid_to_reg_ct {\
.mfield = MLX5_ACTION_IN_FIELD_METADATA_REG_C_5,\
.moffset = 0,\
.mlen = 32,\
.moffset = 8,\
.mlen = 24,\
.soffset = MLX5_BYTE_OFF(fte_match_param,\
misc_parameters_2.metadata_reg_c_5),\
}
......@@ -84,10 +85,8 @@ struct mlx5_ct_attr {
.mlen = ESW_ZONE_ID_BITS,\
}
#define REG_MAPPING_MLEN(reg) (mlx5e_tc_attr_to_reg_mappings[reg].mlen)
#define REG_MAPPING_MOFFSET(reg) (mlx5e_tc_attr_to_reg_mappings[reg].moffset)
#define MLX5_CT_ZONE_BITS (mlx5e_tc_attr_to_reg_mappings[ZONE_TO_REG].mlen)
#define MLX5_CT_ZONE_MASK GENMASK(MLX5_CT_ZONE_BITS - 1, 0)
#define MLX5_CT_ZONE_BITS MLX5_REG_MAPPING_MBITS(ZONE_TO_REG)
#define MLX5_CT_ZONE_MASK MLX5_REG_MAPPING_MASK(ZONE_TO_REG)
#if IS_ENABLED(CONFIG_MLX5_TC_CT)
......
......@@ -203,7 +203,13 @@ struct mlx5_fc *mlx5e_tc_get_counter(struct mlx5e_tc_flow *flow);
struct mlx5e_tc_int_port_priv *
mlx5e_get_int_port_priv(struct mlx5e_priv *priv);
struct mlx5e_flow_meters *mlx5e_get_flow_meters(struct mlx5_core_dev *dev);
void *mlx5e_get_match_headers_value(u32 flags, struct mlx5_flow_spec *spec);
void *mlx5e_get_match_headers_criteria(u32 flags, struct mlx5_flow_spec *spec);
int mlx5e_policer_validate(const struct flow_action *action,
const struct flow_action_entry *act,
struct netlink_ext_ack *extack);
#endif /* __MLX5_EN_TC_PRIV_H__ */
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
/* Copyright (c) 2020, Mellanox Technologies inc. All rights reserved. */
#ifndef __MLX5_IPSEC_STEERING_H__
#define __MLX5_IPSEC_STEERING_H__
#include "en.h"
#include "ipsec.h"
#include "ipsec_offload.h"
#include "en/fs.h"
void mlx5e_accel_ipsec_fs_cleanup(struct mlx5e_ipsec *ipsec);
int mlx5e_accel_ipsec_fs_init(struct mlx5e_ipsec *ipsec);
int mlx5e_accel_ipsec_fs_add_rule(struct mlx5e_priv *priv,
struct mlx5_accel_esp_xfrm_attrs *attrs,
u32 ipsec_obj_id,
struct mlx5e_ipsec_rule *ipsec_rule);
void mlx5e_accel_ipsec_fs_del_rule(struct mlx5e_priv *priv,
struct mlx5_accel_esp_xfrm_attrs *attrs,
struct mlx5e_ipsec_rule *ipsec_rule);
#endif /* __MLX5_IPSEC_STEERING_H__ */
......@@ -62,6 +62,7 @@ struct mlx5_tc_int_port_priv;
struct mlx5e_rep_bond;
struct mlx5e_tc_tun_encap;
struct mlx5e_post_act;
struct mlx5e_flow_meters;
struct mlx5_rep_uplink_priv {
/* indirect block callbacks are invoked on bind/unbind events
......@@ -97,6 +98,8 @@ struct mlx5_rep_uplink_priv {
/* OVS internal port support */
struct mlx5e_tc_int_port_priv *int_port_priv;
struct mlx5e_flow_meters *flow_meters;
};
struct mlx5e_rep_priv {
......
......@@ -59,6 +59,7 @@
#include "en/tc_tun_encap.h"
#include "en/tc/sample.h"
#include "en/tc/act/act.h"
#include "en/tc/post_meter.h"
#include "lib/devcom.h"
#include "lib/geneve.h"
#include "lib/fs_chains.h"
......@@ -104,6 +105,7 @@ struct mlx5e_tc_attr_to_reg_mapping mlx5e_tc_attr_to_reg_mappings[] = {
.mlen = 16,
},
[NIC_ZONE_RESTORE_TO_REG] = nic_zone_restore_to_reg_ct,
[PACKET_COLOR_TO_REG] = packet_color_to_reg,
};
/* To avoid false lock dependency warning set the tc_ht lock
......@@ -240,6 +242,30 @@ mlx5e_get_int_port_priv(struct mlx5e_priv *priv)
return NULL;
}
struct mlx5e_flow_meters *
mlx5e_get_flow_meters(struct mlx5_core_dev *dev)
{
struct mlx5_eswitch *esw = dev->priv.eswitch;
struct mlx5_rep_uplink_priv *uplink_priv;
struct mlx5e_rep_priv *uplink_rpriv;
struct mlx5e_priv *priv;
if (is_mdev_switchdev_mode(dev)) {
uplink_rpriv = mlx5_eswitch_get_uplink_priv(esw, REP_ETH);
uplink_priv = &uplink_rpriv->uplink_priv;
priv = netdev_priv(uplink_rpriv->netdev);
if (!uplink_priv->flow_meters)
uplink_priv->flow_meters =
mlx5e_flow_meters_init(priv,
MLX5_FLOW_NAMESPACE_FDB,
uplink_priv->post_act);
if (!IS_ERR(uplink_priv->flow_meters))
return uplink_priv->flow_meters;
}
return NULL;
}
static struct mlx5_tc_ct_priv *
get_ct_priv(struct mlx5e_priv *priv)
{
......@@ -319,12 +345,39 @@ mlx5_tc_rule_delete(struct mlx5e_priv *priv,
mlx5e_del_offloaded_nic_rule(priv, rule, attr);
}
static bool
is_flow_meter_action(struct mlx5_flow_attr *attr)
{
return ((attr->action & MLX5_FLOW_CONTEXT_ACTION_EXECUTE_ASO) &&
(attr->exe_aso_type == MLX5_EXE_ASO_FLOW_METER));
}
static int
mlx5e_tc_add_flow_meter(struct mlx5e_priv *priv,
struct mlx5_flow_attr *attr)
{
struct mlx5e_flow_meter_handle *meter;
meter = mlx5e_tc_meter_get(priv->mdev, &attr->meter_attr.params);
if (IS_ERR(meter)) {
mlx5_core_err(priv->mdev, "Failed to get flow meter\n");
return PTR_ERR(meter);
}
attr->meter_attr.meter = meter;
attr->dest_ft = mlx5e_tc_meter_get_post_meter_ft(meter->flow_meters);
attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
return 0;
}
struct mlx5_flow_handle *
mlx5e_tc_rule_offload(struct mlx5e_priv *priv,
struct mlx5_flow_spec *spec,
struct mlx5_flow_attr *attr)
{
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
int err;
if (attr->flags & MLX5_ATTR_FLAG_CT) {
struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts =
......@@ -341,6 +394,12 @@ mlx5e_tc_rule_offload(struct mlx5e_priv *priv,
if (attr->flags & MLX5_ATTR_FLAG_SAMPLE)
return mlx5e_tc_sample_offload(get_sample_priv(priv), spec, attr);
if (is_flow_meter_action(attr)) {
err = mlx5e_tc_add_flow_meter(priv, attr);
if (err)
return ERR_PTR(err);
}
return mlx5_eswitch_add_offloaded_rule(esw, spec, attr);
}
......@@ -367,6 +426,9 @@ mlx5e_tc_rule_unoffload(struct mlx5e_priv *priv,
}
mlx5_eswitch_del_offloaded_rule(esw, rule, attr);
if (attr->meter_attr.meter)
mlx5e_tc_meter_put(attr->meter_attr.meter);
}
int
......@@ -4519,7 +4581,7 @@ static int apply_police_params(struct mlx5e_priv *priv, u64 rate,
return err;
}
static int mlx5e_policer_validate(const struct flow_action *action,
int mlx5e_policer_validate(const struct flow_action *action,
const struct flow_action_entry *act,
struct netlink_ext_ack *extack)
{
......@@ -4956,6 +5018,7 @@ void mlx5e_tc_esw_cleanup(struct mlx5_rep_uplink_priv *uplink_priv)
mlx5e_tc_sample_cleanup(uplink_priv->tc_psample);
mlx5e_tc_int_port_cleanup(uplink_priv->int_port_priv);
mlx5_tc_ct_clean(uplink_priv->ct_priv);
mlx5e_flow_meters_cleanup(uplink_priv->flow_meters);
mlx5e_tc_post_act_destroy(uplink_priv->post_act);
}
......@@ -5061,7 +5124,7 @@ bool mlx5e_tc_update_skb(struct mlx5_cqe64 *cqe,
tc_skb_ext->chain = chain;
zone_restore_id = (reg_b >> REG_MAPPING_MOFFSET(NIC_ZONE_RESTORE_TO_REG)) &
zone_restore_id = (reg_b >> MLX5_REG_MAPPING_MOFFSET(NIC_ZONE_RESTORE_TO_REG)) &
ESW_ZONE_ID_MASK;
if (!mlx5e_tc_ct_restore_flow(tc->ct, skb,
......
......@@ -39,6 +39,7 @@
#include "en/tc_ct.h"
#include "en/tc_tun.h"
#include "en/tc/int_port.h"
#include "en/tc/meter.h"
#include "en_rep.h"
#define MLX5E_TC_FLOW_ID_MASK 0x0000ffff
......@@ -71,6 +72,7 @@ struct mlx5_flow_attr {
struct mlx5_modify_hdr *modify_hdr;
struct mlx5_ct_attr ct_attr;
struct mlx5e_sample_attr sample_attr;
struct mlx5e_meter_attr meter_attr;
struct mlx5e_tc_flow_parse_attr *parse_attr;
u32 chain;
u16 prio;
......@@ -83,6 +85,7 @@ struct mlx5_flow_attr {
u8 tun_ip_version;
int tunnel_id; /* mapped tunnel id */
u32 flags;
u32 exe_aso_type;
struct list_head list;
struct mlx5e_post_act_handle *post_act_handle;
struct {
......@@ -229,6 +232,7 @@ enum mlx5e_tc_attr_to_reg {
FTEID_TO_REG,
NIC_CHAIN_TO_REG,
NIC_ZONE_RESTORE_TO_REG,
PACKET_COLOR_TO_REG,
};
struct mlx5e_tc_attr_to_reg_mapping {
......@@ -241,6 +245,10 @@ struct mlx5e_tc_attr_to_reg_mapping {
extern struct mlx5e_tc_attr_to_reg_mapping mlx5e_tc_attr_to_reg_mappings[];
#define MLX5_REG_MAPPING_MOFFSET(reg_id) (mlx5e_tc_attr_to_reg_mappings[reg_id].moffset)
#define MLX5_REG_MAPPING_MBITS(reg_id) (mlx5e_tc_attr_to_reg_mappings[reg_id].mlen)
#define MLX5_REG_MAPPING_MASK(reg_id) (GENMASK(mlx5e_tc_attr_to_reg_mappings[reg_id].mlen - 1, 0))
bool mlx5e_is_valid_eswitch_fwd_dev(struct mlx5e_priv *priv,
struct net_device *out_dev);
......
......@@ -1152,8 +1152,6 @@ mlx5_eswitch_update_num_of_vfs(struct mlx5_eswitch *esw, int num_vfs)
{
const u32 *out;
WARN_ON_ONCE(esw->mode != MLX5_ESWITCH_NONE);
if (num_vfs < 0)
return;
......@@ -1186,6 +1184,9 @@ static int mlx5_esw_acls_ns_init(struct mlx5_eswitch *esw)
int total_vports;
int err;
if (esw->flags & MLX5_ESWITCH_VPORT_ACL_NS_CREATED)
return 0;
total_vports = mlx5_eswitch_get_total_vports(dev);
if (MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support)) {
......@@ -1203,6 +1204,7 @@ static int mlx5_esw_acls_ns_init(struct mlx5_eswitch *esw)
} else {
esw_warn(dev, "ingress ACL is not supported by FW\n");
}
esw->flags |= MLX5_ESWITCH_VPORT_ACL_NS_CREATED;
return 0;
err:
......@@ -1215,6 +1217,7 @@ static void mlx5_esw_acls_ns_cleanup(struct mlx5_eswitch *esw)
{
struct mlx5_core_dev *dev = esw->dev;
esw->flags &= ~MLX5_ESWITCH_VPORT_ACL_NS_CREATED;
if (MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support))
mlx5_fs_ingress_acls_cleanup(dev);
if (MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support))
......@@ -1224,7 +1227,6 @@ static void mlx5_esw_acls_ns_cleanup(struct mlx5_eswitch *esw)
/**
* mlx5_eswitch_enable_locked - Enable eswitch
* @esw: Pointer to eswitch
* @mode: Eswitch mode to enable
* @num_vfs: Enable eswitch for given number of VFs. This is optional.
* Valid value are 0, > 0 and MLX5_ESWITCH_IGNORE_NUM_VFS.
* Caller should pass num_vfs > 0 when enabling eswitch for
......@@ -1238,7 +1240,7 @@ static void mlx5_esw_acls_ns_cleanup(struct mlx5_eswitch *esw)
* mode. If num_vfs >=0 is provided, it setup VF related eswitch vports.
* It returns 0 on success or error code on failure.
*/
int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int mode, int num_vfs)
int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int num_vfs)
{
int err;
......@@ -1257,9 +1259,7 @@ int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int mode, int num_vfs)
mlx5_eswitch_update_num_of_vfs(esw, num_vfs);
esw->mode = mode;
if (mode == MLX5_ESWITCH_LEGACY) {
if (esw->mode == MLX5_ESWITCH_LEGACY) {
err = esw_legacy_enable(esw);
} else {
mlx5_rescan_drivers(esw->dev);
......@@ -1269,22 +1269,19 @@ int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int mode, int num_vfs)
if (err)
goto abort;
esw->fdb_table.flags |= MLX5_ESW_FDB_CREATED;
mlx5_eswitch_event_handlers_register(esw);
esw_info(esw->dev, "Enable: mode(%s), nvfs(%d), active vports(%d)\n",
mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
esw->esw_funcs.num_vfs, esw->enabled_vports);
mlx5_esw_mode_change_notify(esw, mode);
mlx5_esw_mode_change_notify(esw, esw->mode);
return 0;
abort:
esw->mode = MLX5_ESWITCH_NONE;
if (mode == MLX5_ESWITCH_OFFLOADS)
mlx5_rescan_drivers(esw->dev);
mlx5_esw_acls_ns_cleanup(esw);
return err;
}
......@@ -1305,14 +1302,14 @@ int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int num_vfs)
if (!mlx5_esw_allowed(esw))
return 0;
toggle_lag = esw->mode == MLX5_ESWITCH_NONE;
toggle_lag = !mlx5_esw_is_fdb_created(esw);
if (toggle_lag)
mlx5_lag_disable_change(esw->dev);
down_write(&esw->mode_lock);
if (esw->mode == MLX5_ESWITCH_NONE) {
ret = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_LEGACY, num_vfs);
if (!mlx5_esw_is_fdb_created(esw)) {
ret = mlx5_eswitch_enable_locked(esw, num_vfs);
} else {
enum mlx5_eswitch_vport_event vport_events;
......@@ -1330,55 +1327,79 @@ int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int num_vfs)
return ret;
}
void mlx5_eswitch_disable_locked(struct mlx5_eswitch *esw, bool clear_vf)
/* When disabling sriov, free driver level resources. */
void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw, bool clear_vf)
{
struct devlink *devlink = priv_to_devlink(esw->dev);
int old_mode;
lockdep_assert_held_write(&esw->mode_lock);
if (esw->mode == MLX5_ESWITCH_NONE)
if (!mlx5_esw_allowed(esw))
return;
esw_info(esw->dev, "Disable: mode(%s), nvfs(%d), active vports(%d)\n",
down_write(&esw->mode_lock);
/* If driver is unloaded, this function is called twice by remove_one()
* and mlx5_unload(). Prevent the second call.
*/
if (!esw->esw_funcs.num_vfs && !clear_vf)
goto unlock;
esw_info(esw->dev, "Unload vfs: mode(%s), nvfs(%d), active vports(%d)\n",
esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
esw->esw_funcs.num_vfs, esw->enabled_vports);
/* Notify eswitch users that it is exiting from current mode.
* So that it can do necessary cleanup before the eswitch is disabled.
mlx5_eswitch_unload_vf_vports(esw, esw->esw_funcs.num_vfs);
if (clear_vf)
mlx5_eswitch_clear_vf_vports_info(esw);
/* If disabling sriov in switchdev mode, free meta rules here
* because it depends on num_vfs.
*/
mlx5_esw_mode_change_notify(esw, MLX5_ESWITCH_NONE);
if (esw->mode == MLX5_ESWITCH_OFFLOADS) {
struct devlink *devlink = priv_to_devlink(esw->dev);
mlx5_eswitch_event_handlers_unregister(esw);
esw_offloads_del_send_to_vport_meta_rules(esw);
devlink_rate_nodes_destroy(devlink);
}
if (esw->mode == MLX5_ESWITCH_LEGACY)
esw_legacy_disable(esw);
else if (esw->mode == MLX5_ESWITCH_OFFLOADS)
esw_offloads_disable(esw);
esw->esw_funcs.num_vfs = 0;
old_mode = esw->mode;
esw->mode = MLX5_ESWITCH_NONE;
unlock:
up_write(&esw->mode_lock);
}
if (old_mode == MLX5_ESWITCH_OFFLOADS)
mlx5_rescan_drivers(esw->dev);
/* Free resources for corresponding eswitch mode. It is called by devlink
* when changing eswitch mode or modprobe when unloading driver.
*/
void mlx5_eswitch_disable_locked(struct mlx5_eswitch *esw)
{
struct devlink *devlink = priv_to_devlink(esw->dev);
devlink_rate_nodes_destroy(devlink);
/* Notify eswitch users that it is exiting from current mode.
* So that it can do necessary cleanup before the eswitch is disabled.
*/
mlx5_esw_mode_change_notify(esw, MLX5_ESWITCH_LEGACY);
mlx5_eswitch_event_handlers_unregister(esw);
esw_info(esw->dev, "Disable: mode(%s), nvfs(%d), active vports(%d)\n",
esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
esw->esw_funcs.num_vfs, esw->enabled_vports);
esw->fdb_table.flags &= ~MLX5_ESW_FDB_CREATED;
if (esw->mode == MLX5_ESWITCH_OFFLOADS)
esw_offloads_disable(esw);
else if (esw->mode == MLX5_ESWITCH_LEGACY)
esw_legacy_disable(esw);
mlx5_esw_acls_ns_cleanup(esw);
if (clear_vf)
mlx5_eswitch_clear_vf_vports_info(esw);
if (esw->mode == MLX5_ESWITCH_OFFLOADS)
devlink_rate_nodes_destroy(devlink);
}
void mlx5_eswitch_disable(struct mlx5_eswitch *esw, bool clear_vf)
void mlx5_eswitch_disable(struct mlx5_eswitch *esw)
{
if (!mlx5_esw_allowed(esw))
return;
mlx5_lag_disable_change(esw->dev);
down_write(&esw->mode_lock);
mlx5_eswitch_disable_locked(esw, clear_vf);
esw->esw_funcs.num_vfs = 0;
mlx5_eswitch_disable_locked(esw);
up_write(&esw->mode_lock);
mlx5_lag_enable_change(esw->dev);
}
......@@ -1573,7 +1594,7 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev)
refcount_set(&esw->qos.refcnt, 0);
esw->enabled_vports = 0;
esw->mode = MLX5_ESWITCH_NONE;
esw->mode = MLX5_ESWITCH_LEGACY;
esw->offloads.inline_mode = MLX5_INLINE_MODE_NONE;
if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, reformat) &&
MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap))
......@@ -1875,7 +1896,7 @@ u8 mlx5_eswitch_mode(const struct mlx5_core_dev *dev)
{
struct mlx5_eswitch *esw = dev->priv.eswitch;
return mlx5_esw_allowed(esw) ? esw->mode : MLX5_ESWITCH_NONE;
return mlx5_esw_allowed(esw) ? esw->mode : MLX5_ESWITCH_LEGACY;
}
EXPORT_SYMBOL_GPL(mlx5_eswitch_mode);
......@@ -1995,8 +2016,6 @@ int mlx5_esw_try_lock(struct mlx5_eswitch *esw)
*/
void mlx5_esw_unlock(struct mlx5_eswitch *esw)
{
if (!mlx5_esw_allowed(esw))
return;
up_write(&esw->mode_lock);
}
......
......@@ -282,10 +282,15 @@ struct mlx5_esw_functions {
enum {
MLX5_ESWITCH_VPORT_MATCH_METADATA = BIT(0),
MLX5_ESWITCH_REG_C1_LOOPBACK_ENABLED = BIT(1),
MLX5_ESWITCH_VPORT_ACL_NS_CREATED = BIT(2),
};
struct mlx5_esw_bridge_offloads;
enum {
MLX5_ESW_FDB_CREATED = BIT(0),
};
struct mlx5_eswitch {
struct mlx5_core_dev *dev;
struct mlx5_nb nb;
......@@ -337,6 +342,7 @@ void esw_offloads_disable(struct mlx5_eswitch *esw);
int esw_offloads_enable(struct mlx5_eswitch *esw);
void esw_offloads_cleanup_reps(struct mlx5_eswitch *esw);
int esw_offloads_init_reps(struct mlx5_eswitch *esw);
void esw_offloads_del_send_to_vport_meta_rules(struct mlx5_eswitch *esw);
bool mlx5_esw_vport_match_metadata_supported(const struct mlx5_eswitch *esw);
int mlx5_esw_offloads_vport_metadata_set(struct mlx5_eswitch *esw, bool enable);
......@@ -350,10 +356,11 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev);
void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw);
#define MLX5_ESWITCH_IGNORE_NUM_VFS (-1)
int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int mode, int num_vfs);
int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int num_vfs);
int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int num_vfs);
void mlx5_eswitch_disable_locked(struct mlx5_eswitch *esw, bool clear_vf);
void mlx5_eswitch_disable(struct mlx5_eswitch *esw, bool clear_vf);
void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw, bool clear_vf);
void mlx5_eswitch_disable_locked(struct mlx5_eswitch *esw);
void mlx5_eswitch_disable(struct mlx5_eswitch *esw);
int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw,
u16 vport, const u8 *mac);
int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw,
......@@ -575,6 +582,11 @@ mlx5_esw_devlink_port_index_to_vport_num(unsigned int dl_port_index)
return dl_port_index & 0xffff;
}
static inline bool mlx5_esw_is_fdb_created(struct mlx5_eswitch *esw)
{
return esw->fdb_table.flags & MLX5_ESW_FDB_CREATED;
}
/* TODO: This mlx5e_tc function shouldn't be called by eswitch */
void mlx5e_tc_clean_fdb_peer_flows(struct mlx5_eswitch *esw);
......@@ -719,7 +731,8 @@ int mlx5_eswitch_reload_reps(struct mlx5_eswitch *esw);
static inline int mlx5_eswitch_init(struct mlx5_core_dev *dev) { return 0; }
static inline void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw) {}
static inline int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int num_vfs) { return 0; }
static inline void mlx5_eswitch_disable(struct mlx5_eswitch *esw, bool clear_vf) {}
static inline void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw, bool clear_vf) {}
static inline void mlx5_eswitch_disable(struct mlx5_eswitch *esw) {}
static inline bool mlx5_eswitch_is_funcs_handler(struct mlx5_core_dev *dev) { return false; }
static inline
int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw, u16 vport, int link_state) { return 0; }
......
......@@ -1040,6 +1040,15 @@ static void mlx5_eswitch_del_send_to_vport_meta_rules(struct mlx5_eswitch *esw)
mlx5_del_flow_rules(flows[i]);
kvfree(flows);
/* If changing eswitch mode from switchdev to legacy, but num_vfs is not 0,
* meta rules could be freed again. So set it to NULL.
*/
esw->fdb_table.offloads.send_to_vport_meta_rules = NULL;
}
void esw_offloads_del_send_to_vport_meta_rules(struct mlx5_eswitch *esw)
{
mlx5_eswitch_del_send_to_vport_meta_rules(esw);
}
static int
......@@ -2034,7 +2043,7 @@ static int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, u8 *mode)
if (!MLX5_CAP_GEN(dev, vport_group_manager))
return -EOPNOTSUPP;
if (esw->mode == MLX5_ESWITCH_NONE)
if (!mlx5_esw_is_fdb_created(esw))
return -EOPNOTSUPP;
switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
......@@ -2170,18 +2179,18 @@ static int esw_offloads_start(struct mlx5_eswitch *esw,
{
int err, err1;
mlx5_eswitch_disable_locked(esw, false);
err = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_OFFLOADS,
esw->dev->priv.sriov.num_vfs);
esw->mode = MLX5_ESWITCH_OFFLOADS;
err = mlx5_eswitch_enable_locked(esw, esw->dev->priv.sriov.num_vfs);
if (err) {
NL_SET_ERR_MSG_MOD(extack,
"Failed setting eswitch to offloads");
err1 = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_LEGACY,
MLX5_ESWITCH_IGNORE_NUM_VFS);
esw->mode = MLX5_ESWITCH_LEGACY;
err1 = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_IGNORE_NUM_VFS);
if (err1) {
NL_SET_ERR_MSG_MOD(extack,
"Failed setting eswitch back to legacy");
}
mlx5_rescan_drivers(esw->dev);
}
if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) {
if (mlx5_eswitch_inline_mode_get(esw,
......@@ -2894,7 +2903,7 @@ int mlx5_esw_offloads_vport_metadata_set(struct mlx5_eswitch *esw, bool enable)
int err = 0;
down_write(&esw->mode_lock);
if (esw->mode != MLX5_ESWITCH_NONE) {
if (mlx5_esw_is_fdb_created(esw)) {
err = -EBUSY;
goto done;
}
......@@ -3229,13 +3238,12 @@ static int esw_offloads_stop(struct mlx5_eswitch *esw,
{
int err, err1;
mlx5_eswitch_disable_locked(esw, false);
err = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_LEGACY,
MLX5_ESWITCH_IGNORE_NUM_VFS);
esw->mode = MLX5_ESWITCH_LEGACY;
err = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_IGNORE_NUM_VFS);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Failed setting eswitch to legacy");
err1 = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_OFFLOADS,
MLX5_ESWITCH_IGNORE_NUM_VFS);
esw->mode = MLX5_ESWITCH_OFFLOADS;
err1 = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_IGNORE_NUM_VFS);
if (err1) {
NL_SET_ERR_MSG_MOD(extack,
"Failed setting eswitch back to offloads");
......@@ -3334,15 +3342,6 @@ static int esw_inline_mode_to_devlink(u8 mlx5_mode, u8 *mode)
return 0;
}
static int eswitch_devlink_esw_mode_check(const struct mlx5_eswitch *esw)
{
/* devlink commands in NONE eswitch mode are currently supported only
* on ECPF.
*/
return (esw->mode == MLX5_ESWITCH_NONE &&
!mlx5_core_is_ecpf_esw_manager(esw->dev)) ? -EOPNOTSUPP : 0;
}
/* FIXME: devl_unlock() followed by devl_lock() inside driver callback
* is never correct and prone to races. It's a transitional workaround,
* never repeat this pattern.
......@@ -3399,6 +3398,7 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
if (cur_mlx5_mode == mlx5_mode)
goto unlock;
mlx5_eswitch_disable_locked(esw);
if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) {
if (mlx5_devlink_trap_get_num_active(esw->dev)) {
NL_SET_ERR_MSG_MOD(extack,
......@@ -3409,6 +3409,7 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
err = esw_offloads_start(esw, extack);
} else if (mode == DEVLINK_ESWITCH_MODE_LEGACY) {
err = esw_offloads_stop(esw, extack);
mlx5_rescan_drivers(esw->dev);
} else {
err = -EINVAL;
}
......@@ -3431,12 +3432,7 @@ int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
return PTR_ERR(esw);
mlx5_eswtich_mode_callback_enter(devlink, esw);
err = eswitch_devlink_esw_mode_check(esw);
if (err)
goto unlock;
err = esw_mode_to_devlink(esw->mode, mode);
unlock:
mlx5_eswtich_mode_callback_exit(devlink, esw);
return err;
}
......@@ -3485,9 +3481,6 @@ int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode,
return PTR_ERR(esw);
mlx5_eswtich_mode_callback_enter(devlink, esw);
err = eswitch_devlink_esw_mode_check(esw);
if (err)
goto out;
switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
......@@ -3539,12 +3532,7 @@ int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode)
return PTR_ERR(esw);
mlx5_eswtich_mode_callback_enter(devlink, esw);
err = eswitch_devlink_esw_mode_check(esw);
if (err)
goto unlock;
err = esw_inline_mode_to_devlink(esw->offloads.inline_mode, mode);
unlock:
mlx5_eswtich_mode_callback_exit(devlink, esw);
return err;
}
......@@ -3555,16 +3543,13 @@ int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink,
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
struct mlx5_eswitch *esw;
int err;
int err = 0;
esw = mlx5_devlink_eswitch_get(devlink);
if (IS_ERR(esw))
return PTR_ERR(esw);
mlx5_eswtich_mode_callback_enter(devlink, esw);
err = eswitch_devlink_esw_mode_check(esw);
if (err)
goto unlock;
if (encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE &&
(!MLX5_CAP_ESW_FLOWTABLE_FDB(dev, reformat) ||
......@@ -3615,21 +3600,15 @@ int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink,
enum devlink_eswitch_encap_mode *encap)
{
struct mlx5_eswitch *esw;
int err;
esw = mlx5_devlink_eswitch_get(devlink);
if (IS_ERR(esw))
return PTR_ERR(esw);
mlx5_eswtich_mode_callback_enter(devlink, esw);
err = eswitch_devlink_esw_mode_check(esw);
if (err)
goto unlock;
*encap = esw->offloads.encap;
unlock:
mlx5_eswtich_mode_callback_exit(devlink, esw);
return err;
return 0;
}
static bool
......
......@@ -632,6 +632,7 @@ static int mlx5_deactivate_lag(struct mlx5_lag *ldev)
static bool mlx5_lag_check_prereq(struct mlx5_lag *ldev)
{
#ifdef CONFIG_MLX5_ESWITCH
struct mlx5_core_dev *dev;
u8 mode;
#endif
int i;
......@@ -641,11 +642,11 @@ static bool mlx5_lag_check_prereq(struct mlx5_lag *ldev)
return false;
#ifdef CONFIG_MLX5_ESWITCH
mode = mlx5_eswitch_mode(ldev->pf[MLX5_LAG_P1].dev);
if (mode != MLX5_ESWITCH_NONE && mode != MLX5_ESWITCH_OFFLOADS)
dev = ldev->pf[MLX5_LAG_P1].dev;
if ((mlx5_sriov_is_enabled(dev)) && !is_mdev_switchdev_mode(dev))
return false;
mode = mlx5_eswitch_mode(dev);
for (i = 0; i < ldev->ports; i++)
if (mlx5_eswitch_mode(ldev->pf[i].dev) != mode)
return false;
......@@ -760,8 +761,7 @@ static bool mlx5_lag_is_roce_lag(struct mlx5_lag *ldev)
#ifdef CONFIG_MLX5_ESWITCH
for (i = 0; i < ldev->ports; i++)
roce_lag = roce_lag &&
ldev->pf[i].dev->priv.eswitch->mode == MLX5_ESWITCH_NONE;
roce_lag = roce_lag && is_mdev_legacy_mode(ldev->pf[i].dev);
#endif
return roce_lag;
......
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
#ifndef __MLX5_LIB_ASO_H__
#define __MLX5_LIB_ASO_H__
#include <linux/mlx5/qp.h>
#include "mlx5_core.h"
#define MLX5_ASO_WQEBBS \
(DIV_ROUND_UP(sizeof(struct mlx5_aso_wqe), MLX5_SEND_WQE_BB))
#define MLX5_ASO_WQEBBS_DATA \
(DIV_ROUND_UP(sizeof(struct mlx5_aso_wqe_data), MLX5_SEND_WQE_BB))
#define MLX5_WQE_CTRL_WQE_OPC_MOD_SHIFT 24
struct mlx5_wqe_aso_ctrl_seg {
__be32 va_h;
__be32 va_l; /* include read_enable */
__be32 l_key;
u8 data_mask_mode;
u8 condition_1_0_operand;
u8 condition_1_0_offset;
u8 data_offset_condition_operand;
__be32 condition_0_data;
__be32 condition_0_mask;
__be32 condition_1_data;
__be32 condition_1_mask;
__be64 bitwise_data;
__be64 data_mask;
};
struct mlx5_wqe_aso_data_seg {
__be32 bytewise_data[16];
};
struct mlx5_aso_wqe {
struct mlx5_wqe_ctrl_seg ctrl;
struct mlx5_wqe_aso_ctrl_seg aso_ctrl;
};
struct mlx5_aso_wqe_data {
struct mlx5_wqe_ctrl_seg ctrl;
struct mlx5_wqe_aso_ctrl_seg aso_ctrl;
struct mlx5_wqe_aso_data_seg aso_data;
};
enum {
MLX5_ASO_LOGICAL_AND,
MLX5_ASO_LOGICAL_OR,
};
enum {
MLX5_ASO_ALWAYS_FALSE,
MLX5_ASO_ALWAYS_TRUE,
MLX5_ASO_EQUAL,
MLX5_ASO_NOT_EQUAL,
MLX5_ASO_GREATER_OR_EQUAL,
MLX5_ASO_LESSER_OR_EQUAL,
MLX5_ASO_LESSER,
MLX5_ASO_GREATER,
MLX5_ASO_CYCLIC_GREATER,
MLX5_ASO_CYCLIC_LESSER,
};
enum {
MLX5_ASO_DATA_MASK_MODE_BITWISE_64BIT,
MLX5_ASO_DATA_MASK_MODE_BYTEWISE_64BYTE,
MLX5_ASO_DATA_MASK_MODE_CALCULATED_64BYTE,
};
enum {
MLX5_ACCESS_ASO_OPC_MOD_FLOW_METER = 0x2,
};
struct mlx5_aso;
void *mlx5_aso_get_wqe(struct mlx5_aso *aso);
void mlx5_aso_build_wqe(struct mlx5_aso *aso, u8 ds_cnt,
struct mlx5_aso_wqe *aso_wqe,
u32 obj_id, u32 opc_mode);
void mlx5_aso_post_wqe(struct mlx5_aso *aso, bool with_data,
struct mlx5_wqe_ctrl_seg *doorbell_cseg);
int mlx5_aso_poll_cq(struct mlx5_aso *aso, bool with_data, u32 interval_ms);
struct mlx5_aso *mlx5_aso_create(struct mlx5_core_dev *mdev, u32 pdn);
void mlx5_aso_destroy(struct mlx5_aso *aso);
#endif /* __MLX5_LIB_ASO_H__ */
......@@ -1250,6 +1250,7 @@ static void mlx5_unload(struct mlx5_core_dev *dev)
{
mlx5_sf_dev_table_destroy(dev);
mlx5_sriov_detach(dev);
mlx5_eswitch_disable(dev->priv.eswitch);
mlx5_lag_remove_mdev(dev);
mlx5_ec_cleanup(dev);
mlx5_sf_hw_table_destroy(dev);
......
......@@ -501,7 +501,7 @@ static int mlx5_sf_esw_event(struct notifier_block *nb, unsigned long event, voi
case MLX5_ESWITCH_OFFLOADS:
mlx5_sf_table_enable(table);
break;
case MLX5_ESWITCH_NONE:
case MLX5_ESWITCH_LEGACY:
mlx5_sf_table_disable(table);
break;
default:
......
......@@ -145,8 +145,7 @@ mlx5_device_disable_sriov(struct mlx5_core_dev *dev, int num_vfs, bool clear_vf)
sriov->vfs_ctx[vf].enabled = 0;
}
if (MLX5_ESWITCH_MANAGER(dev))
mlx5_eswitch_disable(dev->priv.eswitch, clear_vf);
mlx5_eswitch_disable_sriov(dev->priv.eswitch, clear_vf);
if (mlx5_wait_for_pages(dev, &dev->priv.vfs_pages))
mlx5_core_warn(dev, "timeout reclaiming VFs pages\n");
......
......@@ -12,7 +12,6 @@
#define MLX5_ESWITCH_MANAGER(mdev) MLX5_CAP_GEN(mdev, eswitch_manager)
enum {
MLX5_ESWITCH_NONE,
MLX5_ESWITCH_LEGACY,
MLX5_ESWITCH_OFFLOADS
};
......@@ -153,7 +152,7 @@ struct mlx5_core_dev *mlx5_eswitch_get_core_dev(struct mlx5_eswitch *esw);
static inline u8 mlx5_eswitch_mode(const struct mlx5_core_dev *dev)
{
return MLX5_ESWITCH_NONE;
return MLX5_ESWITCH_LEGACY;
}
static inline enum devlink_eswitch_encap_mode
......@@ -198,6 +197,11 @@ static inline struct mlx5_core_dev *mlx5_eswitch_get_core_dev(struct mlx5_eswitc
#endif /* CONFIG_MLX5_ESWITCH */
static inline bool is_mdev_legacy_mode(struct mlx5_core_dev *dev)
{
return mlx5_eswitch_mode(dev) == MLX5_ESWITCH_LEGACY;
}
static inline bool is_mdev_switchdev_mode(struct mlx5_core_dev *dev)
{
return mlx5_eswitch_mode(dev) == MLX5_ESWITCH_OFFLOADS;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment