Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'for-net-next' of git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux

Saeed Mahameed says:

====================
Mellanox, mlx5 E-Switch chains and prios

This series has two parts,

1) A merge commit with mlx5-next branch that include updates for mlx5
HW layouts needed for this and upcoming submissions.

2) From Paul, Increase the number of chains and prios

Currently the Mellanox driver supports offloading tc rules that
are defined on the first 4 chains and the first 16 priorities.
The restriction stems from the firmware flow level enforcement
requiring a flow table of a certain level to point to a flow
table of a higher level. This limitation may be ignored by setting
the ignore_flow_level bit when creating flow table entries.
Use unmanaged tables and ignore flow level to create more tables than
declared by fs_core steering. Manually manage the connections between the
tables themselves.

HW table is instantiated for every tc <chain,prio> tuple. The miss rule
of every table either jumps to the next <chain,prio> table, or continues
to slow_fdb. This logic is realized by following this sequence:

1. Create an auto-grouped flow table for the specified priority with
reserved entries

Reserved entries are allocated at the end of the flow table.
Flow groups are evaluated in sequence and therefore it is guaranteed
that the flow group defined on the last FTEs will be the last to evaluate.

Define a "match all" flow group on the reserved entries, providing
the platform to add table miss actions.

2. Set the miss rule action to jump to the next <chain,prio> table
or the slow_fdb.

3. Link the previous priority table to point to the new table by
updating its miss rule.

Please pull and let me know if there's any problem.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+1253 -361
+6 -4
drivers/infiniband/hw/mlx5/main.c
··· 3276 3276 int num_entries, int num_groups, 3277 3277 u32 flags) 3278 3278 { 3279 + struct mlx5_flow_table_attr ft_attr = {}; 3279 3280 struct mlx5_flow_table *ft; 3280 3281 3281 - ft = mlx5_create_auto_grouped_flow_table(ns, priority, 3282 - num_entries, 3283 - num_groups, 3284 - 0, flags); 3282 + ft_attr.prio = priority; 3283 + ft_attr.max_fte = num_entries; 3284 + ft_attr.flags = flags; 3285 + ft_attr.autogroup.max_num_groups = num_groups; 3286 + ft = mlx5_create_auto_grouped_flow_table(ns, &ft_attr); 3285 3287 if (IS_ERR(ft)) 3286 3288 return ERR_CAST(ft); 3287 3289
+1 -1
drivers/net/ethernet/mellanox/mlx5/core/Makefile
··· 42 42 # Core extra 43 43 # 44 44 mlx5_core-$(CONFIG_MLX5_ESWITCH) += eswitch.o eswitch_offloads.o eswitch_offloads_termtbl.o \ 45 - ecpf.o rdma.o 45 + ecpf.o rdma.o eswitch_offloads_chains.o 46 46 mlx5_core-$(CONFIG_MLX5_MPFS) += lib/mpfs.o 47 47 mlx5_core-$(CONFIG_VXLAN) += lib/vxlan.o 48 48 mlx5_core-$(CONFIG_PTP_1588_CLOCK) += lib/clock.o
+6 -3
drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
··· 58 58 struct ethtool_rx_flow_spec *fs, 59 59 int num_tuples) 60 60 { 61 + struct mlx5_flow_table_attr ft_attr = {}; 61 62 struct mlx5e_ethtool_table *eth_ft; 62 63 struct mlx5_flow_namespace *ns; 63 64 struct mlx5_flow_table *ft; ··· 103 102 table_size = min_t(u32, BIT(MLX5_CAP_FLOWTABLE(priv->mdev, 104 103 flow_table_properties_nic_receive.log_max_ft_size)), 105 104 MLX5E_ETHTOOL_NUM_ENTRIES); 106 - ft = mlx5_create_auto_grouped_flow_table(ns, prio, 107 - table_size, 108 - MLX5E_ETHTOOL_NUM_GROUPS, 0, 0); 105 + 106 + ft_attr.prio = prio; 107 + ft_attr.max_fte = table_size; 108 + ft_attr.autogroup.max_num_groups = MLX5E_ETHTOOL_NUM_GROUPS; 109 + ft = mlx5_create_auto_grouped_flow_table(ns, &ft_attr); 109 110 if (IS_ERR(ft)) 110 111 return (void *)ft; 111 112
+21 -7
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
··· 41 41 #include <net/ipv6_stubs.h> 42 42 43 43 #include "eswitch.h" 44 + #include "eswitch_offloads_chains.h" 44 45 #include "en.h" 45 46 #include "en_rep.h" 46 47 #include "en_tc.h" ··· 1248 1247 static int mlx5e_rep_setup_ft_cb(enum tc_setup_type type, void *type_data, 1249 1248 void *cb_priv) 1250 1249 { 1251 - struct flow_cls_offload *f = type_data; 1252 - struct flow_cls_offload cls_flower; 1250 + struct flow_cls_offload tmp, *f = type_data; 1253 1251 struct mlx5e_priv *priv = cb_priv; 1254 1252 struct mlx5_eswitch *esw; 1255 1253 unsigned long flags; ··· 1261 1261 1262 1262 switch (type) { 1263 1263 case TC_SETUP_CLSFLOWER: 1264 - if (!mlx5_eswitch_prios_supported(esw) || f->common.chain_index) 1264 + memcpy(&tmp, f, sizeof(*f)); 1265 + 1266 + if (!mlx5_esw_chains_prios_supported(esw) || 1267 + tmp.common.chain_index) 1265 1268 return -EOPNOTSUPP; 1266 1269 1267 1270 /* Re-use tc offload path by moving the ft flow to the 1268 1271 * reserved ft chain. 1272 + * 1273 + * FT offload can use prio range [0, INT_MAX], so we normalize 1274 + * it to range [1, mlx5_esw_chains_get_prio_range(esw)] 1275 + * as with tc, where prio 0 isn't supported. 1276 + * 1277 + * We only support chain 0 of FT offload. 1269 1278 */ 1270 - memcpy(&cls_flower, f, sizeof(*f)); 1271 - cls_flower.common.chain_index = FDB_FT_CHAIN; 1272 - err = mlx5e_rep_setup_tc_cls_flower(priv, &cls_flower, flags); 1273 - memcpy(&f->stats, &cls_flower.stats, sizeof(f->stats)); 1279 + if (tmp.common.prio >= mlx5_esw_chains_get_prio_range(esw)) 1280 + return -EOPNOTSUPP; 1281 + if (tmp.common.chain_index != 0) 1282 + return -EOPNOTSUPP; 1283 + 1284 + tmp.common.chain_index = mlx5_esw_chains_get_ft_chain(esw); 1285 + tmp.common.prio++; 1286 + err = mlx5e_rep_setup_tc_cls_flower(priv, &tmp, flags); 1287 + memcpy(&f->stats, &tmp.stats, sizeof(f->stats)); 1274 1288 return err; 1275 1289 default: 1276 1290 return -EOPNOTSUPP;
+1
drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
··· 1133 1133 static const struct counter_desc pport_per_prio_traffic_stats_desc[] = { 1134 1134 { "rx_prio%d_bytes", PPORT_PER_PRIO_OFF(rx_octets) }, 1135 1135 { "rx_prio%d_packets", PPORT_PER_PRIO_OFF(rx_frames) }, 1136 + { "rx_prio%d_discards", PPORT_PER_PRIO_OFF(rx_discards) }, 1136 1137 { "tx_prio%d_bytes", PPORT_PER_PRIO_OFF(tx_octets) }, 1137 1138 { "tx_prio%d_packets", PPORT_PER_PRIO_OFF(tx_frames) }, 1138 1139 };
+16 -11
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
··· 51 51 #include "en_rep.h" 52 52 #include "en_tc.h" 53 53 #include "eswitch.h" 54 + #include "eswitch_offloads_chains.h" 54 55 #include "fs_core.h" 55 56 #include "en/port.h" 56 57 #include "en/tc_tun.h" ··· 961 960 962 961 mutex_lock(&priv->fs.tc.t_lock); 963 962 if (IS_ERR_OR_NULL(priv->fs.tc.t)) { 964 - int tc_grp_size, tc_tbl_size; 963 + struct mlx5_flow_table_attr ft_attr = {}; 964 + int tc_grp_size, tc_tbl_size, tc_num_grps; 965 965 u32 max_flow_counter; 966 966 967 967 max_flow_counter = (MLX5_CAP_GEN(dev, max_flow_counter_31_16) << 16) | ··· 972 970 973 971 tc_tbl_size = min_t(int, tc_grp_size * MLX5E_TC_TABLE_NUM_GROUPS, 974 972 BIT(MLX5_CAP_FLOWTABLE_NIC_RX(dev, log_max_ft_size))); 973 + tc_num_grps = MLX5E_TC_TABLE_NUM_GROUPS; 975 974 975 + ft_attr.prio = MLX5E_TC_PRIO; 976 + ft_attr.max_fte = tc_tbl_size; 977 + ft_attr.level = MLX5E_TC_FT_LEVEL; 978 + ft_attr.autogroup.max_num_groups = tc_num_grps; 976 979 priv->fs.tc.t = 977 980 mlx5_create_auto_grouped_flow_table(priv->fs.ns, 978 - MLX5E_TC_PRIO, 979 - tc_tbl_size, 980 - MLX5E_TC_TABLE_NUM_GROUPS, 981 - MLX5E_TC_FT_LEVEL, 0); 981 + &ft_attr); 982 982 if (IS_ERR(priv->fs.tc.t)) { 983 983 mutex_unlock(&priv->fs.tc.t_lock); 984 984 NL_SET_ERR_MSG_MOD(extack, ··· 1084 1080 memcpy(slow_attr, flow->esw_attr, sizeof(*slow_attr)); 1085 1081 slow_attr->action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; 1086 1082 slow_attr->split_count = 0; 1087 - slow_attr->dest_chain = FDB_TC_SLOW_PATH_CHAIN; 1083 + slow_attr->flags |= MLX5_ESW_ATTR_FLAG_SLOW_PATH; 1088 1084 1089 1085 rule = mlx5e_tc_offload_fdb_rules(esw, flow, spec, slow_attr); 1090 1086 if (!IS_ERR(rule)) ··· 1101 1097 memcpy(slow_attr, flow->esw_attr, sizeof(*slow_attr)); 1102 1098 slow_attr->action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; 1103 1099 slow_attr->split_count = 0; 1104 - slow_attr->dest_chain = FDB_TC_SLOW_PATH_CHAIN; 1100 + slow_attr->flags |= MLX5_ESW_ATTR_FLAG_SLOW_PATH; 1105 1101 mlx5e_tc_unoffload_fdb_rules(esw, flow, slow_attr); 1106 1102 flow_flag_clear(flow, SLOW); 1107 1103 } ··· 1161 1157 struct netlink_ext_ack *extack) 1162 1158 { 1163 1159 struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 1164 - u32 max_chain = mlx5_eswitch_get_chain_range(esw); 1165 1160 struct mlx5_esw_flow_attr *attr = flow->esw_attr; 1166 1161 struct mlx5e_tc_flow_parse_attr *parse_attr = attr->parse_attr; 1167 - u16 max_prio = mlx5_eswitch_get_prio_range(esw); 1168 1162 struct net_device *out_dev, *encap_dev = NULL; 1169 1163 struct mlx5_fc *counter = NULL; 1170 1164 struct mlx5e_rep_priv *rpriv; 1171 1165 struct mlx5e_priv *out_priv; 1172 1166 bool encap_valid = true; 1167 + u32 max_prio, max_chain; 1173 1168 int err = 0; 1174 1169 int out_index; 1175 1170 1176 - if (!mlx5_eswitch_prios_supported(esw) && attr->prio != 1) { 1171 + if (!mlx5_esw_chains_prios_supported(esw) && attr->prio != 1) { 1177 1172 NL_SET_ERR_MSG(extack, "E-switch priorities unsupported, upgrade FW"); 1178 1173 return -EOPNOTSUPP; 1179 1174 } ··· 1182 1179 * FDB_FT_CHAIN which is outside tc range. 1183 1180 * See mlx5e_rep_setup_ft_cb(). 1184 1181 */ 1182 + max_chain = mlx5_esw_chains_get_chain_range(esw); 1185 1183 if (!mlx5e_is_ft_flow(flow) && attr->chain > max_chain) { 1186 1184 NL_SET_ERR_MSG(extack, "Requested chain is out of supported range"); 1187 1185 return -EOPNOTSUPP; 1188 1186 } 1189 1187 1188 + max_prio = mlx5_esw_chains_get_prio_range(esw); 1190 1189 if (attr->prio > max_prio) { 1191 1190 NL_SET_ERR_MSG(extack, "Requested priority is out of supported range"); 1192 1191 return -EOPNOTSUPP; ··· 3471 3466 break; 3472 3467 case FLOW_ACTION_GOTO: { 3473 3468 u32 dest_chain = act->chain_index; 3474 - u32 max_chain = mlx5_eswitch_get_chain_range(esw); 3469 + u32 max_chain = mlx5_esw_chains_get_chain_range(esw); 3475 3470 3476 3471 if (ft_flow) { 3477 3472 NL_SET_ERR_MSG_MOD(extack, "Goto action is not supported");
+5 -2
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
··· 277 277 278 278 static int esw_create_legacy_vepa_table(struct mlx5_eswitch *esw) 279 279 { 280 + struct mlx5_flow_table_attr ft_attr = {}; 280 281 struct mlx5_core_dev *dev = esw->dev; 281 282 struct mlx5_flow_namespace *root_ns; 282 283 struct mlx5_flow_table *fdb; ··· 290 289 } 291 290 292 291 /* num FTE 2, num FG 2 */ 293 - fdb = mlx5_create_auto_grouped_flow_table(root_ns, LEGACY_VEPA_PRIO, 294 - 2, 2, 0, 0); 292 + ft_attr.prio = LEGACY_VEPA_PRIO; 293 + ft_attr.max_fte = 2; 294 + ft_attr.autogroup.max_num_groups = 2; 295 + fdb = mlx5_create_auto_grouped_flow_table(root_ns, &ft_attr); 295 296 if (IS_ERR(fdb)) { 296 297 err = PTR_ERR(fdb); 297 298 esw_warn(dev, "Failed to create VEPA FDB err %d\n", err);
+8 -19
drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
··· 157 157 ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED = BIT(0), 158 158 }; 159 159 160 - extern const unsigned int ESW_POOLS[4]; 160 + struct mlx5_esw_chains_priv; 161 161 162 162 struct mlx5_eswitch_fdb { 163 163 union { ··· 182 182 struct mlx5_flow_handle *miss_rule_multi; 183 183 int vlan_push_pop_refcount; 184 184 185 - struct { 186 - struct mlx5_flow_table *fdb; 187 - u32 num_rules; 188 - } fdb_prio[FDB_NUM_CHAINS][FDB_TC_MAX_PRIO + 1][FDB_TC_LEVELS_PER_PRIO]; 189 - /* Protects fdb_prio table */ 190 - struct mutex fdb_prio_lock; 191 - 192 - int fdb_left[ARRAY_SIZE(ESW_POOLS)]; 185 + struct mlx5_esw_chains_priv *esw_chains_priv; 193 186 } offloads; 194 187 }; 195 188 u32 flags; ··· 348 355 struct mlx5_flow_handle *rule, 349 356 struct mlx5_esw_flow_attr *attr); 350 357 351 - bool 352 - mlx5_eswitch_prios_supported(struct mlx5_eswitch *esw); 353 - 354 - u16 355 - mlx5_eswitch_get_prio_range(struct mlx5_eswitch *esw); 356 - 357 - u32 358 - mlx5_eswitch_get_chain_range(struct mlx5_eswitch *esw); 359 - 360 358 struct mlx5_flow_handle * 361 359 mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, u16 vport, 362 360 struct mlx5_flow_destination *dest); ··· 372 388 MLX5_ESW_DEST_ENCAP_VALID = BIT(1), 373 389 }; 374 390 391 + enum { 392 + MLX5_ESW_ATTR_FLAG_VLAN_HANDLED = BIT(0), 393 + MLX5_ESW_ATTR_FLAG_SLOW_PATH = BIT(1), 394 + }; 395 + 375 396 struct mlx5_esw_flow_attr { 376 397 struct mlx5_eswitch_rep *in_rep; 377 398 struct mlx5_core_dev *in_mdev; ··· 390 401 u16 vlan_vid[MLX5_FS_VLAN_DEPTH]; 391 402 u8 vlan_prio[MLX5_FS_VLAN_DEPTH]; 392 403 u8 total_vlan; 393 - bool vlan_handled; 394 404 struct { 395 405 u32 flags; 396 406 struct mlx5_eswitch_rep *rep; ··· 404 416 u32 chain; 405 417 u16 prio; 406 418 u32 dest_chain; 419 + u32 flags; 407 420 struct mlx5e_tc_flow_parse_attr *parse_attr; 408 421 }; 409 422
+46 -252
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
··· 37 37 #include <linux/mlx5/fs.h> 38 38 #include "mlx5_core.h" 39 39 #include "eswitch.h" 40 + #include "eswitch_offloads_chains.h" 40 41 #include "rdma.h" 41 42 #include "en.h" 42 43 #include "fs_core.h" ··· 48 47 * one for multicast. 49 48 */ 50 49 #define MLX5_ESW_MISS_FLOWS (2) 51 - 52 - #define fdb_prio_table(esw, chain, prio, level) \ 53 - (esw)->fdb_table.offloads.fdb_prio[(chain)][(prio)][(level)] 54 - 55 50 #define UPLINK_REP_INDEX 0 56 51 57 52 static struct mlx5_eswitch_rep *mlx5_eswitch_get_rep(struct mlx5_eswitch *esw, ··· 57 60 58 61 WARN_ON(idx > esw->total_vports - 1); 59 62 return &esw->offloads.vport_reps[idx]; 60 - } 61 - 62 - static struct mlx5_flow_table * 63 - esw_get_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level); 64 - static void 65 - esw_put_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level); 66 - 67 - bool mlx5_eswitch_prios_supported(struct mlx5_eswitch *esw) 68 - { 69 - return (!!(esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED)); 70 - } 71 - 72 - u32 mlx5_eswitch_get_chain_range(struct mlx5_eswitch *esw) 73 - { 74 - if (esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED) 75 - return FDB_TC_MAX_CHAIN; 76 - 77 - return 0; 78 - } 79 - 80 - u16 mlx5_eswitch_get_prio_range(struct mlx5_eswitch *esw) 81 - { 82 - if (esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED) 83 - return FDB_TC_MAX_PRIO; 84 - 85 - return 1; 86 63 } 87 64 88 65 static bool ··· 146 175 } 147 176 148 177 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) { 149 - if (attr->dest_chain) { 150 - struct mlx5_flow_table *ft; 178 + struct mlx5_flow_table *ft; 151 179 152 - ft = esw_get_prio_table(esw, attr->dest_chain, 1, 0); 180 + if (attr->flags & MLX5_ESW_ATTR_FLAG_SLOW_PATH) { 181 + flow_act.flags |= FLOW_ACT_IGNORE_FLOW_LEVEL; 182 + dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; 183 + dest[i].ft = mlx5_esw_chains_get_tc_end_ft(esw); 184 + i++; 185 + } else if (attr->dest_chain) { 186 + flow_act.flags |= FLOW_ACT_IGNORE_FLOW_LEVEL; 187 + ft = mlx5_esw_chains_get_table(esw, attr->dest_chain, 188 + 1, 0); 153 189 if (IS_ERR(ft)) { 154 190 rule = ERR_CAST(ft); 155 191 goto err_create_goto_table; ··· 201 223 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) 202 224 flow_act.modify_hdr = attr->modify_hdr; 203 225 204 - fdb = esw_get_prio_table(esw, attr->chain, attr->prio, !!split); 226 + fdb = mlx5_esw_chains_get_table(esw, attr->chain, attr->prio, 227 + !!split); 205 228 if (IS_ERR(fdb)) { 206 229 rule = ERR_CAST(fdb); 207 230 goto err_esw_get; ··· 221 242 return rule; 222 243 223 244 err_add_rule: 224 - esw_put_prio_table(esw, attr->chain, attr->prio, !!split); 245 + mlx5_esw_chains_put_table(esw, attr->chain, attr->prio, !!split); 225 246 err_esw_get: 226 - if (attr->dest_chain) 227 - esw_put_prio_table(esw, attr->dest_chain, 1, 0); 247 + if (!(attr->flags & MLX5_ESW_ATTR_FLAG_SLOW_PATH) && attr->dest_chain) 248 + mlx5_esw_chains_put_table(esw, attr->dest_chain, 1, 0); 228 249 err_create_goto_table: 229 250 return rule; 230 251 } ··· 241 262 struct mlx5_flow_handle *rule; 242 263 int i; 243 264 244 - fast_fdb = esw_get_prio_table(esw, attr->chain, attr->prio, 0); 265 + fast_fdb = mlx5_esw_chains_get_table(esw, attr->chain, attr->prio, 0); 245 266 if (IS_ERR(fast_fdb)) { 246 267 rule = ERR_CAST(fast_fdb); 247 268 goto err_get_fast; 248 269 } 249 270 250 - fwd_fdb = esw_get_prio_table(esw, attr->chain, attr->prio, 1); 271 + fwd_fdb = mlx5_esw_chains_get_table(esw, attr->chain, attr->prio, 1); 251 272 if (IS_ERR(fwd_fdb)) { 252 273 rule = ERR_CAST(fwd_fdb); 253 274 goto err_get_fwd; ··· 275 296 if (attr->outer_match_level != MLX5_MATCH_NONE) 276 297 spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS; 277 298 299 + flow_act.flags |= FLOW_ACT_IGNORE_FLOW_LEVEL; 278 300 rule = mlx5_add_flow_rules(fast_fdb, spec, &flow_act, dest, i); 279 301 280 302 if (IS_ERR(rule)) ··· 285 305 286 306 return rule; 287 307 add_err: 288 - esw_put_prio_table(esw, attr->chain, attr->prio, 1); 308 + mlx5_esw_chains_put_table(esw, attr->chain, attr->prio, 1); 289 309 err_get_fwd: 290 - esw_put_prio_table(esw, attr->chain, attr->prio, 0); 310 + mlx5_esw_chains_put_table(esw, attr->chain, attr->prio, 0); 291 311 err_get_fast: 292 312 return rule; 293 313 } ··· 312 332 atomic64_dec(&esw->offloads.num_flows); 313 333 314 334 if (fwd_rule) { 315 - esw_put_prio_table(esw, attr->chain, attr->prio, 1); 316 - esw_put_prio_table(esw, attr->chain, attr->prio, 0); 335 + mlx5_esw_chains_put_table(esw, attr->chain, attr->prio, 1); 336 + mlx5_esw_chains_put_table(esw, attr->chain, attr->prio, 0); 317 337 } else { 318 - esw_put_prio_table(esw, attr->chain, attr->prio, !!split); 338 + mlx5_esw_chains_put_table(esw, attr->chain, attr->prio, 339 + !!split); 319 340 if (attr->dest_chain) 320 - esw_put_prio_table(esw, attr->dest_chain, 1, 0); 341 + mlx5_esw_chains_put_table(esw, attr->dest_chain, 1, 0); 321 342 } 322 343 } 323 344 ··· 432 451 if (err) 433 452 goto unlock; 434 453 435 - attr->vlan_handled = false; 454 + attr->flags &= ~MLX5_ESW_ATTR_FLAG_VLAN_HANDLED; 436 455 437 456 vport = esw_vlan_action_get_vport(attr, push, pop); 438 457 ··· 440 459 /* tracks VF --> wire rules without vlan push action */ 441 460 if (attr->dests[0].rep->vport == MLX5_VPORT_UPLINK) { 442 461 vport->vlan_refcount++; 443 - attr->vlan_handled = true; 462 + attr->flags |= MLX5_ESW_ATTR_FLAG_VLAN_HANDLED; 444 463 } 445 464 446 465 goto unlock; ··· 471 490 } 472 491 out: 473 492 if (!err) 474 - attr->vlan_handled = true; 493 + attr->flags |= MLX5_ESW_ATTR_FLAG_VLAN_HANDLED; 475 494 unlock: 476 495 mutex_unlock(&esw->state_lock); 477 496 return err; ··· 489 508 if (mlx5_eswitch_vlan_actions_supported(esw->dev, 1)) 490 509 return 0; 491 510 492 - if (!attr->vlan_handled) 511 + if (!(attr->flags & MLX5_ESW_ATTR_FLAG_VLAN_HANDLED)) 493 512 return 0; 494 513 495 514 push = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH); ··· 563 582 dest.vport.num = vport; 564 583 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; 565 584 566 - flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb, spec, 567 - &flow_act, &dest, 1); 585 + flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb, 586 + spec, &flow_act, &dest, 1); 568 587 if (IS_ERR(flow_rule)) 569 588 esw_warn(esw->dev, "FDB: Failed to add send to vport rule err %ld\n", PTR_ERR(flow_rule)); 570 589 out: ··· 805 824 dest.vport.num = esw->manager_vport; 806 825 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; 807 826 808 - flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb, spec, 809 - &flow_act, &dest, 1); 827 + flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb, 828 + spec, &flow_act, &dest, 1); 810 829 if (IS_ERR(flow_rule)) { 811 830 err = PTR_ERR(flow_rule); 812 831 esw_warn(esw->dev, "FDB: Failed to add unicast miss flow rule err %d\n", err); ··· 820 839 dmac_v = MLX5_ADDR_OF(fte_match_param, headers_v, 821 840 outer_headers.dmac_47_16); 822 841 dmac_v[0] = 0x01; 823 - flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb, spec, 824 - &flow_act, &dest, 1); 842 + flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb, 843 + spec, &flow_act, &dest, 1); 825 844 if (IS_ERR(flow_rule)) { 826 845 err = PTR_ERR(flow_rule); 827 846 esw_warn(esw->dev, "FDB: Failed to add multicast miss flow rule err %d\n", err); ··· 834 853 out: 835 854 kvfree(spec); 836 855 return err; 837 - } 838 - 839 - #define ESW_OFFLOADS_NUM_GROUPS 4 840 - 841 - /* Firmware currently has 4 pool of 4 sizes that it supports (ESW_POOLS), 842 - * and a virtual memory region of 16M (ESW_SIZE), this region is duplicated 843 - * for each flow table pool. We can allocate up to 16M of each pool, 844 - * and we keep track of how much we used via put/get_sz_to_pool. 845 - * Firmware doesn't report any of this for now. 846 - * ESW_POOL is expected to be sorted from large to small 847 - */ 848 - #define ESW_SIZE (16 * 1024 * 1024) 849 - const unsigned int ESW_POOLS[4] = { 4 * 1024 * 1024, 1 * 1024 * 1024, 850 - 64 * 1024, 4 * 1024 }; 851 - 852 - static int 853 - get_sz_from_pool(struct mlx5_eswitch *esw) 854 - { 855 - int sz = 0, i; 856 - 857 - for (i = 0; i < ARRAY_SIZE(ESW_POOLS); i++) { 858 - if (esw->fdb_table.offloads.fdb_left[i]) { 859 - --esw->fdb_table.offloads.fdb_left[i]; 860 - sz = ESW_POOLS[i]; 861 - break; 862 - } 863 - } 864 - 865 - return sz; 866 - } 867 - 868 - static void 869 - put_sz_to_pool(struct mlx5_eswitch *esw, int sz) 870 - { 871 - int i; 872 - 873 - for (i = 0; i < ARRAY_SIZE(ESW_POOLS); i++) { 874 - if (sz >= ESW_POOLS[i]) { 875 - ++esw->fdb_table.offloads.fdb_left[i]; 876 - break; 877 - } 878 - } 879 - } 880 - 881 - static struct mlx5_flow_table * 882 - create_next_size_table(struct mlx5_eswitch *esw, 883 - struct mlx5_flow_namespace *ns, 884 - u16 table_prio, 885 - int level, 886 - u32 flags) 887 - { 888 - struct mlx5_flow_table *fdb; 889 - int sz; 890 - 891 - sz = get_sz_from_pool(esw); 892 - if (!sz) 893 - return ERR_PTR(-ENOSPC); 894 - 895 - fdb = mlx5_create_auto_grouped_flow_table(ns, 896 - table_prio, 897 - sz, 898 - ESW_OFFLOADS_NUM_GROUPS, 899 - level, 900 - flags); 901 - if (IS_ERR(fdb)) { 902 - esw_warn(esw->dev, "Failed to create FDB Table err %d (table prio: %d, level: %d, size: %d)\n", 903 - (int)PTR_ERR(fdb), table_prio, level, sz); 904 - put_sz_to_pool(esw, sz); 905 - } 906 - 907 - return fdb; 908 - } 909 - 910 - static struct mlx5_flow_table * 911 - esw_get_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level) 912 - { 913 - struct mlx5_core_dev *dev = esw->dev; 914 - struct mlx5_flow_table *fdb = NULL; 915 - struct mlx5_flow_namespace *ns; 916 - int table_prio, l = 0; 917 - u32 flags = 0; 918 - 919 - if (chain == FDB_TC_SLOW_PATH_CHAIN) 920 - return esw->fdb_table.offloads.slow_fdb; 921 - 922 - mutex_lock(&esw->fdb_table.offloads.fdb_prio_lock); 923 - 924 - fdb = fdb_prio_table(esw, chain, prio, level).fdb; 925 - if (fdb) { 926 - /* take ref on earlier levels as well */ 927 - while (level >= 0) 928 - fdb_prio_table(esw, chain, prio, level--).num_rules++; 929 - mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock); 930 - return fdb; 931 - } 932 - 933 - ns = mlx5_get_fdb_sub_ns(dev, chain); 934 - if (!ns) { 935 - esw_warn(dev, "Failed to get FDB sub namespace\n"); 936 - mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock); 937 - return ERR_PTR(-EOPNOTSUPP); 938 - } 939 - 940 - if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE) 941 - flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT | 942 - MLX5_FLOW_TABLE_TUNNEL_EN_DECAP); 943 - 944 - table_prio = prio - 1; 945 - 946 - /* create earlier levels for correct fs_core lookup when 947 - * connecting tables 948 - */ 949 - for (l = 0; l <= level; l++) { 950 - if (fdb_prio_table(esw, chain, prio, l).fdb) { 951 - fdb_prio_table(esw, chain, prio, l).num_rules++; 952 - continue; 953 - } 954 - 955 - fdb = create_next_size_table(esw, ns, table_prio, l, flags); 956 - if (IS_ERR(fdb)) { 957 - l--; 958 - goto err_create_fdb; 959 - } 960 - 961 - fdb_prio_table(esw, chain, prio, l).fdb = fdb; 962 - fdb_prio_table(esw, chain, prio, l).num_rules = 1; 963 - } 964 - 965 - mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock); 966 - return fdb; 967 - 968 - err_create_fdb: 969 - mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock); 970 - if (l >= 0) 971 - esw_put_prio_table(esw, chain, prio, l); 972 - 973 - return fdb; 974 - } 975 - 976 - static void 977 - esw_put_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level) 978 - { 979 - int l; 980 - 981 - if (chain == FDB_TC_SLOW_PATH_CHAIN) 982 - return; 983 - 984 - mutex_lock(&esw->fdb_table.offloads.fdb_prio_lock); 985 - 986 - for (l = level; l >= 0; l--) { 987 - if (--(fdb_prio_table(esw, chain, prio, l).num_rules) > 0) 988 - continue; 989 - 990 - put_sz_to_pool(esw, fdb_prio_table(esw, chain, prio, l).fdb->max_fte); 991 - mlx5_destroy_flow_table(fdb_prio_table(esw, chain, prio, l).fdb); 992 - fdb_prio_table(esw, chain, prio, l).fdb = NULL; 993 - } 994 - 995 - mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock); 996 - } 997 - 998 - static void esw_destroy_offloads_fast_fdb_tables(struct mlx5_eswitch *esw) 999 - { 1000 - /* If lazy creation isn't supported, deref the fast path tables */ 1001 - if (!(esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED)) { 1002 - esw_put_prio_table(esw, 0, 1, 1); 1003 - esw_put_prio_table(esw, 0, 1, 0); 1004 - } 1005 856 } 1006 857 1007 858 #define MAX_PF_SQ 256 ··· 868 1055 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); 869 1056 struct mlx5_flow_table_attr ft_attr = {}; 870 1057 struct mlx5_core_dev *dev = esw->dev; 871 - u32 *flow_group_in, max_flow_counter; 872 1058 struct mlx5_flow_namespace *root_ns; 873 1059 struct mlx5_flow_table *fdb = NULL; 874 - int table_size, ix, err = 0, i; 1060 + u32 flags = 0, *flow_group_in; 1061 + int table_size, ix, err = 0; 875 1062 struct mlx5_flow_group *g; 876 - u32 flags = 0, fdb_max; 877 1063 void *match_criteria; 878 1064 u8 *dmac; 879 1065 880 1066 esw_debug(esw->dev, "Create offloads FDB Tables\n"); 1067 + 881 1068 flow_group_in = kvzalloc(inlen, GFP_KERNEL); 882 1069 if (!flow_group_in) 883 1070 return -ENOMEM; ··· 895 1082 esw_warn(dev, "Failed to set FDB namespace steering mode\n"); 896 1083 goto ns_err; 897 1084 } 898 - 899 - max_flow_counter = (MLX5_CAP_GEN(dev, max_flow_counter_31_16) << 16) | 900 - MLX5_CAP_GEN(dev, max_flow_counter_15_0); 901 - fdb_max = 1 << MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size); 902 - 903 - esw_debug(dev, "Create offloads FDB table, min (max esw size(2^%d), max counters(%d), groups(%d), max flow table size(%d))\n", 904 - MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size), 905 - max_flow_counter, ESW_OFFLOADS_NUM_GROUPS, 906 - fdb_max); 907 - 908 - for (i = 0; i < ARRAY_SIZE(ESW_POOLS); i++) 909 - esw->fdb_table.offloads.fdb_left[i] = 910 - ESW_POOLS[i] <= fdb_max ? ESW_SIZE / ESW_POOLS[i] : 0; 911 1085 912 1086 table_size = nvports * MAX_SQ_NVPORTS + MAX_PF_SQ + 913 1087 MLX5_ESW_MISS_FLOWS + esw->total_vports; ··· 918 1118 } 919 1119 esw->fdb_table.offloads.slow_fdb = fdb; 920 1120 921 - /* If lazy creation isn't supported, open the fast path tables now */ 922 - if (!MLX5_CAP_ESW_FLOWTABLE(esw->dev, multi_fdb_encap) && 923 - esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE) { 924 - esw->fdb_table.flags &= ~ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED; 925 - esw_warn(dev, "Lazy creation of flow tables isn't supported, ignoring priorities\n"); 926 - esw_get_prio_table(esw, 0, 1, 0); 927 - esw_get_prio_table(esw, 0, 1, 1); 928 - } else { 929 - esw_debug(dev, "Lazy creation of flow tables supported, deferring table opening\n"); 930 - esw->fdb_table.flags |= ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED; 1121 + err = mlx5_esw_chains_create(esw); 1122 + if (err) { 1123 + esw_warn(dev, "Failed to create fdb chains err(%d)\n", err); 1124 + goto fdb_chains_err; 931 1125 } 932 1126 933 1127 /* create send-to-vport group */ ··· 1012 1218 peer_miss_err: 1013 1219 mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp); 1014 1220 send_vport_err: 1015 - esw_destroy_offloads_fast_fdb_tables(esw); 1221 + mlx5_esw_chains_destroy(esw); 1222 + fdb_chains_err: 1016 1223 mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb); 1017 1224 slow_fdb_err: 1018 1225 /* Holds true only as long as DMFS is the default */ ··· 1035 1240 mlx5_destroy_flow_group(esw->fdb_table.offloads.peer_miss_grp); 1036 1241 mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp); 1037 1242 1243 + mlx5_esw_chains_destroy(esw); 1038 1244 mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb); 1039 - esw_destroy_offloads_fast_fdb_tables(esw); 1040 1245 /* Holds true only as long as DMFS is the default */ 1041 1246 mlx5_flow_namespace_set_mode(esw->fdb_table.offloads.ns, 1042 1247 MLX5_FLOW_STEERING_MODE_DMFS); ··· 1906 2111 total_vports = num_vfs + MLX5_SPECIAL_VPORTS(esw->dev); 1907 2112 1908 2113 memset(&esw->fdb_table.offloads, 0, sizeof(struct offloads_fdb)); 1909 - mutex_init(&esw->fdb_table.offloads.fdb_prio_lock); 1910 2114 1911 2115 err = esw_create_uplink_offloads_acl_tables(esw); 1912 2116 if (err)
+758
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_chains.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 + // Copyright (c) 2020 Mellanox Technologies. 3 + 4 + #include <linux/mlx5/driver.h> 5 + #include <linux/mlx5/mlx5_ifc.h> 6 + #include <linux/mlx5/fs.h> 7 + 8 + #include "eswitch_offloads_chains.h" 9 + #include "mlx5_core.h" 10 + #include "fs_core.h" 11 + #include "eswitch.h" 12 + #include "en.h" 13 + 14 + #define esw_chains_priv(esw) ((esw)->fdb_table.offloads.esw_chains_priv) 15 + #define esw_chains_lock(esw) (esw_chains_priv(esw)->lock) 16 + #define esw_chains_ht(esw) (esw_chains_priv(esw)->chains_ht) 17 + #define esw_prios_ht(esw) (esw_chains_priv(esw)->prios_ht) 18 + #define fdb_pool_left(esw) (esw_chains_priv(esw)->fdb_left) 19 + #define tc_slow_fdb(esw) ((esw)->fdb_table.offloads.slow_fdb) 20 + #define tc_end_fdb(esw) (esw_chains_priv(esw)->tc_end_fdb) 21 + #define fdb_ignore_flow_level_supported(esw) \ 22 + (MLX5_CAP_ESW_FLOWTABLE_FDB((esw)->dev, ignore_flow_level)) 23 + 24 + #define ESW_OFFLOADS_NUM_GROUPS 4 25 + 26 + /* Firmware currently has 4 pool of 4 sizes that it supports (ESW_POOLS), 27 + * and a virtual memory region of 16M (ESW_SIZE), this region is duplicated 28 + * for each flow table pool. We can allocate up to 16M of each pool, 29 + * and we keep track of how much we used via get_next_avail_sz_from_pool. 30 + * Firmware doesn't report any of this for now. 31 + * ESW_POOL is expected to be sorted from large to small and match firmware 32 + * pools. 33 + */ 34 + #define ESW_SIZE (16 * 1024 * 1024) 35 + const unsigned int ESW_POOLS[] = { 4 * 1024 * 1024, 36 + 1 * 1024 * 1024, 37 + 64 * 1024, 38 + 4 * 1024, }; 39 + 40 + struct mlx5_esw_chains_priv { 41 + struct rhashtable chains_ht; 42 + struct rhashtable prios_ht; 43 + /* Protects above chains_ht and prios_ht */ 44 + struct mutex lock; 45 + 46 + struct mlx5_flow_table *tc_end_fdb; 47 + 48 + int fdb_left[ARRAY_SIZE(ESW_POOLS)]; 49 + }; 50 + 51 + struct fdb_chain { 52 + struct rhash_head node; 53 + 54 + u32 chain; 55 + 56 + int ref; 57 + 58 + struct mlx5_eswitch *esw; 59 + struct list_head prios_list; 60 + }; 61 + 62 + struct fdb_prio_key { 63 + u32 chain; 64 + u32 prio; 65 + u32 level; 66 + }; 67 + 68 + struct fdb_prio { 69 + struct rhash_head node; 70 + struct list_head list; 71 + 72 + struct fdb_prio_key key; 73 + 74 + int ref; 75 + 76 + struct fdb_chain *fdb_chain; 77 + struct mlx5_flow_table *fdb; 78 + struct mlx5_flow_table *next_fdb; 79 + struct mlx5_flow_group *miss_group; 80 + struct mlx5_flow_handle *miss_rule; 81 + }; 82 + 83 + static const struct rhashtable_params chain_params = { 84 + .head_offset = offsetof(struct fdb_chain, node), 85 + .key_offset = offsetof(struct fdb_chain, chain), 86 + .key_len = sizeof_field(struct fdb_chain, chain), 87 + .automatic_shrinking = true, 88 + }; 89 + 90 + static const struct rhashtable_params prio_params = { 91 + .head_offset = offsetof(struct fdb_prio, node), 92 + .key_offset = offsetof(struct fdb_prio, key), 93 + .key_len = sizeof_field(struct fdb_prio, key), 94 + .automatic_shrinking = true, 95 + }; 96 + 97 + bool mlx5_esw_chains_prios_supported(struct mlx5_eswitch *esw) 98 + { 99 + return esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED; 100 + } 101 + 102 + u32 mlx5_esw_chains_get_chain_range(struct mlx5_eswitch *esw) 103 + { 104 + if (!mlx5_esw_chains_prios_supported(esw)) 105 + return 1; 106 + 107 + if (fdb_ignore_flow_level_supported(esw)) 108 + return UINT_MAX - 1; 109 + 110 + return FDB_TC_MAX_CHAIN; 111 + } 112 + 113 + u32 mlx5_esw_chains_get_ft_chain(struct mlx5_eswitch *esw) 114 + { 115 + return mlx5_esw_chains_get_chain_range(esw) + 1; 116 + } 117 + 118 + u32 mlx5_esw_chains_get_prio_range(struct mlx5_eswitch *esw) 119 + { 120 + if (!mlx5_esw_chains_prios_supported(esw)) 121 + return 1; 122 + 123 + if (fdb_ignore_flow_level_supported(esw)) 124 + return UINT_MAX; 125 + 126 + return FDB_TC_MAX_PRIO; 127 + } 128 + 129 + static unsigned int mlx5_esw_chains_get_level_range(struct mlx5_eswitch *esw) 130 + { 131 + if (fdb_ignore_flow_level_supported(esw)) 132 + return UINT_MAX; 133 + 134 + return FDB_TC_LEVELS_PER_PRIO; 135 + } 136 + 137 + #define POOL_NEXT_SIZE 0 138 + static int 139 + mlx5_esw_chains_get_avail_sz_from_pool(struct mlx5_eswitch *esw, 140 + int desired_size) 141 + { 142 + int i, found_i = -1; 143 + 144 + for (i = ARRAY_SIZE(ESW_POOLS) - 1; i >= 0; i--) { 145 + if (fdb_pool_left(esw)[i] && ESW_POOLS[i] > desired_size) { 146 + found_i = i; 147 + if (desired_size != POOL_NEXT_SIZE) 148 + break; 149 + } 150 + } 151 + 152 + if (found_i != -1) { 153 + --fdb_pool_left(esw)[found_i]; 154 + return ESW_POOLS[found_i]; 155 + } 156 + 157 + return 0; 158 + } 159 + 160 + static void 161 + mlx5_esw_chains_put_sz_to_pool(struct mlx5_eswitch *esw, int sz) 162 + { 163 + int i; 164 + 165 + for (i = ARRAY_SIZE(ESW_POOLS) - 1; i >= 0; i--) { 166 + if (sz == ESW_POOLS[i]) { 167 + ++fdb_pool_left(esw)[i]; 168 + return; 169 + } 170 + } 171 + 172 + WARN_ONCE(1, "Couldn't find size %d in fdb size pool", sz); 173 + } 174 + 175 + static void 176 + mlx5_esw_chains_init_sz_pool(struct mlx5_eswitch *esw) 177 + { 178 + u32 fdb_max; 179 + int i; 180 + 181 + fdb_max = 1 << MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, log_max_ft_size); 182 + 183 + for (i = ARRAY_SIZE(ESW_POOLS) - 1; i >= 0; i--) 184 + fdb_pool_left(esw)[i] = 185 + ESW_POOLS[i] <= fdb_max ? ESW_SIZE / ESW_POOLS[i] : 0; 186 + } 187 + 188 + static struct mlx5_flow_table * 189 + mlx5_esw_chains_create_fdb_table(struct mlx5_eswitch *esw, 190 + u32 chain, u32 prio, u32 level) 191 + { 192 + struct mlx5_flow_table_attr ft_attr = {}; 193 + struct mlx5_flow_namespace *ns; 194 + struct mlx5_flow_table *fdb; 195 + int sz; 196 + 197 + if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE) 198 + ft_attr.flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT | 199 + MLX5_FLOW_TABLE_TUNNEL_EN_DECAP); 200 + 201 + sz = mlx5_esw_chains_get_avail_sz_from_pool(esw, POOL_NEXT_SIZE); 202 + if (!sz) 203 + return ERR_PTR(-ENOSPC); 204 + ft_attr.max_fte = sz; 205 + 206 + /* We use tc_slow_fdb(esw) as the table's next_ft till 207 + * ignore_flow_level is allowed on FT creation and not just for FTEs. 208 + * Instead caller should add an explicit miss rule if needed. 209 + */ 210 + ft_attr.next_ft = tc_slow_fdb(esw); 211 + 212 + /* The root table(chain 0, prio 1, level 0) is required to be 213 + * connected to the previous prio (FDB_BYPASS_PATH if exists). 214 + * We always create it, as a managed table, in order to align with 215 + * fs_core logic. 216 + */ 217 + if (!fdb_ignore_flow_level_supported(esw) || 218 + (chain == 0 && prio == 1 && level == 0)) { 219 + ft_attr.level = level; 220 + ft_attr.prio = prio - 1; 221 + ns = mlx5_get_fdb_sub_ns(esw->dev, chain); 222 + } else { 223 + ft_attr.flags |= MLX5_FLOW_TABLE_UNMANAGED; 224 + ft_attr.prio = FDB_TC_OFFLOAD; 225 + /* Firmware doesn't allow us to create another level 0 table, 226 + * so we create all unmanaged tables as level 1. 227 + * 228 + * To connect them, we use explicit miss rules with 229 + * ignore_flow_level. Caller is responsible to create 230 + * these rules (if needed). 231 + */ 232 + ft_attr.level = 1; 233 + ns = mlx5_get_flow_namespace(esw->dev, MLX5_FLOW_NAMESPACE_FDB); 234 + } 235 + 236 + ft_attr.autogroup.num_reserved_entries = 2; 237 + ft_attr.autogroup.max_num_groups = ESW_OFFLOADS_NUM_GROUPS; 238 + fdb = mlx5_create_auto_grouped_flow_table(ns, &ft_attr); 239 + if (IS_ERR(fdb)) { 240 + esw_warn(esw->dev, 241 + "Failed to create FDB table err %d (chain: %d, prio: %d, level: %d, size: %d)\n", 242 + (int)PTR_ERR(fdb), chain, prio, level, sz); 243 + mlx5_esw_chains_put_sz_to_pool(esw, sz); 244 + return fdb; 245 + } 246 + 247 + return fdb; 248 + } 249 + 250 + static void 251 + mlx5_esw_chains_destroy_fdb_table(struct mlx5_eswitch *esw, 252 + struct mlx5_flow_table *fdb) 253 + { 254 + mlx5_esw_chains_put_sz_to_pool(esw, fdb->max_fte); 255 + mlx5_destroy_flow_table(fdb); 256 + } 257 + 258 + static struct fdb_chain * 259 + mlx5_esw_chains_create_fdb_chain(struct mlx5_eswitch *esw, u32 chain) 260 + { 261 + struct fdb_chain *fdb_chain = NULL; 262 + int err; 263 + 264 + fdb_chain = kvzalloc(sizeof(*fdb_chain), GFP_KERNEL); 265 + if (!fdb_chain) 266 + return ERR_PTR(-ENOMEM); 267 + 268 + fdb_chain->esw = esw; 269 + fdb_chain->chain = chain; 270 + INIT_LIST_HEAD(&fdb_chain->prios_list); 271 + 272 + err = rhashtable_insert_fast(&esw_chains_ht(esw), &fdb_chain->node, 273 + chain_params); 274 + if (err) 275 + goto err_insert; 276 + 277 + return fdb_chain; 278 + 279 + err_insert: 280 + kvfree(fdb_chain); 281 + return ERR_PTR(err); 282 + } 283 + 284 + static void 285 + mlx5_esw_chains_destroy_fdb_chain(struct fdb_chain *fdb_chain) 286 + { 287 + struct mlx5_eswitch *esw = fdb_chain->esw; 288 + 289 + rhashtable_remove_fast(&esw_chains_ht(esw), &fdb_chain->node, 290 + chain_params); 291 + kvfree(fdb_chain); 292 + } 293 + 294 + static struct fdb_chain * 295 + mlx5_esw_chains_get_fdb_chain(struct mlx5_eswitch *esw, u32 chain) 296 + { 297 + struct fdb_chain *fdb_chain; 298 + 299 + fdb_chain = rhashtable_lookup_fast(&esw_chains_ht(esw), &chain, 300 + chain_params); 301 + if (!fdb_chain) { 302 + fdb_chain = mlx5_esw_chains_create_fdb_chain(esw, chain); 303 + if (IS_ERR(fdb_chain)) 304 + return fdb_chain; 305 + } 306 + 307 + fdb_chain->ref++; 308 + 309 + return fdb_chain; 310 + } 311 + 312 + static struct mlx5_flow_handle * 313 + mlx5_esw_chains_add_miss_rule(struct mlx5_flow_table *fdb, 314 + struct mlx5_flow_table *next_fdb) 315 + { 316 + static const struct mlx5_flow_spec spec = {}; 317 + struct mlx5_flow_destination dest = {}; 318 + struct mlx5_flow_act act = {}; 319 + 320 + act.flags = FLOW_ACT_IGNORE_FLOW_LEVEL | FLOW_ACT_NO_APPEND; 321 + act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; 322 + dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; 323 + dest.ft = next_fdb; 324 + 325 + return mlx5_add_flow_rules(fdb, &spec, &act, &dest, 1); 326 + } 327 + 328 + static int 329 + mlx5_esw_chains_update_prio_prevs(struct fdb_prio *fdb_prio, 330 + struct mlx5_flow_table *next_fdb) 331 + { 332 + struct mlx5_flow_handle *miss_rules[FDB_TC_LEVELS_PER_PRIO + 1] = {}; 333 + struct fdb_chain *fdb_chain = fdb_prio->fdb_chain; 334 + struct fdb_prio *pos; 335 + int n = 0, err; 336 + 337 + if (fdb_prio->key.level) 338 + return 0; 339 + 340 + /* Iterate in reverse order until reaching the level 0 rule of 341 + * the previous priority, adding all the miss rules first, so we can 342 + * revert them if any of them fails. 343 + */ 344 + pos = fdb_prio; 345 + list_for_each_entry_continue_reverse(pos, 346 + &fdb_chain->prios_list, 347 + list) { 348 + miss_rules[n] = mlx5_esw_chains_add_miss_rule(pos->fdb, 349 + next_fdb); 350 + if (IS_ERR(miss_rules[n])) { 351 + err = PTR_ERR(miss_rules[n]); 352 + goto err_prev_rule; 353 + } 354 + 355 + n++; 356 + if (!pos->key.level) 357 + break; 358 + } 359 + 360 + /* Success, delete old miss rules, and update the pointers. */ 361 + n = 0; 362 + pos = fdb_prio; 363 + list_for_each_entry_continue_reverse(pos, 364 + &fdb_chain->prios_list, 365 + list) { 366 + mlx5_del_flow_rules(pos->miss_rule); 367 + 368 + pos->miss_rule = miss_rules[n]; 369 + pos->next_fdb = next_fdb; 370 + 371 + n++; 372 + if (!pos->key.level) 373 + break; 374 + } 375 + 376 + return 0; 377 + 378 + err_prev_rule: 379 + while (--n >= 0) 380 + mlx5_del_flow_rules(miss_rules[n]); 381 + 382 + return err; 383 + } 384 + 385 + static void 386 + mlx5_esw_chains_put_fdb_chain(struct fdb_chain *fdb_chain) 387 + { 388 + if (--fdb_chain->ref == 0) 389 + mlx5_esw_chains_destroy_fdb_chain(fdb_chain); 390 + } 391 + 392 + static struct fdb_prio * 393 + mlx5_esw_chains_create_fdb_prio(struct mlx5_eswitch *esw, 394 + u32 chain, u32 prio, u32 level) 395 + { 396 + int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); 397 + struct mlx5_flow_handle *miss_rule = NULL; 398 + struct mlx5_flow_group *miss_group; 399 + struct fdb_prio *fdb_prio = NULL; 400 + struct mlx5_flow_table *next_fdb; 401 + struct fdb_chain *fdb_chain; 402 + struct mlx5_flow_table *fdb; 403 + struct list_head *pos; 404 + u32 *flow_group_in; 405 + int err; 406 + 407 + fdb_chain = mlx5_esw_chains_get_fdb_chain(esw, chain); 408 + if (IS_ERR(fdb_chain)) 409 + return ERR_CAST(fdb_chain); 410 + 411 + fdb_prio = kvzalloc(sizeof(*fdb_prio), GFP_KERNEL); 412 + flow_group_in = kvzalloc(inlen, GFP_KERNEL); 413 + if (!fdb_prio || !flow_group_in) { 414 + err = -ENOMEM; 415 + goto err_alloc; 416 + } 417 + 418 + /* Chain's prio list is sorted by prio and level. 419 + * And all levels of some prio point to the next prio's level 0. 420 + * Example list (prio, level): 421 + * (3,0)->(3,1)->(5,0)->(5,1)->(6,1)->(7,0) 422 + * In hardware, we will we have the following pointers: 423 + * (3,0) -> (5,0) -> (7,0) -> Slow path 424 + * (3,1) -> (5,0) 425 + * (5,1) -> (7,0) 426 + * (6,1) -> (7,0) 427 + */ 428 + 429 + /* Default miss for each chain: */ 430 + next_fdb = (chain == mlx5_esw_chains_get_ft_chain(esw)) ? 431 + tc_slow_fdb(esw) : 432 + tc_end_fdb(esw); 433 + list_for_each(pos, &fdb_chain->prios_list) { 434 + struct fdb_prio *p = list_entry(pos, struct fdb_prio, list); 435 + 436 + /* exit on first pos that is larger */ 437 + if (prio < p->key.prio || (prio == p->key.prio && 438 + level < p->key.level)) { 439 + /* Get next level 0 table */ 440 + next_fdb = p->key.level == 0 ? p->fdb : p->next_fdb; 441 + break; 442 + } 443 + } 444 + 445 + fdb = mlx5_esw_chains_create_fdb_table(esw, chain, prio, level); 446 + if (IS_ERR(fdb)) { 447 + err = PTR_ERR(fdb); 448 + goto err_create; 449 + } 450 + 451 + MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 452 + fdb->max_fte - 2); 453 + MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 454 + fdb->max_fte - 1); 455 + miss_group = mlx5_create_flow_group(fdb, flow_group_in); 456 + if (IS_ERR(miss_group)) { 457 + err = PTR_ERR(miss_group); 458 + goto err_group; 459 + } 460 + 461 + /* Add miss rule to next_fdb */ 462 + miss_rule = mlx5_esw_chains_add_miss_rule(fdb, next_fdb); 463 + if (IS_ERR(miss_rule)) { 464 + err = PTR_ERR(miss_rule); 465 + goto err_miss_rule; 466 + } 467 + 468 + fdb_prio->miss_group = miss_group; 469 + fdb_prio->miss_rule = miss_rule; 470 + fdb_prio->next_fdb = next_fdb; 471 + fdb_prio->fdb_chain = fdb_chain; 472 + fdb_prio->key.chain = chain; 473 + fdb_prio->key.prio = prio; 474 + fdb_prio->key.level = level; 475 + fdb_prio->fdb = fdb; 476 + 477 + err = rhashtable_insert_fast(&esw_prios_ht(esw), &fdb_prio->node, 478 + prio_params); 479 + if (err) 480 + goto err_insert; 481 + 482 + list_add(&fdb_prio->list, pos->prev); 483 + 484 + /* Table is ready, connect it */ 485 + err = mlx5_esw_chains_update_prio_prevs(fdb_prio, fdb); 486 + if (err) 487 + goto err_update; 488 + 489 + kvfree(flow_group_in); 490 + return fdb_prio; 491 + 492 + err_update: 493 + list_del(&fdb_prio->list); 494 + rhashtable_remove_fast(&esw_prios_ht(esw), &fdb_prio->node, 495 + prio_params); 496 + err_insert: 497 + mlx5_del_flow_rules(miss_rule); 498 + err_miss_rule: 499 + mlx5_destroy_flow_group(miss_group); 500 + err_group: 501 + mlx5_esw_chains_destroy_fdb_table(esw, fdb); 502 + err_create: 503 + err_alloc: 504 + kvfree(fdb_prio); 505 + kvfree(flow_group_in); 506 + mlx5_esw_chains_put_fdb_chain(fdb_chain); 507 + return ERR_PTR(err); 508 + } 509 + 510 + static void 511 + mlx5_esw_chains_destroy_fdb_prio(struct mlx5_eswitch *esw, 512 + struct fdb_prio *fdb_prio) 513 + { 514 + struct fdb_chain *fdb_chain = fdb_prio->fdb_chain; 515 + 516 + WARN_ON(mlx5_esw_chains_update_prio_prevs(fdb_prio, 517 + fdb_prio->next_fdb)); 518 + 519 + list_del(&fdb_prio->list); 520 + rhashtable_remove_fast(&esw_prios_ht(esw), &fdb_prio->node, 521 + prio_params); 522 + mlx5_del_flow_rules(fdb_prio->miss_rule); 523 + mlx5_destroy_flow_group(fdb_prio->miss_group); 524 + mlx5_esw_chains_destroy_fdb_table(esw, fdb_prio->fdb); 525 + mlx5_esw_chains_put_fdb_chain(fdb_chain); 526 + kvfree(fdb_prio); 527 + } 528 + 529 + struct mlx5_flow_table * 530 + mlx5_esw_chains_get_table(struct mlx5_eswitch *esw, u32 chain, u32 prio, 531 + u32 level) 532 + { 533 + struct mlx5_flow_table *prev_fts; 534 + struct fdb_prio *fdb_prio; 535 + struct fdb_prio_key key; 536 + int l = 0; 537 + 538 + if ((chain > mlx5_esw_chains_get_chain_range(esw) && 539 + chain != mlx5_esw_chains_get_ft_chain(esw)) || 540 + prio > mlx5_esw_chains_get_prio_range(esw) || 541 + level > mlx5_esw_chains_get_level_range(esw)) 542 + return ERR_PTR(-EOPNOTSUPP); 543 + 544 + /* create earlier levels for correct fs_core lookup when 545 + * connecting tables. 546 + */ 547 + for (l = 0; l < level; l++) { 548 + prev_fts = mlx5_esw_chains_get_table(esw, chain, prio, l); 549 + if (IS_ERR(prev_fts)) { 550 + fdb_prio = ERR_CAST(prev_fts); 551 + goto err_get_prevs; 552 + } 553 + } 554 + 555 + key.chain = chain; 556 + key.prio = prio; 557 + key.level = level; 558 + 559 + mutex_lock(&esw_chains_lock(esw)); 560 + fdb_prio = rhashtable_lookup_fast(&esw_prios_ht(esw), &key, 561 + prio_params); 562 + if (!fdb_prio) { 563 + fdb_prio = mlx5_esw_chains_create_fdb_prio(esw, chain, 564 + prio, level); 565 + if (IS_ERR(fdb_prio)) 566 + goto err_create_prio; 567 + } 568 + 569 + ++fdb_prio->ref; 570 + mutex_unlock(&esw_chains_lock(esw)); 571 + 572 + return fdb_prio->fdb; 573 + 574 + err_create_prio: 575 + mutex_unlock(&esw_chains_lock(esw)); 576 + err_get_prevs: 577 + while (--l >= 0) 578 + mlx5_esw_chains_put_table(esw, chain, prio, l); 579 + return ERR_CAST(fdb_prio); 580 + } 581 + 582 + void 583 + mlx5_esw_chains_put_table(struct mlx5_eswitch *esw, u32 chain, u32 prio, 584 + u32 level) 585 + { 586 + struct fdb_prio *fdb_prio; 587 + struct fdb_prio_key key; 588 + 589 + key.chain = chain; 590 + key.prio = prio; 591 + key.level = level; 592 + 593 + mutex_lock(&esw_chains_lock(esw)); 594 + fdb_prio = rhashtable_lookup_fast(&esw_prios_ht(esw), &key, 595 + prio_params); 596 + if (!fdb_prio) 597 + goto err_get_prio; 598 + 599 + if (--fdb_prio->ref == 0) 600 + mlx5_esw_chains_destroy_fdb_prio(esw, fdb_prio); 601 + mutex_unlock(&esw_chains_lock(esw)); 602 + 603 + while (level-- > 0) 604 + mlx5_esw_chains_put_table(esw, chain, prio, level); 605 + 606 + return; 607 + 608 + err_get_prio: 609 + mutex_unlock(&esw_chains_lock(esw)); 610 + WARN_ONCE(1, 611 + "Couldn't find table: (chain: %d prio: %d level: %d)", 612 + chain, prio, level); 613 + } 614 + 615 + struct mlx5_flow_table * 616 + mlx5_esw_chains_get_tc_end_ft(struct mlx5_eswitch *esw) 617 + { 618 + return tc_end_fdb(esw); 619 + } 620 + 621 + static int 622 + mlx5_esw_chains_init(struct mlx5_eswitch *esw) 623 + { 624 + struct mlx5_esw_chains_priv *chains_priv; 625 + struct mlx5_core_dev *dev = esw->dev; 626 + u32 max_flow_counter, fdb_max; 627 + int err; 628 + 629 + chains_priv = kzalloc(sizeof(*chains_priv), GFP_KERNEL); 630 + if (!chains_priv) 631 + return -ENOMEM; 632 + esw_chains_priv(esw) = chains_priv; 633 + 634 + max_flow_counter = (MLX5_CAP_GEN(dev, max_flow_counter_31_16) << 16) | 635 + MLX5_CAP_GEN(dev, max_flow_counter_15_0); 636 + fdb_max = 1 << MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size); 637 + 638 + esw_debug(dev, 639 + "Init esw offloads chains, max counters(%d), groups(%d), max flow table size(%d)\n", 640 + max_flow_counter, ESW_OFFLOADS_NUM_GROUPS, fdb_max); 641 + 642 + mlx5_esw_chains_init_sz_pool(esw); 643 + 644 + if (!MLX5_CAP_ESW_FLOWTABLE(esw->dev, multi_fdb_encap) && 645 + esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE) { 646 + esw->fdb_table.flags &= ~ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED; 647 + esw_warn(dev, "Tc chains and priorities offload aren't supported, update firmware if needed\n"); 648 + } else { 649 + esw->fdb_table.flags |= ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED; 650 + esw_info(dev, "Supported tc offload range - chains: %u, prios: %u\n", 651 + mlx5_esw_chains_get_chain_range(esw), 652 + mlx5_esw_chains_get_prio_range(esw)); 653 + } 654 + 655 + err = rhashtable_init(&esw_chains_ht(esw), &chain_params); 656 + if (err) 657 + goto init_chains_ht_err; 658 + 659 + err = rhashtable_init(&esw_prios_ht(esw), &prio_params); 660 + if (err) 661 + goto init_prios_ht_err; 662 + 663 + mutex_init(&esw_chains_lock(esw)); 664 + 665 + return 0; 666 + 667 + init_prios_ht_err: 668 + rhashtable_destroy(&esw_chains_ht(esw)); 669 + init_chains_ht_err: 670 + kfree(chains_priv); 671 + return err; 672 + } 673 + 674 + static void 675 + mlx5_esw_chains_cleanup(struct mlx5_eswitch *esw) 676 + { 677 + mutex_destroy(&esw_chains_lock(esw)); 678 + rhashtable_destroy(&esw_prios_ht(esw)); 679 + rhashtable_destroy(&esw_chains_ht(esw)); 680 + 681 + kfree(esw_chains_priv(esw)); 682 + } 683 + 684 + static int 685 + mlx5_esw_chains_open(struct mlx5_eswitch *esw) 686 + { 687 + struct mlx5_flow_table *ft; 688 + int err; 689 + 690 + /* Create tc_end_fdb(esw) which is the always created ft chain */ 691 + ft = mlx5_esw_chains_get_table(esw, mlx5_esw_chains_get_ft_chain(esw), 692 + 1, 0); 693 + if (IS_ERR(ft)) 694 + return PTR_ERR(ft); 695 + 696 + tc_end_fdb(esw) = ft; 697 + 698 + /* Always open the root for fast path */ 699 + ft = mlx5_esw_chains_get_table(esw, 0, 1, 0); 700 + if (IS_ERR(ft)) { 701 + err = PTR_ERR(ft); 702 + goto level_0_err; 703 + } 704 + 705 + /* Open level 1 for split rules now if prios isn't supported */ 706 + if (!mlx5_esw_chains_prios_supported(esw)) { 707 + ft = mlx5_esw_chains_get_table(esw, 0, 1, 1); 708 + 709 + if (IS_ERR(ft)) { 710 + err = PTR_ERR(ft); 711 + goto level_1_err; 712 + } 713 + } 714 + 715 + return 0; 716 + 717 + level_1_err: 718 + mlx5_esw_chains_put_table(esw, 0, 1, 0); 719 + level_0_err: 720 + mlx5_esw_chains_put_table(esw, mlx5_esw_chains_get_ft_chain(esw), 1, 0); 721 + return err; 722 + } 723 + 724 + static void 725 + mlx5_esw_chains_close(struct mlx5_eswitch *esw) 726 + { 727 + if (!mlx5_esw_chains_prios_supported(esw)) 728 + mlx5_esw_chains_put_table(esw, 0, 1, 1); 729 + mlx5_esw_chains_put_table(esw, 0, 1, 0); 730 + mlx5_esw_chains_put_table(esw, mlx5_esw_chains_get_ft_chain(esw), 1, 0); 731 + } 732 + 733 + int 734 + mlx5_esw_chains_create(struct mlx5_eswitch *esw) 735 + { 736 + int err; 737 + 738 + err = mlx5_esw_chains_init(esw); 739 + if (err) 740 + return err; 741 + 742 + err = mlx5_esw_chains_open(esw); 743 + if (err) 744 + goto err_open; 745 + 746 + return 0; 747 + 748 + err_open: 749 + mlx5_esw_chains_cleanup(esw); 750 + return err; 751 + } 752 + 753 + void 754 + mlx5_esw_chains_destroy(struct mlx5_eswitch *esw) 755 + { 756 + mlx5_esw_chains_close(esw); 757 + mlx5_esw_chains_cleanup(esw); 758 + }
+30
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_chains.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ 2 + /* Copyright (c) 2020 Mellanox Technologies. */ 3 + 4 + #ifndef __ML5_ESW_CHAINS_H__ 5 + #define __ML5_ESW_CHAINS_H__ 6 + 7 + bool 8 + mlx5_esw_chains_prios_supported(struct mlx5_eswitch *esw); 9 + u32 10 + mlx5_esw_chains_get_prio_range(struct mlx5_eswitch *esw); 11 + u32 12 + mlx5_esw_chains_get_chain_range(struct mlx5_eswitch *esw); 13 + u32 14 + mlx5_esw_chains_get_ft_chain(struct mlx5_eswitch *esw); 15 + 16 + struct mlx5_flow_table * 17 + mlx5_esw_chains_get_table(struct mlx5_eswitch *esw, u32 chain, u32 prio, 18 + u32 level); 19 + void 20 + mlx5_esw_chains_put_table(struct mlx5_eswitch *esw, u32 chain, u32 prio, 21 + u32 level); 22 + 23 + struct mlx5_flow_table * 24 + mlx5_esw_chains_get_tc_end_ft(struct mlx5_eswitch *esw); 25 + 26 + int mlx5_esw_chains_create(struct mlx5_eswitch *esw); 27 + void mlx5_esw_chains_destroy(struct mlx5_eswitch *esw); 28 + 29 + #endif /* __ML5_ESW_CHAINS_H__ */ 30 +
+6 -5
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_termtbl.c
··· 50 50 struct mlx5_flow_act *flow_act) 51 51 { 52 52 static const struct mlx5_flow_spec spec = {}; 53 + struct mlx5_flow_table_attr ft_attr = {}; 53 54 struct mlx5_flow_namespace *root_ns; 54 - int prio, flags; 55 55 int err; 56 56 57 57 root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB); ··· 63 63 /* As this is the terminating action then the termination table is the 64 64 * same prio as the slow path 65 65 */ 66 - prio = FDB_SLOW_PATH; 67 - flags = MLX5_FLOW_TABLE_TERMINATION; 68 - tt->termtbl = mlx5_create_auto_grouped_flow_table(root_ns, prio, 1, 1, 69 - 0, flags); 66 + ft_attr.flags = MLX5_FLOW_TABLE_TERMINATION; 67 + ft_attr.prio = FDB_SLOW_PATH; 68 + ft_attr.max_fte = 1; 69 + ft_attr.autogroup.max_num_groups = 1; 70 + tt->termtbl = mlx5_create_auto_grouped_flow_table(root_ns, &ft_attr); 70 71 if (IS_ERR(tt->termtbl)) { 71 72 esw_warn(dev, "Failed to create termination table\n"); 72 73 return -EOPNOTSUPP;
+3
drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c
··· 432 432 MLX5_SET(set_fte_in, in, table_type, ft->type); 433 433 MLX5_SET(set_fte_in, in, table_id, ft->id); 434 434 MLX5_SET(set_fte_in, in, flow_index, fte->index); 435 + MLX5_SET(set_fte_in, in, ignore_flow_level, 436 + !!(fte->action.flags & FLOW_ACT_IGNORE_FLOW_LEVEL)); 437 + 435 438 if (ft->vport) { 436 439 MLX5_SET(set_fte_in, in, vport_number, ft->vport); 437 440 MLX5_SET(set_fte_in, in, other_vport, 1);
+62 -34
drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
··· 579 579 580 580 rhashtable_destroy(&fg->ftes_hash); 581 581 ida_destroy(&fg->fte_allocator); 582 - if (ft->autogroup.active && fg->max_ftes == ft->autogroup.group_size) 582 + if (ft->autogroup.active && 583 + fg->max_ftes == ft->autogroup.group_size && 584 + fg->start_index < ft->autogroup.max_fte) 583 585 ft->autogroup.num_groups--; 584 586 err = rhltable_remove(&ft->fgs_hash, 585 587 &fg->hash, ··· 1008 1006 u16 vport) 1009 1007 { 1010 1008 struct mlx5_flow_root_namespace *root = find_root(&ns->node); 1011 - struct mlx5_flow_table *next_ft = NULL; 1009 + bool unmanaged = ft_attr->flags & MLX5_FLOW_TABLE_UNMANAGED; 1010 + struct mlx5_flow_table *next_ft; 1012 1011 struct fs_prio *fs_prio = NULL; 1013 1012 struct mlx5_flow_table *ft; 1014 1013 int log_table_sz; ··· 1026 1023 err = -EINVAL; 1027 1024 goto unlock_root; 1028 1025 } 1029 - if (ft_attr->level >= fs_prio->num_levels) { 1030 - err = -ENOSPC; 1031 - goto unlock_root; 1026 + if (!unmanaged) { 1027 + /* The level is related to the 1028 + * priority level range. 1029 + */ 1030 + if (ft_attr->level >= fs_prio->num_levels) { 1031 + err = -ENOSPC; 1032 + goto unlock_root; 1033 + } 1034 + 1035 + ft_attr->level += fs_prio->start_level; 1032 1036 } 1037 + 1033 1038 /* The level is related to the 1034 1039 * priority level range. 1035 1040 */ 1036 - ft_attr->level += fs_prio->start_level; 1037 1041 ft = alloc_flow_table(ft_attr->level, 1038 1042 vport, 1039 1043 ft_attr->max_fte ? roundup_pow_of_two(ft_attr->max_fte) : 0, ··· 1053 1043 1054 1044 tree_init_node(&ft->node, del_hw_flow_table, del_sw_flow_table); 1055 1045 log_table_sz = ft->max_fte ? ilog2(ft->max_fte) : 0; 1056 - next_ft = find_next_chained_ft(fs_prio); 1046 + next_ft = unmanaged ? ft_attr->next_ft : 1047 + find_next_chained_ft(fs_prio); 1057 1048 ft->def_miss_action = ns->def_miss_action; 1058 1049 err = root->cmds->create_flow_table(root, ft, log_table_sz, next_ft); 1059 1050 if (err) 1060 1051 goto free_ft; 1061 1052 1062 - err = connect_flow_table(root->dev, ft, fs_prio); 1063 - if (err) 1064 - goto destroy_ft; 1053 + if (!unmanaged) { 1054 + err = connect_flow_table(root->dev, ft, fs_prio); 1055 + if (err) 1056 + goto destroy_ft; 1057 + } 1058 + 1065 1059 ft->node.active = true; 1066 1060 down_write_ref_node(&fs_prio->node, false); 1067 - tree_add_node(&ft->node, &fs_prio->node); 1068 - list_add_flow_table(ft, fs_prio); 1061 + if (!unmanaged) { 1062 + tree_add_node(&ft->node, &fs_prio->node); 1063 + list_add_flow_table(ft, fs_prio); 1064 + } else { 1065 + ft->node.root = fs_prio->node.root; 1066 + } 1069 1067 fs_prio->num_ft++; 1070 1068 up_write_ref_node(&fs_prio->node, false); 1071 1069 mutex_unlock(&root->chain_lock); ··· 1121 1103 1122 1104 struct mlx5_flow_table* 1123 1105 mlx5_create_auto_grouped_flow_table(struct mlx5_flow_namespace *ns, 1124 - int prio, 1125 - int num_flow_table_entries, 1126 - int max_num_groups, 1127 - u32 level, 1128 - u32 flags) 1106 + struct mlx5_flow_table_attr *ft_attr) 1129 1107 { 1130 - struct mlx5_flow_table_attr ft_attr = {}; 1108 + int num_reserved_entries = ft_attr->autogroup.num_reserved_entries; 1109 + int autogroups_max_fte = ft_attr->max_fte - num_reserved_entries; 1110 + int max_num_groups = ft_attr->autogroup.max_num_groups; 1131 1111 struct mlx5_flow_table *ft; 1132 1112 1133 - if (max_num_groups > num_flow_table_entries) 1113 + if (max_num_groups > autogroups_max_fte) 1114 + return ERR_PTR(-EINVAL); 1115 + if (num_reserved_entries > ft_attr->max_fte) 1134 1116 return ERR_PTR(-EINVAL); 1135 1117 1136 - ft_attr.max_fte = num_flow_table_entries; 1137 - ft_attr.prio = prio; 1138 - ft_attr.level = level; 1139 - ft_attr.flags = flags; 1140 - 1141 - ft = mlx5_create_flow_table(ns, &ft_attr); 1118 + ft = mlx5_create_flow_table(ns, ft_attr); 1142 1119 if (IS_ERR(ft)) 1143 1120 return ft; 1144 1121 1145 1122 ft->autogroup.active = true; 1146 1123 ft->autogroup.required_groups = max_num_groups; 1124 + ft->autogroup.max_fte = autogroups_max_fte; 1147 1125 /* We save place for flow groups in addition to max types */ 1148 - ft->autogroup.group_size = ft->max_fte / (max_num_groups + 1); 1126 + ft->autogroup.group_size = autogroups_max_fte / (max_num_groups + 1); 1149 1127 1150 1128 return ft; 1151 1129 } ··· 1163 1149 struct mlx5_flow_group *fg; 1164 1150 int err; 1165 1151 1166 - if (ft->autogroup.active) 1152 + if (ft->autogroup.active && start_index < ft->autogroup.max_fte) 1167 1153 return ERR_PTR(-EPERM); 1168 1154 1169 1155 down_write_ref_node(&ft->node, false); ··· 1336 1322 const struct mlx5_flow_spec *spec) 1337 1323 { 1338 1324 struct list_head *prev = &ft->node.children; 1339 - struct mlx5_flow_group *fg; 1325 + u32 max_fte = ft->autogroup.max_fte; 1340 1326 unsigned int candidate_index = 0; 1341 1327 unsigned int group_size = 0; 1328 + struct mlx5_flow_group *fg; 1342 1329 1343 1330 if (!ft->autogroup.active) 1344 1331 return ERR_PTR(-ENOENT); ··· 1347 1332 if (ft->autogroup.num_groups < ft->autogroup.required_groups) 1348 1333 group_size = ft->autogroup.group_size; 1349 1334 1350 - /* ft->max_fte == ft->autogroup.max_types */ 1335 + /* max_fte == ft->autogroup.max_types */ 1351 1336 if (group_size == 0) 1352 1337 group_size = 1; 1353 1338 ··· 1360 1345 prev = &fg->node.list; 1361 1346 } 1362 1347 1363 - if (candidate_index + group_size > ft->max_fte) 1348 + if (candidate_index + group_size > max_fte) 1364 1349 return ERR_PTR(-ENOSPC); 1365 1350 1366 1351 fg = alloc_insert_flow_group(ft, ··· 1544 1529 } 1545 1530 1546 1531 static bool dest_is_valid(struct mlx5_flow_destination *dest, 1547 - u32 action, 1532 + struct mlx5_flow_act *flow_act, 1548 1533 struct mlx5_flow_table *ft) 1549 1534 { 1535 + bool ignore_level = flow_act->flags & FLOW_ACT_IGNORE_FLOW_LEVEL; 1536 + u32 action = flow_act->action; 1537 + 1550 1538 if (dest && (dest->type == MLX5_FLOW_DESTINATION_TYPE_COUNTER)) 1551 1539 return counter_is_valid(action); 1552 1540 1553 1541 if (!(action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST)) 1554 1542 return true; 1555 1543 1544 + if (ignore_level) { 1545 + if (ft->type != FS_FT_FDB) 1546 + return false; 1547 + 1548 + if (dest->type == MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE && 1549 + dest->ft->type != FS_FT_FDB) 1550 + return false; 1551 + } 1552 + 1556 1553 if (!dest || ((dest->type == 1557 1554 MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE) && 1558 - (dest->ft->level <= ft->level))) 1555 + (dest->ft->level <= ft->level && !ignore_level))) 1559 1556 return false; 1560 1557 return true; 1561 1558 } ··· 1797 1770 return ERR_PTR(-EINVAL); 1798 1771 1799 1772 for (i = 0; i < dest_num; i++) { 1800 - if (!dest_is_valid(&dest[i], flow_act->action, ft)) 1773 + if (!dest_is_valid(&dest[i], flow_act, ft)) 1801 1774 return ERR_PTR(-EINVAL); 1802 1775 } 1803 1776 nested_down_read_ref_node(&ft->node, FS_LOCK_GRANDPARENT); ··· 2060 2033 int err = 0; 2061 2034 2062 2035 mutex_lock(&root->chain_lock); 2063 - err = disconnect_flow_table(ft); 2036 + if (!(ft->flags & MLX5_FLOW_TABLE_UNMANAGED)) 2037 + err = disconnect_flow_table(ft); 2064 2038 if (err) { 2065 2039 mutex_unlock(&root->chain_lock); 2066 2040 return err;
+1
drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
··· 164 164 unsigned int required_groups; 165 165 unsigned int group_size; 166 166 unsigned int num_groups; 167 + unsigned int max_fte; 167 168 } autogroup; 168 169 /* Protect fwd_rules */ 169 170 struct mutex lock;
+16 -6
drivers/net/ethernet/mellanox/mlx5/core/fw.c
··· 131 131 MLX5_PCAM_REGS_5000_TO_507F); 132 132 } 133 133 134 - static int mlx5_get_mcam_reg(struct mlx5_core_dev *dev) 134 + static int mlx5_get_mcam_access_reg_group(struct mlx5_core_dev *dev, 135 + enum mlx5_mcam_reg_groups group) 135 136 { 136 - return mlx5_query_mcam_reg(dev, dev->caps.mcam, 137 - MLX5_MCAM_FEATURE_ENHANCED_FEATURES, 138 - MLX5_MCAM_REGS_FIRST_128); 137 + return mlx5_query_mcam_reg(dev, dev->caps.mcam[group], 138 + MLX5_MCAM_FEATURE_ENHANCED_FEATURES, group); 139 139 } 140 140 141 141 static int mlx5_get_qcam_reg(struct mlx5_core_dev *dev) ··· 221 221 if (MLX5_CAP_GEN(dev, pcam_reg)) 222 222 mlx5_get_pcam_reg(dev); 223 223 224 - if (MLX5_CAP_GEN(dev, mcam_reg)) 225 - mlx5_get_mcam_reg(dev); 224 + if (MLX5_CAP_GEN(dev, mcam_reg)) { 225 + mlx5_get_mcam_access_reg_group(dev, MLX5_MCAM_REGS_FIRST_128); 226 + mlx5_get_mcam_access_reg_group(dev, MLX5_MCAM_REGS_0x9080_0x90FF); 227 + mlx5_get_mcam_access_reg_group(dev, MLX5_MCAM_REGS_0x9100_0x917F); 228 + } 226 229 227 230 if (MLX5_CAP_GEN(dev, qcam_reg)) 228 231 mlx5_get_qcam_reg(dev); ··· 244 241 245 242 if (MLX5_CAP_GEN(dev, tls)) { 246 243 err = mlx5_core_get_caps(dev, MLX5_CAP_TLS); 244 + if (err) 245 + return err; 246 + } 247 + 248 + if (MLX5_CAP_GEN_64(dev, general_obj_types) & 249 + MLX5_GENERAL_OBJ_TYPES_CAP_VIRTIO_NET_Q) { 250 + err = mlx5_core_get_caps(dev, MLX5_CAP_VDPA_EMULATION); 247 251 if (err) 248 252 return err; 249 253 }
+22 -1
include/linux/mlx5/device.h
··· 1105 1105 MLX5_CAP_DEV_MEM, 1106 1106 MLX5_CAP_RESERVED_16, 1107 1107 MLX5_CAP_TLS, 1108 + MLX5_CAP_VDPA_EMULATION = 0x13, 1108 1109 MLX5_CAP_DEV_EVENT = 0x14, 1109 1110 /* NUM OF CAP Types */ 1110 1111 MLX5_CAP_NUM ··· 1121 1120 1122 1121 enum mlx5_mcam_reg_groups { 1123 1122 MLX5_MCAM_REGS_FIRST_128 = 0x0, 1123 + MLX5_MCAM_REGS_0x9080_0x90FF = 0x1, 1124 + MLX5_MCAM_REGS_0x9100_0x917F = 0x2, 1125 + MLX5_MCAM_REGS_NUM = 0x3, 1124 1126 }; 1125 1127 1126 1128 enum mlx5_mcam_feature_groups { ··· 1272 1268 MLX5_GET(pcam_reg, (mdev)->caps.pcam, port_access_reg_cap_mask.regs_5000_to_507f.reg) 1273 1269 1274 1270 #define MLX5_CAP_MCAM_REG(mdev, reg) \ 1275 - MLX5_GET(mcam_reg, (mdev)->caps.mcam, mng_access_reg_cap_mask.access_regs.reg) 1271 + MLX5_GET(mcam_reg, (mdev)->caps.mcam[MLX5_MCAM_REGS_FIRST_128], \ 1272 + mng_access_reg_cap_mask.access_regs.reg) 1273 + 1274 + #define MLX5_CAP_MCAM_REG1(mdev, reg) \ 1275 + MLX5_GET(mcam_reg, (mdev)->caps.mcam[MLX5_MCAM_REGS_0x9080_0x90FF], \ 1276 + mng_access_reg_cap_mask.access_regs1.reg) 1277 + 1278 + #define MLX5_CAP_MCAM_REG2(mdev, reg) \ 1279 + MLX5_GET(mcam_reg, (mdev)->caps.mcam[MLX5_MCAM_REGS_0x9100_0x917F], \ 1280 + mng_access_reg_cap_mask.access_regs2.reg) 1276 1281 1277 1282 #define MLX5_CAP_MCAM_FEATURE(mdev, fld) \ 1278 1283 MLX5_GET(mcam_reg, (mdev)->caps.mcam, mng_feature_cap_mask.enhanced_features.fld) ··· 1309 1296 1310 1297 #define MLX5_CAP_DEV_EVENT(mdev, cap)\ 1311 1298 MLX5_ADDR_OF(device_event_cap, (mdev)->caps.hca_cur[MLX5_CAP_DEV_EVENT], cap) 1299 + 1300 + #define MLX5_CAP_DEV_VDPA_EMULATION(mdev, cap)\ 1301 + MLX5_GET(device_virtio_emulation_cap, \ 1302 + (mdev)->caps.hca_cur[MLX5_CAP_VDPA_EMULATION], cap) 1303 + 1304 + #define MLX5_CAP64_DEV_VDPA_EMULATION(mdev, cap)\ 1305 + MLX5_GET64(device_virtio_emulation_cap, \ 1306 + (mdev)->caps.hca_cur[MLX5_CAP_VDPA_EMULATION], cap) 1312 1307 1313 1308 enum { 1314 1309 MLX5_CMD_STAT_OK = 0x0,
+3 -1
include/linux/mlx5/driver.h
··· 145 145 MLX5_REG_MCC = 0x9062, 146 146 MLX5_REG_MCDA = 0x9063, 147 147 MLX5_REG_MCAM = 0x907f, 148 + MLX5_REG_MIRC = 0x9162, 149 + MLX5_REG_RESOURCE_DUMP = 0xC000, 148 150 }; 149 151 150 152 enum mlx5_qpts_trust_state { ··· 686 684 u32 hca_cur[MLX5_CAP_NUM][MLX5_UN_SZ_DW(hca_cap_union)]; 687 685 u32 hca_max[MLX5_CAP_NUM][MLX5_UN_SZ_DW(hca_cap_union)]; 688 686 u32 pcam[MLX5_ST_SZ_DW(pcam_reg)]; 689 - u32 mcam[MLX5_ST_SZ_DW(mcam_reg)]; 687 + u32 mcam[MLX5_MCAM_REGS_NUM][MLX5_ST_SZ_DW(mcam_reg)]; 690 688 u32 fpga[MLX5_ST_SZ_DW(fpga_cap)]; 691 689 u32 qcam[MLX5_ST_SZ_DW(qcam_reg)]; 692 690 u8 embedded_cpu;
+12 -8
include/linux/mlx5/fs.h
··· 48 48 MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT = BIT(0), 49 49 MLX5_FLOW_TABLE_TUNNEL_EN_DECAP = BIT(1), 50 50 MLX5_FLOW_TABLE_TERMINATION = BIT(2), 51 + MLX5_FLOW_TABLE_UNMANAGED = BIT(3), 51 52 }; 52 53 53 54 #define LEFTOVERS_RULE_NUM 2 ··· 146 145 enum mlx5_flow_namespace_type type, 147 146 int vport); 148 147 149 - struct mlx5_flow_table * 150 - mlx5_create_auto_grouped_flow_table(struct mlx5_flow_namespace *ns, 151 - int prio, 152 - int num_flow_table_entries, 153 - int max_num_groups, 154 - u32 level, 155 - u32 flags); 156 - 157 148 struct mlx5_flow_table_attr { 158 149 int prio; 159 150 int max_fte; 160 151 u32 level; 161 152 u32 flags; 153 + struct mlx5_flow_table *next_ft; 154 + 155 + struct { 156 + int max_num_groups; 157 + int num_reserved_entries; 158 + } autogroup; 162 159 }; 163 160 164 161 struct mlx5_flow_table * 165 162 mlx5_create_flow_table(struct mlx5_flow_namespace *ns, 166 163 struct mlx5_flow_table_attr *ft_attr); 164 + 165 + struct mlx5_flow_table * 166 + mlx5_create_auto_grouped_flow_table(struct mlx5_flow_namespace *ns, 167 + struct mlx5_flow_table_attr *ft_attr); 167 168 168 169 struct mlx5_flow_table * 169 170 mlx5_create_vport_flow_table(struct mlx5_flow_namespace *ns, ··· 197 194 198 195 enum { 199 196 FLOW_ACT_NO_APPEND = BIT(0), 197 + FLOW_ACT_IGNORE_FLOW_LEVEL = BIT(1), 200 198 }; 201 199 202 200 struct mlx5_flow_act {
+230 -7
include/linux/mlx5/mlx5_ifc.h
··· 87 87 enum { 88 88 MLX5_GENERAL_OBJ_TYPES_CAP_SW_ICM = (1ULL << MLX5_OBJ_TYPE_SW_ICM), 89 89 MLX5_GENERAL_OBJ_TYPES_CAP_GENEVE_TLV_OPT = (1ULL << 11), 90 + MLX5_GENERAL_OBJ_TYPES_CAP_VIRTIO_NET_Q = (1ULL << 13), 90 91 }; 91 92 92 93 enum { ··· 375 374 u8 outer_esp_spi[0x1]; 376 375 u8 reserved_at_58[0x2]; 377 376 u8 bth_dst_qp[0x1]; 377 + u8 reserved_at_5b[0x5]; 378 378 379 - u8 reserved_at_5b[0x25]; 379 + u8 reserved_at_60[0x18]; 380 + u8 metadata_reg_c_7[0x1]; 381 + u8 metadata_reg_c_6[0x1]; 382 + u8 metadata_reg_c_5[0x1]; 383 + u8 metadata_reg_c_4[0x1]; 384 + u8 metadata_reg_c_3[0x1]; 385 + u8 metadata_reg_c_2[0x1]; 386 + u8 metadata_reg_c_1[0x1]; 387 + u8 metadata_reg_c_0[0x1]; 380 388 }; 381 389 382 390 struct mlx5_ifc_flow_table_prop_layout_bits { ··· 410 400 u8 reformat_l3_tunnel_to_l2[0x1]; 411 401 u8 reformat_l2_to_l3_tunnel[0x1]; 412 402 u8 reformat_and_modify_action[0x1]; 413 - u8 reserved_at_15[0x2]; 403 + u8 ignore_flow_level[0x1]; 404 + u8 reserved_at_16[0x1]; 414 405 u8 table_miss_action_domain[0x1]; 415 406 u8 termination_table[0x1]; 416 407 u8 reserved_at_19[0x7]; ··· 732 721 733 722 struct mlx5_ifc_flow_table_eswitch_cap_bits { 734 723 u8 fdb_to_vport_reg_c_id[0x8]; 735 - u8 reserved_at_8[0xf]; 724 + u8 reserved_at_8[0xd]; 725 + u8 fdb_modify_header_fwd_to_table[0x1]; 726 + u8 reserved_at_16[0x1]; 736 727 u8 flow_source[0x1]; 737 728 u8 reserved_at_18[0x2]; 738 729 u8 multi_fdb_encap[0x1]; ··· 835 822 struct mlx5_ifc_debug_cap_bits { 836 823 u8 core_dump_general[0x1]; 837 824 u8 core_dump_qp[0x1]; 838 - u8 reserved_at_2[0x1e]; 825 + u8 reserved_at_2[0x7]; 826 + u8 resource_dump[0x1]; 827 + u8 reserved_at_a[0x16]; 839 828 840 829 u8 reserved_at_20[0x2]; 841 830 u8 stall_detect[0x1]; ··· 966 951 u8 user_affiliated_events[4][0x40]; 967 952 968 953 u8 user_unaffiliated_events[4][0x40]; 954 + }; 955 + 956 + struct mlx5_ifc_device_virtio_emulation_cap_bits { 957 + u8 reserved_at_0[0x20]; 958 + 959 + u8 reserved_at_20[0x13]; 960 + u8 log_doorbell_stride[0x5]; 961 + u8 reserved_at_38[0x3]; 962 + u8 log_doorbell_bar_size[0x5]; 963 + 964 + u8 doorbell_bar_offset[0x40]; 965 + 966 + u8 reserved_at_80[0x780]; 969 967 }; 970 968 971 969 enum { ··· 1781 1753 u8 resize_field_select[0x20]; 1782 1754 }; 1783 1755 1756 + struct mlx5_ifc_resource_dump_bits { 1757 + u8 more_dump[0x1]; 1758 + u8 inline_dump[0x1]; 1759 + u8 reserved_at_2[0xa]; 1760 + u8 seq_num[0x4]; 1761 + u8 segment_type[0x10]; 1762 + 1763 + u8 reserved_at_20[0x10]; 1764 + u8 vhca_id[0x10]; 1765 + 1766 + u8 index1[0x20]; 1767 + 1768 + u8 index2[0x20]; 1769 + 1770 + u8 num_of_obj1[0x10]; 1771 + u8 num_of_obj2[0x10]; 1772 + 1773 + u8 reserved_at_a0[0x20]; 1774 + 1775 + u8 device_opaque[0x40]; 1776 + 1777 + u8 mkey[0x20]; 1778 + 1779 + u8 size[0x20]; 1780 + 1781 + u8 address[0x40]; 1782 + 1783 + u8 inline_data[52][0x20]; 1784 + }; 1785 + 1786 + struct mlx5_ifc_resource_dump_menu_record_bits { 1787 + u8 reserved_at_0[0x4]; 1788 + u8 num_of_obj2_supports_active[0x1]; 1789 + u8 num_of_obj2_supports_all[0x1]; 1790 + u8 must_have_num_of_obj2[0x1]; 1791 + u8 support_num_of_obj2[0x1]; 1792 + u8 num_of_obj1_supports_active[0x1]; 1793 + u8 num_of_obj1_supports_all[0x1]; 1794 + u8 must_have_num_of_obj1[0x1]; 1795 + u8 support_num_of_obj1[0x1]; 1796 + u8 must_have_index2[0x1]; 1797 + u8 support_index2[0x1]; 1798 + u8 must_have_index1[0x1]; 1799 + u8 support_index1[0x1]; 1800 + u8 segment_type[0x10]; 1801 + 1802 + u8 segment_name[4][0x20]; 1803 + 1804 + u8 index1_name[4][0x20]; 1805 + 1806 + u8 index2_name[4][0x20]; 1807 + }; 1808 + 1809 + struct mlx5_ifc_resource_dump_segment_header_bits { 1810 + u8 length_dw[0x10]; 1811 + u8 segment_type[0x10]; 1812 + }; 1813 + 1814 + struct mlx5_ifc_resource_dump_command_segment_bits { 1815 + struct mlx5_ifc_resource_dump_segment_header_bits segment_header; 1816 + 1817 + u8 segment_called[0x10]; 1818 + u8 vhca_id[0x10]; 1819 + 1820 + u8 index1[0x20]; 1821 + 1822 + u8 index2[0x20]; 1823 + 1824 + u8 num_of_obj1[0x10]; 1825 + u8 num_of_obj2[0x10]; 1826 + }; 1827 + 1828 + struct mlx5_ifc_resource_dump_error_segment_bits { 1829 + struct mlx5_ifc_resource_dump_segment_header_bits segment_header; 1830 + 1831 + u8 reserved_at_20[0x10]; 1832 + u8 syndrome_id[0x10]; 1833 + 1834 + u8 reserved_at_40[0x40]; 1835 + 1836 + u8 error[8][0x20]; 1837 + }; 1838 + 1839 + struct mlx5_ifc_resource_dump_info_segment_bits { 1840 + struct mlx5_ifc_resource_dump_segment_header_bits segment_header; 1841 + 1842 + u8 reserved_at_20[0x18]; 1843 + u8 dump_version[0x8]; 1844 + 1845 + u8 hw_version[0x20]; 1846 + 1847 + u8 fw_version[0x20]; 1848 + }; 1849 + 1850 + struct mlx5_ifc_resource_dump_menu_segment_bits { 1851 + struct mlx5_ifc_resource_dump_segment_header_bits segment_header; 1852 + 1853 + u8 reserved_at_20[0x10]; 1854 + u8 num_of_records[0x10]; 1855 + 1856 + struct mlx5_ifc_resource_dump_menu_record_bits record[0]; 1857 + }; 1858 + 1859 + struct mlx5_ifc_resource_dump_resource_segment_bits { 1860 + struct mlx5_ifc_resource_dump_segment_header_bits segment_header; 1861 + 1862 + u8 reserved_at_20[0x20]; 1863 + 1864 + u8 index1[0x20]; 1865 + 1866 + u8 index2[0x20]; 1867 + 1868 + u8 payload[0][0x20]; 1869 + }; 1870 + 1871 + struct mlx5_ifc_resource_dump_terminate_segment_bits { 1872 + struct mlx5_ifc_resource_dump_segment_header_bits segment_header; 1873 + }; 1874 + 1875 + struct mlx5_ifc_menu_resource_dump_response_bits { 1876 + struct mlx5_ifc_resource_dump_info_segment_bits info; 1877 + struct mlx5_ifc_resource_dump_command_segment_bits cmd; 1878 + struct mlx5_ifc_resource_dump_menu_segment_bits menu; 1879 + struct mlx5_ifc_resource_dump_terminate_segment_bits terminate; 1880 + }; 1881 + 1784 1882 enum { 1785 1883 MLX5_MODIFY_FIELD_SELECT_MODIFY_FIELD_SELECT_CQ_PERIOD = 0x1, 1786 1884 MLX5_MODIFY_FIELD_SELECT_MODIFY_FIELD_SELECT_CQ_MAX_COUNT = 0x2, ··· 2180 2026 2181 2027 u8 rx_pause_transition_low[0x20]; 2182 2028 2183 - u8 reserved_at_3c0[0x40]; 2029 + u8 rx_discards_high[0x20]; 2030 + 2031 + u8 rx_discards_low[0x20]; 2184 2032 2185 2033 u8 device_stall_minor_watermark_cnt_high[0x20]; 2186 2034 ··· 2907 2751 struct mlx5_ifc_fpga_cap_bits fpga_cap; 2908 2752 struct mlx5_ifc_tls_cap_bits tls_cap; 2909 2753 struct mlx5_ifc_device_mem_cap_bits device_mem_cap; 2754 + struct mlx5_ifc_device_virtio_emulation_cap_bits virtio_emulation_cap; 2910 2755 u8 reserved_at_0[0x8000]; 2911 2756 }; 2912 2757 ··· 4155 3998 u8 reserved_at_a0[0x8]; 4156 3999 u8 table_id[0x18]; 4157 4000 4158 - u8 reserved_at_c0[0x18]; 4001 + u8 ignore_flow_level[0x1]; 4002 + u8 reserved_at_c1[0x17]; 4159 4003 u8 modify_enable_mask[0x8]; 4160 4004 4161 4005 u8 reserved_at_e0[0x20]; ··· 5624 5466 u8 data[0x20]; 5625 5467 }; 5626 5468 5469 + struct mlx5_ifc_copy_action_in_bits { 5470 + u8 action_type[0x4]; 5471 + u8 src_field[0xc]; 5472 + u8 reserved_at_10[0x3]; 5473 + u8 src_offset[0x5]; 5474 + u8 reserved_at_18[0x3]; 5475 + u8 length[0x5]; 5476 + 5477 + u8 reserved_at_20[0x4]; 5478 + u8 dst_field[0xc]; 5479 + u8 reserved_at_30[0x3]; 5480 + u8 dst_offset[0x5]; 5481 + u8 reserved_at_38[0x8]; 5482 + }; 5483 + 5627 5484 union mlx5_ifc_set_action_in_add_action_in_auto_bits { 5628 5485 struct mlx5_ifc_set_action_in_bits set_action_in; 5629 5486 struct mlx5_ifc_add_action_in_bits add_action_in; 5487 + struct mlx5_ifc_copy_action_in_bits copy_action_in; 5630 5488 u8 reserved_at_0[0x40]; 5631 5489 }; 5632 5490 5633 5491 enum { 5634 5492 MLX5_ACTION_TYPE_SET = 0x1, 5635 5493 MLX5_ACTION_TYPE_ADD = 0x2, 5494 + MLX5_ACTION_TYPE_COPY = 0x3, 5636 5495 }; 5637 5496 5638 5497 enum { ··· 5685 5510 MLX5_ACTION_IN_FIELD_METADATA_REG_C_3 = 0x54, 5686 5511 MLX5_ACTION_IN_FIELD_METADATA_REG_C_4 = 0x55, 5687 5512 MLX5_ACTION_IN_FIELD_METADATA_REG_C_5 = 0x56, 5513 + MLX5_ACTION_IN_FIELD_METADATA_REG_C_6 = 0x57, 5514 + MLX5_ACTION_IN_FIELD_METADATA_REG_C_7 = 0x58, 5688 5515 MLX5_ACTION_IN_FIELD_OUT_TCP_SEQ_NUM = 0x59, 5689 5516 MLX5_ACTION_IN_FIELD_OUT_TCP_ACK_NUM = 0x5B, 5690 5517 }; ··· 8583 8406 u8 fec_override_admin_50g[0x4]; 8584 8407 u8 fec_override_admin_25g[0x4]; 8585 8408 u8 fec_override_admin_10g_40g[0x4]; 8409 + 8410 + u8 fec_override_cap_400g_8x[0x10]; 8411 + u8 fec_override_cap_200g_4x[0x10]; 8412 + 8413 + u8 fec_override_cap_100g_2x[0x10]; 8414 + u8 fec_override_cap_50g_1x[0x10]; 8415 + 8416 + u8 fec_override_admin_400g_8x[0x10]; 8417 + u8 fec_override_admin_200g_4x[0x10]; 8418 + 8419 + u8 fec_override_admin_100g_2x[0x10]; 8420 + u8 fec_override_admin_50g_1x[0x10]; 8586 8421 }; 8587 8422 8588 8423 struct mlx5_ifc_ppcnt_reg_bits { ··· 8921 8732 }; 8922 8733 8923 8734 struct mlx5_ifc_pcam_enhanced_features_bits { 8924 - u8 reserved_at_0[0x6d]; 8735 + u8 reserved_at_0[0x68]; 8736 + u8 fec_50G_per_lane_in_pplm[0x1]; 8737 + u8 reserved_at_69[0x4]; 8925 8738 u8 rx_icrc_encapsulated_counter[0x1]; 8926 8739 u8 reserved_at_6e[0x4]; 8927 8740 u8 ptys_extended_ethernet[0x1]; ··· 9008 8817 u8 regs_31_to_0[0x20]; 9009 8818 }; 9010 8819 8820 + struct mlx5_ifc_mcam_access_reg_bits1 { 8821 + u8 regs_127_to_96[0x20]; 8822 + 8823 + u8 regs_95_to_64[0x20]; 8824 + 8825 + u8 regs_63_to_32[0x20]; 8826 + 8827 + u8 regs_31_to_0[0x20]; 8828 + }; 8829 + 8830 + struct mlx5_ifc_mcam_access_reg_bits2 { 8831 + u8 regs_127_to_99[0x1d]; 8832 + u8 mirc[0x1]; 8833 + u8 regs_97_to_96[0x2]; 8834 + 8835 + u8 regs_95_to_64[0x20]; 8836 + 8837 + u8 regs_63_to_32[0x20]; 8838 + 8839 + u8 regs_31_to_0[0x20]; 8840 + }; 8841 + 9011 8842 struct mlx5_ifc_mcam_reg_bits { 9012 8843 u8 reserved_at_0[0x8]; 9013 8844 u8 feature_group[0x8]; ··· 9040 8827 9041 8828 union { 9042 8829 struct mlx5_ifc_mcam_access_reg_bits access_regs; 8830 + struct mlx5_ifc_mcam_access_reg_bits1 access_regs1; 8831 + struct mlx5_ifc_mcam_access_reg_bits2 access_regs2; 9043 8832 u8 reserved_at_0[0x80]; 9044 8833 } mng_access_reg_cap_mask; 9045 8834 ··· 9647 9432 u8 data[0][0x20]; 9648 9433 }; 9649 9434 9435 + struct mlx5_ifc_mirc_reg_bits { 9436 + u8 reserved_at_0[0x18]; 9437 + u8 status_code[0x8]; 9438 + 9439 + u8 reserved_at_20[0x20]; 9440 + }; 9441 + 9650 9442 union mlx5_ifc_ports_control_registers_document_bits { 9651 9443 struct mlx5_ifc_bufferx_reg_bits bufferx_reg; 9652 9444 struct mlx5_ifc_eth_2819_cntrs_grp_data_layout_bits eth_2819_cntrs_grp_data_layout; ··· 9709 9487 struct mlx5_ifc_mcqi_reg_bits mcqi_reg; 9710 9488 struct mlx5_ifc_mcc_reg_bits mcc_reg; 9711 9489 struct mlx5_ifc_mcda_reg_bits mcda_reg; 9490 + struct mlx5_ifc_mirc_reg_bits mirc_reg; 9712 9491 u8 reserved_at_0[0x60e0]; 9713 9492 }; 9714 9493