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

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'e-switch-vport-sharing-delegation'

Saeed Mahameed says:

====================
E-Switch vport sharing & delegation

An mlx5 E-Switch FDB table can manage vports belonging to other sibling
physical functions, such as ECPF (ARM embedded cores) and Host PF (x86).
This enables a single source of truth for SDN software to manage network
pipelines from one host. While such functionality already exists in mlx5,
it is currently limited by static vport allocation,
meaning the number of vports shared between multi-host functions
must be known pre-boot.

This patchset enables delegated/external vports to be discovered
dynamically when switchdev mode is enabled, leveraging new firmware
capabilities for dynamic vport creation.

Adjacent functions that delegate their SR-IOV VFs to sibling PFs, can be
dynamically discovered on the sibling PF's switchdev mode enabling,
after sriov was enabled on the originating PF, allowing for more
flexible and scalable management in multi-host and ECPF-to-host
scenarios.

The patchset consists of the following changes:

- Refactoring of ACL root namespace handling: The storage of vport ACL root
namespaces is converted from a linear array to an xarray, allowing dynamic
creation of ACLs per individual vport.
- Improvements for vhca_id to vport mapping.
- Dynamic querying and creation of delegated functions/vports.
====================

Link: https://patch.msgid.link/20250829223722.900629-1-saeed@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

+510 -186
+1 -1
drivers/net/ethernet/mellanox/mlx5/core/Makefile
··· 69 69 # Core extra 70 70 # 71 71 mlx5_core-$(CONFIG_MLX5_ESWITCH) += eswitch.o eswitch_offloads.o eswitch_offloads_termtbl.o \ 72 - ecpf.o rdma.o esw/legacy.o \ 72 + ecpf.o rdma.o esw/legacy.o esw/adj_vport.o \ 73 73 esw/devlink_port.o esw/vporttbl.o esw/qos.o esw/ipsec.o 74 74 75 75 mlx5_core-$(CONFIG_MLX5_ESWITCH) += esw/acl/helper.o \
+209
drivers/net/ethernet/mellanox/mlx5/core/esw/adj_vport.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 + // Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 + 4 + #include "fs_core.h" 5 + #include "eswitch.h" 6 + 7 + enum { 8 + MLX5_ADJ_VPORT_DISCONNECT = 0x0, 9 + MLX5_ADJ_VPORT_CONNECT = 0x1, 10 + }; 11 + 12 + static int mlx5_esw_adj_vport_modify(struct mlx5_core_dev *dev, 13 + u16 vport, bool connect) 14 + { 15 + u32 in[MLX5_ST_SZ_DW(modify_vport_state_in)] = {}; 16 + 17 + MLX5_SET(modify_vport_state_in, in, opcode, 18 + MLX5_CMD_OP_MODIFY_VPORT_STATE); 19 + MLX5_SET(modify_vport_state_in, in, op_mod, 20 + MLX5_VPORT_STATE_OP_MOD_ESW_VPORT); 21 + MLX5_SET(modify_vport_state_in, in, other_vport, 1); 22 + MLX5_SET(modify_vport_state_in, in, vport_number, vport); 23 + MLX5_SET(modify_vport_state_in, in, ingress_connect_valid, 1); 24 + MLX5_SET(modify_vport_state_in, in, egress_connect_valid, 1); 25 + MLX5_SET(modify_vport_state_in, in, ingress_connect, connect); 26 + MLX5_SET(modify_vport_state_in, in, egress_connect, connect); 27 + 28 + return mlx5_cmd_exec_in(dev, modify_vport_state, in); 29 + } 30 + 31 + static void mlx5_esw_destroy_esw_vport(struct mlx5_core_dev *dev, u16 vport) 32 + { 33 + u32 in[MLX5_ST_SZ_DW(destroy_esw_vport_in)] = {}; 34 + 35 + MLX5_SET(destroy_esw_vport_in, in, opcode, 36 + MLX5_CMD_OPCODE_DESTROY_ESW_VPORT); 37 + MLX5_SET(destroy_esw_vport_in, in, vport_num, vport); 38 + 39 + mlx5_cmd_exec_in(dev, destroy_esw_vport, in); 40 + } 41 + 42 + static int mlx5_esw_create_esw_vport(struct mlx5_core_dev *dev, u16 vhca_id, 43 + u16 *vport_num) 44 + { 45 + u32 out[MLX5_ST_SZ_DW(create_esw_vport_out)] = {}; 46 + u32 in[MLX5_ST_SZ_DW(create_esw_vport_in)] = {}; 47 + int err; 48 + 49 + MLX5_SET(create_esw_vport_in, in, opcode, 50 + MLX5_CMD_OPCODE_CREATE_ESW_VPORT); 51 + MLX5_SET(create_esw_vport_in, in, managed_vhca_id, vhca_id); 52 + 53 + err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 54 + if (!err) 55 + *vport_num = MLX5_GET(create_esw_vport_out, out, vport_num); 56 + 57 + return err; 58 + } 59 + 60 + static int mlx5_esw_adj_vport_create(struct mlx5_eswitch *esw, u16 vhca_id, 61 + const void *rid_info_reg) 62 + { 63 + struct mlx5_vport *vport; 64 + u16 vport_num; 65 + int err; 66 + 67 + err = mlx5_esw_create_esw_vport(esw->dev, vhca_id, &vport_num); 68 + if (err) { 69 + esw_warn(esw->dev, 70 + "Failed to create adjacent vport for vhca_id %d, err %d\n", 71 + vhca_id, err); 72 + return err; 73 + } 74 + 75 + esw_debug(esw->dev, "Created adjacent vport[%d] %d for vhca_id 0x%x\n", 76 + esw->last_vport_idx, vport_num, vhca_id); 77 + 78 + err = mlx5_esw_vport_alloc(esw, esw->last_vport_idx++, vport_num); 79 + if (err) 80 + goto destroy_esw_vport; 81 + 82 + xa_set_mark(&esw->vports, vport_num, MLX5_ESW_VPT_VF); 83 + vport = mlx5_eswitch_get_vport(esw, vport_num); 84 + vport->adjacent = true; 85 + vport->vhca_id = vhca_id; 86 + 87 + vport->adj_info.parent_pci_devfn = 88 + MLX5_GET(function_vhca_rid_info_reg, rid_info_reg, 89 + parent_pci_device_function); 90 + vport->adj_info.function_id = 91 + MLX5_GET(function_vhca_rid_info_reg, rid_info_reg, function_id); 92 + 93 + mlx5_fs_vport_egress_acl_ns_add(esw->dev->priv.steering, vport->index); 94 + mlx5_fs_vport_ingress_acl_ns_add(esw->dev->priv.steering, vport->index); 95 + err = mlx5_esw_offloads_rep_add(esw, vport); 96 + if (err) 97 + goto acl_ns_remove; 98 + 99 + mlx5_esw_adj_vport_modify(esw->dev, vport_num, MLX5_ADJ_VPORT_CONNECT); 100 + return 0; 101 + 102 + acl_ns_remove: 103 + mlx5_fs_vport_ingress_acl_ns_remove(esw->dev->priv.steering, 104 + vport->index); 105 + mlx5_fs_vport_egress_acl_ns_remove(esw->dev->priv.steering, 106 + vport->index); 107 + mlx5_esw_vport_free(esw, vport); 108 + destroy_esw_vport: 109 + mlx5_esw_destroy_esw_vport(esw->dev, vport_num); 110 + return err; 111 + } 112 + 113 + static void mlx5_esw_adj_vport_destroy(struct mlx5_eswitch *esw, 114 + struct mlx5_vport *vport) 115 + { 116 + u16 vport_num = vport->vport; 117 + 118 + esw_debug(esw->dev, "Destroying adjacent vport %d for vhca_id 0x%x\n", 119 + vport_num, vport->vhca_id); 120 + mlx5_esw_adj_vport_modify(esw->dev, vport_num, 121 + MLX5_ADJ_VPORT_DISCONNECT); 122 + mlx5_esw_offloads_rep_remove(esw, vport); 123 + mlx5_fs_vport_egress_acl_ns_remove(esw->dev->priv.steering, 124 + vport->index); 125 + mlx5_fs_vport_ingress_acl_ns_remove(esw->dev->priv.steering, 126 + vport->index); 127 + mlx5_esw_vport_free(esw, vport); 128 + /* Reset the vport index back so new adj vports can use this index. 129 + * When vport count can incrementally change, this needs to be modified. 130 + */ 131 + esw->last_vport_idx--; 132 + mlx5_esw_destroy_esw_vport(esw->dev, vport_num); 133 + } 134 + 135 + void mlx5_esw_adjacent_vhcas_cleanup(struct mlx5_eswitch *esw) 136 + { 137 + struct mlx5_vport *vport; 138 + unsigned long i; 139 + 140 + if (!MLX5_CAP_GEN_2(esw->dev, delegated_vhca_max)) 141 + return; 142 + 143 + mlx5_esw_for_each_vf_vport(esw, i, vport, U16_MAX) { 144 + if (!vport->adjacent) 145 + continue; 146 + mlx5_esw_adj_vport_destroy(esw, vport); 147 + } 148 + } 149 + 150 + void mlx5_esw_adjacent_vhcas_setup(struct mlx5_eswitch *esw) 151 + { 152 + u32 delegated_vhca_max = MLX5_CAP_GEN_2(esw->dev, delegated_vhca_max); 153 + u32 in[MLX5_ST_SZ_DW(query_delegated_vhca_in)] = {}; 154 + int outlen, err, i = 0; 155 + u8 *out; 156 + u32 count; 157 + 158 + if (!delegated_vhca_max) 159 + return; 160 + 161 + outlen = MLX5_ST_SZ_BYTES(query_delegated_vhca_out) + 162 + delegated_vhca_max * 163 + MLX5_ST_SZ_BYTES(delegated_function_vhca_rid_info); 164 + 165 + esw_debug(esw->dev, "delegated_vhca_max=%d\n", delegated_vhca_max); 166 + 167 + out = kvzalloc(outlen, GFP_KERNEL); 168 + if (!out) 169 + return; 170 + 171 + MLX5_SET(query_delegated_vhca_in, in, opcode, 172 + MLX5_CMD_OPCODE_QUERY_DELEGATED_VHCA); 173 + 174 + err = mlx5_cmd_exec(esw->dev, in, sizeof(in), out, outlen); 175 + if (err) { 176 + kvfree(out); 177 + esw_warn(esw->dev, "Failed to query delegated vhca, err %d\n", 178 + err); 179 + return; 180 + } 181 + 182 + count = MLX5_GET(query_delegated_vhca_out, out, functions_count); 183 + esw_debug(esw->dev, "Delegated vhca functions count %d\n", count); 184 + 185 + for (i = 0; i < count; i++) { 186 + const void *rid_info, *rid_info_reg; 187 + u16 vhca_id; 188 + 189 + rid_info = MLX5_ADDR_OF(query_delegated_vhca_out, out, 190 + delegated_function_vhca_rid_info[i]); 191 + 192 + rid_info_reg = MLX5_ADDR_OF(delegated_function_vhca_rid_info, 193 + rid_info, function_vhca_rid_info); 194 + 195 + vhca_id = MLX5_GET(function_vhca_rid_info_reg, rid_info_reg, 196 + vhca_id); 197 + esw_debug(esw->dev, "Delegating vhca_id 0x%x\n", vhca_id); 198 + 199 + err = mlx5_esw_adj_vport_create(esw, vhca_id, rid_info_reg); 200 + if (err) { 201 + esw_warn(esw->dev, 202 + "Failed to init adjacent vhca 0x%x, err %d\n", 203 + vhca_id, err); 204 + break; 205 + } 206 + } 207 + 208 + kvfree(out); 209 + }
+119 -12
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
··· 1217 1217 unsigned long i; 1218 1218 1219 1219 mlx5_esw_for_each_vf_vport(esw, i, vport, num_vfs) { 1220 - if (!vport->enabled) 1220 + /* Adjacent VFs are unloaded separately */ 1221 + if (!vport->enabled || vport->adjacent) 1221 1222 continue; 1222 1223 mlx5_eswitch_unload_pf_vf_vport(esw, vport->vport); 1223 1224 } ··· 1235 1234 continue; 1236 1235 mlx5_eswitch_unload_pf_vf_vport(esw, vport->vport); 1237 1236 } 1237 + } 1238 + 1239 + static void mlx5_eswitch_unload_adj_vf_vports(struct mlx5_eswitch *esw) 1240 + { 1241 + struct mlx5_vport *vport; 1242 + unsigned long i; 1243 + 1244 + mlx5_esw_for_each_vf_vport(esw, i, vport, U16_MAX) { 1245 + if (!vport->enabled || !vport->adjacent) 1246 + continue; 1247 + mlx5_eswitch_unload_pf_vf_vport(esw, vport->vport); 1248 + } 1249 + } 1250 + 1251 + static int 1252 + mlx5_eswitch_load_adj_vf_vports(struct mlx5_eswitch *esw, 1253 + enum mlx5_eswitch_vport_event enabled_events) 1254 + { 1255 + struct mlx5_vport *vport; 1256 + unsigned long i; 1257 + int err; 1258 + 1259 + mlx5_esw_for_each_vf_vport(esw, i, vport, U16_MAX) { 1260 + if (!vport->adjacent) 1261 + continue; 1262 + err = mlx5_eswitch_load_pf_vf_vport(esw, vport->vport, 1263 + enabled_events); 1264 + if (err) 1265 + goto unload_adj_vf_vport; 1266 + } 1267 + 1268 + return 0; 1269 + 1270 + unload_adj_vf_vport: 1271 + mlx5_eswitch_unload_adj_vf_vports(esw); 1272 + return err; 1238 1273 } 1239 1274 1240 1275 int mlx5_eswitch_load_vf_vports(struct mlx5_eswitch *esw, u16 num_vfs, ··· 1382 1345 enabled_events); 1383 1346 if (ret) 1384 1347 goto vf_err; 1348 + 1349 + /* Enable adjacent VF vports */ 1350 + ret = mlx5_eswitch_load_adj_vf_vports(esw, enabled_events); 1351 + if (ret) 1352 + goto unload_vf_vports; 1353 + 1385 1354 return 0; 1386 1355 1356 + unload_vf_vports: 1357 + mlx5_eswitch_unload_vf_vports(esw, esw->esw_funcs.num_vfs); 1387 1358 vf_err: 1388 1359 if (mlx5_core_ec_sriov_enabled(esw->dev)) 1389 1360 mlx5_eswitch_unload_ec_vf_vports(esw, esw->esw_funcs.num_ec_vfs); ··· 1412 1367 */ 1413 1368 void mlx5_eswitch_disable_pf_vf_vports(struct mlx5_eswitch *esw) 1414 1369 { 1370 + mlx5_eswitch_unload_adj_vf_vports(esw); 1371 + 1415 1372 mlx5_eswitch_unload_vf_vports(esw, esw->esw_funcs.num_vfs); 1416 1373 1417 1374 if (mlx5_core_ec_sriov_enabled(esw->dev)) ··· 1486 1439 blocking_notifier_call_chain(&esw->n_head, 0, &info); 1487 1440 } 1488 1441 1442 + static int mlx5_esw_egress_acls_init(struct mlx5_core_dev *dev) 1443 + { 1444 + struct mlx5_flow_steering *steering = dev->priv.steering; 1445 + int total_vports = mlx5_eswitch_get_total_vports(dev); 1446 + int err; 1447 + int i; 1448 + 1449 + for (i = 0; i < total_vports; i++) { 1450 + err = mlx5_fs_vport_egress_acl_ns_add(steering, i); 1451 + if (err) 1452 + goto acl_ns_remove; 1453 + } 1454 + return 0; 1455 + 1456 + acl_ns_remove: 1457 + while (i--) 1458 + mlx5_fs_vport_egress_acl_ns_remove(steering, i); 1459 + return err; 1460 + } 1461 + 1462 + static void mlx5_esw_egress_acls_cleanup(struct mlx5_core_dev *dev) 1463 + { 1464 + struct mlx5_flow_steering *steering = dev->priv.steering; 1465 + int total_vports = mlx5_eswitch_get_total_vports(dev); 1466 + int i; 1467 + 1468 + for (i = total_vports - 1; i >= 0; i--) 1469 + mlx5_fs_vport_egress_acl_ns_remove(steering, i); 1470 + } 1471 + 1472 + static int mlx5_esw_ingress_acls_init(struct mlx5_core_dev *dev) 1473 + { 1474 + struct mlx5_flow_steering *steering = dev->priv.steering; 1475 + int total_vports = mlx5_eswitch_get_total_vports(dev); 1476 + int err; 1477 + int i; 1478 + 1479 + for (i = 0; i < total_vports; i++) { 1480 + err = mlx5_fs_vport_ingress_acl_ns_add(steering, i); 1481 + if (err) 1482 + goto acl_ns_remove; 1483 + } 1484 + return 0; 1485 + 1486 + acl_ns_remove: 1487 + while (i--) 1488 + mlx5_fs_vport_ingress_acl_ns_remove(steering, i); 1489 + return err; 1490 + } 1491 + 1492 + static void mlx5_esw_ingress_acls_cleanup(struct mlx5_core_dev *dev) 1493 + { 1494 + struct mlx5_flow_steering *steering = dev->priv.steering; 1495 + int total_vports = mlx5_eswitch_get_total_vports(dev); 1496 + int i; 1497 + 1498 + for (i = total_vports - 1; i >= 0; i--) 1499 + mlx5_fs_vport_ingress_acl_ns_remove(steering, i); 1500 + } 1501 + 1489 1502 static int mlx5_esw_acls_ns_init(struct mlx5_eswitch *esw) 1490 1503 { 1491 1504 struct mlx5_core_dev *dev = esw->dev; 1492 - int total_vports; 1493 1505 int err; 1494 1506 1495 1507 if (esw->flags & MLX5_ESWITCH_VPORT_ACL_NS_CREATED) 1496 1508 return 0; 1497 1509 1498 - total_vports = mlx5_eswitch_get_total_vports(dev); 1499 - 1500 1510 if (MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support)) { 1501 - err = mlx5_fs_egress_acls_init(dev, total_vports); 1511 + err = mlx5_esw_egress_acls_init(dev); 1502 1512 if (err) 1503 1513 return err; 1504 1514 } else { ··· 1563 1459 } 1564 1460 1565 1461 if (MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support)) { 1566 - err = mlx5_fs_ingress_acls_init(dev, total_vports); 1462 + err = mlx5_esw_ingress_acls_init(dev); 1567 1463 if (err) 1568 1464 goto err; 1569 1465 } else { ··· 1574 1470 1575 1471 err: 1576 1472 if (MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support)) 1577 - mlx5_fs_egress_acls_cleanup(dev); 1473 + mlx5_esw_egress_acls_cleanup(dev); 1578 1474 return err; 1579 1475 } 1580 1476 ··· 1584 1480 1585 1481 esw->flags &= ~MLX5_ESWITCH_VPORT_ACL_NS_CREATED; 1586 1482 if (MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support)) 1587 - mlx5_fs_ingress_acls_cleanup(dev); 1483 + mlx5_esw_ingress_acls_cleanup(dev); 1588 1484 if (MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support)) 1589 - mlx5_fs_egress_acls_cleanup(dev); 1485 + mlx5_esw_egress_acls_cleanup(dev); 1590 1486 } 1591 1487 1592 1488 /** ··· 1838 1734 return err; 1839 1735 } 1840 1736 1841 - static int mlx5_esw_vport_alloc(struct mlx5_eswitch *esw, 1842 - int index, u16 vport_num) 1737 + int mlx5_esw_vport_alloc(struct mlx5_eswitch *esw, int index, u16 vport_num) 1843 1738 { 1844 1739 struct mlx5_vport *vport; 1845 1740 int err; ··· 1865 1762 return err; 1866 1763 } 1867 1764 1868 - static void mlx5_esw_vport_free(struct mlx5_eswitch *esw, struct mlx5_vport *vport) 1765 + void mlx5_esw_vport_free(struct mlx5_eswitch *esw, struct mlx5_vport *vport) 1869 1766 { 1767 + esw->total_vports--; 1870 1768 xa_erase(&esw->vports, vport->vport); 1871 1769 kfree(vport); 1872 1770 } ··· 1951 1847 err = mlx5_esw_vport_alloc(esw, idx, MLX5_VPORT_UPLINK); 1952 1848 if (err) 1953 1849 goto err; 1850 + 1851 + /* Adjacent vports or other dynamically create vports will use this */ 1852 + esw->last_vport_idx = ++idx; 1954 1853 return 0; 1955 1854 1956 1855 err:
+17
drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
··· 216 216 u32 metadata; 217 217 int vhca_id; 218 218 219 + bool adjacent; /* delegated vhca from adjacent function */ 220 + struct { 221 + u16 parent_pci_devfn; /* Adjacent parent PCI device function */ 222 + u16 function_id; /* Function ID of the delegated VPort */ 223 + } adj_info; 224 + 219 225 struct mlx5_vport_info info; 220 226 221 227 /* Protected with the E-Switch qos domain lock. The Vport QoS can ··· 390 384 391 385 struct mlx5_esw_bridge_offloads *br_offloads; 392 386 struct mlx5_esw_offload offloads; 387 + u32 last_vport_idx; 393 388 int mode; 394 389 u16 manager_vport; 395 390 u16 first_host_vport; ··· 424 417 /* E-Switch API */ 425 418 int mlx5_eswitch_init(struct mlx5_core_dev *dev); 426 419 void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw); 420 + int mlx5_esw_vport_alloc(struct mlx5_eswitch *esw, int index, u16 vport_num); 421 + void mlx5_esw_vport_free(struct mlx5_eswitch *esw, struct mlx5_vport *vport); 427 422 428 423 #define MLX5_ESWITCH_IGNORE_NUM_VFS (-1) 429 424 int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int num_vfs); ··· 630 621 struct mlx5_core_dev *dev1); 631 622 632 623 const u32 *mlx5_esw_query_functions(struct mlx5_core_dev *dev); 624 + 625 + void mlx5_esw_adjacent_vhcas_setup(struct mlx5_eswitch *esw); 626 + void mlx5_esw_adjacent_vhcas_cleanup(struct mlx5_eswitch *esw); 633 627 634 628 #define MLX5_DEBUG_ESWITCH_MASK BIT(3) 635 629 ··· 842 830 struct mlx5_vport *vport); 843 831 int mlx5_eswitch_vhca_id_to_vport(struct mlx5_eswitch *esw, u16 vhca_id, u16 *vport_num); 844 832 bool mlx5_esw_vport_vhca_id(struct mlx5_eswitch *esw, u16 vportn, u16 *vhca_id); 833 + 834 + void mlx5_esw_offloads_rep_remove(struct mlx5_eswitch *esw, 835 + const struct mlx5_vport *vport); 836 + int mlx5_esw_offloads_rep_add(struct mlx5_eswitch *esw, 837 + const struct mlx5_vport *vport); 845 838 846 839 /** 847 840 * struct mlx5_esw_event_info - Indicates eswitch mode changed/changing.
+32 -5
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
··· 2378 2378 return 0; 2379 2379 } 2380 2380 2381 - static int mlx5_esw_offloads_rep_init(struct mlx5_eswitch *esw, const struct mlx5_vport *vport) 2381 + void mlx5_esw_offloads_rep_remove(struct mlx5_eswitch *esw, 2382 + const struct mlx5_vport *vport) 2383 + { 2384 + struct mlx5_eswitch_rep *rep = xa_load(&esw->offloads.vport_reps, 2385 + vport->vport); 2386 + 2387 + if (!rep) 2388 + return; 2389 + xa_erase(&esw->offloads.vport_reps, vport->vport); 2390 + kfree(rep); 2391 + } 2392 + 2393 + int mlx5_esw_offloads_rep_add(struct mlx5_eswitch *esw, 2394 + const struct mlx5_vport *vport) 2382 2395 { 2383 2396 struct mlx5_eswitch_rep *rep; 2384 2397 int rep_type; ··· 2403 2390 2404 2391 rep->vport = vport->vport; 2405 2392 rep->vport_index = vport->index; 2406 - for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) 2407 - atomic_set(&rep->rep_data[rep_type].state, REP_UNREGISTERED); 2408 - 2393 + for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) { 2394 + if (!esw->offloads.rep_ops[rep_type]) { 2395 + atomic_set(&rep->rep_data[rep_type].state, 2396 + REP_UNREGISTERED); 2397 + continue; 2398 + } 2399 + /* Dynamic/delegated vports add their representors after 2400 + * mlx5_eswitch_register_vport_reps, so mark them as registered 2401 + * for them to be loaded later with the others. 2402 + */ 2403 + rep->esw = esw; 2404 + atomic_set(&rep->rep_data[rep_type].state, REP_REGISTERED); 2405 + } 2409 2406 err = xa_insert(&esw->offloads.vport_reps, rep->vport, rep, GFP_KERNEL); 2410 2407 if (err) 2411 2408 goto insert_err; ··· 2453 2430 xa_init(&esw->offloads.vport_reps); 2454 2431 2455 2432 mlx5_esw_for_each_vport(esw, i, vport) { 2456 - err = mlx5_esw_offloads_rep_init(esw, vport); 2433 + err = mlx5_esw_offloads_rep_add(esw, vport); 2457 2434 if (err) 2458 2435 goto err; 2459 2436 } ··· 3561 3538 int err; 3562 3539 3563 3540 mutex_init(&esw->offloads.termtbl_mutex); 3541 + mlx5_esw_adjacent_vhcas_setup(esw); 3542 + 3564 3543 err = mlx5_rdma_enable_roce(esw->dev); 3565 3544 if (err) 3566 3545 goto err_roce; ··· 3627 3602 err_metadata: 3628 3603 mlx5_rdma_disable_roce(esw->dev); 3629 3604 err_roce: 3605 + mlx5_esw_adjacent_vhcas_cleanup(esw); 3630 3606 mutex_destroy(&esw->offloads.termtbl_mutex); 3631 3607 return err; 3632 3608 } ··· 3661 3635 mapping_destroy(esw->offloads.reg_c0_obj_pool); 3662 3636 esw_offloads_metadata_uninit(esw); 3663 3637 mlx5_rdma_disable_roce(esw->dev); 3638 + mlx5_esw_adjacent_vhcas_cleanup(esw); 3664 3639 mutex_destroy(&esw->offloads.termtbl_mutex); 3665 3640 } 3666 3641
+98 -105
drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
··· 2793 2793 } 2794 2794 EXPORT_SYMBOL(mlx5_get_flow_namespace); 2795 2795 2796 + struct mlx5_vport_acl_root_ns { 2797 + u16 vport_idx; 2798 + struct mlx5_flow_root_namespace *root_ns; 2799 + }; 2800 + 2796 2801 struct mlx5_flow_namespace * 2797 2802 mlx5_get_flow_vport_namespace(struct mlx5_core_dev *dev, 2798 2803 enum mlx5_flow_namespace_type type, int vport_idx) 2799 2804 { 2800 2805 struct mlx5_flow_steering *steering = dev->priv.steering; 2806 + struct mlx5_vport_acl_root_ns *vport_ns; 2801 2807 2802 2808 if (!steering) 2803 2809 return NULL; 2804 2810 2805 2811 switch (type) { 2806 2812 case MLX5_FLOW_NAMESPACE_ESW_EGRESS: 2807 - if (vport_idx >= steering->esw_egress_acl_vports) 2808 - return NULL; 2809 - if (steering->esw_egress_root_ns && 2810 - steering->esw_egress_root_ns[vport_idx]) 2811 - return &steering->esw_egress_root_ns[vport_idx]->ns; 2813 + vport_ns = xa_load(&steering->esw_egress_root_ns, vport_idx); 2814 + if (vport_ns) 2815 + return &vport_ns->root_ns->ns; 2812 2816 else 2813 2817 return NULL; 2814 2818 case MLX5_FLOW_NAMESPACE_ESW_INGRESS: 2815 - if (vport_idx >= steering->esw_ingress_acl_vports) 2816 - return NULL; 2817 - if (steering->esw_ingress_root_ns && 2818 - steering->esw_ingress_root_ns[vport_idx]) 2819 - return &steering->esw_ingress_root_ns[vport_idx]->ns; 2819 + vport_ns = xa_load(&steering->esw_ingress_root_ns, vport_idx); 2820 + if (vport_ns) 2821 + return &vport_ns->root_ns->ns; 2820 2822 else 2821 2823 return NULL; 2822 2824 case MLX5_FLOW_NAMESPACE_RDMA_TRANSPORT_RX: ··· 3577 3575 return err; 3578 3576 } 3579 3577 3580 - static int init_egress_acl_root_ns(struct mlx5_flow_steering *steering, int vport) 3578 + static void 3579 + mlx5_fs_remove_vport_acl_root_ns(struct xarray *esw_acl_root_ns, u16 vport_idx) 3581 3580 { 3582 - struct fs_prio *prio; 3581 + struct mlx5_vport_acl_root_ns *vport_ns; 3583 3582 3584 - steering->esw_egress_root_ns[vport] = create_root_ns(steering, FS_FT_ESW_EGRESS_ACL); 3585 - if (!steering->esw_egress_root_ns[vport]) 3586 - return -ENOMEM; 3587 - 3588 - /* create 1 prio*/ 3589 - prio = fs_create_prio(&steering->esw_egress_root_ns[vport]->ns, 0, 1); 3590 - return PTR_ERR_OR_ZERO(prio); 3591 - } 3592 - 3593 - static int init_ingress_acl_root_ns(struct mlx5_flow_steering *steering, int vport) 3594 - { 3595 - struct fs_prio *prio; 3596 - 3597 - steering->esw_ingress_root_ns[vport] = create_root_ns(steering, FS_FT_ESW_INGRESS_ACL); 3598 - if (!steering->esw_ingress_root_ns[vport]) 3599 - return -ENOMEM; 3600 - 3601 - /* create 1 prio*/ 3602 - prio = fs_create_prio(&steering->esw_ingress_root_ns[vport]->ns, 0, 1); 3603 - return PTR_ERR_OR_ZERO(prio); 3604 - } 3605 - 3606 - int mlx5_fs_egress_acls_init(struct mlx5_core_dev *dev, int total_vports) 3607 - { 3608 - struct mlx5_flow_steering *steering = dev->priv.steering; 3609 - int err; 3610 - int i; 3611 - 3612 - steering->esw_egress_root_ns = 3613 - kcalloc(total_vports, 3614 - sizeof(*steering->esw_egress_root_ns), 3615 - GFP_KERNEL); 3616 - if (!steering->esw_egress_root_ns) 3617 - return -ENOMEM; 3618 - 3619 - for (i = 0; i < total_vports; i++) { 3620 - err = init_egress_acl_root_ns(steering, i); 3621 - if (err) 3622 - goto cleanup_root_ns; 3583 + vport_ns = xa_erase(esw_acl_root_ns, vport_idx); 3584 + if (vport_ns) { 3585 + cleanup_root_ns(vport_ns->root_ns); 3586 + kfree(vport_ns); 3623 3587 } 3624 - steering->esw_egress_acl_vports = total_vports; 3588 + } 3589 + 3590 + static int 3591 + mlx5_fs_add_vport_acl_root_ns(struct mlx5_flow_steering *steering, 3592 + struct xarray *esw_acl_root_ns, 3593 + enum fs_flow_table_type table_type, 3594 + u16 vport_idx) 3595 + { 3596 + struct mlx5_vport_acl_root_ns *vport_ns; 3597 + struct fs_prio *prio; 3598 + int err; 3599 + 3600 + /* sanity check, intended xarrays are used */ 3601 + if (WARN_ON(esw_acl_root_ns != &steering->esw_egress_root_ns && 3602 + esw_acl_root_ns != &steering->esw_ingress_root_ns)) 3603 + return -EINVAL; 3604 + 3605 + if (table_type != FS_FT_ESW_EGRESS_ACL && 3606 + table_type != FS_FT_ESW_INGRESS_ACL) { 3607 + mlx5_core_err(steering->dev, 3608 + "Invalid table type %d for egress/ingress ACLs\n", 3609 + table_type); 3610 + return -EINVAL; 3611 + } 3612 + 3613 + if (xa_load(esw_acl_root_ns, vport_idx)) 3614 + return -EEXIST; 3615 + 3616 + vport_ns = kzalloc(sizeof(*vport_ns), GFP_KERNEL); 3617 + if (!vport_ns) 3618 + return -ENOMEM; 3619 + 3620 + vport_ns->root_ns = create_root_ns(steering, table_type); 3621 + if (!vport_ns->root_ns) { 3622 + err = -ENOMEM; 3623 + goto kfree_vport_ns; 3624 + } 3625 + 3626 + /* create 1 prio*/ 3627 + prio = fs_create_prio(&vport_ns->root_ns->ns, 0, 1); 3628 + if (IS_ERR(prio)) { 3629 + err = PTR_ERR(prio); 3630 + goto cleanup_root_ns; 3631 + } 3632 + 3633 + vport_ns->vport_idx = vport_idx; 3634 + err = xa_insert(esw_acl_root_ns, vport_idx, vport_ns, GFP_KERNEL); 3635 + if (err) 3636 + goto cleanup_root_ns; 3625 3637 return 0; 3626 3638 3627 3639 cleanup_root_ns: 3628 - for (i--; i >= 0; i--) 3629 - cleanup_root_ns(steering->esw_egress_root_ns[i]); 3630 - kfree(steering->esw_egress_root_ns); 3631 - steering->esw_egress_root_ns = NULL; 3640 + cleanup_root_ns(vport_ns->root_ns); 3641 + kfree_vport_ns: 3642 + kfree(vport_ns); 3632 3643 return err; 3633 3644 } 3634 3645 3635 - void mlx5_fs_egress_acls_cleanup(struct mlx5_core_dev *dev) 3646 + int mlx5_fs_vport_egress_acl_ns_add(struct mlx5_flow_steering *steering, 3647 + u16 vport_idx) 3636 3648 { 3637 - struct mlx5_flow_steering *steering = dev->priv.steering; 3638 - int i; 3639 - 3640 - if (!steering->esw_egress_root_ns) 3641 - return; 3642 - 3643 - for (i = 0; i < steering->esw_egress_acl_vports; i++) 3644 - cleanup_root_ns(steering->esw_egress_root_ns[i]); 3645 - 3646 - kfree(steering->esw_egress_root_ns); 3647 - steering->esw_egress_root_ns = NULL; 3649 + return mlx5_fs_add_vport_acl_root_ns(steering, 3650 + &steering->esw_egress_root_ns, 3651 + FS_FT_ESW_EGRESS_ACL, vport_idx); 3648 3652 } 3649 3653 3650 - int mlx5_fs_ingress_acls_init(struct mlx5_core_dev *dev, int total_vports) 3654 + int mlx5_fs_vport_ingress_acl_ns_add(struct mlx5_flow_steering *steering, 3655 + u16 vport_idx) 3651 3656 { 3652 - struct mlx5_flow_steering *steering = dev->priv.steering; 3653 - int err; 3654 - int i; 3655 - 3656 - steering->esw_ingress_root_ns = 3657 - kcalloc(total_vports, 3658 - sizeof(*steering->esw_ingress_root_ns), 3659 - GFP_KERNEL); 3660 - if (!steering->esw_ingress_root_ns) 3661 - return -ENOMEM; 3662 - 3663 - for (i = 0; i < total_vports; i++) { 3664 - err = init_ingress_acl_root_ns(steering, i); 3665 - if (err) 3666 - goto cleanup_root_ns; 3667 - } 3668 - steering->esw_ingress_acl_vports = total_vports; 3669 - return 0; 3670 - 3671 - cleanup_root_ns: 3672 - for (i--; i >= 0; i--) 3673 - cleanup_root_ns(steering->esw_ingress_root_ns[i]); 3674 - kfree(steering->esw_ingress_root_ns); 3675 - steering->esw_ingress_root_ns = NULL; 3676 - return err; 3657 + return mlx5_fs_add_vport_acl_root_ns(steering, 3658 + &steering->esw_ingress_root_ns, 3659 + FS_FT_ESW_INGRESS_ACL, vport_idx); 3677 3660 } 3678 3661 3679 - void mlx5_fs_ingress_acls_cleanup(struct mlx5_core_dev *dev) 3662 + void mlx5_fs_vport_egress_acl_ns_remove(struct mlx5_flow_steering *steering, 3663 + int vport_idx) 3680 3664 { 3681 - struct mlx5_flow_steering *steering = dev->priv.steering; 3682 - int i; 3665 + mlx5_fs_remove_vport_acl_root_ns(&steering->esw_egress_root_ns, 3666 + vport_idx); 3667 + } 3683 3668 3684 - if (!steering->esw_ingress_root_ns) 3685 - return; 3686 - 3687 - for (i = 0; i < steering->esw_ingress_acl_vports; i++) 3688 - cleanup_root_ns(steering->esw_ingress_root_ns[i]); 3689 - 3690 - kfree(steering->esw_ingress_root_ns); 3691 - steering->esw_ingress_root_ns = NULL; 3669 + void mlx5_fs_vport_ingress_acl_ns_remove(struct mlx5_flow_steering *steering, 3670 + int vport_idx) 3671 + { 3672 + mlx5_fs_remove_vport_acl_root_ns(&steering->esw_ingress_root_ns, 3673 + vport_idx); 3692 3674 } 3693 3675 3694 3676 u32 mlx5_fs_get_capabilities(struct mlx5_core_dev *dev, enum mlx5_flow_namespace_type type) ··· 3804 3818 { 3805 3819 struct mlx5_flow_steering *steering = dev->priv.steering; 3806 3820 3821 + WARN_ON(!xa_empty(&steering->esw_egress_root_ns)); 3822 + WARN_ON(!xa_empty(&steering->esw_ingress_root_ns)); 3823 + xa_destroy(&steering->esw_egress_root_ns); 3824 + xa_destroy(&steering->esw_ingress_root_ns); 3825 + 3807 3826 cleanup_root_ns(steering->root_ns); 3808 3827 cleanup_fdb_root_ns(steering); 3809 3828 cleanup_root_ns(steering->port_sel_root_ns); ··· 3899 3908 goto err; 3900 3909 } 3901 3910 3911 + xa_init(&steering->esw_egress_root_ns); 3912 + xa_init(&steering->esw_ingress_root_ns); 3902 3913 return 0; 3903 3914 3904 3915 err:
+10 -8
drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
··· 151 151 struct mlx5_flow_root_namespace *root_ns; 152 152 struct mlx5_flow_root_namespace *fdb_root_ns; 153 153 struct mlx5_flow_namespace **fdb_sub_ns; 154 - struct mlx5_flow_root_namespace **esw_egress_root_ns; 155 - struct mlx5_flow_root_namespace **esw_ingress_root_ns; 154 + struct xarray esw_egress_root_ns; 155 + struct xarray esw_ingress_root_ns; 156 156 struct mlx5_flow_root_namespace *sniffer_tx_root_ns; 157 157 struct mlx5_flow_root_namespace *sniffer_rx_root_ns; 158 158 struct mlx5_flow_root_namespace *rdma_rx_root_ns; 159 159 struct mlx5_flow_root_namespace *rdma_tx_root_ns; 160 160 struct mlx5_flow_root_namespace *egress_root_ns; 161 161 struct mlx5_flow_root_namespace *port_sel_root_ns; 162 - int esw_egress_acl_vports; 163 - int esw_ingress_acl_vports; 164 162 struct mlx5_flow_root_namespace **rdma_transport_rx_root_ns; 165 163 struct mlx5_flow_root_namespace **rdma_transport_tx_root_ns; 166 164 int rdma_transport_rx_vports; ··· 376 378 int mlx5_fs_core_init(struct mlx5_core_dev *dev); 377 379 void mlx5_fs_core_cleanup(struct mlx5_core_dev *dev); 378 380 379 - int mlx5_fs_egress_acls_init(struct mlx5_core_dev *dev, int total_vports); 380 - void mlx5_fs_egress_acls_cleanup(struct mlx5_core_dev *dev); 381 - int mlx5_fs_ingress_acls_init(struct mlx5_core_dev *dev, int total_vports); 382 - void mlx5_fs_ingress_acls_cleanup(struct mlx5_core_dev *dev); 381 + int mlx5_fs_vport_egress_acl_ns_add(struct mlx5_flow_steering *steering, 382 + u16 vport_idx); 383 + int mlx5_fs_vport_ingress_acl_ns_add(struct mlx5_flow_steering *steering, 384 + u16 vport_idx); 385 + void mlx5_fs_vport_egress_acl_ns_remove(struct mlx5_flow_steering *steering, 386 + int vport_idx); 387 + void mlx5_fs_vport_ingress_acl_ns_remove(struct mlx5_flow_steering *steering, 388 + int vport_idx); 383 389 384 390 u32 mlx5_fs_get_capabilities(struct mlx5_core_dev *dev, enum mlx5_flow_namespace_type type); 385 391
+7 -27
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.c
··· 1200 1200 int mlx5hws_cmd_query_gvmi(struct mlx5_core_dev *mdev, bool other_function, 1201 1201 u16 vport_number, u16 *gvmi) 1202 1202 { 1203 - u32 in[MLX5_ST_SZ_DW(query_hca_cap_in)] = {}; 1204 - int out_size; 1205 - void *out; 1206 1203 int err; 1207 1204 1208 - if (other_function) { 1209 - err = mlx5_vport_get_vhca_id(mdev, vport_number, gvmi); 1210 - if (!err) 1211 - return 0; 1205 + if (!other_function) { 1206 + /* self vhca_id */ 1207 + *gvmi = MLX5_CAP_GEN(mdev, vhca_id); 1208 + return 0; 1209 + } 1212 1210 1211 + err = mlx5_vport_get_vhca_id(mdev, vport_number, gvmi); 1212 + if (err) { 1213 1213 mlx5_core_err(mdev, "Failed to get vport vhca id for vport %d\n", 1214 1214 vport_number); 1215 1215 return err; 1216 1216 } 1217 - 1218 - /* get vhca_id for `this` function */ 1219 - out_size = MLX5_ST_SZ_BYTES(query_hca_cap_out); 1220 - out = kzalloc(out_size, GFP_KERNEL); 1221 - if (!out) 1222 - return -ENOMEM; 1223 - 1224 - MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); 1225 - MLX5_SET(query_hca_cap_in, in, op_mod, 1226 - MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE << 1 | HCA_CAP_OPMOD_GET_CUR); 1227 - 1228 - err = mlx5_cmd_exec_inout(mdev, query_hca_cap, in, out); 1229 - if (err) { 1230 - kfree(out); 1231 - return err; 1232 - } 1233 - 1234 - *gvmi = MLX5_GET(query_hca_cap_out, out, capability.cmd_hca_cap.vhca_id); 1235 - 1236 - kfree(out); 1237 1217 1238 1218 return 0; 1239 1219 }
+7 -27
drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_cmd.c
··· 35 35 int mlx5dr_cmd_query_gvmi(struct mlx5_core_dev *mdev, bool other_vport, 36 36 u16 vport_number, u16 *gvmi) 37 37 { 38 - u32 in[MLX5_ST_SZ_DW(query_hca_cap_in)] = {}; 39 - int out_size; 40 - void *out; 41 38 int err; 42 39 43 - if (other_vport) { 44 - err = mlx5_vport_get_vhca_id(mdev, vport_number, gvmi); 45 - if (!err) 46 - return 0; 40 + if (!other_vport) { 41 + /* self vhca_id */ 42 + *gvmi = MLX5_CAP_GEN(mdev, vhca_id); 43 + return 0; 44 + } 47 45 46 + err = mlx5_vport_get_vhca_id(mdev, vport_number, gvmi); 47 + if (err) { 48 48 mlx5_core_err(mdev, "Failed to get vport vhca id for vport %d\n", 49 49 vport_number); 50 50 return err; 51 51 } 52 52 53 - /* get vhca_id for `this` function */ 54 - out_size = MLX5_ST_SZ_BYTES(query_hca_cap_out); 55 - out = kzalloc(out_size, GFP_KERNEL); 56 - if (!out) 57 - return -ENOMEM; 58 - 59 - MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); 60 - MLX5_SET(query_hca_cap_in, in, op_mod, 61 - MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE << 1 | 62 - HCA_CAP_OPMOD_GET_CUR); 63 - 64 - err = mlx5_cmd_exec_inout(mdev, query_hca_cap, in, out); 65 - if (err) { 66 - kfree(out); 67 - return err; 68 - } 69 - 70 - *gvmi = MLX5_GET(query_hca_cap_out, out, capability.cmd_hca_cap.vhca_id); 71 - 72 - kfree(out); 73 53 return 0; 74 54 } 75 55