Merge tag 'mlx5-updates-2022-07-13' of git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux
Saeed Mahameed says: ==================== mlx5-updates-2022-07-13 1) Support 802.1ad for bridge offloads Vlad Buslov Says: ================= Current mlx5 bridge VLAN offload implementation only supports 802.1Q VLAN Ethernet protocol. That protocol type is assumed by default and SWITCHDEV_ATTR_ID_BRIDGE_VLAN_PROTOCOL notification is ignored. In order to support dynamically setting VLAN protocol handle SWITCHDEV_ATTR_ID_BRIDGE_VLAN_PROTOCOL notification by flushing FDB and re-creating VLAN modify header actions with a new protocol. Implement support for 802.1ad protocol by saving the current VLAN protocol to per-bridge variable and re-create the necessary flow groups according to its current value (either use cvlan or svlan flow fields). ================== 2) debugfs to count ongoing FW commands 3) debugfs to query eswitch vport firmware diagnostic counters 4) Add missing meter configuration in flow action 5) Some misc cleanup * tag 'mlx5-updates-2022-07-13' of git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux: net/mlx5e: Remove the duplicating check for striding RQ when enabling LRO net/mlx5e: Move the LRO-XSK check to mlx5e_fix_features net/mlx5e: Extend flower police validation net/mlx5e: configure meter in flow action net/mlx5e: Removed useless code in function net/mlx5: Bridge, implement QinQ support net/mlx5: Bridge, implement infrastructure for VLAN protocol change net/mlx5: Bridge, extract VLAN push/pop actions creation net/mlx5: Bridge, rename filter fg to vlan_filter net/mlx5: Bridge, refactor groups sizes and indices net/mlx5: debugfs, Add num of in-use FW command interface slots net/mlx5: Expose vnic diagnostic counters for eswitch managed vports net/mlx5: Use software VHCA id when it's supported net/mlx5: Introduce ifc bits for using software vhca id net/mlx5: Use the bitmap API to allocate bitmaps ==================== Link: https://lore.kernel.org/r/20220713225859.401241-1-saeed@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -68,7 +68,7 @@ mlx5_core-$(CONFIG_MLX5_TC_SAMPLE) += en/tc/sample.o
|
||||
#
|
||||
mlx5_core-$(CONFIG_MLX5_ESWITCH) += eswitch.o eswitch_offloads.o eswitch_offloads_termtbl.o \
|
||||
ecpf.o rdma.o esw/legacy.o \
|
||||
esw/devlink_port.o esw/vporttbl.o esw/qos.o
|
||||
esw/debugfs.o esw/devlink_port.o esw/vporttbl.o esw/qos.o
|
||||
|
||||
mlx5_core-$(CONFIG_MLX5_ESWITCH) += esw/acl/helper.o \
|
||||
esw/acl/egress_lgcy.o esw/acl/egress_ofld.o \
|
||||
|
||||
@@ -166,6 +166,28 @@ static const struct file_operations stats_fops = {
|
||||
.write = average_write,
|
||||
};
|
||||
|
||||
static ssize_t slots_read(struct file *filp, char __user *buf, size_t count,
|
||||
loff_t *pos)
|
||||
{
|
||||
struct mlx5_cmd *cmd;
|
||||
char tbuf[6];
|
||||
int weight;
|
||||
int field;
|
||||
int ret;
|
||||
|
||||
cmd = filp->private_data;
|
||||
weight = bitmap_weight(&cmd->bitmask, cmd->max_reg_cmds);
|
||||
field = cmd->max_reg_cmds - weight;
|
||||
ret = snprintf(tbuf, sizeof(tbuf), "%d\n", field);
|
||||
return simple_read_from_buffer(buf, count, pos, tbuf, ret);
|
||||
}
|
||||
|
||||
static const struct file_operations slots_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = simple_open,
|
||||
.read = slots_read,
|
||||
};
|
||||
|
||||
void mlx5_cmdif_debugfs_init(struct mlx5_core_dev *dev)
|
||||
{
|
||||
struct mlx5_cmd_stats *stats;
|
||||
@@ -176,6 +198,8 @@ void mlx5_cmdif_debugfs_init(struct mlx5_core_dev *dev)
|
||||
cmd = &dev->priv.dbg.cmdif_debugfs;
|
||||
*cmd = debugfs_create_dir("commands", dev->priv.dbg.dbg_root);
|
||||
|
||||
debugfs_create_file("slots_inuse", 0400, *cmd, &dev->cmd, &slots_fops);
|
||||
|
||||
for (i = 0; i < MLX5_CMD_OP_MAX; i++) {
|
||||
stats = &dev->cmd.stats[i];
|
||||
namep = mlx5_command_str(i);
|
||||
|
||||
@@ -269,6 +269,12 @@ mlx5_esw_bridge_port_obj_attr_set(struct net_device *dev,
|
||||
err = mlx5_esw_bridge_vlan_filtering_set(vport_num, esw_owner_vhca_id,
|
||||
attr->u.vlan_filtering, br_offloads);
|
||||
break;
|
||||
case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_PROTOCOL:
|
||||
err = mlx5_esw_bridge_vlan_proto_set(vport_num,
|
||||
esw_owner_vhca_id,
|
||||
attr->u.vlan_protocol,
|
||||
br_offloads);
|
||||
break;
|
||||
default:
|
||||
err = -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,12 @@ tc_act_can_offload_police(struct mlx5e_tc_act_parse_state *parse_state,
|
||||
int act_index,
|
||||
struct mlx5_flow_attr *attr)
|
||||
{
|
||||
if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
|
||||
act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
|
||||
NL_SET_ERR_MSG_MOD(parse_state->extack,
|
||||
"Offload not supported when conform action is not pipe or ok");
|
||||
return false;
|
||||
}
|
||||
if (mlx5e_policer_validate(parse_state->flow_action, act,
|
||||
parse_state->extack))
|
||||
return false;
|
||||
|
||||
@@ -742,10 +742,7 @@ mlx5e_ethtool_flow_replace(struct mlx5e_priv *priv,
|
||||
|
||||
eth_rule->flow_spec = *fs;
|
||||
eth_rule->eth_ft = eth_ft;
|
||||
if (!eth_ft->ft) {
|
||||
err = -EINVAL;
|
||||
goto del_ethtool_rule;
|
||||
}
|
||||
|
||||
rule = add_ethtool_flow_rule(priv, eth_rule, eth_ft->ft, fs, rss_context);
|
||||
if (IS_ERR(rule)) {
|
||||
err = PTR_ERR(rule);
|
||||
|
||||
@@ -3594,20 +3594,7 @@ static int set_feature_lro(struct net_device *netdev, bool enable)
|
||||
|
||||
mutex_lock(&priv->state_lock);
|
||||
|
||||
if (enable && priv->xsk.refcnt) {
|
||||
netdev_warn(netdev, "LRO is incompatible with AF_XDP (%u XSKs are active)\n",
|
||||
priv->xsk.refcnt);
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cur_params = &priv->channels.params;
|
||||
if (enable && !MLX5E_GET_PFLAG(cur_params, MLX5E_PFLAG_RX_STRIDING_RQ)) {
|
||||
netdev_warn(netdev, "can't set LRO with legacy RQ\n");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
new_params = *cur_params;
|
||||
|
||||
if (enable)
|
||||
@@ -3916,6 +3903,11 @@ static netdev_features_t mlx5e_fix_features(struct net_device *netdev,
|
||||
}
|
||||
|
||||
if (priv->xsk.refcnt) {
|
||||
if (features & NETIF_F_LRO) {
|
||||
netdev_warn(netdev, "LRO is incompatible with AF_XDP (%u XSKs are active)\n",
|
||||
priv->xsk.refcnt);
|
||||
features &= ~NETIF_F_LRO;
|
||||
}
|
||||
if (features & NETIF_F_GRO_HW) {
|
||||
netdev_warn(netdev, "HW GRO is incompatible with AF_XDP (%u XSKs are active)\n",
|
||||
priv->xsk.refcnt);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
|
||||
/* Copyright (c) 2021 Mellanox Technologies. */
|
||||
|
||||
#include <linux/build_bug.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <net/netevent.h>
|
||||
@@ -12,26 +13,57 @@
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "diag/bridge_tracepoint.h"
|
||||
|
||||
#define MLX5_ESW_BRIDGE_INGRESS_TABLE_SIZE 64000
|
||||
#define MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_SIZE 12000
|
||||
#define MLX5_ESW_BRIDGE_INGRESS_TABLE_UNTAGGED_GRP_SIZE 16000
|
||||
#define MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_IDX_FROM 0
|
||||
#define MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_IDX_TO (MLX5_ESW_BRIDGE_INGRESS_TABLE_SIZE / 4 - 1)
|
||||
#define MLX5_ESW_BRIDGE_INGRESS_TABLE_FILTER_GRP_IDX_FROM \
|
||||
#define MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_IDX_TO \
|
||||
(MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_SIZE - 1)
|
||||
#define MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_FILTER_GRP_IDX_FROM \
|
||||
(MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_IDX_TO + 1)
|
||||
#define MLX5_ESW_BRIDGE_INGRESS_TABLE_FILTER_GRP_IDX_TO \
|
||||
(MLX5_ESW_BRIDGE_INGRESS_TABLE_SIZE / 2 - 1)
|
||||
#define MLX5_ESW_BRIDGE_INGRESS_TABLE_MAC_GRP_IDX_FROM \
|
||||
(MLX5_ESW_BRIDGE_INGRESS_TABLE_FILTER_GRP_IDX_TO + 1)
|
||||
#define MLX5_ESW_BRIDGE_INGRESS_TABLE_MAC_GRP_IDX_TO (MLX5_ESW_BRIDGE_INGRESS_TABLE_SIZE - 1)
|
||||
#define MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_FILTER_GRP_IDX_TO \
|
||||
(MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_FILTER_GRP_IDX_FROM + \
|
||||
MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_SIZE - 1)
|
||||
#define MLX5_ESW_BRIDGE_INGRESS_TABLE_QINQ_GRP_IDX_FROM \
|
||||
(MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_FILTER_GRP_IDX_TO + 1)
|
||||
#define MLX5_ESW_BRIDGE_INGRESS_TABLE_QINQ_GRP_IDX_TO \
|
||||
(MLX5_ESW_BRIDGE_INGRESS_TABLE_QINQ_GRP_IDX_FROM + \
|
||||
MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_SIZE - 1)
|
||||
#define MLX5_ESW_BRIDGE_INGRESS_TABLE_QINQ_FILTER_GRP_IDX_FROM \
|
||||
(MLX5_ESW_BRIDGE_INGRESS_TABLE_QINQ_GRP_IDX_TO + 1)
|
||||
#define MLX5_ESW_BRIDGE_INGRESS_TABLE_QINQ_FILTER_GRP_IDX_TO \
|
||||
(MLX5_ESW_BRIDGE_INGRESS_TABLE_QINQ_FILTER_GRP_IDX_FROM + \
|
||||
MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_SIZE - 1)
|
||||
#define MLX5_ESW_BRIDGE_INGRESS_TABLE_MAC_GRP_IDX_FROM \
|
||||
(MLX5_ESW_BRIDGE_INGRESS_TABLE_QINQ_FILTER_GRP_IDX_TO + 1)
|
||||
#define MLX5_ESW_BRIDGE_INGRESS_TABLE_MAC_GRP_IDX_TO \
|
||||
(MLX5_ESW_BRIDGE_INGRESS_TABLE_MAC_GRP_IDX_FROM + \
|
||||
MLX5_ESW_BRIDGE_INGRESS_TABLE_UNTAGGED_GRP_SIZE - 1)
|
||||
#define MLX5_ESW_BRIDGE_INGRESS_TABLE_SIZE \
|
||||
(MLX5_ESW_BRIDGE_INGRESS_TABLE_MAC_GRP_IDX_TO + 1)
|
||||
static_assert(MLX5_ESW_BRIDGE_INGRESS_TABLE_SIZE == 64000);
|
||||
|
||||
#define MLX5_ESW_BRIDGE_EGRESS_TABLE_SIZE 64000
|
||||
#define MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_SIZE 16000
|
||||
#define MLX5_ESW_BRIDGE_EGRESS_TABLE_MAC_GRP_SIZE (32000 - 1)
|
||||
#define MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_IDX_FROM 0
|
||||
#define MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_IDX_TO (MLX5_ESW_BRIDGE_EGRESS_TABLE_SIZE / 2 - 1)
|
||||
#define MLX5_ESW_BRIDGE_EGRESS_TABLE_MAC_GRP_IDX_FROM \
|
||||
#define MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_IDX_TO \
|
||||
(MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_SIZE - 1)
|
||||
#define MLX5_ESW_BRIDGE_EGRESS_TABLE_QINQ_GRP_IDX_FROM \
|
||||
(MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_IDX_TO + 1)
|
||||
#define MLX5_ESW_BRIDGE_EGRESS_TABLE_MAC_GRP_IDX_TO (MLX5_ESW_BRIDGE_EGRESS_TABLE_SIZE - 2)
|
||||
#define MLX5_ESW_BRIDGE_EGRESS_TABLE_QINQ_GRP_IDX_TO \
|
||||
(MLX5_ESW_BRIDGE_EGRESS_TABLE_QINQ_GRP_IDX_FROM + \
|
||||
MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_SIZE - 1)
|
||||
#define MLX5_ESW_BRIDGE_EGRESS_TABLE_MAC_GRP_IDX_FROM \
|
||||
(MLX5_ESW_BRIDGE_EGRESS_TABLE_QINQ_GRP_IDX_TO + 1)
|
||||
#define MLX5_ESW_BRIDGE_EGRESS_TABLE_MAC_GRP_IDX_TO \
|
||||
(MLX5_ESW_BRIDGE_EGRESS_TABLE_MAC_GRP_IDX_FROM + \
|
||||
MLX5_ESW_BRIDGE_EGRESS_TABLE_MAC_GRP_SIZE - 1)
|
||||
#define MLX5_ESW_BRIDGE_EGRESS_TABLE_MISS_GRP_IDX_FROM \
|
||||
(MLX5_ESW_BRIDGE_EGRESS_TABLE_MAC_GRP_IDX_TO + 1)
|
||||
#define MLX5_ESW_BRIDGE_EGRESS_TABLE_MISS_GRP_IDX_TO (MLX5_ESW_BRIDGE_EGRESS_TABLE_SIZE - 1)
|
||||
#define MLX5_ESW_BRIDGE_EGRESS_TABLE_MISS_GRP_IDX_TO \
|
||||
MLX5_ESW_BRIDGE_EGRESS_TABLE_MISS_GRP_IDX_FROM
|
||||
#define MLX5_ESW_BRIDGE_EGRESS_TABLE_SIZE \
|
||||
(MLX5_ESW_BRIDGE_EGRESS_TABLE_MISS_GRP_IDX_TO + 1)
|
||||
static_assert(MLX5_ESW_BRIDGE_EGRESS_TABLE_SIZE == 64000);
|
||||
|
||||
#define MLX5_ESW_BRIDGE_SKIP_TABLE_SIZE 0
|
||||
|
||||
@@ -63,12 +95,14 @@ struct mlx5_esw_bridge {
|
||||
|
||||
struct mlx5_flow_table *egress_ft;
|
||||
struct mlx5_flow_group *egress_vlan_fg;
|
||||
struct mlx5_flow_group *egress_qinq_fg;
|
||||
struct mlx5_flow_group *egress_mac_fg;
|
||||
struct mlx5_flow_group *egress_miss_fg;
|
||||
struct mlx5_pkt_reformat *egress_miss_pkt_reformat;
|
||||
struct mlx5_flow_handle *egress_miss_handle;
|
||||
unsigned long ageing_time;
|
||||
u32 flags;
|
||||
u16 vlan_proto;
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -138,7 +172,9 @@ mlx5_esw_bridge_table_create(int max_fte, u32 level, struct mlx5_eswitch *esw)
|
||||
}
|
||||
|
||||
static struct mlx5_flow_group *
|
||||
mlx5_esw_bridge_ingress_vlan_fg_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *ingress_ft)
|
||||
mlx5_esw_bridge_ingress_vlan_proto_fg_create(unsigned int from, unsigned int to, u16 vlan_proto,
|
||||
struct mlx5_eswitch *esw,
|
||||
struct mlx5_flow_table *ingress_ft)
|
||||
{
|
||||
int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
|
||||
struct mlx5_flow_group *fg;
|
||||
@@ -154,30 +190,53 @@ mlx5_esw_bridge_ingress_vlan_fg_create(struct mlx5_eswitch *esw, struct mlx5_flo
|
||||
|
||||
MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.smac_47_16);
|
||||
MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.smac_15_0);
|
||||
MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.cvlan_tag);
|
||||
if (vlan_proto == ETH_P_8021Q)
|
||||
MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.cvlan_tag);
|
||||
else if (vlan_proto == ETH_P_8021AD)
|
||||
MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.svlan_tag);
|
||||
MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.first_vid);
|
||||
|
||||
MLX5_SET(fte_match_param, match, misc_parameters_2.metadata_reg_c_0,
|
||||
mlx5_eswitch_get_vport_metadata_mask());
|
||||
|
||||
MLX5_SET(create_flow_group_in, in, start_flow_index,
|
||||
MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_IDX_FROM);
|
||||
MLX5_SET(create_flow_group_in, in, end_flow_index,
|
||||
MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_IDX_TO);
|
||||
MLX5_SET(create_flow_group_in, in, start_flow_index, from);
|
||||
MLX5_SET(create_flow_group_in, in, end_flow_index, to);
|
||||
|
||||
fg = mlx5_create_flow_group(ingress_ft, in);
|
||||
kvfree(in);
|
||||
if (IS_ERR(fg))
|
||||
esw_warn(esw->dev,
|
||||
"Failed to create VLAN flow group for bridge ingress table (err=%ld)\n",
|
||||
PTR_ERR(fg));
|
||||
"Failed to create VLAN(proto=%x) flow group for bridge ingress table (err=%ld)\n",
|
||||
vlan_proto, PTR_ERR(fg));
|
||||
|
||||
return fg;
|
||||
}
|
||||
|
||||
static struct mlx5_flow_group *
|
||||
mlx5_esw_bridge_ingress_filter_fg_create(struct mlx5_eswitch *esw,
|
||||
struct mlx5_flow_table *ingress_ft)
|
||||
mlx5_esw_bridge_ingress_vlan_fg_create(struct mlx5_eswitch *esw,
|
||||
struct mlx5_flow_table *ingress_ft)
|
||||
{
|
||||
unsigned int from = MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_IDX_FROM;
|
||||
unsigned int to = MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_IDX_TO;
|
||||
|
||||
return mlx5_esw_bridge_ingress_vlan_proto_fg_create(from, to, ETH_P_8021Q, esw, ingress_ft);
|
||||
}
|
||||
|
||||
static struct mlx5_flow_group *
|
||||
mlx5_esw_bridge_ingress_qinq_fg_create(struct mlx5_eswitch *esw,
|
||||
struct mlx5_flow_table *ingress_ft)
|
||||
{
|
||||
unsigned int from = MLX5_ESW_BRIDGE_INGRESS_TABLE_QINQ_GRP_IDX_FROM;
|
||||
unsigned int to = MLX5_ESW_BRIDGE_INGRESS_TABLE_QINQ_GRP_IDX_TO;
|
||||
|
||||
return mlx5_esw_bridge_ingress_vlan_proto_fg_create(from, to, ETH_P_8021AD, esw,
|
||||
ingress_ft);
|
||||
}
|
||||
|
||||
static struct mlx5_flow_group *
|
||||
mlx5_esw_bridge_ingress_vlan_proto_filter_fg_create(unsigned int from, unsigned int to,
|
||||
u16 vlan_proto, struct mlx5_eswitch *esw,
|
||||
struct mlx5_flow_table *ingress_ft)
|
||||
{
|
||||
int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
|
||||
struct mlx5_flow_group *fg;
|
||||
@@ -193,26 +252,47 @@ mlx5_esw_bridge_ingress_filter_fg_create(struct mlx5_eswitch *esw,
|
||||
|
||||
MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.smac_47_16);
|
||||
MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.smac_15_0);
|
||||
MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.cvlan_tag);
|
||||
|
||||
if (vlan_proto == ETH_P_8021Q)
|
||||
MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.cvlan_tag);
|
||||
else if (vlan_proto == ETH_P_8021AD)
|
||||
MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.svlan_tag);
|
||||
MLX5_SET(fte_match_param, match, misc_parameters_2.metadata_reg_c_0,
|
||||
mlx5_eswitch_get_vport_metadata_mask());
|
||||
|
||||
MLX5_SET(create_flow_group_in, in, start_flow_index,
|
||||
MLX5_ESW_BRIDGE_INGRESS_TABLE_FILTER_GRP_IDX_FROM);
|
||||
MLX5_SET(create_flow_group_in, in, end_flow_index,
|
||||
MLX5_ESW_BRIDGE_INGRESS_TABLE_FILTER_GRP_IDX_TO);
|
||||
MLX5_SET(create_flow_group_in, in, start_flow_index, from);
|
||||
MLX5_SET(create_flow_group_in, in, end_flow_index, to);
|
||||
|
||||
fg = mlx5_create_flow_group(ingress_ft, in);
|
||||
if (IS_ERR(fg))
|
||||
esw_warn(esw->dev,
|
||||
"Failed to create bridge ingress table VLAN filter flow group (err=%ld)\n",
|
||||
PTR_ERR(fg));
|
||||
|
||||
kvfree(in);
|
||||
return fg;
|
||||
}
|
||||
|
||||
static struct mlx5_flow_group *
|
||||
mlx5_esw_bridge_ingress_vlan_filter_fg_create(struct mlx5_eswitch *esw,
|
||||
struct mlx5_flow_table *ingress_ft)
|
||||
{
|
||||
unsigned int from = MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_FILTER_GRP_IDX_FROM;
|
||||
unsigned int to = MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_FILTER_GRP_IDX_TO;
|
||||
|
||||
return mlx5_esw_bridge_ingress_vlan_proto_filter_fg_create(from, to, ETH_P_8021Q, esw,
|
||||
ingress_ft);
|
||||
}
|
||||
|
||||
static struct mlx5_flow_group *
|
||||
mlx5_esw_bridge_ingress_qinq_filter_fg_create(struct mlx5_eswitch *esw,
|
||||
struct mlx5_flow_table *ingress_ft)
|
||||
{
|
||||
unsigned int from = MLX5_ESW_BRIDGE_INGRESS_TABLE_QINQ_FILTER_GRP_IDX_FROM;
|
||||
unsigned int to = MLX5_ESW_BRIDGE_INGRESS_TABLE_QINQ_FILTER_GRP_IDX_TO;
|
||||
|
||||
return mlx5_esw_bridge_ingress_vlan_proto_filter_fg_create(from, to, ETH_P_8021AD, esw,
|
||||
ingress_ft);
|
||||
}
|
||||
|
||||
static struct mlx5_flow_group *
|
||||
mlx5_esw_bridge_ingress_mac_fg_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *ingress_ft)
|
||||
{
|
||||
@@ -250,7 +330,9 @@ mlx5_esw_bridge_ingress_mac_fg_create(struct mlx5_eswitch *esw, struct mlx5_flow
|
||||
}
|
||||
|
||||
static struct mlx5_flow_group *
|
||||
mlx5_esw_bridge_egress_vlan_fg_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *egress_ft)
|
||||
mlx5_esw_bridge_egress_vlan_proto_fg_create(unsigned int from, unsigned int to, u16 vlan_proto,
|
||||
struct mlx5_eswitch *esw,
|
||||
struct mlx5_flow_table *egress_ft)
|
||||
{
|
||||
int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
|
||||
struct mlx5_flow_group *fg;
|
||||
@@ -265,13 +347,14 @@ mlx5_esw_bridge_egress_vlan_fg_create(struct mlx5_eswitch *esw, struct mlx5_flow
|
||||
|
||||
MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.dmac_47_16);
|
||||
MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.dmac_15_0);
|
||||
MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.cvlan_tag);
|
||||
if (vlan_proto == ETH_P_8021Q)
|
||||
MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.cvlan_tag);
|
||||
else if (vlan_proto == ETH_P_8021AD)
|
||||
MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.svlan_tag);
|
||||
MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.first_vid);
|
||||
|
||||
MLX5_SET(create_flow_group_in, in, start_flow_index,
|
||||
MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_IDX_FROM);
|
||||
MLX5_SET(create_flow_group_in, in, end_flow_index,
|
||||
MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_IDX_TO);
|
||||
MLX5_SET(create_flow_group_in, in, start_flow_index, from);
|
||||
MLX5_SET(create_flow_group_in, in, end_flow_index, to);
|
||||
|
||||
fg = mlx5_create_flow_group(egress_ft, in);
|
||||
if (IS_ERR(fg))
|
||||
@@ -282,6 +365,25 @@ mlx5_esw_bridge_egress_vlan_fg_create(struct mlx5_eswitch *esw, struct mlx5_flow
|
||||
return fg;
|
||||
}
|
||||
|
||||
static struct mlx5_flow_group *
|
||||
mlx5_esw_bridge_egress_vlan_fg_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *egress_ft)
|
||||
{
|
||||
unsigned int from = MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_IDX_FROM;
|
||||
unsigned int to = MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_IDX_TO;
|
||||
|
||||
return mlx5_esw_bridge_egress_vlan_proto_fg_create(from, to, ETH_P_8021Q, esw, egress_ft);
|
||||
}
|
||||
|
||||
static struct mlx5_flow_group *
|
||||
mlx5_esw_bridge_egress_qinq_fg_create(struct mlx5_eswitch *esw,
|
||||
struct mlx5_flow_table *egress_ft)
|
||||
{
|
||||
unsigned int from = MLX5_ESW_BRIDGE_EGRESS_TABLE_QINQ_GRP_IDX_FROM;
|
||||
unsigned int to = MLX5_ESW_BRIDGE_EGRESS_TABLE_QINQ_GRP_IDX_TO;
|
||||
|
||||
return mlx5_esw_bridge_egress_vlan_proto_fg_create(from, to, ETH_P_8021AD, esw, egress_ft);
|
||||
}
|
||||
|
||||
static struct mlx5_flow_group *
|
||||
mlx5_esw_bridge_egress_mac_fg_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *egress_ft)
|
||||
{
|
||||
@@ -346,7 +448,7 @@ mlx5_esw_bridge_egress_miss_fg_create(struct mlx5_eswitch *esw, struct mlx5_flow
|
||||
static int
|
||||
mlx5_esw_bridge_ingress_table_init(struct mlx5_esw_bridge_offloads *br_offloads)
|
||||
{
|
||||
struct mlx5_flow_group *mac_fg, *filter_fg, *vlan_fg;
|
||||
struct mlx5_flow_group *mac_fg, *qinq_filter_fg, *qinq_fg, *vlan_filter_fg, *vlan_fg;
|
||||
struct mlx5_flow_table *ingress_ft, *skip_ft;
|
||||
struct mlx5_eswitch *esw = br_offloads->esw;
|
||||
int err;
|
||||
@@ -374,10 +476,22 @@ mlx5_esw_bridge_ingress_table_init(struct mlx5_esw_bridge_offloads *br_offloads)
|
||||
goto err_vlan_fg;
|
||||
}
|
||||
|
||||
filter_fg = mlx5_esw_bridge_ingress_filter_fg_create(esw, ingress_ft);
|
||||
if (IS_ERR(filter_fg)) {
|
||||
err = PTR_ERR(filter_fg);
|
||||
goto err_filter_fg;
|
||||
vlan_filter_fg = mlx5_esw_bridge_ingress_vlan_filter_fg_create(esw, ingress_ft);
|
||||
if (IS_ERR(vlan_filter_fg)) {
|
||||
err = PTR_ERR(vlan_filter_fg);
|
||||
goto err_vlan_filter_fg;
|
||||
}
|
||||
|
||||
qinq_fg = mlx5_esw_bridge_ingress_qinq_fg_create(esw, ingress_ft);
|
||||
if (IS_ERR(qinq_fg)) {
|
||||
err = PTR_ERR(qinq_fg);
|
||||
goto err_qinq_fg;
|
||||
}
|
||||
|
||||
qinq_filter_fg = mlx5_esw_bridge_ingress_qinq_filter_fg_create(esw, ingress_ft);
|
||||
if (IS_ERR(qinq_filter_fg)) {
|
||||
err = PTR_ERR(qinq_filter_fg);
|
||||
goto err_qinq_filter_fg;
|
||||
}
|
||||
|
||||
mac_fg = mlx5_esw_bridge_ingress_mac_fg_create(esw, ingress_ft);
|
||||
@@ -389,13 +503,19 @@ mlx5_esw_bridge_ingress_table_init(struct mlx5_esw_bridge_offloads *br_offloads)
|
||||
br_offloads->ingress_ft = ingress_ft;
|
||||
br_offloads->skip_ft = skip_ft;
|
||||
br_offloads->ingress_vlan_fg = vlan_fg;
|
||||
br_offloads->ingress_filter_fg = filter_fg;
|
||||
br_offloads->ingress_vlan_filter_fg = vlan_filter_fg;
|
||||
br_offloads->ingress_qinq_fg = qinq_fg;
|
||||
br_offloads->ingress_qinq_filter_fg = qinq_filter_fg;
|
||||
br_offloads->ingress_mac_fg = mac_fg;
|
||||
return 0;
|
||||
|
||||
err_mac_fg:
|
||||
mlx5_destroy_flow_group(filter_fg);
|
||||
err_filter_fg:
|
||||
mlx5_destroy_flow_group(qinq_filter_fg);
|
||||
err_qinq_filter_fg:
|
||||
mlx5_destroy_flow_group(qinq_fg);
|
||||
err_qinq_fg:
|
||||
mlx5_destroy_flow_group(vlan_filter_fg);
|
||||
err_vlan_filter_fg:
|
||||
mlx5_destroy_flow_group(vlan_fg);
|
||||
err_vlan_fg:
|
||||
mlx5_destroy_flow_table(skip_ft);
|
||||
@@ -409,8 +529,12 @@ mlx5_esw_bridge_ingress_table_cleanup(struct mlx5_esw_bridge_offloads *br_offloa
|
||||
{
|
||||
mlx5_destroy_flow_group(br_offloads->ingress_mac_fg);
|
||||
br_offloads->ingress_mac_fg = NULL;
|
||||
mlx5_destroy_flow_group(br_offloads->ingress_filter_fg);
|
||||
br_offloads->ingress_filter_fg = NULL;
|
||||
mlx5_destroy_flow_group(br_offloads->ingress_qinq_filter_fg);
|
||||
br_offloads->ingress_qinq_filter_fg = NULL;
|
||||
mlx5_destroy_flow_group(br_offloads->ingress_qinq_fg);
|
||||
br_offloads->ingress_qinq_fg = NULL;
|
||||
mlx5_destroy_flow_group(br_offloads->ingress_vlan_filter_fg);
|
||||
br_offloads->ingress_vlan_filter_fg = NULL;
|
||||
mlx5_destroy_flow_group(br_offloads->ingress_vlan_fg);
|
||||
br_offloads->ingress_vlan_fg = NULL;
|
||||
mlx5_destroy_flow_table(br_offloads->skip_ft);
|
||||
@@ -428,7 +552,7 @@ static int
|
||||
mlx5_esw_bridge_egress_table_init(struct mlx5_esw_bridge_offloads *br_offloads,
|
||||
struct mlx5_esw_bridge *bridge)
|
||||
{
|
||||
struct mlx5_flow_group *miss_fg = NULL, *mac_fg, *vlan_fg;
|
||||
struct mlx5_flow_group *miss_fg = NULL, *mac_fg, *vlan_fg, *qinq_fg;
|
||||
struct mlx5_pkt_reformat *miss_pkt_reformat = NULL;
|
||||
struct mlx5_flow_handle *miss_handle = NULL;
|
||||
struct mlx5_eswitch *esw = br_offloads->esw;
|
||||
@@ -447,6 +571,12 @@ mlx5_esw_bridge_egress_table_init(struct mlx5_esw_bridge_offloads *br_offloads,
|
||||
goto err_vlan_fg;
|
||||
}
|
||||
|
||||
qinq_fg = mlx5_esw_bridge_egress_qinq_fg_create(esw, egress_ft);
|
||||
if (IS_ERR(qinq_fg)) {
|
||||
err = PTR_ERR(qinq_fg);
|
||||
goto err_qinq_fg;
|
||||
}
|
||||
|
||||
mac_fg = mlx5_esw_bridge_egress_mac_fg_create(esw, egress_ft);
|
||||
if (IS_ERR(mac_fg)) {
|
||||
err = PTR_ERR(mac_fg);
|
||||
@@ -491,6 +621,7 @@ skip_miss_flow:
|
||||
|
||||
bridge->egress_ft = egress_ft;
|
||||
bridge->egress_vlan_fg = vlan_fg;
|
||||
bridge->egress_qinq_fg = qinq_fg;
|
||||
bridge->egress_mac_fg = mac_fg;
|
||||
bridge->egress_miss_fg = miss_fg;
|
||||
bridge->egress_miss_pkt_reformat = miss_pkt_reformat;
|
||||
@@ -498,6 +629,8 @@ skip_miss_flow:
|
||||
return 0;
|
||||
|
||||
err_mac_fg:
|
||||
mlx5_destroy_flow_group(qinq_fg);
|
||||
err_qinq_fg:
|
||||
mlx5_destroy_flow_group(vlan_fg);
|
||||
err_vlan_fg:
|
||||
mlx5_destroy_flow_table(egress_ft);
|
||||
@@ -515,6 +648,7 @@ mlx5_esw_bridge_egress_table_cleanup(struct mlx5_esw_bridge *bridge)
|
||||
if (bridge->egress_miss_fg)
|
||||
mlx5_destroy_flow_group(bridge->egress_miss_fg);
|
||||
mlx5_destroy_flow_group(bridge->egress_mac_fg);
|
||||
mlx5_destroy_flow_group(bridge->egress_qinq_fg);
|
||||
mlx5_destroy_flow_group(bridge->egress_vlan_fg);
|
||||
mlx5_destroy_flow_table(bridge->egress_ft);
|
||||
}
|
||||
@@ -559,10 +693,17 @@ mlx5_esw_bridge_ingress_flow_with_esw_create(u16 vport_num, const unsigned char
|
||||
flow_act.pkt_reformat = vlan->pkt_reformat_push;
|
||||
flow_act.modify_hdr = vlan->pkt_mod_hdr_push_mark;
|
||||
} else if (vlan) {
|
||||
MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria,
|
||||
outer_headers.cvlan_tag);
|
||||
MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_value,
|
||||
outer_headers.cvlan_tag);
|
||||
if (bridge->vlan_proto == ETH_P_8021Q) {
|
||||
MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria,
|
||||
outer_headers.cvlan_tag);
|
||||
MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_value,
|
||||
outer_headers.cvlan_tag);
|
||||
} else if (bridge->vlan_proto == ETH_P_8021AD) {
|
||||
MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria,
|
||||
outer_headers.svlan_tag);
|
||||
MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_value,
|
||||
outer_headers.svlan_tag);
|
||||
}
|
||||
MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria,
|
||||
outer_headers.first_vid);
|
||||
MLX5_SET(fte_match_param, rule_spec->match_value, outer_headers.first_vid,
|
||||
@@ -645,10 +786,17 @@ mlx5_esw_bridge_ingress_filter_flow_create(u16 vport_num, const unsigned char *a
|
||||
MLX5_SET(fte_match_param, rule_spec->match_value, misc_parameters_2.metadata_reg_c_0,
|
||||
mlx5_eswitch_get_vport_metadata_for_match(br_offloads->esw, vport_num));
|
||||
|
||||
MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria,
|
||||
outer_headers.cvlan_tag);
|
||||
MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_value,
|
||||
outer_headers.cvlan_tag);
|
||||
if (bridge->vlan_proto == ETH_P_8021Q) {
|
||||
MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria,
|
||||
outer_headers.cvlan_tag);
|
||||
MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_value,
|
||||
outer_headers.cvlan_tag);
|
||||
} else if (bridge->vlan_proto == ETH_P_8021AD) {
|
||||
MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria,
|
||||
outer_headers.svlan_tag);
|
||||
MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_value,
|
||||
outer_headers.svlan_tag);
|
||||
}
|
||||
|
||||
handle = mlx5_add_flow_rules(br_offloads->ingress_ft, rule_spec, &flow_act, &dest, 1);
|
||||
|
||||
@@ -696,10 +844,17 @@ mlx5_esw_bridge_egress_flow_create(u16 vport_num, u16 esw_owner_vhca_id, const u
|
||||
flow_act.pkt_reformat = vlan->pkt_reformat_pop;
|
||||
}
|
||||
|
||||
MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria,
|
||||
outer_headers.cvlan_tag);
|
||||
MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_value,
|
||||
outer_headers.cvlan_tag);
|
||||
if (bridge->vlan_proto == ETH_P_8021Q) {
|
||||
MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria,
|
||||
outer_headers.cvlan_tag);
|
||||
MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_value,
|
||||
outer_headers.cvlan_tag);
|
||||
} else if (bridge->vlan_proto == ETH_P_8021AD) {
|
||||
MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria,
|
||||
outer_headers.svlan_tag);
|
||||
MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_value,
|
||||
outer_headers.svlan_tag);
|
||||
}
|
||||
MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria,
|
||||
outer_headers.first_vid);
|
||||
MLX5_SET(fte_match_param, rule_spec->match_value, outer_headers.first_vid,
|
||||
@@ -774,6 +929,7 @@ static struct mlx5_esw_bridge *mlx5_esw_bridge_create(int ifindex,
|
||||
bridge->ifindex = ifindex;
|
||||
bridge->refcnt = 1;
|
||||
bridge->ageing_time = clock_t_to_jiffies(BR_DEFAULT_AGEING_TIME);
|
||||
bridge->vlan_proto = ETH_P_8021Q;
|
||||
list_add(&bridge->list, &br_offloads->bridges);
|
||||
|
||||
return bridge;
|
||||
@@ -911,12 +1067,13 @@ mlx5_esw_bridge_vlan_lookup(u16 vid, struct mlx5_esw_bridge_port *port)
|
||||
}
|
||||
|
||||
static int
|
||||
mlx5_esw_bridge_vlan_push_create(struct mlx5_esw_bridge_vlan *vlan, struct mlx5_eswitch *esw)
|
||||
mlx5_esw_bridge_vlan_push_create(u16 vlan_proto, struct mlx5_esw_bridge_vlan *vlan,
|
||||
struct mlx5_eswitch *esw)
|
||||
{
|
||||
struct {
|
||||
__be16 h_vlan_proto;
|
||||
__be16 h_vlan_TCI;
|
||||
} vlan_hdr = { htons(ETH_P_8021Q), htons(vlan->vid) };
|
||||
} vlan_hdr = { htons(vlan_proto), htons(vlan->vid) };
|
||||
struct mlx5_pkt_reformat_params reformat_params = {};
|
||||
struct mlx5_pkt_reformat *pkt_reformat;
|
||||
|
||||
@@ -1008,8 +1165,41 @@ mlx5_esw_bridge_vlan_push_mark_cleanup(struct mlx5_esw_bridge_vlan *vlan, struct
|
||||
vlan->pkt_mod_hdr_push_mark = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
mlx5_esw_bridge_vlan_push_pop_create(u16 vlan_proto, u16 flags, struct mlx5_esw_bridge_vlan *vlan,
|
||||
struct mlx5_eswitch *esw)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (flags & BRIDGE_VLAN_INFO_PVID) {
|
||||
err = mlx5_esw_bridge_vlan_push_create(vlan_proto, vlan, esw);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = mlx5_esw_bridge_vlan_push_mark_create(vlan, esw);
|
||||
if (err)
|
||||
goto err_vlan_push_mark;
|
||||
}
|
||||
|
||||
if (flags & BRIDGE_VLAN_INFO_UNTAGGED) {
|
||||
err = mlx5_esw_bridge_vlan_pop_create(vlan, esw);
|
||||
if (err)
|
||||
goto err_vlan_pop;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_vlan_pop:
|
||||
if (vlan->pkt_mod_hdr_push_mark)
|
||||
mlx5_esw_bridge_vlan_push_mark_cleanup(vlan, esw);
|
||||
err_vlan_push_mark:
|
||||
if (vlan->pkt_reformat_push)
|
||||
mlx5_esw_bridge_vlan_push_cleanup(vlan, esw);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct mlx5_esw_bridge_vlan *
|
||||
mlx5_esw_bridge_vlan_create(u16 vid, u16 flags, struct mlx5_esw_bridge_port *port,
|
||||
mlx5_esw_bridge_vlan_create(u16 vlan_proto, u16 vid, u16 flags, struct mlx5_esw_bridge_port *port,
|
||||
struct mlx5_eswitch *esw)
|
||||
{
|
||||
struct mlx5_esw_bridge_vlan *vlan;
|
||||
@@ -1023,20 +1213,9 @@ mlx5_esw_bridge_vlan_create(u16 vid, u16 flags, struct mlx5_esw_bridge_port *por
|
||||
vlan->flags = flags;
|
||||
INIT_LIST_HEAD(&vlan->fdb_list);
|
||||
|
||||
if (flags & BRIDGE_VLAN_INFO_PVID) {
|
||||
err = mlx5_esw_bridge_vlan_push_create(vlan, esw);
|
||||
if (err)
|
||||
goto err_vlan_push;
|
||||
|
||||
err = mlx5_esw_bridge_vlan_push_mark_create(vlan, esw);
|
||||
if (err)
|
||||
goto err_vlan_push_mark;
|
||||
}
|
||||
if (flags & BRIDGE_VLAN_INFO_UNTAGGED) {
|
||||
err = mlx5_esw_bridge_vlan_pop_create(vlan, esw);
|
||||
if (err)
|
||||
goto err_vlan_pop;
|
||||
}
|
||||
err = mlx5_esw_bridge_vlan_push_pop_create(vlan_proto, flags, vlan, esw);
|
||||
if (err)
|
||||
goto err_vlan_push_pop;
|
||||
|
||||
err = xa_insert(&port->vlans, vid, vlan, GFP_KERNEL);
|
||||
if (err)
|
||||
@@ -1048,13 +1227,11 @@ mlx5_esw_bridge_vlan_create(u16 vid, u16 flags, struct mlx5_esw_bridge_port *por
|
||||
err_xa_insert:
|
||||
if (vlan->pkt_reformat_pop)
|
||||
mlx5_esw_bridge_vlan_pop_cleanup(vlan, esw);
|
||||
err_vlan_pop:
|
||||
if (vlan->pkt_mod_hdr_push_mark)
|
||||
mlx5_esw_bridge_vlan_push_mark_cleanup(vlan, esw);
|
||||
err_vlan_push_mark:
|
||||
if (vlan->pkt_reformat_push)
|
||||
mlx5_esw_bridge_vlan_push_cleanup(vlan, esw);
|
||||
err_vlan_push:
|
||||
err_vlan_push_pop:
|
||||
kvfree(vlan);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
@@ -1102,6 +1279,50 @@ static void mlx5_esw_bridge_port_vlans_flush(struct mlx5_esw_bridge_port *port,
|
||||
mlx5_esw_bridge_vlan_cleanup(port, vlan, bridge);
|
||||
}
|
||||
|
||||
static int mlx5_esw_bridge_port_vlans_recreate(struct mlx5_esw_bridge_port *port,
|
||||
struct mlx5_esw_bridge *bridge)
|
||||
{
|
||||
struct mlx5_esw_bridge_offloads *br_offloads = bridge->br_offloads;
|
||||
struct mlx5_esw_bridge_vlan *vlan;
|
||||
unsigned long i;
|
||||
int err;
|
||||
|
||||
xa_for_each(&port->vlans, i, vlan) {
|
||||
mlx5_esw_bridge_vlan_flush(vlan, bridge);
|
||||
err = mlx5_esw_bridge_vlan_push_pop_create(bridge->vlan_proto, vlan->flags, vlan,
|
||||
br_offloads->esw);
|
||||
if (err) {
|
||||
esw_warn(br_offloads->esw->dev,
|
||||
"Failed to create VLAN=%u(proto=%x) push/pop actions (vport=%u,err=%d)\n",
|
||||
vlan->vid, bridge->vlan_proto, port->vport_num,
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mlx5_esw_bridge_vlans_recreate(struct mlx5_esw_bridge *bridge)
|
||||
{
|
||||
struct mlx5_esw_bridge_offloads *br_offloads = bridge->br_offloads;
|
||||
struct mlx5_esw_bridge_port *port;
|
||||
unsigned long i;
|
||||
int err;
|
||||
|
||||
xa_for_each(&br_offloads->ports, i, port) {
|
||||
if (port->bridge != bridge)
|
||||
continue;
|
||||
|
||||
err = mlx5_esw_bridge_port_vlans_recreate(port, bridge);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mlx5_esw_bridge_vlan *
|
||||
mlx5_esw_bridge_port_vlan_lookup(u16 vid, u16 vport_num, u16 esw_owner_vhca_id,
|
||||
struct mlx5_esw_bridge *bridge, struct mlx5_eswitch *esw)
|
||||
@@ -1287,6 +1508,32 @@ int mlx5_esw_bridge_vlan_filtering_set(u16 vport_num, u16 esw_owner_vhca_id, boo
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlx5_esw_bridge_vlan_proto_set(u16 vport_num, u16 esw_owner_vhca_id, u16 proto,
|
||||
struct mlx5_esw_bridge_offloads *br_offloads)
|
||||
{
|
||||
struct mlx5_esw_bridge_port *port;
|
||||
struct mlx5_esw_bridge *bridge;
|
||||
|
||||
port = mlx5_esw_bridge_port_lookup(vport_num, esw_owner_vhca_id,
|
||||
br_offloads);
|
||||
if (!port)
|
||||
return -EINVAL;
|
||||
|
||||
bridge = port->bridge;
|
||||
if (bridge->vlan_proto == proto)
|
||||
return 0;
|
||||
if (proto != ETH_P_8021Q && proto != ETH_P_8021AD) {
|
||||
esw_warn(br_offloads->esw->dev, "Can't set unsupported VLAN protocol %x", proto);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
mlx5_esw_bridge_fdb_flush(bridge);
|
||||
bridge->vlan_proto = proto;
|
||||
mlx5_esw_bridge_vlans_recreate(bridge);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlx5_esw_bridge_vport_init(u16 vport_num, u16 esw_owner_vhca_id, u16 flags,
|
||||
struct mlx5_esw_bridge_offloads *br_offloads,
|
||||
struct mlx5_esw_bridge *bridge)
|
||||
@@ -1434,7 +1681,8 @@ int mlx5_esw_bridge_port_vlan_add(u16 vport_num, u16 esw_owner_vhca_id, u16 vid,
|
||||
mlx5_esw_bridge_vlan_cleanup(port, vlan, port->bridge);
|
||||
}
|
||||
|
||||
vlan = mlx5_esw_bridge_vlan_create(vid, flags, port, br_offloads->esw);
|
||||
vlan = mlx5_esw_bridge_vlan_create(port->bridge->vlan_proto, vid, flags, port,
|
||||
br_offloads->esw);
|
||||
if (IS_ERR(vlan)) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Failed to create VLAN entry");
|
||||
return PTR_ERR(vlan);
|
||||
|
||||
@@ -26,7 +26,9 @@ struct mlx5_esw_bridge_offloads {
|
||||
|
||||
struct mlx5_flow_table *ingress_ft;
|
||||
struct mlx5_flow_group *ingress_vlan_fg;
|
||||
struct mlx5_flow_group *ingress_filter_fg;
|
||||
struct mlx5_flow_group *ingress_vlan_filter_fg;
|
||||
struct mlx5_flow_group *ingress_qinq_fg;
|
||||
struct mlx5_flow_group *ingress_qinq_filter_fg;
|
||||
struct mlx5_flow_group *ingress_mac_fg;
|
||||
|
||||
struct mlx5_flow_table *skip_ft;
|
||||
@@ -60,6 +62,8 @@ int mlx5_esw_bridge_ageing_time_set(u16 vport_num, u16 esw_owner_vhca_id, unsign
|
||||
struct mlx5_esw_bridge_offloads *br_offloads);
|
||||
int mlx5_esw_bridge_vlan_filtering_set(u16 vport_num, u16 esw_owner_vhca_id, bool enable,
|
||||
struct mlx5_esw_bridge_offloads *br_offloads);
|
||||
int mlx5_esw_bridge_vlan_proto_set(u16 vport_num, u16 esw_owner_vhca_id, u16 proto,
|
||||
struct mlx5_esw_bridge_offloads *br_offloads);
|
||||
int mlx5_esw_bridge_port_vlan_add(u16 vport_num, u16 esw_owner_vhca_id, u16 vid, u16 flags,
|
||||
struct mlx5_esw_bridge_offloads *br_offloads,
|
||||
struct netlink_ext_ack *extack);
|
||||
|
||||
182
drivers/net/ethernet/mellanox/mlx5/core/esw/debugfs.c
Normal file
182
drivers/net/ethernet/mellanox/mlx5/core/esw/debugfs.c
Normal file
@@ -0,0 +1,182 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
|
||||
/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include "eswitch.h"
|
||||
|
||||
enum vnic_diag_counter {
|
||||
MLX5_VNIC_DIAG_TOTAL_Q_UNDER_PROCESSOR_HANDLE,
|
||||
MLX5_VNIC_DIAG_SEND_QUEUE_PRIORITY_UPDATE_FLOW,
|
||||
MLX5_VNIC_DIAG_COMP_EQ_OVERRUN,
|
||||
MLX5_VNIC_DIAG_ASYNC_EQ_OVERRUN,
|
||||
MLX5_VNIC_DIAG_CQ_OVERRUN,
|
||||
MLX5_VNIC_DIAG_INVALID_COMMAND,
|
||||
MLX5_VNIC_DIAG_QOUTA_EXCEEDED_COMMAND,
|
||||
};
|
||||
|
||||
static int mlx5_esw_query_vnic_diag(struct mlx5_vport *vport, enum vnic_diag_counter counter,
|
||||
u32 *val)
|
||||
{
|
||||
u32 out[MLX5_ST_SZ_DW(query_vnic_env_out)] = {};
|
||||
u32 in[MLX5_ST_SZ_DW(query_vnic_env_in)] = {};
|
||||
struct mlx5_core_dev *dev = vport->dev;
|
||||
u16 vport_num = vport->vport;
|
||||
void *vnic_diag_out;
|
||||
int err;
|
||||
|
||||
MLX5_SET(query_vnic_env_in, in, opcode, MLX5_CMD_OP_QUERY_VNIC_ENV);
|
||||
MLX5_SET(query_vnic_env_in, in, vport_number, vport_num);
|
||||
if (!mlx5_esw_is_manager_vport(dev->priv.eswitch, vport_num))
|
||||
MLX5_SET(query_vnic_env_in, in, other_vport, 1);
|
||||
|
||||
err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
vnic_diag_out = MLX5_ADDR_OF(query_vnic_env_out, out, vport_env);
|
||||
switch (counter) {
|
||||
case MLX5_VNIC_DIAG_TOTAL_Q_UNDER_PROCESSOR_HANDLE:
|
||||
*val = MLX5_GET(vnic_diagnostic_statistics, vnic_diag_out, total_error_queues);
|
||||
break;
|
||||
case MLX5_VNIC_DIAG_SEND_QUEUE_PRIORITY_UPDATE_FLOW:
|
||||
*val = MLX5_GET(vnic_diagnostic_statistics, vnic_diag_out,
|
||||
send_queue_priority_update_flow);
|
||||
break;
|
||||
case MLX5_VNIC_DIAG_COMP_EQ_OVERRUN:
|
||||
*val = MLX5_GET(vnic_diagnostic_statistics, vnic_diag_out, comp_eq_overrun);
|
||||
break;
|
||||
case MLX5_VNIC_DIAG_ASYNC_EQ_OVERRUN:
|
||||
*val = MLX5_GET(vnic_diagnostic_statistics, vnic_diag_out, async_eq_overrun);
|
||||
break;
|
||||
case MLX5_VNIC_DIAG_CQ_OVERRUN:
|
||||
*val = MLX5_GET(vnic_diagnostic_statistics, vnic_diag_out, cq_overrun);
|
||||
break;
|
||||
case MLX5_VNIC_DIAG_INVALID_COMMAND:
|
||||
*val = MLX5_GET(vnic_diagnostic_statistics, vnic_diag_out, invalid_command);
|
||||
break;
|
||||
case MLX5_VNIC_DIAG_QOUTA_EXCEEDED_COMMAND:
|
||||
*val = MLX5_GET(vnic_diagnostic_statistics, vnic_diag_out, quota_exceeded_command);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __show_vnic_diag(struct seq_file *file, struct mlx5_vport *vport,
|
||||
enum vnic_diag_counter type)
|
||||
{
|
||||
u32 val = 0;
|
||||
int ret;
|
||||
|
||||
ret = mlx5_esw_query_vnic_diag(vport, type, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
seq_printf(file, "%d\n", val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int total_q_under_processor_handle_show(struct seq_file *file, void *priv)
|
||||
{
|
||||
return __show_vnic_diag(file, file->private, MLX5_VNIC_DIAG_TOTAL_Q_UNDER_PROCESSOR_HANDLE);
|
||||
}
|
||||
|
||||
static int send_queue_priority_update_flow_show(struct seq_file *file, void *priv)
|
||||
{
|
||||
return __show_vnic_diag(file, file->private,
|
||||
MLX5_VNIC_DIAG_SEND_QUEUE_PRIORITY_UPDATE_FLOW);
|
||||
}
|
||||
|
||||
static int comp_eq_overrun_show(struct seq_file *file, void *priv)
|
||||
{
|
||||
return __show_vnic_diag(file, file->private, MLX5_VNIC_DIAG_COMP_EQ_OVERRUN);
|
||||
}
|
||||
|
||||
static int async_eq_overrun_show(struct seq_file *file, void *priv)
|
||||
{
|
||||
return __show_vnic_diag(file, file->private, MLX5_VNIC_DIAG_ASYNC_EQ_OVERRUN);
|
||||
}
|
||||
|
||||
static int cq_overrun_show(struct seq_file *file, void *priv)
|
||||
{
|
||||
return __show_vnic_diag(file, file->private, MLX5_VNIC_DIAG_CQ_OVERRUN);
|
||||
}
|
||||
|
||||
static int invalid_command_show(struct seq_file *file, void *priv)
|
||||
{
|
||||
return __show_vnic_diag(file, file->private, MLX5_VNIC_DIAG_INVALID_COMMAND);
|
||||
}
|
||||
|
||||
static int quota_exceeded_command_show(struct seq_file *file, void *priv)
|
||||
{
|
||||
return __show_vnic_diag(file, file->private, MLX5_VNIC_DIAG_QOUTA_EXCEEDED_COMMAND);
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(total_q_under_processor_handle);
|
||||
DEFINE_SHOW_ATTRIBUTE(send_queue_priority_update_flow);
|
||||
DEFINE_SHOW_ATTRIBUTE(comp_eq_overrun);
|
||||
DEFINE_SHOW_ATTRIBUTE(async_eq_overrun);
|
||||
DEFINE_SHOW_ATTRIBUTE(cq_overrun);
|
||||
DEFINE_SHOW_ATTRIBUTE(invalid_command);
|
||||
DEFINE_SHOW_ATTRIBUTE(quota_exceeded_command);
|
||||
|
||||
void mlx5_esw_vport_debugfs_destroy(struct mlx5_eswitch *esw, u16 vport_num)
|
||||
{
|
||||
struct mlx5_vport *vport = mlx5_eswitch_get_vport(esw, vport_num);
|
||||
|
||||
debugfs_remove_recursive(vport->dbgfs);
|
||||
vport->dbgfs = NULL;
|
||||
}
|
||||
|
||||
/* vnic diag dir name is "pf", "ecpf" or "{vf/sf}_xxxx" */
|
||||
#define VNIC_DIAG_DIR_NAME_MAX_LEN 8
|
||||
|
||||
void mlx5_esw_vport_debugfs_create(struct mlx5_eswitch *esw, u16 vport_num, bool is_sf, u16 sf_num)
|
||||
{
|
||||
struct mlx5_vport *vport = mlx5_eswitch_get_vport(esw, vport_num);
|
||||
struct dentry *vnic_diag;
|
||||
char dir_name[VNIC_DIAG_DIR_NAME_MAX_LEN];
|
||||
int err;
|
||||
|
||||
if (!MLX5_CAP_GEN(esw->dev, vport_group_manager))
|
||||
return;
|
||||
|
||||
if (vport_num == MLX5_VPORT_PF) {
|
||||
strcpy(dir_name, "pf");
|
||||
} else if (vport_num == MLX5_VPORT_ECPF) {
|
||||
strcpy(dir_name, "ecpf");
|
||||
} else {
|
||||
err = snprintf(dir_name, VNIC_DIAG_DIR_NAME_MAX_LEN, "%s_%d", is_sf ? "sf" : "vf",
|
||||
is_sf ? sf_num : vport_num - MLX5_VPORT_FIRST_VF);
|
||||
if (WARN_ON(err < 0))
|
||||
return;
|
||||
}
|
||||
|
||||
vport->dbgfs = debugfs_create_dir(dir_name, esw->dbgfs);
|
||||
vnic_diag = debugfs_create_dir("vnic_diag", vport->dbgfs);
|
||||
|
||||
if (MLX5_CAP_GEN(esw->dev, vnic_env_queue_counters)) {
|
||||
debugfs_create_file("total_q_under_processor_handle", 0444, vnic_diag, vport,
|
||||
&total_q_under_processor_handle_fops);
|
||||
debugfs_create_file("send_queue_priority_update_flow", 0444, vnic_diag, vport,
|
||||
&send_queue_priority_update_flow_fops);
|
||||
}
|
||||
|
||||
if (MLX5_CAP_GEN(esw->dev, eq_overrun_count)) {
|
||||
debugfs_create_file("comp_eq_overrun", 0444, vnic_diag, vport,
|
||||
&comp_eq_overrun_fops);
|
||||
debugfs_create_file("async_eq_overrun", 0444, vnic_diag, vport,
|
||||
&async_eq_overrun_fops);
|
||||
}
|
||||
|
||||
if (MLX5_CAP_GEN(esw->dev, vnic_env_cq_overrun))
|
||||
debugfs_create_file("cq_overrun", 0444, vnic_diag, vport, &cq_overrun_fops);
|
||||
|
||||
if (MLX5_CAP_GEN(esw->dev, invalid_command_count))
|
||||
debugfs_create_file("invalid_command", 0444, vnic_diag, vport,
|
||||
&invalid_command_fops);
|
||||
|
||||
if (MLX5_CAP_GEN(esw->dev, quota_exceeded_count))
|
||||
debugfs_create_file("quota_exceeded_command", 0444, vnic_diag, vport,
|
||||
"a_exceeded_command_fops);
|
||||
}
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <linux/mlx5/vport.h>
|
||||
#include <linux/mlx5/fs.h>
|
||||
#include <linux/mlx5/mpfs.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include "esw/acl/lgcy.h"
|
||||
#include "esw/legacy.h"
|
||||
#include "esw/qos.h"
|
||||
@@ -1002,6 +1003,7 @@ int mlx5_eswitch_load_vport(struct mlx5_eswitch *esw, u16 vport_num,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mlx5_esw_vport_debugfs_create(esw, vport_num, false, 0);
|
||||
err = esw_offloads_load_rep(esw, vport_num);
|
||||
if (err)
|
||||
goto err_rep;
|
||||
@@ -1009,6 +1011,7 @@ int mlx5_eswitch_load_vport(struct mlx5_eswitch *esw, u16 vport_num,
|
||||
return err;
|
||||
|
||||
err_rep:
|
||||
mlx5_esw_vport_debugfs_destroy(esw, vport_num);
|
||||
mlx5_esw_vport_disable(esw, vport_num);
|
||||
return err;
|
||||
}
|
||||
@@ -1016,6 +1019,7 @@ err_rep:
|
||||
void mlx5_eswitch_unload_vport(struct mlx5_eswitch *esw, u16 vport_num)
|
||||
{
|
||||
esw_offloads_unload_rep(esw, vport_num);
|
||||
mlx5_esw_vport_debugfs_destroy(esw, vport_num);
|
||||
mlx5_esw_vport_disable(esw, vport_num);
|
||||
}
|
||||
|
||||
@@ -1622,6 +1626,7 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev)
|
||||
dev->priv.eswitch = esw;
|
||||
BLOCKING_INIT_NOTIFIER_HEAD(&esw->n_head);
|
||||
|
||||
esw->dbgfs = debugfs_create_dir("esw", mlx5_debugfs_get_dev_root(esw->dev));
|
||||
esw_info(dev,
|
||||
"Total vports %d, per vport: max uc(%d) max mc(%d)\n",
|
||||
esw->total_vports,
|
||||
@@ -1645,6 +1650,7 @@ void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw)
|
||||
|
||||
esw_info(esw->dev, "cleanup\n");
|
||||
|
||||
debugfs_remove_recursive(esw->dbgfs);
|
||||
esw->dev->priv.eswitch = NULL;
|
||||
destroy_workqueue(esw->work_queue);
|
||||
WARN_ON(refcount_read(&esw->qos.refcnt));
|
||||
|
||||
@@ -191,6 +191,7 @@ struct mlx5_vport {
|
||||
enum mlx5_eswitch_vport_event enabled_events;
|
||||
int index;
|
||||
struct devlink_port *dl_port;
|
||||
struct dentry *dbgfs;
|
||||
};
|
||||
|
||||
struct mlx5_esw_indir_table;
|
||||
@@ -336,6 +337,7 @@ struct mlx5_eswitch {
|
||||
u32 large_group_num;
|
||||
} params;
|
||||
struct blocking_notifier_head n_head;
|
||||
struct dentry *dbgfs;
|
||||
};
|
||||
|
||||
void esw_offloads_disable(struct mlx5_eswitch *esw);
|
||||
@@ -684,6 +686,9 @@ int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, u16 vport_
|
||||
void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_eswitch *esw, u16 vport_num);
|
||||
struct devlink_port *mlx5_esw_offloads_devlink_port(struct mlx5_eswitch *esw, u16 vport_num);
|
||||
|
||||
void mlx5_esw_vport_debugfs_create(struct mlx5_eswitch *esw, u16 vport_num, bool is_sf, u16 sf_num);
|
||||
void mlx5_esw_vport_debugfs_destroy(struct mlx5_eswitch *esw, u16 vport_num);
|
||||
|
||||
int mlx5_esw_devlink_sf_port_register(struct mlx5_eswitch *esw, struct devlink_port *dl_port,
|
||||
u16 vport_num, u32 controller, u32 sfnum);
|
||||
void mlx5_esw_devlink_sf_port_unregister(struct mlx5_eswitch *esw, u16 vport_num);
|
||||
|
||||
@@ -512,6 +512,20 @@ esw_cleanup_dests(struct mlx5_eswitch *esw,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
esw_setup_meter(struct mlx5_flow_attr *attr, struct mlx5_flow_act *flow_act)
|
||||
{
|
||||
struct mlx5e_flow_meter_handle *meter;
|
||||
|
||||
meter = attr->meter_attr.meter;
|
||||
flow_act->exe_aso.type = attr->exe_aso_type;
|
||||
flow_act->exe_aso.object_id = meter->obj_id;
|
||||
flow_act->exe_aso.flow_meter.meter_idx = meter->idx;
|
||||
flow_act->exe_aso.flow_meter.init_color = MLX5_FLOW_METER_COLOR_GREEN;
|
||||
/* use metadata reg 5 for packet color */
|
||||
flow_act->exe_aso.return_reg_id = 5;
|
||||
}
|
||||
|
||||
struct mlx5_flow_handle *
|
||||
mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
|
||||
struct mlx5_flow_spec *spec,
|
||||
@@ -579,6 +593,10 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
|
||||
if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
|
||||
flow_act.modify_hdr = attr->modify_hdr;
|
||||
|
||||
if ((flow_act.action & MLX5_FLOW_CONTEXT_ACTION_EXECUTE_ASO) &&
|
||||
attr->exe_aso_type == MLX5_EXE_ASO_FLOW_METER)
|
||||
esw_setup_meter(attr, &flow_act);
|
||||
|
||||
if (split) {
|
||||
fwd_attr.chain = attr->chain;
|
||||
fwd_attr.prio = attr->prio;
|
||||
@@ -3704,12 +3722,14 @@ int mlx5_esw_offloads_sf_vport_enable(struct mlx5_eswitch *esw, struct devlink_p
|
||||
if (err)
|
||||
goto devlink_err;
|
||||
|
||||
mlx5_esw_vport_debugfs_create(esw, vport_num, true, sfnum);
|
||||
err = mlx5_esw_offloads_rep_load(esw, vport_num);
|
||||
if (err)
|
||||
goto rep_err;
|
||||
return 0;
|
||||
|
||||
rep_err:
|
||||
mlx5_esw_vport_debugfs_destroy(esw, vport_num);
|
||||
mlx5_esw_devlink_sf_port_unregister(esw, vport_num);
|
||||
devlink_err:
|
||||
mlx5_esw_vport_disable(esw, vport_num);
|
||||
@@ -3719,6 +3739,7 @@ devlink_err:
|
||||
void mlx5_esw_offloads_sf_vport_disable(struct mlx5_eswitch *esw, u16 vport_num)
|
||||
{
|
||||
mlx5_esw_offloads_rep_unload(esw, vport_num);
|
||||
mlx5_esw_vport_debugfs_destroy(esw, vport_num);
|
||||
mlx5_esw_devlink_sf_port_unregister(esw, vport_num);
|
||||
mlx5_esw_vport_disable(esw, vport_num);
|
||||
}
|
||||
|
||||
@@ -289,6 +289,10 @@ int mlx5_cmd_init_hca(struct mlx5_core_dev *dev, uint32_t *sw_owner_id)
|
||||
sw_owner_id[i]);
|
||||
}
|
||||
|
||||
if (MLX5_CAP_GEN_2_MAX(dev, sw_vhca_id_valid) &&
|
||||
dev->priv.sw_vhca_id > 0)
|
||||
MLX5_SET(init_hca_in, in, sw_vhca_id, dev->priv.sw_vhca_id);
|
||||
|
||||
return mlx5_cmd_exec_in(dev, init_hca, in);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,8 +38,7 @@ struct mlx5_dm *mlx5_dm_create(struct mlx5_core_dev *dev)
|
||||
MLX5_LOG_SW_ICM_BLOCK_SIZE(dev));
|
||||
|
||||
dm->steering_sw_icm_alloc_blocks =
|
||||
kcalloc(BITS_TO_LONGS(steering_icm_blocks),
|
||||
sizeof(unsigned long), GFP_KERNEL);
|
||||
bitmap_zalloc(steering_icm_blocks, GFP_KERNEL);
|
||||
if (!dm->steering_sw_icm_alloc_blocks)
|
||||
goto err_steering;
|
||||
}
|
||||
@@ -50,8 +49,7 @@ struct mlx5_dm *mlx5_dm_create(struct mlx5_core_dev *dev)
|
||||
MLX5_LOG_SW_ICM_BLOCK_SIZE(dev));
|
||||
|
||||
dm->header_modify_sw_icm_alloc_blocks =
|
||||
kcalloc(BITS_TO_LONGS(header_modify_icm_blocks),
|
||||
sizeof(unsigned long), GFP_KERNEL);
|
||||
bitmap_zalloc(header_modify_icm_blocks, GFP_KERNEL);
|
||||
if (!dm->header_modify_sw_icm_alloc_blocks)
|
||||
goto err_modify_hdr;
|
||||
}
|
||||
@@ -66,8 +64,7 @@ struct mlx5_dm *mlx5_dm_create(struct mlx5_core_dev *dev)
|
||||
MLX5_LOG_SW_ICM_BLOCK_SIZE(dev));
|
||||
|
||||
dm->header_modify_pattern_sw_icm_alloc_blocks =
|
||||
kcalloc(BITS_TO_LONGS(header_modify_pattern_icm_blocks),
|
||||
sizeof(unsigned long), GFP_KERNEL);
|
||||
bitmap_zalloc(header_modify_pattern_icm_blocks, GFP_KERNEL);
|
||||
if (!dm->header_modify_pattern_sw_icm_alloc_blocks)
|
||||
goto err_pattern;
|
||||
}
|
||||
@@ -75,10 +72,10 @@ struct mlx5_dm *mlx5_dm_create(struct mlx5_core_dev *dev)
|
||||
return dm;
|
||||
|
||||
err_pattern:
|
||||
kfree(dm->header_modify_sw_icm_alloc_blocks);
|
||||
bitmap_free(dm->header_modify_sw_icm_alloc_blocks);
|
||||
|
||||
err_modify_hdr:
|
||||
kfree(dm->steering_sw_icm_alloc_blocks);
|
||||
bitmap_free(dm->steering_sw_icm_alloc_blocks);
|
||||
|
||||
err_steering:
|
||||
kfree(dm);
|
||||
@@ -97,7 +94,7 @@ void mlx5_dm_cleanup(struct mlx5_core_dev *dev)
|
||||
WARN_ON(!bitmap_empty(dm->steering_sw_icm_alloc_blocks,
|
||||
BIT(MLX5_CAP_DEV_MEM(dev, log_steering_sw_icm_size) -
|
||||
MLX5_LOG_SW_ICM_BLOCK_SIZE(dev))));
|
||||
kfree(dm->steering_sw_icm_alloc_blocks);
|
||||
bitmap_free(dm->steering_sw_icm_alloc_blocks);
|
||||
}
|
||||
|
||||
if (dm->header_modify_sw_icm_alloc_blocks) {
|
||||
@@ -105,7 +102,7 @@ void mlx5_dm_cleanup(struct mlx5_core_dev *dev)
|
||||
BIT(MLX5_CAP_DEV_MEM(dev,
|
||||
log_header_modify_sw_icm_size) -
|
||||
MLX5_LOG_SW_ICM_BLOCK_SIZE(dev))));
|
||||
kfree(dm->header_modify_sw_icm_alloc_blocks);
|
||||
bitmap_free(dm->header_modify_sw_icm_alloc_blocks);
|
||||
}
|
||||
|
||||
if (dm->header_modify_pattern_sw_icm_alloc_blocks) {
|
||||
@@ -113,7 +110,7 @@ void mlx5_dm_cleanup(struct mlx5_core_dev *dev)
|
||||
BIT(MLX5_CAP_DEV_MEM(dev,
|
||||
log_header_modify_pattern_sw_icm_size) -
|
||||
MLX5_LOG_SW_ICM_BLOCK_SIZE(dev))));
|
||||
kfree(dm->header_modify_pattern_sw_icm_alloc_blocks);
|
||||
bitmap_free(dm->header_modify_pattern_sw_icm_alloc_blocks);
|
||||
}
|
||||
|
||||
kfree(dm);
|
||||
|
||||
@@ -90,6 +90,8 @@ module_param_named(prof_sel, prof_sel, uint, 0444);
|
||||
MODULE_PARM_DESC(prof_sel, "profile selector. Valid range 0 - 2");
|
||||
|
||||
static u32 sw_owner_id[4];
|
||||
#define MAX_SW_VHCA_ID (BIT(__mlx5_bit_sz(cmd_hca_cap_2, sw_vhca_id)) - 1)
|
||||
static DEFINE_IDA(sw_vhca_ida);
|
||||
|
||||
enum {
|
||||
MLX5_ATOMIC_REQ_MODE_BE = 0x0,
|
||||
@@ -492,6 +494,31 @@ static int max_uc_list_get_devlink_param(struct mlx5_core_dev *dev)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int handle_hca_cap_2(struct mlx5_core_dev *dev, void *set_ctx)
|
||||
{
|
||||
void *set_hca_cap;
|
||||
int err;
|
||||
|
||||
if (!MLX5_CAP_GEN_MAX(dev, hca_cap_2))
|
||||
return 0;
|
||||
|
||||
err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL_2);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!MLX5_CAP_GEN_2_MAX(dev, sw_vhca_id_valid) ||
|
||||
!(dev->priv.sw_vhca_id > 0))
|
||||
return 0;
|
||||
|
||||
set_hca_cap = MLX5_ADDR_OF(set_hca_cap_in, set_ctx,
|
||||
capability);
|
||||
memcpy(set_hca_cap, dev->caps.hca[MLX5_CAP_GENERAL_2]->cur,
|
||||
MLX5_ST_SZ_BYTES(cmd_hca_cap_2));
|
||||
MLX5_SET(cmd_hca_cap_2, set_hca_cap, sw_vhca_id_valid, 1);
|
||||
|
||||
return set_caps(dev, set_ctx, MLX5_CAP_GENERAL_2);
|
||||
}
|
||||
|
||||
static int handle_hca_cap(struct mlx5_core_dev *dev, void *set_ctx)
|
||||
{
|
||||
struct mlx5_profile *prof = &dev->profile;
|
||||
@@ -662,6 +689,13 @@ static int set_hca_cap(struct mlx5_core_dev *dev)
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(set_ctx, 0, set_sz);
|
||||
err = handle_hca_cap_2(dev, set_ctx);
|
||||
if (err) {
|
||||
mlx5_core_err(dev, "handle_hca_cap_2 failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(set_ctx);
|
||||
return err;
|
||||
@@ -1506,6 +1540,18 @@ int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx)
|
||||
if (err)
|
||||
goto err_hca_caps;
|
||||
|
||||
/* The conjunction of sw_vhca_id with sw_owner_id will be a global
|
||||
* unique id per function which uses mlx5_core.
|
||||
* Those values are supplied to FW as part of the init HCA command to
|
||||
* be used by both driver and FW when it's applicable.
|
||||
*/
|
||||
dev->priv.sw_vhca_id = ida_alloc_range(&sw_vhca_ida, 1,
|
||||
MAX_SW_VHCA_ID,
|
||||
GFP_KERNEL);
|
||||
if (dev->priv.sw_vhca_id < 0)
|
||||
mlx5_core_err(dev, "failed to allocate sw_vhca_id, err=%d\n",
|
||||
dev->priv.sw_vhca_id);
|
||||
|
||||
return 0;
|
||||
|
||||
err_hca_caps:
|
||||
@@ -1530,6 +1576,9 @@ void mlx5_mdev_uninit(struct mlx5_core_dev *dev)
|
||||
{
|
||||
struct mlx5_priv *priv = &dev->priv;
|
||||
|
||||
if (priv->sw_vhca_id > 0)
|
||||
ida_free(&sw_vhca_ida, dev->priv.sw_vhca_id);
|
||||
|
||||
mlx5_hca_caps_free(dev);
|
||||
mlx5_adev_cleanup(dev);
|
||||
mlx5_pagealloc_cleanup(dev);
|
||||
|
||||
@@ -1086,9 +1086,17 @@ int mlx5_nic_vport_affiliate_multiport(struct mlx5_core_dev *master_mdev,
|
||||
goto free;
|
||||
|
||||
MLX5_SET(modify_nic_vport_context_in, in, field_select.affiliation, 1);
|
||||
MLX5_SET(modify_nic_vport_context_in, in,
|
||||
nic_vport_context.affiliated_vhca_id,
|
||||
MLX5_CAP_GEN(master_mdev, vhca_id));
|
||||
if (MLX5_CAP_GEN_2(master_mdev, sw_vhca_id_valid)) {
|
||||
MLX5_SET(modify_nic_vport_context_in, in,
|
||||
nic_vport_context.vhca_id_type, VHCA_ID_TYPE_SW);
|
||||
MLX5_SET(modify_nic_vport_context_in, in,
|
||||
nic_vport_context.affiliated_vhca_id,
|
||||
MLX5_CAP_GEN_2(master_mdev, sw_vhca_id));
|
||||
} else {
|
||||
MLX5_SET(modify_nic_vport_context_in, in,
|
||||
nic_vport_context.affiliated_vhca_id,
|
||||
MLX5_CAP_GEN(master_mdev, vhca_id));
|
||||
}
|
||||
MLX5_SET(modify_nic_vport_context_in, in,
|
||||
nic_vport_context.affiliation_criteria,
|
||||
MLX5_CAP_GEN(port_mdev, affiliate_nic_vport_criteria));
|
||||
|
||||
@@ -610,6 +610,7 @@ struct mlx5_priv {
|
||||
spinlock_t ctx_lock;
|
||||
struct mlx5_adev **adev;
|
||||
int adev_idx;
|
||||
int sw_vhca_id;
|
||||
struct mlx5_events *events;
|
||||
|
||||
struct mlx5_flow_steering *steering;
|
||||
|
||||
@@ -1826,7 +1826,14 @@ struct mlx5_ifc_cmd_hca_cap_2_bits {
|
||||
u8 max_reformat_remove_size[0x8];
|
||||
u8 max_reformat_remove_offset[0x8];
|
||||
|
||||
u8 reserved_at_c0[0x740];
|
||||
u8 reserved_at_c0[0x160];
|
||||
|
||||
u8 reserved_at_220[0x1];
|
||||
u8 sw_vhca_id_valid[0x1];
|
||||
u8 sw_vhca_id[0xe];
|
||||
u8 reserved_at_230[0x10];
|
||||
|
||||
u8 reserved_at_240[0x5c0];
|
||||
};
|
||||
|
||||
enum mlx5_ifc_flow_destination_type {
|
||||
@@ -3782,6 +3789,11 @@ struct mlx5_ifc_rmpc_bits {
|
||||
struct mlx5_ifc_wq_bits wq;
|
||||
};
|
||||
|
||||
enum {
|
||||
VHCA_ID_TYPE_HW = 0,
|
||||
VHCA_ID_TYPE_SW = 1,
|
||||
};
|
||||
|
||||
struct mlx5_ifc_nic_vport_context_bits {
|
||||
u8 reserved_at_0[0x5];
|
||||
u8 min_wqe_inline_mode[0x3];
|
||||
@@ -3798,8 +3810,8 @@ struct mlx5_ifc_nic_vport_context_bits {
|
||||
u8 event_on_mc_address_change[0x1];
|
||||
u8 event_on_uc_address_change[0x1];
|
||||
|
||||
u8 reserved_at_40[0xc];
|
||||
|
||||
u8 vhca_id_type[0x1];
|
||||
u8 reserved_at_41[0xb];
|
||||
u8 affiliation_criteria[0x4];
|
||||
u8 affiliated_vhca_id[0x10];
|
||||
|
||||
@@ -7259,7 +7271,12 @@ struct mlx5_ifc_init_hca_in_bits {
|
||||
u8 reserved_at_20[0x10];
|
||||
u8 op_mod[0x10];
|
||||
|
||||
u8 reserved_at_40[0x40];
|
||||
u8 reserved_at_40[0x20];
|
||||
|
||||
u8 reserved_at_60[0x2];
|
||||
u8 sw_vhca_id[0xe];
|
||||
u8 reserved_at_70[0x10];
|
||||
|
||||
u8 sw_owner_id[4][0x20];
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user