* [PATCH net-next 00/15] net/mlx5: LAG over VFs/SFs (virtual LAG)
@ 2026-11-03 17:09 Tariq Toukan
2026-11-03 17:09 ` [PATCH net-next 01/15] net/mlx5: Distinguish VFs/SFs in the SW system image GUID for LAG grouping Tariq Toukan
` (14 more replies)
0 siblings, 15 replies; 16+ messages in thread
From: Tariq Toukan @ 2026-11-03 17:09 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Carolina Jubran, Cosmin Ratiu, Edward Srouji,
Gal Pressman, Leon Romanovsky, open list, linux-rdma, Mark Bloch,
Moshe Shemesh, Or Har-Toov, Patrisious Haddad, Saeed Mahameed,
Shay Drory, Tariq Toukan
Hi,
This series by Shay enables a LAG over functions that do not represent a
physical port - a "virtual LAG" (virt LAG) of VFs or SFs acting as nested
e-switch managers. New FW lets a VF/SF front the physical uplinks through
a multi-uplink e-switch; such a function reports num_lag_ports < 2 and
drives port selection via the e-switch (port_select_eswitch) rather than
the HW port-selection flow table. A virt LAG is therefore a
software-managed, shared-FDB MPESW LAG: the driver builds the LAG demux
and vport-LAG in software and skips the FW LAG commands.
The patches fall into three parts.
LAG code cleanup (patches 5, 6, 7, 8, 9)
- Finish removing the fixed MLX5_MAX_PORTS sizing the first series
began: convert the remaining structures to dynamic, port-count-based
allocation and inline iteration. A virt LAG's member count is
unrelated to the physical port count.
- Rename the LAG "pf" naming to "func", since a member is now any
function (PF, VF or SF), not necessarily a PF.
- Resolve the queue-affinity member indices only in that mode, so the
other port-select modes are not rejected for indices they never use.
Virtual LAG core (patches 1, 2, 3, 4, 10, 15)
- Distinguish VFs/SFs from their PF in the SW system image GUID, so they
group into their own LAG instead of with the PF.
- Select the MPESW master from the live member snapshot: VF/SF members
are dynamic and not marked by the devcom PAIR event, so the master is
chosen from the current membership (tie-broken by PCI BDF for VFs,
sfnum for SFs).
- Skip the phys-LAG prerequisites (port_select_flow_table,
create_lag_when_not_master_up, ...) for a virt LAG, and require
port_select_eswitch instead.
- Treat a virt LAG as a software-managed LAG (demux + vport-LAG in SW).
- Do not add a device to an already-active LAG.
- Enable LAG over functions that do not represent a physical port - the
gate that admits a virt LAG.
E-switch and representors (patches 11, 12, 13, 14)
- A dedicated match-metadata allocator for nested VF/SF e-switches, so
VFs/SFs sharing an FDB get unique source-port metadata.
- Match the master egress bounce rule by vport metadata.
- Drop the master egress rule while a software vport LAG is installed:
the SW emulation is a rule in the slave's egress ACL and cannot act on
a packet the master egress rule redirects after the FDB. Restore it
when the vport LAG is removed.
- Register a VF/SF e-switch-manager self-port with a switch-id so it
groups with the representors it manages.
Regards,
Tariq
Answers to sashiko comments:
net/mlx5: LAG, treat virt LAG as a software managed LAG
> -static int mlx5_lag_is_sw_lag(struct mlx5_core_dev *dev)
> +int mlx5_lag_is_sw_managed(struct mlx5_core_dev *dev)
> {
> - return mlx5_lag_is_sd(dev);
> + struct mlx5_lag *ldev = mlx5_lag_dev(dev);
Q: If dev is NULL, does mlx5_lag_dev(dev) NULL-deref dev->priv.lag? When
called from mlx5_lag_multipath_check_prereq() via the FIB notifier,
pf->dev can be NULL due to concurrent removal in mlx5_ldev_remove_mdev().
__mlx5_lag_is_sd() was safe (lockless pointer compare). Does this need a
NULL check?
[SD] mlx5_lag_is_sw_managed() assumes a valid dev pointer, like the rest
of the mlx5_lag_is_* APIs. It is true mlx5_lag_multipath_check_prereq()
can provide an invalid device pointer, but that is an existing bug there
which should be handled in its own patch.
net/mlx5: LAG, decouple iteration end-of-walk from MLX5_MAX_PORTS
> - if (i < MLX5_MAX_PORTS) {
> + if (i < ldev->ports) {
> slave = bond_slave_get_rcu(ndev_tmp);
Q: Could this loop-termination change break LAG activation, since
physical ports share the XArray ldev->pfs with VFs/SFs?
[SD] No. mlx5 creates and populates an ldev per sw_guid, and PFs have a
different sw_guid than VFs/SFs. Hence PFs cannot share an ldev with
VFs/SFs.
> - err = xa_alloc(&ldev->pfs, &idx, pf, XA_LIMIT(0, MLX5_MAX_PORTS - 1),
> + err = xa_alloc(&ldev->pfs, &idx, pf, XA_LIMIT(0, U8_MAX - 1),
Q: Physical members and Socket Direct secondaries share the xarray index
space. Can a physical member get an index >= MLX5_MAX_PORTS and make
mlx5_ldev_add_netdev() write beyond tracker.netdev_state[]?
[SD] Such HW doesn't exist; it needs LAG over SD with more than
MLX5_MAX_PORTS / 2 ports, and when it does MLX5_MAX_PORTS will be
increased. To protect a new HW running an old driver, a check that
num_lag_ports times the SD group size fits in MLX5_MAX_PORTS will be added
to mlx5_lag_is_supported() separately.
net/mlx5: LAG: replace fixed MLX5_MAX_PORTS arrays with dynamic allocation
> + ldev = mlx5_lag_dev(dev);
> + num_ports = ldev ? max_t(int, ldev->ports, 1) : 1;
> + mdev = kcalloc(num_ports, sizeof(mdev[0]), GFP_KERNEL);
Q: Could mlx5_lag_query_cong_counters() keep a freed ldev across this
sleeping allocation if teardown removes the association and drops the
last LAG reference before the query resumes?
[SD] No. The query runs on the IB device of dev, and dev leaves the LAG
only in its own teardown, after its IB device is unregistered.
net/mlx5: LAG, Drop MLX5_MAX_PORTS scratch array from device rescan
> + mlx5_lag_for_each(i, 0, ldev, filter) {
> + pf = mlx5_lag_pf(ldev, i);
> + ...
> + mlx5_rescan_drivers_locked(pf->dev);
Q: Is it safe to iterate the LAG PFs and deref pf->dev while ldev->lock is
dropped?
[SD] Valid. Membership can be removed by SD cleanup while ldev->lock
is dropped; this will be fixed in a separate patch.
Q: Does using the sparse XArray index directly as a dense-array index
cause OOB writes elsewhere? With Socket Direct the XArray index (i) for a
primary port can exceed ldev->ports, and it is used directly in
mlx5_infer_tx_affinity_mapping() (ports[idx]) and
mlx5_handle_changelowerstate_event() (tracker->netdev_state[idx]) - could
these overflow the heap/stack buffers?
[SD] All these buffers aren't used in LAG over SD; only MPESW is, and
MPESW doesn't use these APIs.
net/mlx5: E-switch, add match-metadata allocator for nested VF/SF eswitches
> + if (!mlx5_core_is_pf(esw->dev) && !mlx5_virt_lag_nonmember(esw->dev))
> + return mlx5_nested_esw_match_metadata_alloc(esw);
Q: mlx5_virt_lag_nonmember() is false when virt LAG is unsupported, so a
standalone non-PF eswitch without virt LAG support takes the nested path
and fails switchdev with -ENOSPC. Could it keep the PFNUM allocator?
[SD] A non-PF eswitch manager without virt LAG support doesn't exist at
the moment.
net/mlx5: LAG, enable LAG over functions that do not represent a physical port
> - if (group_id)
> + if (group_id || ldev->virt_lag)
> return 0;
Q: mlx5_lag_set_vports_agg_speed() iterates ports only, so a virt LAG gets
no aggregate vport speed, and its members skip the port-change notifier.
Is there an alternative virt LAG speed policy?
[SD] This is on purpose.
Q: members_show() uses mlx5_ldev_for_each(), so the debugfs members file
is empty for a virt LAG. Could it list all members?
[SD] Left as is for now, since all VFs in the system share the LAG.
Shay Drory (15):
net/mlx5: Distinguish VFs/SFs in the SW system image GUID for LAG
grouping
net/mlx5: LAG, select the MPESW master from the live member snapshot
net/mlx5: LAG, skip phys LAG prerequisites for a virt LAG
net/mlx5: LAG, treat virt LAG as a software managed LAG
net/mlx5: LAG, decouple iteration end-of-walk from MLX5_MAX_PORTS
net/mlx5: LAG, rename PF naming to fn
net/mlx5: LAG, resolve affinity indices only in queue-affinity mode
net/mlx5: LAG: replace fixed MLX5_MAX_PORTS arrays with dynamic
allocation
net/mlx5: LAG, drop MLX5_MAX_PORTS scratch array from device rescan
net/mlx5: LAG, do not add a device to an already-active LAG
net/mlx5: E-switch, add match-metadata allocator for nested VF/SF
eswitches
net/mlx5: E-switch, match master egress rule by vport metadata
net/mlx5: E-switch, drop master egress rule under a SW vport LAG
net/mlx5e: Register eswitch-manager VF/SF self-port with switch-id
net/mlx5: LAG, enable LAG over functions that do not represent a
physical port
.../ethernet/mellanox/mlx5/core/en/devlink.c | 5 +
.../net/ethernet/mellanox/mlx5/core/eswitch.h | 3 +-
.../mellanox/mlx5/core/eswitch_offloads.c | 154 ++++-
.../ethernet/mellanox/mlx5/core/lag/debugfs.c | 2 +-
.../net/ethernet/mellanox/mlx5/core/lag/lag.c | 604 ++++++++++--------
.../net/ethernet/mellanox/mlx5/core/lag/lag.h | 71 +-
.../net/ethernet/mellanox/mlx5/core/lag/mp.c | 29 +-
.../ethernet/mellanox/mlx5/core/lag/mpesw.c | 129 ++--
.../ethernet/mellanox/mlx5/core/lag/mpesw.h | 2 +-
.../mellanox/mlx5/core/lag/port_sel.c | 25 +-
.../mellanox/mlx5/core/lag/shared_fdb.c | 50 +-
.../net/ethernet/mellanox/mlx5/core/lib/sd.c | 32 +-
.../ethernet/mellanox/mlx5/core/mlx5_core.h | 1 +
.../ethernet/mellanox/mlx5/core/sf/dev/dev.h | 12 +
.../net/ethernet/mellanox/mlx5/core/vport.c | 41 +-
include/linux/mlx5/driver.h | 2 +-
16 files changed, 744 insertions(+), 418 deletions(-)
base-commit: 7b6ab4dbc156e2f96419715130b3d5738a306c93
--
2.44.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net-next 01/15] net/mlx5: Distinguish VFs/SFs in the SW system image GUID for LAG grouping
2026-11-03 17:09 [PATCH net-next 00/15] net/mlx5: LAG over VFs/SFs (virtual LAG) Tariq Toukan
@ 2026-11-03 17:09 ` Tariq Toukan
2026-11-03 17:09 ` [PATCH net-next 02/15] net/mlx5: LAG, select the MPESW master from the live member snapshot Tariq Toukan
` (13 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tariq Toukan @ 2026-11-03 17:09 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Carolina Jubran, Cosmin Ratiu, Edward Srouji,
Gal Pressman, Leon Romanovsky, open list, linux-rdma, Mark Bloch,
Moshe Shemesh, Or Har-Toov, Patrisious Haddad, Saeed Mahameed,
Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
mlx5_query_nic_sw_system_image_guid() builds the key used to group
devices that may form a LAG. A PF and its VFs/SFs share the same FW
system image GUID, so without a discriminator a VF/SF that can join a
virt LAG would be grouped with its PF.
Appending bare discriminator bytes at conditional offsets is not enough:
distinct capability sets can collapse to the same key (a PF ending in a
load_balance byte of 0x01 vs a VF whose marker is 0x01). Give each
discriminator a fixed position instead, and add the VF and SF as such
fields. Trailing zero fields are trimmed, so keys of devices that set
none of the new fields are unchanged.
Set the VF/SF markers only when mlx5_virt_lag_is_supported(). The same
key also backs mlx5_same_hw_devs(), so a VF/SF that cannot join a virt
LAG keeps its current key and is still identified as the same HW as its
PF.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../net/ethernet/mellanox/mlx5/core/lag/lag.h | 9 ++++
.../net/ethernet/mellanox/mlx5/core/vport.c | 41 +++++++++++++++++--
include/linux/mlx5/driver.h | 2 +-
3 files changed, 48 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
index 8552792b9035..0ff337983a6d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
@@ -266,6 +266,15 @@ static inline void mlx5_lag_set_vports_agg_speed(struct mlx5_lag *ldev) {}
static inline void mlx5_lag_reset_vports_speed(struct mlx5_lag *ldev) {}
#endif
+static inline bool mlx5_virt_lag_is_supported(const struct mlx5_core_dev *dev)
+{
+ if (!MLX5_CAP_GEN(dev, multi_uplink_eswitch) ||
+ !MLX5_CAP_GEN(dev, lag_master) ||
+ MLX5_CAP_GEN(dev, num_lag_ports) >= 2)
+ return false;
+ return true;
+}
+
static inline bool mlx5_lag_is_supported(struct mlx5_core_dev *dev)
{
if (!MLX5_CAP_GEN(dev, vport_group_manager) ||
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c
index 78f3d15b599d..50d2609374c4 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c
@@ -38,6 +38,7 @@
#include "mlx5_core.h"
#include "eswitch.h"
#include "sf/sf.h"
+#include "lag/lag.h"
/* Mutex to hold while enabling or disabling RoCE */
static DEFINE_MUTEX(mlx5_roce_en_lock);
@@ -1308,10 +1309,37 @@ u64 mlx5_query_nic_system_image_guid(struct mlx5_core_dev *mdev)
}
EXPORT_SYMBOL_GPL(mlx5_query_nic_system_image_guid);
+static u8 mlx5_sw_guid_load_balance(const struct mlx5_core_dev *mdev)
+{
+ if (MLX5_CAP_GEN_2(mdev, load_balance_id) &&
+ MLX5_CAP_GEN_2(mdev, lag_per_mp_group))
+ return MLX5_CAP_GEN_2(mdev, load_balance_id);
+ return 0;
+}
+
+static u8 mlx5_sw_guid_sf(const struct mlx5_core_dev *mdev)
+{
+ return mlx5_core_is_sf(mdev) && mlx5_virt_lag_is_supported(mdev);
+}
+
+static u8 mlx5_sw_guid_vf(const struct mlx5_core_dev *mdev)
+{
+ return mlx5_core_is_vf(mdev) && mlx5_virt_lag_is_supported(mdev);
+}
+
+static u8 (* const mlx5_sw_guid_fields[])(const struct mlx5_core_dev *mdev) = {
+ mlx5_sw_guid_load_balance,
+ mlx5_sw_guid_vf,
+ mlx5_sw_guid_sf,
+ /* New fields should be added at the end */
+};
+
void mlx5_query_nic_sw_system_image_guid(struct mlx5_core_dev *mdev, u8 *buf,
u8 *len)
{
u64 fw_system_image_guid;
+ u8 trim_len;
+ int i;
*len = 0;
@@ -1321,10 +1349,17 @@ void mlx5_query_nic_sw_system_image_guid(struct mlx5_core_dev *mdev, u8 *buf,
memcpy(buf, &fw_system_image_guid, sizeof(fw_system_image_guid));
*len += sizeof(fw_system_image_guid);
+ trim_len = *len;
- if (MLX5_CAP_GEN_2(mdev, load_balance_id) &&
- MLX5_CAP_GEN_2(mdev, lag_per_mp_group))
- buf[(*len)++] = MLX5_CAP_GEN_2(mdev, load_balance_id);
+ for (i = 0; i < ARRAY_SIZE(mlx5_sw_guid_fields); i++) {
+ u8 val = mlx5_sw_guid_fields[i](mdev);
+
+ buf[(*len)++] = val;
+ if (val)
+ trim_len = *len;
+ }
+
+ *len = trim_len;
}
bool mlx5_vport_use_vhca_id_as_func_id(struct mlx5_core_dev *dev,
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index abb99371ff13..d9d91faa0a1d 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -1395,7 +1395,7 @@ static inline struct net *mlx5_core_net(struct mlx5_core_dev *dev)
return devlink_net(priv_to_devlink(dev));
}
-#define MLX5_SW_IMAGE_GUID_MAX_BYTES 9
+#define MLX5_SW_IMAGE_GUID_MAX_BYTES 11
static inline bool mlx5_data_direct_supported(struct mlx5_core_dev *mdev)
{
--
2.44.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net-next 02/15] net/mlx5: LAG, select the MPESW master from the live member snapshot
2026-11-03 17:09 [PATCH net-next 00/15] net/mlx5: LAG over VFs/SFs (virtual LAG) Tariq Toukan
2026-11-03 17:09 ` [PATCH net-next 01/15] net/mlx5: Distinguish VFs/SFs in the SW system image GUID for LAG grouping Tariq Toukan
@ 2026-11-03 17:09 ` Tariq Toukan
2026-11-03 17:09 ` [PATCH net-next 03/15] net/mlx5: LAG, skip phys LAG prerequisites for a virt LAG Tariq Toukan
` (12 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tariq Toukan @ 2026-11-03 17:09 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Carolina Jubran, Cosmin Ratiu, Edward Srouji,
Gal Pressman, Leon Romanovsky, open list, linux-rdma, Mark Bloch,
Moshe Shemesh, Or Har-Toov, Patrisious Haddad, Saeed Mahameed,
Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
The LAG master is marked by the devcom PAIR event when all physical
ports have registered (mlx5_lag_num_devs() == ldev->ports). That does
not work for a virtual LAG of VFs/SFs: those functions are unrelated to
the physical port count.
Select the master from the current membership snapshot in
mlx5_lag_enable_mpesw() via mlx5_virt_lag_mark_master(), and clear it in
mlx5_lag_disable_mpesw(). Unlike the regular path, it walks all LAG
members.
mlx5_get_dev_index() is identical for a PF and all its VFs/SFs, so
tie-break by a stable per-member key is used - PCI BDF for VFs, sfnum
for SFs.
This is gated by a new ldev->virt_lag bit identifying this type of LAG.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../net/ethernet/mellanox/mlx5/core/lag/lag.c | 46 +++++++++++++++++--
.../net/ethernet/mellanox/mlx5/core/lag/lag.h | 3 ++
.../ethernet/mellanox/mlx5/core/lag/mpesw.c | 42 +++++++++++++----
.../ethernet/mellanox/mlx5/core/sf/dev/dev.h | 12 +++++
4 files changed, 90 insertions(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
index 24086267b4a7..46f125d24f15 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
@@ -39,6 +39,7 @@
#include "lib/mlx5.h"
#include "lib/devcom.h"
#include "mlx5_core.h"
+#include "sf/dev/dev.h"
#include "eswitch.h"
#include "esw/acl/ofld.h"
#include "lag.h"
@@ -598,7 +599,43 @@ static void mlx5_lag_mark_master(struct mlx5_lag *ldev)
xa_set_mark(&ldev->pfs, master_xa_idx, MLX5_LAG_XA_MARK_MASTER);
}
-static void mlx5_lag_clear_master(struct mlx5_lag *ldev)
+static u64 mlx5_lag_member_tiebreak(struct mlx5_core_dev *dev)
+{
+ struct pci_dev *pdev = dev->pdev;
+
+ if (mlx5_core_is_sf(dev))
+ return mlx5_sf_coredev_sfnum(dev);
+
+ return ((u64)pci_domain_nr(pdev->bus) << 16) | pci_dev_id(pdev);
+}
+
+void mlx5_virt_lag_mark_master(struct mlx5_lag *ldev)
+{
+ u64 lowest_tiebreak = U64_MAX;
+ int lowest_dev_idx = INT_MAX;
+ int master_xa_idx = -1;
+ struct lag_func *pf;
+ u64 tiebreak;
+ int dev_idx;
+ int i;
+
+ mlx5_lag_for_each(i, 0, ldev, MLX5_LAG_FILTER_ALL) {
+ pf = mlx5_lag_pf(ldev, i);
+ dev_idx = mlx5_get_dev_index(pf->dev);
+ tiebreak = mlx5_lag_member_tiebreak(pf->dev);
+ if (dev_idx < lowest_dev_idx ||
+ (dev_idx == lowest_dev_idx && tiebreak < lowest_tiebreak)) {
+ lowest_dev_idx = dev_idx;
+ lowest_tiebreak = tiebreak;
+ master_xa_idx = i;
+ }
+ }
+
+ if (master_xa_idx >= 0)
+ xa_set_mark(&ldev->pfs, master_xa_idx, MLX5_LAG_XA_MARK_MASTER);
+}
+
+void mlx5_lag_clear_master(struct mlx5_lag *ldev)
{
unsigned long idx = 0;
void *entry;
@@ -618,7 +655,7 @@ static int mlx5_lag_devcom_event(int event, void *my_data, void *event_data)
int idx;
ldev = mlx5_lag_dev(dev);
- if (!ldev)
+ if (!ldev || ldev->virt_lag)
return 0;
mutex_lock(&ldev->lock);
@@ -1785,10 +1822,13 @@ struct mlx5_devcom_comp_dev *mlx5_lag_get_devcom_comp(struct mlx5_lag *ldev)
{
struct mlx5_devcom_comp_dev *devcom = NULL;
struct lag_func *pf;
+ u32 filter;
int i;
mutex_lock(&ldev->lock);
- i = mlx5_get_next_lag_func(ldev, 0, MLX5_LAG_FILTER_PORTS);
+ filter = ldev->virt_lag ? MLX5_LAG_FILTER_ALL :
+ MLX5_LAG_FILTER_PORTS;
+ i = mlx5_get_next_lag_func(ldev, 0, filter);
if (i < MLX5_MAX_PORTS) {
pf = mlx5_lag_pf(ldev, i);
devcom = pf->dev->priv.hca_devcom_comp;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
index 0ff337983a6d..dff04f40d8f3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
@@ -84,6 +84,7 @@ struct mlx5_lag {
unsigned long state_flags;
u8 ports;
u8 buckets;
+ bool virt_lag;
int mode_changes_in_progress;
u8 *v2p_map;
struct kref ref;
@@ -225,6 +226,8 @@ static inline bool mlx5_lag_shared_fdb_supported(struct mlx5_lag *ldev)
}
#endif
bool mlx5_lag_check_prereq(struct mlx5_lag *ldev);
+void mlx5_virt_lag_mark_master(struct mlx5_lag *ldev);
+void mlx5_lag_clear_master(struct mlx5_lag *ldev);
bool mlx5_lag_is_sd(struct mlx5_core_dev *dev);
int mlx5_lag_demux_init(struct mlx5_core_dev *dev,
struct mlx5_flow_table_attr *ft_attr);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
index abf72026c751..cdaf72cb0595 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
@@ -109,8 +109,8 @@ static bool mlx5_lag_has_sd_group(struct mlx5_lag *ldev)
static int mlx5_lag_enable_mpesw(struct mlx5_lag *ldev)
{
- int idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1);
struct mlx5_core_dev *dev0;
+ int idx;
int err;
if (ldev->mode == MLX5_LAG_MODE_MPESW)
@@ -119,20 +119,32 @@ static int mlx5_lag_enable_mpesw(struct mlx5_lag *ldev)
if (ldev->mode != MLX5_LAG_MODE_NONE)
return -EINVAL;
- if (idx < 0)
- return -EINVAL;
+ /* VFs/SFs (nested LAG) are not marked by the LAG devcom PAIR event;
+ * select the master from the current snapshot before resolving it via
+ * mlx5_lag_get_dev_index_by_seq().
+ */
+ if (ldev->virt_lag)
+ mlx5_virt_lag_mark_master(ldev);
+
+ idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1);
+ if (idx < 0) {
+ err = -EINVAL;
+ goto err_clear_master;
+ }
dev0 = mlx5_lag_pf(ldev, idx)->dev;
if (mlx5_eswitch_mode(dev0) != MLX5_ESWITCH_OFFLOADS ||
!MLX5_CAP_PORT_SELECTION(dev0, port_select_flow_table) ||
!MLX5_CAP_GEN(dev0, create_lag_when_not_master_up) ||
!mlx5_lag_check_prereq(ldev) ||
- !mlx5_lag_shared_fdb_supported_filter(ldev, MLX5_LAG_FILTER_ALL))
- return -EOPNOTSUPP;
+ !mlx5_lag_shared_fdb_supported_filter(ldev, MLX5_LAG_FILTER_ALL)) {
+ err = -EOPNOTSUPP;
+ goto err_clear_master;
+ }
err = mlx5_mpesw_metadata_set(ldev);
if (err)
- return err;
+ goto err_clear_master;
if (mlx5_lag_has_sd_group(ldev))
mlx5_mpesw_teardown_sd_fdb(ldev);
@@ -143,13 +155,19 @@ static int mlx5_lag_enable_mpesw(struct mlx5_lag *ldev)
mlx5_core_warn(dev0,
"Failed to create LAG in MPESW mode (%d)\n",
err);
- if (mlx5_lag_has_sd_group(ldev))
- mlx5_mpesw_restore_sd_fdb(ldev);
- mlx5_mpesw_metadata_cleanup(ldev);
- return err;
+ goto err_restore;
}
return 0;
+
+err_restore:
+ if (mlx5_lag_has_sd_group(ldev))
+ mlx5_mpesw_restore_sd_fdb(ldev);
+ mlx5_mpesw_metadata_cleanup(ldev);
+err_clear_master:
+ if (ldev->virt_lag)
+ mlx5_lag_clear_master(ldev);
+ return err;
}
void mlx5_lag_disable_mpesw(struct mlx5_lag *ldev)
@@ -161,6 +179,10 @@ void mlx5_lag_disable_mpesw(struct mlx5_lag *ldev)
mlx5_lag_shared_fdb_destroy(ldev, MLX5_LAG_FILTER_ALL);
if (mlx5_lag_has_sd_group(ldev))
mlx5_mpesw_restore_sd_fdb(ldev);
+
+ /* Pair with the master mark taken at MPESW create for VFs. */
+ if (ldev->virt_lag)
+ mlx5_lag_clear_master(ldev);
}
void mlx5_mpesw_sd_devcoms_lock(struct mlx5_lag *ldev)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.h b/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.h
index 3ab0449c770c..382162baabdb 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.h
@@ -19,6 +19,13 @@ struct mlx5_sf_dev {
u16 fn_id;
};
+static inline u32 mlx5_sf_coredev_sfnum(struct mlx5_core_dev *mdev)
+{
+ struct auxiliary_device *adev = mlx5_sf_coredev_to_adev(mdev);
+
+ return container_of(adev, struct mlx5_sf_dev, adev)->sfnum;
+}
+
struct mlx5_sf_peer_devlink_event_ctx {
u16 fn_id;
struct devlink *devlink;
@@ -68,6 +75,11 @@ static inline bool mlx5_sf_dev_allocated(const struct mlx5_core_dev *dev)
return false;
}
+static inline u32 mlx5_sf_coredev_sfnum(struct mlx5_core_dev *mdev)
+{
+ return 0;
+}
+
#endif
#endif
--
2.44.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net-next 03/15] net/mlx5: LAG, skip phys LAG prerequisites for a virt LAG
2026-11-03 17:09 [PATCH net-next 00/15] net/mlx5: LAG over VFs/SFs (virtual LAG) Tariq Toukan
2026-11-03 17:09 ` [PATCH net-next 01/15] net/mlx5: Distinguish VFs/SFs in the SW system image GUID for LAG grouping Tariq Toukan
2026-11-03 17:09 ` [PATCH net-next 02/15] net/mlx5: LAG, select the MPESW master from the live member snapshot Tariq Toukan
@ 2026-11-03 17:09 ` Tariq Toukan
2026-11-03 17:09 ` [PATCH net-next 04/15] net/mlx5: LAG, treat virt LAG as a software managed LAG Tariq Toukan
` (11 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tariq Toukan @ 2026-11-03 17:09 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Carolina Jubran, Cosmin Ratiu, Edward Srouji,
Gal Pressman, Leon Romanovsky, open list, linux-rdma, Mark Bloch,
Moshe Shemesh, Or Har-Toov, Patrisious Haddad, Saeed Mahameed,
Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
mlx5_lag_enable_mpesw() gates on port_select_flow_table and
create_lag_when_not_master_up, and on mlx5_lag_check_prereq(). Those
describe the phys LAG: the port-selection flow table and the
physical-LAG prerequisites (e.g. member count equal to the physical port
count).
A LAG of VFs/SFs is a software-only shared-FDB MPESW LAG, so these
checks do not apply and would reject it outright. Require them only when
it is a phys LAG; a LAG of VFs/SFs instead requires port_select_eswitch.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../ethernet/mellanox/mlx5/core/lag/mpesw.c | 31 ++++++++++++++++---
1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
index cdaf72cb0595..b65ad9a26f71 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
@@ -107,9 +107,32 @@ static bool mlx5_lag_has_sd_group(struct mlx5_lag *ldev)
return false;
}
+static bool mlx5_phys_mpesw_validate(struct mlx5_lag *ldev,
+ struct mlx5_core_dev *dev0)
+{
+ if (mlx5_eswitch_mode(dev0) != MLX5_ESWITCH_OFFLOADS ||
+ !MLX5_CAP_PORT_SELECTION(dev0, port_select_flow_table) ||
+ !MLX5_CAP_GEN(dev0, create_lag_when_not_master_up) ||
+ !mlx5_lag_check_prereq(ldev) ||
+ !mlx5_lag_shared_fdb_supported_filter(ldev, MLX5_LAG_FILTER_ALL))
+ return false;
+ return true;
+}
+
+static bool mlx5_virt_mpesw_validate(struct mlx5_lag *ldev,
+ struct mlx5_core_dev *dev0)
+{
+ if (mlx5_eswitch_mode(dev0) != MLX5_ESWITCH_OFFLOADS ||
+ !MLX5_CAP_PORT_SELECTION(dev0, port_select_eswitch) ||
+ !mlx5_lag_shared_fdb_supported_filter(ldev, MLX5_LAG_FILTER_ALL))
+ return false;
+ return true;
+}
+
static int mlx5_lag_enable_mpesw(struct mlx5_lag *ldev)
{
struct mlx5_core_dev *dev0;
+ bool valid;
int idx;
int err;
@@ -133,11 +156,9 @@ static int mlx5_lag_enable_mpesw(struct mlx5_lag *ldev)
}
dev0 = mlx5_lag_pf(ldev, idx)->dev;
- if (mlx5_eswitch_mode(dev0) != MLX5_ESWITCH_OFFLOADS ||
- !MLX5_CAP_PORT_SELECTION(dev0, port_select_flow_table) ||
- !MLX5_CAP_GEN(dev0, create_lag_when_not_master_up) ||
- !mlx5_lag_check_prereq(ldev) ||
- !mlx5_lag_shared_fdb_supported_filter(ldev, MLX5_LAG_FILTER_ALL)) {
+ valid = ldev->virt_lag ? mlx5_virt_mpesw_validate(ldev, dev0) :
+ mlx5_phys_mpesw_validate(ldev, dev0);
+ if (!valid) {
err = -EOPNOTSUPP;
goto err_clear_master;
}
--
2.44.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net-next 04/15] net/mlx5: LAG, treat virt LAG as a software managed LAG
2026-11-03 17:09 [PATCH net-next 00/15] net/mlx5: LAG over VFs/SFs (virtual LAG) Tariq Toukan
` (2 preceding siblings ...)
2026-11-03 17:09 ` [PATCH net-next 03/15] net/mlx5: LAG, skip phys LAG prerequisites for a virt LAG Tariq Toukan
@ 2026-11-03 17:09 ` Tariq Toukan
2026-11-03 17:09 ` [PATCH net-next 05/15] net/mlx5: LAG, decouple iteration end-of-walk from MLX5_MAX_PORTS Tariq Toukan
` (10 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tariq Toukan @ 2026-11-03 17:09 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Carolina Jubran, Cosmin Ratiu, Edward Srouji,
Gal Pressman, Leon Romanovsky, open list, linux-rdma, Mark Bloch,
Moshe Shemesh, Or Har-Toov, Patrisious Haddad, Saeed Mahameed,
Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
mlx5_lag_is_sw_managed() (renamed from mlx5_lag_is_sw_lag()) marks the
LAG paths the driver builds in software - the LAG demux and vport-LAG -
which must skip the FW vport-LAG commands. A virt LAG is
software-managed like an SD LAG.
In the same manner, block multipath LAG over virt LAG as well.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c | 12 +++++++-----
drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h | 1 +
drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c | 4 ++--
3 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
index 46f125d24f15..b2ac5c671ae6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
@@ -173,9 +173,11 @@ static u32 mlx5_lag_dev_group_id(struct mlx5_core_dev *dev)
return 0;
}
-static int mlx5_lag_is_sw_lag(struct mlx5_core_dev *dev)
+bool mlx5_lag_is_sw_managed(struct mlx5_core_dev *dev)
{
- return mlx5_lag_is_sd(dev);
+ struct mlx5_lag *ldev = mlx5_lag_dev(dev);
+
+ return mlx5_lag_is_sd(dev) || (ldev && ldev->virt_lag);
}
int mlx5_cmd_create_vport_lag(struct mlx5_core_dev *dev)
@@ -184,7 +186,7 @@ int mlx5_cmd_create_vport_lag(struct mlx5_core_dev *dev)
struct mlx5_lag *ldev = mlx5_lag_dev(dev);
int ret;
- if (mlx5_lag_is_sw_lag(dev)) {
+ if (mlx5_lag_is_sw_managed(dev)) {
if (!ldev)
return -ENODEV;
@@ -206,7 +208,7 @@ int mlx5_cmd_destroy_vport_lag(struct mlx5_core_dev *dev)
u32 in[MLX5_ST_SZ_DW(destroy_vport_lag_in)] = {};
struct mlx5_lag *ldev = mlx5_lag_dev(dev);
- if (mlx5_lag_is_sw_lag(dev)) {
+ if (mlx5_lag_is_sw_managed(dev)) {
if (!ldev)
return 0;
@@ -1912,7 +1914,7 @@ int mlx5_lag_demux_init(struct mlx5_core_dev *dev,
xa_init(&pf->lag_demux_rules);
- if (mlx5_lag_is_sw_lag(dev))
+ if (mlx5_lag_is_sw_managed(dev))
return mlx5_lag_demux_ft_fg_init(dev, ft_attr, pf);
return mlx5_lag_demux_fw_init(dev, ft_attr, pf);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
index dff04f40d8f3..872cc769297c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
@@ -229,6 +229,7 @@ bool mlx5_lag_check_prereq(struct mlx5_lag *ldev);
void mlx5_virt_lag_mark_master(struct mlx5_lag *ldev);
void mlx5_lag_clear_master(struct mlx5_lag *ldev);
bool mlx5_lag_is_sd(struct mlx5_core_dev *dev);
+bool mlx5_lag_is_sw_managed(struct mlx5_core_dev *dev);
int mlx5_lag_demux_init(struct mlx5_core_dev *dev,
struct mlx5_flow_table_attr *ft_attr);
void mlx5_lag_demux_cleanup(struct mlx5_core_dev *dev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c
index 65c76bd748c6..2077fc5d80c7 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c
@@ -26,8 +26,8 @@ static bool mlx5_lag_multipath_check_prereq(struct mlx5_lag *ldev)
if (__mlx5_lag_is_active(ldev) && !__mlx5_lag_is_multipath(ldev))
return false;
- if (__mlx5_lag_is_sd(ldev, mlx5_lag_pf(ldev, idx0)->dev) ||
- __mlx5_lag_is_sd(ldev, mlx5_lag_pf(ldev, idx1)->dev))
+ if (mlx5_lag_is_sw_managed(mlx5_lag_pf(ldev, idx0)->dev) ||
+ mlx5_lag_is_sw_managed(mlx5_lag_pf(ldev, idx1)->dev))
return false;
if (ldev->ports > MLX5_LAG_MULTIPATH_OFFLOADS_SUPPORTED_PORTS)
--
2.44.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net-next 05/15] net/mlx5: LAG, decouple iteration end-of-walk from MLX5_MAX_PORTS
2026-11-03 17:09 [PATCH net-next 00/15] net/mlx5: LAG over VFs/SFs (virtual LAG) Tariq Toukan
` (3 preceding siblings ...)
2026-11-03 17:09 ` [PATCH net-next 04/15] net/mlx5: LAG, treat virt LAG as a software managed LAG Tariq Toukan
@ 2026-11-03 17:09 ` Tariq Toukan
2026-11-03 17:10 ` [PATCH net-next 06/15] net/mlx5: LAG, rename PF naming to fn Tariq Toukan
` (9 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tariq Toukan @ 2026-11-03 17:09 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Carolina Jubran, Cosmin Ratiu, Edward Srouji,
Gal Pressman, Leon Romanovsky, open list, linux-rdma, Mark Bloch,
Moshe Shemesh, Or Har-Toov, Patrisious Haddad, Saeed Mahameed,
Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
The LAG xarray iterators returned MLX5_MAX_PORTS as their end-of-walk
sentinel, and the open-coded callers compared the current index against
MLX5_MAX_PORTS to detect the end of iteration. This ties iteration to a
compile-time maximum rather than to the actual number of LAG members.
Add ldev->max_funcs, and use it as the loop bound. Update the open-coded
callers accordingly. When a member is added at an xarray index >=
ldev->max_funcs, increase max_funcs.
In addition, remove the xa_alloc() limit of MLX5_MAX_PORTS.
No functional change; this only removes the dependency on
MLX5_MAX_PORTS.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../net/ethernet/mellanox/mlx5/core/lag/lag.c | 22 +++++++++++--------
.../net/ethernet/mellanox/mlx5/core/lag/lag.h | 3 ++-
.../ethernet/mellanox/mlx5/core/lag/mpesw.c | 2 +-
.../mellanox/mlx5/core/lag/shared_fdb.c | 2 +-
4 files changed, 17 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
index b2ac5c671ae6..73bce918cddb 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
@@ -395,6 +395,7 @@ static struct mlx5_lag *mlx5_lag_dev_alloc(struct mlx5_core_dev *dev)
mlx5_core_err(dev, "Failed to init multipath lag err=%d\n",
err);
+ ldev->max_funcs = ldev->ports;
return ldev;
err_wq:
@@ -1284,7 +1285,7 @@ static void mlx5_lag_assert_locked_transition(struct mlx5_lag *ldev, u32 filter)
lockdep_assert_held(&ldev->lock);
i = mlx5_get_next_lag_func(ldev, 0, filter);
- if (i < MLX5_MAX_PORTS) {
+ if (i < ldev->max_funcs) {
pf = mlx5_lag_pf(ldev, i);
if (filter == MLX5_LAG_FILTER_PORTS ||
filter == MLX5_LAG_FILTER_ALL)
@@ -1831,7 +1832,7 @@ struct mlx5_devcom_comp_dev *mlx5_lag_get_devcom_comp(struct mlx5_lag *ldev)
filter = ldev->virt_lag ? MLX5_LAG_FILTER_ALL :
MLX5_LAG_FILTER_PORTS;
i = mlx5_get_next_lag_func(ldev, 0, filter);
- if (i < MLX5_MAX_PORTS) {
+ if (i < ldev->max_funcs) {
pf = mlx5_lag_pf(ldev, i);
devcom = pf->dev->priv.hca_devcom_comp;
}
@@ -2095,7 +2096,7 @@ static int mlx5_handle_changeupper_event(struct mlx5_lag *ldev,
break;
}
}
- if (i < MLX5_MAX_PORTS) {
+ if (i < ldev->ports) {
if (netif_is_bond_master(upper)) {
slave = bond_slave_get_rcu(ndev_tmp);
if (slave)
@@ -2360,13 +2361,16 @@ int mlx5_ldev_add_mdev(struct mlx5_lag *ldev,
if (!pf)
return -ENOMEM;
- err = xa_alloc(&ldev->pfs, &idx, pf, XA_LIMIT(0, MLX5_MAX_PORTS - 1),
+ err = xa_alloc(&ldev->pfs, &idx, pf, XA_LIMIT(0, U8_MAX - 1),
GFP_KERNEL);
if (err) {
kfree(pf);
return err;
}
+ /* max_funcs is the iteration ceiling; grow it, never shrink. */
+ if (idx >= ldev->max_funcs)
+ ldev->max_funcs = idx + 1;
pf->idx = idx;
pf->dev = dev;
pf->group_id = group_id;
@@ -2395,7 +2399,7 @@ void mlx5_ldev_remove_mdev(struct mlx5_lag *ldev,
if (pf->dev == dev)
break;
}
- if (i >= MLX5_MAX_PORTS)
+ if (i >= ldev->max_funcs)
return;
if (pf->port_change_nb.nb.notifier_call)
@@ -2608,7 +2612,7 @@ int mlx5_get_next_lag_func(struct mlx5_lag *ldev, int start_idx, u32 filter)
MLX5_LAG_XA_MARK_PORT, start_idx)
if (pf->dev)
return idx;
- return MLX5_MAX_PORTS;
+ return ldev->max_funcs;
}
xa_for_each_start(&ldev->pfs, idx, pf, start_idx) {
@@ -2618,7 +2622,7 @@ int mlx5_get_next_lag_func(struct mlx5_lag *ldev, int start_idx, u32 filter)
filter == pf->group_id)
return idx;
}
- return MLX5_MAX_PORTS;
+ return ldev->max_funcs;
}
bool mlx5_lag_is_roce(struct mlx5_core_dev *dev)
@@ -2868,7 +2872,7 @@ struct mlx5_core_dev *mlx5_lag_get_next_peer_mdev(struct mlx5_core_dev *dev, int
if (!ldev)
goto unlock;
- if (*i == MLX5_MAX_PORTS)
+ if (*i == ldev->max_funcs)
goto unlock;
mlx5_lag_for_each(idx, *i, ldev, mlx5_lag_get_filter(ldev, dev)) {
pf = mlx5_lag_pf(ldev, idx);
@@ -2876,7 +2880,7 @@ struct mlx5_core_dev *mlx5_lag_get_next_peer_mdev(struct mlx5_core_dev *dev, int
break;
}
- if (idx == MLX5_MAX_PORTS) {
+ if (idx == ldev->max_funcs) {
*i = idx;
goto unlock;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
index 872cc769297c..479d9f42ff3f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
@@ -83,6 +83,7 @@ struct mlx5_lag {
unsigned long mode_flags;
unsigned long state_flags;
u8 ports;
+ u8 max_funcs;
u8 buckets;
bool virt_lag;
int mode_changes_in_progress;
@@ -298,7 +299,7 @@ static inline bool mlx5_lag_is_supported(struct mlx5_core_dev *dev)
#define mlx5_lag_for_each(i, start_index, ldev, filter) \
for (int tmp = start_index; \
tmp = mlx5_get_next_lag_func(ldev, tmp, filter), \
- i = tmp, tmp < MLX5_MAX_PORTS; tmp++)
+ i = tmp, tmp < (ldev)->max_funcs; tmp++)
#define mlx5_lag_for_each_reverse(i, start_index, end_index, ldev, filter) \
for (int tmp = start_index, tmp1 = end_index; \
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
index b65ad9a26f71..56faa1d498c7 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
@@ -223,7 +223,7 @@ void mlx5_mpesw_sd_devcoms_unlock(struct mlx5_lag *ldev)
struct mlx5_devcom_comp_dev *sd_devcom;
int i;
- mlx5_ldev_for_each_reverse(i, MLX5_MAX_PORTS, 0, ldev) {
+ mlx5_ldev_for_each_reverse(i, ldev->max_funcs, 0, ldev) {
sd_devcom = mlx5_sd_get_devcom(mlx5_lag_pf(ldev, i)->dev);
if (sd_devcom)
mlx5_devcom_comp_unlock(sd_devcom);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c
index 7c7e6c832a93..29048b0c2797 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c
@@ -71,7 +71,7 @@ static int mlx5_lag_create_single_fdb_filter(struct mlx5_lag *ldev, u32 filter)
err = mlx5_eswitch_offloads_single_fdb_add_one(master_esw,
slave_esw,
- ldev->ports);
+ ldev->max_funcs);
if (err)
goto err;
}
--
2.44.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net-next 06/15] net/mlx5: LAG, rename PF naming to fn
2026-11-03 17:09 [PATCH net-next 00/15] net/mlx5: LAG over VFs/SFs (virtual LAG) Tariq Toukan
` (4 preceding siblings ...)
2026-11-03 17:09 ` [PATCH net-next 05/15] net/mlx5: LAG, decouple iteration end-of-walk from MLX5_MAX_PORTS Tariq Toukan
@ 2026-11-03 17:10 ` Tariq Toukan
2026-11-03 17:10 ` [PATCH net-next 07/15] net/mlx5: LAG, resolve affinity indices only in queue-affinity mode Tariq Toukan
` (8 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tariq Toukan @ 2026-11-03 17:10 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Carolina Jubran, Cosmin Ratiu, Edward Srouji,
Gal Pressman, Leon Romanovsky, open list, linux-rdma, Mark Bloch,
Moshe Shemesh, Or Har-Toov, Patrisious Haddad, Saeed Mahameed,
Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
The LAG member bookkeeping is named after physical functions: the xarray
is ldev->pfs, the lookup helpers are mlx5_lag_pf(),
mlx5_lag_pf_by_dev(), mlx5_lag_pf_by_dev_idx() and
mlx5_lag_dev_get_master_pf(), and the local variables holding the result
are pf.
A later patch enables virt LAG, which means LAG members won't always be
physical functions.
Rename the xarray to ldev->fns, the helpers to mlx5_lag_fn*(), and the
locals to fn, so the naming matches struct lag_fn.
No functional change.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../ethernet/mellanox/mlx5/core/lag/debugfs.c | 2 +-
.../net/ethernet/mellanox/mlx5/core/lag/lag.c | 472 +++++++++---------
.../net/ethernet/mellanox/mlx5/core/lag/lag.h | 54 +-
.../net/ethernet/mellanox/mlx5/core/lag/mp.c | 29 +-
.../ethernet/mellanox/mlx5/core/lag/mpesw.c | 42 +-
.../mellanox/mlx5/core/lag/port_sel.c | 25 +-
.../mellanox/mlx5/core/lag/shared_fdb.c | 44 +-
.../net/ethernet/mellanox/mlx5/core/lib/sd.c | 32 +-
8 files changed, 354 insertions(+), 346 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
index b6125c7bd91b..116432cb7ce5 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
@@ -154,7 +154,7 @@ static int members_show(struct seq_file *file, void *priv)
mutex_lock(&ldev->lock);
mlx5_ldev_for_each(i, 0, ldev)
seq_printf(file, "%s\n",
- dev_name(mlx5_lag_pf(ldev, i)->dev->device));
+ dev_name(mlx5_lag_fn(ldev, i)->dev->device));
mutex_unlock(&ldev->lock);
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
index 73bce918cddb..1b065033a2a1 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
@@ -159,16 +159,16 @@ static int mlx5_cmd_modify_lag(struct mlx5_core_dev *dev, struct mlx5_lag *ldev,
static u32 mlx5_lag_dev_group_id(struct mlx5_core_dev *dev)
{
struct mlx5_lag *ldev = mlx5_lag_dev(dev);
- struct lag_func *pf;
+ struct lag_fn *fn;
int i;
if (!ldev)
return 0;
mlx5_lag_for_each(i, 0, ldev, MLX5_LAG_FILTER_ALL) {
- pf = mlx5_lag_pf(ldev, i);
- if (pf->dev == dev)
- return pf->sd_fdb_active ? pf->group_id : 0;
+ fn = mlx5_lag_fn(ldev, i);
+ if (fn->dev == dev)
+ return fn->sd_fdb_active ? fn->group_id : 0;
}
return 0;
}
@@ -313,7 +313,7 @@ static void mlx5_do_bond_work(struct work_struct *work);
static void mlx5_ldev_free(struct kref *ref)
{
struct mlx5_lag *ldev = container_of(ref, struct mlx5_lag, ref);
- struct lag_func *pf;
+ struct lag_fn *fn;
struct net *net;
int i;
@@ -323,16 +323,16 @@ static void mlx5_ldev_free(struct kref *ref)
}
mlx5_lag_for_each(i, 0, ldev, MLX5_LAG_FILTER_ALL) {
- pf = mlx5_lag_pf(ldev, i);
- if (pf->port_change_nb.nb.notifier_call) {
- struct mlx5_nb *nb = &pf->port_change_nb;
+ fn = mlx5_lag_fn(ldev, i);
+ if (fn->port_change_nb.nb.notifier_call) {
+ struct mlx5_nb *nb = &fn->port_change_nb;
- mlx5_eq_notifier_unregister(pf->dev, nb);
+ mlx5_eq_notifier_unregister(fn->dev, nb);
}
- xa_erase(&ldev->pfs, i);
- kfree(pf);
+ xa_erase(&ldev->fns, i);
+ kfree(fn);
}
- xa_destroy(&ldev->pfs);
+ xa_destroy(&ldev->fns);
mlx5_lag_mp_cleanup(ldev);
cancel_delayed_work_sync(&ldev->bond_work);
@@ -375,7 +375,7 @@ static struct mlx5_lag *mlx5_lag_dev_alloc(struct mlx5_core_dev *dev)
kref_init(&ldev->ref);
mutex_init(&ldev->lock);
- xa_init_flags(&ldev->pfs, XA_FLAGS_ALLOC);
+ xa_init_flags(&ldev->fns, XA_FLAGS_ALLOC);
INIT_DELAYED_WORK(&ldev->bond_work, mlx5_do_bond_work);
INIT_WORK(&ldev->speed_update_work, mlx5_mpesw_speed_update_work);
@@ -395,7 +395,7 @@ static struct mlx5_lag *mlx5_lag_dev_alloc(struct mlx5_core_dev *dev)
mlx5_core_err(dev, "Failed to init multipath lag err=%d\n",
err);
- ldev->max_funcs = ldev->ports;
+ ldev->max_fns = ldev->ports;
return ldev;
err_wq:
@@ -408,12 +408,12 @@ static struct mlx5_lag *mlx5_lag_dev_alloc(struct mlx5_core_dev *dev)
int mlx5_lag_dev_get_netdev_idx(struct mlx5_lag *ldev,
struct net_device *ndev)
{
- struct lag_func *pf;
+ struct lag_fn *fn;
int i;
mlx5_ldev_for_each(i, 0, ldev) {
- pf = mlx5_lag_pf(ldev, i);
- if (pf->netdev == ndev)
+ fn = mlx5_lag_fn(ldev, i);
+ if (fn->netdev == ndev)
return i;
}
@@ -428,7 +428,7 @@ static int mlx5_lag_get_master_idx(struct mlx5_lag *ldev)
if (!ldev)
return -ENOENT;
- entry = xa_find(&ldev->pfs, &idx, U8_MAX, MLX5_LAG_XA_MARK_MASTER);
+ entry = xa_find(&ldev->fns, &idx, U8_MAX, MLX5_LAG_XA_MARK_MASTER);
if (!entry)
return -ENOENT;
@@ -470,11 +470,11 @@ int mlx5_lag_get_dev_index_by_seq(struct mlx5_lag *ldev, int seq)
*/
static u32 mlx5_lag_get_filter(struct mlx5_lag *ldev, struct mlx5_core_dev *dev)
{
- struct lag_func *pf = mlx5_lag_pf_by_dev(ldev, dev);
+ struct lag_fn *fn = mlx5_lag_fn_by_dev(ldev, dev);
- if (pf && pf->sd_fdb_active)
- return pf->group_id;
- if (pf && pf->group_id)
+ if (fn && fn->sd_fdb_active)
+ return fn->group_id;
+ if (fn && fn->group_id)
return MLX5_LAG_FILTER_ALL;
return MLX5_LAG_FILTER_PORTS;
}
@@ -487,7 +487,7 @@ int mlx5_lag_get_dev_seq(struct mlx5_core_dev *dev)
{
struct mlx5_lag *ldev = mlx5_lag_dev(dev);
int master_idx, i, num = 1;
- struct lag_func *pf;
+ struct lag_fn *fn;
u32 filter;
if (!ldev)
@@ -498,15 +498,15 @@ int mlx5_lag_get_dev_seq(struct mlx5_core_dev *dev)
if (master_idx < 0)
return -ENOENT;
- pf = mlx5_lag_pf(ldev, master_idx);
- if (pf && pf->dev == dev)
+ fn = mlx5_lag_fn(ldev, master_idx);
+ if (fn && fn->dev == dev)
return 0;
mlx5_lag_for_each(i, 0, ldev, filter) {
if (i == master_idx)
continue;
- pf = mlx5_lag_pf(ldev, i);
- if (pf->dev == dev)
+ fn = mlx5_lag_fn(ldev, i);
+ if (fn->dev == dev)
return num;
num++;
}
@@ -544,7 +544,7 @@ static int mlx5_lag_get_dev_index_by_seq_group(struct mlx5_lag *ldev, int seq,
int i, num = 0;
mlx5_lag_for_each(i, 0, ldev, group_id) {
- if (xa_get_mark(&ldev->pfs, i, MLX5_LAG_XA_MARK_PORT)) {
+ if (xa_get_mark(&ldev->fns, i, MLX5_LAG_XA_MARK_PORT)) {
if (seq == 0)
return i;
num++;
@@ -553,7 +553,7 @@ static int mlx5_lag_get_dev_index_by_seq_group(struct mlx5_lag *ldev, int seq,
}
mlx5_lag_for_each(i, 0, ldev, group_id) {
- if (xa_get_mark(&ldev->pfs, i, MLX5_LAG_XA_MARK_PORT))
+ if (xa_get_mark(&ldev->fns, i, MLX5_LAG_XA_MARK_PORT))
continue;
if (num == seq)
return i;
@@ -584,14 +584,14 @@ int mlx5_lag_get_dev_index_by_seq_filter(struct mlx5_lag *ldev, int seq,
static void mlx5_lag_mark_master(struct mlx5_lag *ldev)
{
int lowest_dev_idx = INT_MAX;
- struct lag_func *pf;
+ struct lag_fn *fn;
int master_xa_idx = -1;
int dev_idx;
int i;
mlx5_ldev_for_each(i, 0, ldev) {
- pf = mlx5_lag_pf(ldev, i);
- dev_idx = mlx5_get_dev_index(pf->dev);
+ fn = mlx5_lag_fn(ldev, i);
+ dev_idx = mlx5_get_dev_index(fn->dev);
if (dev_idx < lowest_dev_idx) {
lowest_dev_idx = dev_idx;
master_xa_idx = i;
@@ -599,7 +599,7 @@ static void mlx5_lag_mark_master(struct mlx5_lag *ldev)
}
if (master_xa_idx >= 0)
- xa_set_mark(&ldev->pfs, master_xa_idx, MLX5_LAG_XA_MARK_MASTER);
+ xa_set_mark(&ldev->fns, master_xa_idx, MLX5_LAG_XA_MARK_MASTER);
}
static u64 mlx5_lag_member_tiebreak(struct mlx5_core_dev *dev)
@@ -617,15 +617,15 @@ void mlx5_virt_lag_mark_master(struct mlx5_lag *ldev)
u64 lowest_tiebreak = U64_MAX;
int lowest_dev_idx = INT_MAX;
int master_xa_idx = -1;
- struct lag_func *pf;
+ struct lag_fn *fn;
u64 tiebreak;
int dev_idx;
int i;
mlx5_lag_for_each(i, 0, ldev, MLX5_LAG_FILTER_ALL) {
- pf = mlx5_lag_pf(ldev, i);
- dev_idx = mlx5_get_dev_index(pf->dev);
- tiebreak = mlx5_lag_member_tiebreak(pf->dev);
+ fn = mlx5_lag_fn(ldev, i);
+ dev_idx = mlx5_get_dev_index(fn->dev);
+ tiebreak = mlx5_lag_member_tiebreak(fn->dev);
if (dev_idx < lowest_dev_idx ||
(dev_idx == lowest_dev_idx && tiebreak < lowest_tiebreak)) {
lowest_dev_idx = dev_idx;
@@ -635,7 +635,7 @@ void mlx5_virt_lag_mark_master(struct mlx5_lag *ldev)
}
if (master_xa_idx >= 0)
- xa_set_mark(&ldev->pfs, master_xa_idx, MLX5_LAG_XA_MARK_MASTER);
+ xa_set_mark(&ldev->fns, master_xa_idx, MLX5_LAG_XA_MARK_MASTER);
}
void mlx5_lag_clear_master(struct mlx5_lag *ldev)
@@ -643,11 +643,11 @@ void mlx5_lag_clear_master(struct mlx5_lag *ldev)
unsigned long idx = 0;
void *entry;
- entry = xa_find(&ldev->pfs, &idx, U8_MAX, MLX5_LAG_XA_MARK_MASTER);
+ entry = xa_find(&ldev->fns, &idx, U8_MAX, MLX5_LAG_XA_MARK_MASTER);
if (!entry)
return;
- xa_clear_mark(&ldev->pfs, idx, MLX5_LAG_XA_MARK_MASTER);
+ xa_clear_mark(&ldev->fns, idx, MLX5_LAG_XA_MARK_MASTER);
}
/* Devcom event handler to manage LAG master marking */
@@ -698,15 +698,15 @@ int mlx5_lag_num_devs(struct mlx5_lag *ldev)
int mlx5_lag_num_netdevs(struct mlx5_lag *ldev)
{
- struct lag_func *pf;
+ struct lag_fn *fn;
int i, num = 0;
if (!ldev)
return 0;
mlx5_ldev_for_each(i, 0, ldev) {
- pf = mlx5_lag_pf(ldev, i);
- if (pf->netdev)
+ fn = mlx5_lag_fn(ldev, i);
+ if (fn->netdev)
num++;
}
return num;
@@ -725,9 +725,9 @@ static bool __mlx5_lag_is_sriov(struct mlx5_lag *ldev)
static bool __mlx5_lag_is_sd_active(struct mlx5_lag *ldev,
struct mlx5_core_dev *dev)
{
- struct lag_func *pf = mlx5_lag_pf_by_dev(ldev, dev);
+ struct lag_fn *fn = mlx5_lag_fn_by_dev(ldev, dev);
- return pf && pf->sd_fdb_active;
+ return fn && fn->sd_fdb_active;
}
/* Create a mapping between steering slots and active ports.
@@ -802,12 +802,12 @@ static int mlx5_infer_tx_affinity_mapping(struct lag_tracker *tracker,
static bool mlx5_lag_has_drop_rule(struct mlx5_lag *ldev)
{
- struct lag_func *pf;
+ struct lag_fn *fn;
int i;
mlx5_ldev_for_each(i, 0, ldev) {
- pf = mlx5_lag_pf(ldev, i);
- if (pf->has_drop)
+ fn = mlx5_lag_fn(ldev, i);
+ if (fn->has_drop)
return true;
}
return false;
@@ -815,17 +815,19 @@ static bool mlx5_lag_has_drop_rule(struct mlx5_lag *ldev)
static void mlx5_lag_drop_rule_cleanup(struct mlx5_lag *ldev)
{
- struct lag_func *pf;
+ struct mlx5_eswitch *esw;
+ struct lag_fn *fn;
int i;
mlx5_ldev_for_each(i, 0, ldev) {
- pf = mlx5_lag_pf(ldev, i);
- if (!pf->has_drop)
+ fn = mlx5_lag_fn(ldev, i);
+ if (!fn->has_drop)
continue;
- mlx5_esw_acl_ingress_vport_drop_rule_destroy(pf->dev->priv.eswitch,
+ esw = fn->dev->priv.eswitch;
+ mlx5_esw_acl_ingress_vport_drop_rule_destroy(esw,
MLX5_VPORT_UPLINK);
- pf->has_drop = false;
+ fn->has_drop = false;
}
}
@@ -833,7 +835,7 @@ static void mlx5_lag_drop_rule_setup(struct mlx5_lag *ldev,
struct lag_tracker *tracker)
{
struct mlx5_core_dev *dev;
- struct lag_func *pf;
+ struct lag_fn *fn;
int err;
int i;
@@ -849,12 +851,12 @@ static void mlx5_lag_drop_rule_setup(struct mlx5_lag *ldev,
if (tracker->netdev_state[i].tx_enabled &&
tracker->netdev_state[i].link_up)
continue;
- pf = mlx5_lag_pf(ldev, i);
- dev = pf->dev;
+ fn = mlx5_lag_fn(ldev, i);
+ dev = fn->dev;
err = mlx5_esw_acl_ingress_vport_drop_rule_create(dev->priv.eswitch,
MLX5_VPORT_UPLINK);
if (!err)
- pf->has_drop = true;
+ fn->has_drop = true;
else
mlx5_core_err(dev,
"Failed to create lag drop rule, error: %d",
@@ -888,7 +890,7 @@ static int _mlx5_modify_lag(struct mlx5_lag *ldev,
if (idx < 0)
return -EINVAL;
- dev0 = mlx5_lag_pf(ldev, idx)->dev;
+ dev0 = mlx5_lag_fn(ldev, idx)->dev;
if (test_bit(MLX5_LAG_MODE_FLAG_HASH_BASED, &ldev->mode_flags)) {
ret = mlx5_lag_port_sel_modify(ldev, ports);
if (ret ||
@@ -908,7 +910,7 @@ static int _mlx5_modify_lag(struct mlx5_lag *ldev,
static struct net_device *mlx5_lag_active_backup_get_netdev(struct mlx5_core_dev *dev)
{
struct net_device *ndev = NULL;
- struct lag_func *pf;
+ struct lag_fn *fn;
struct mlx5_lag *ldev;
unsigned long flags;
int i, last_idx;
@@ -920,16 +922,16 @@ static struct net_device *mlx5_lag_active_backup_get_netdev(struct mlx5_core_dev
goto unlock;
mlx5_ldev_for_each(i, 0, ldev) {
- pf = mlx5_lag_pf(ldev, i);
+ fn = mlx5_lag_fn(ldev, i);
if (ldev->tracker.netdev_state[i].tx_enabled)
- ndev = pf->netdev;
+ ndev = fn->netdev;
}
if (!ndev) {
last_idx = mlx5_lag_get_dev_index_by_seq(ldev, ldev->ports - 1);
if (last_idx < 0)
goto unlock;
- pf = mlx5_lag_pf(ldev, last_idx);
- ndev = pf->netdev;
+ fn = mlx5_lag_fn(ldev, last_idx);
+ ndev = fn->netdev;
}
dev_hold(ndev);
@@ -954,7 +956,7 @@ void mlx5_modify_lag(struct mlx5_lag *ldev,
if (first_idx < 0)
return;
- dev0 = mlx5_lag_pf(ldev, first_idx)->dev;
+ dev0 = mlx5_lag_fn(ldev, first_idx)->dev;
ports = kcalloc(ldev->ports * MLX5_LAG_MAX_HASH_BUCKETS,
sizeof(*ports), GFP_KERNEL);
@@ -1022,7 +1024,7 @@ static int mlx5_lag_set_port_sel_mode(struct mlx5_lag *ldev,
mode == MLX5_LAG_MODE_MULTIPATH)
return 0;
- dev0 = mlx5_lag_pf(ldev, first_idx)->dev;
+ dev0 = mlx5_lag_fn(ldev, first_idx)->dev;
if (!MLX5_CAP_PORT_SELECTION(dev0, port_select_flow_table)) {
if (ldev->ports > 2)
@@ -1080,7 +1082,7 @@ static int mlx5_create_lag(struct mlx5_lag *ldev,
if (first_idx < 0)
return -EINVAL;
- dev0 = mlx5_lag_pf(ldev, first_idx)->dev;
+ dev0 = mlx5_lag_fn(ldev, first_idx)->dev;
if (tracker)
mlx5_lag_print_mapping(dev0, ldev, tracker, flags);
mlx5_core_info(dev0, "shared_fdb:%d mode:%s\n",
@@ -1128,7 +1130,7 @@ int mlx5_activate_lag(struct mlx5_lag *ldev,
if (master_idx < 0)
return -EINVAL;
- dev0 = mlx5_lag_pf(ldev, master_idx)->dev;
+ dev0 = mlx5_lag_fn(ldev, master_idx)->dev;
err = mlx5_lag_set_flags(ldev, mode, tracker, shared_fdb, &flags);
if (err)
return err;
@@ -1191,7 +1193,7 @@ int mlx5_deactivate_lag(struct mlx5_lag *ldev)
if (master_idx < 0)
return -EINVAL;
- dev0 = mlx5_lag_pf(ldev, master_idx)->dev;
+ dev0 = mlx5_lag_fn(ldev, master_idx)->dev;
ldev->mode = MLX5_LAG_MODE_NONE;
ldev->mode_flags = 0;
mlx5_lag_mp_reset(ldev);
@@ -1232,7 +1234,7 @@ bool mlx5_lag_check_prereq(struct mlx5_lag *ldev)
struct mlx5_core_dev *dev;
u8 mode;
#endif
- struct lag_func *pf;
+ struct lag_fn *fn;
bool roce_support;
int i;
@@ -1241,35 +1243,35 @@ bool mlx5_lag_check_prereq(struct mlx5_lag *ldev)
#ifdef CONFIG_MLX5_ESWITCH
mlx5_ldev_for_each(i, 0, ldev) {
- pf = mlx5_lag_pf(ldev, i);
- dev = pf->dev;
+ fn = mlx5_lag_fn(ldev, i);
+ dev = fn->dev;
if (mlx5_eswitch_num_vfs(dev->priv.eswitch) && !is_mdev_switchdev_mode(dev))
return false;
}
- pf = mlx5_lag_pf(ldev, master_idx);
- dev = pf->dev;
+ fn = mlx5_lag_fn(ldev, master_idx);
+ dev = fn->dev;
mode = mlx5_eswitch_mode(dev);
mlx5_ldev_for_each(i, 0, ldev) {
- pf = mlx5_lag_pf(ldev, i);
- if (mlx5_eswitch_mode(pf->dev) != mode)
+ fn = mlx5_lag_fn(ldev, i);
+ if (mlx5_eswitch_mode(fn->dev) != mode)
return false;
}
#else
mlx5_ldev_for_each(i, 0, ldev) {
- pf = mlx5_lag_pf(ldev, i);
- if (mlx5_sriov_is_enabled(pf->dev))
+ fn = mlx5_lag_fn(ldev, i);
+ if (mlx5_sriov_is_enabled(fn->dev))
return false;
}
#endif
- pf = mlx5_lag_pf(ldev, master_idx);
- roce_support = mlx5_get_roce_state(pf->dev);
+ fn = mlx5_lag_fn(ldev, master_idx);
+ roce_support = mlx5_get_roce_state(fn->dev);
mlx5_ldev_for_each(i, 0, ldev) {
if (i == master_idx)
continue;
- pf = mlx5_lag_pf(ldev, i);
- if (mlx5_get_roce_state(pf->dev) != roce_support)
+ fn = mlx5_lag_fn(ldev, i);
+ if (mlx5_get_roce_state(fn->dev) != roce_support)
return false;
}
@@ -1279,19 +1281,19 @@ bool mlx5_lag_check_prereq(struct mlx5_lag *ldev)
static void mlx5_lag_assert_locked_transition(struct mlx5_lag *ldev, u32 filter)
{
struct mlx5_devcom_comp_dev *devcom = NULL;
- struct lag_func *pf;
+ struct lag_fn *fn;
int i;
lockdep_assert_held(&ldev->lock);
i = mlx5_get_next_lag_func(ldev, 0, filter);
- if (i < ldev->max_funcs) {
- pf = mlx5_lag_pf(ldev, i);
+ if (i < ldev->max_fns) {
+ fn = mlx5_lag_fn(ldev, i);
if (filter == MLX5_LAG_FILTER_PORTS ||
filter == MLX5_LAG_FILTER_ALL)
- devcom = pf->dev->priv.hca_devcom_comp;
+ devcom = fn->dev->priv.hca_devcom_comp;
else
- devcom = mlx5_sd_get_devcom(pf->dev);
+ devcom = mlx5_sd_get_devcom(fn->dev);
}
mlx5_devcom_comp_assert_locked(devcom);
}
@@ -1338,22 +1340,22 @@ static void mlx5_lag_rescan_devices_locked_filter(struct mlx5_lag *ldev,
bool enable, u32 filter)
{
struct mlx5_core_dev *devs[MLX5_MAX_PORTS];
- struct lag_func *pf;
+ struct lag_fn *fn;
int num_devs = 0;
int i;
mlx5_lag_assert_locked_transition(ldev, filter);
mlx5_lag_for_each(i, 0, ldev, filter) {
- pf = mlx5_lag_pf(ldev, i);
- if (pf->dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV)
+ fn = mlx5_lag_fn(ldev, i);
+ if (fn->dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV)
continue;
if (enable)
- pf->dev->priv.flags &= ~MLX5_PRIV_FLAGS_DISABLE_IB_ADEV;
+ fn->dev->priv.flags &= ~MLX5_PRIV_FLAGS_DISABLE_IB_ADEV;
else
- pf->dev->priv.flags |= MLX5_PRIV_FLAGS_DISABLE_IB_ADEV;
- devs[num_devs++] = pf->dev;
+ fn->dev->priv.flags |= MLX5_PRIV_FLAGS_DISABLE_IB_ADEV;
+ devs[num_devs++] = fn->dev;
}
mlx5_lag_drop_lock_for_reps(ldev, filter);
@@ -1385,14 +1387,14 @@ void mlx5_lag_remove_devices(struct mlx5_lag *ldev)
static int mlx5_lag_reload_ib_reps_idx(struct mlx5_lag *ldev, int idx,
u32 flags)
{
- struct lag_func *pf = mlx5_lag_pf(ldev, idx);
+ struct lag_fn *fn = mlx5_lag_fn(ldev, idx);
struct mlx5_eswitch *esw;
int ret;
- if (pf->dev->priv.flags & flags)
+ if (fn->dev->priv.flags & flags)
return 0;
- esw = pf->dev->priv.eswitch;
+ esw = fn->dev->priv.eswitch;
mlx5_esw_reps_block(esw);
ret = mlx5_eswitch_reload_ib_reps(esw);
mlx5_esw_reps_unblock(esw);
@@ -1453,14 +1455,14 @@ int mlx5_lag_reload_ib_reps_from_locked(struct mlx5_lag *ldev, u32 flags,
static void mlx5_lag_unload_reps_unlocked(struct mlx5_lag *ldev, u32 filter)
{
- struct lag_func *pf;
+ struct lag_fn *fn;
int i;
mlx5_lag_for_each(i, 0, ldev, filter) {
struct mlx5_eswitch *esw;
- pf = mlx5_lag_pf(ldev, i);
- esw = pf->dev->priv.eswitch;
+ fn = mlx5_lag_fn(ldev, i);
+ esw = fn->dev->priv.eswitch;
mlx5_esw_reps_block(esw);
mlx5_eswitch_unload_reps(esw);
mlx5_esw_reps_unblock(esw);
@@ -1494,7 +1496,7 @@ void mlx5_disable_lag(struct mlx5_lag *ldev)
return;
}
- dev0 = mlx5_lag_pf(ldev, idx)->dev;
+ dev0 = mlx5_lag_fn(ldev, idx)->dev;
roce_lag = __mlx5_lag_is_roce(ldev);
if (roce_lag) {
@@ -1502,7 +1504,7 @@ void mlx5_disable_lag(struct mlx5_lag *ldev)
mlx5_ldev_for_each(i, 0, ldev) {
if (i == idx)
continue;
- mlx5_nic_vport_disable_roce(mlx5_lag_pf(ldev, i)->dev);
+ mlx5_nic_vport_disable_roce(mlx5_lag_fn(ldev, i)->dev);
}
}
@@ -1517,18 +1519,18 @@ void mlx5_disable_lag(struct mlx5_lag *ldev)
static bool mlx5_lag_is_roce_lag(struct mlx5_lag *ldev)
{
bool roce_lag = true;
- struct lag_func *pf;
+ struct lag_fn *fn;
int i;
mlx5_ldev_for_each(i, 0, ldev) {
- pf = mlx5_lag_pf(ldev, i);
- roce_lag = roce_lag && !mlx5_sriov_is_enabled(pf->dev);
+ fn = mlx5_lag_fn(ldev, i);
+ roce_lag = roce_lag && !mlx5_sriov_is_enabled(fn->dev);
}
#ifdef CONFIG_MLX5_ESWITCH
mlx5_ldev_for_each(i, 0, ldev) {
- pf = mlx5_lag_pf(ldev, i);
- roce_lag = roce_lag && is_mdev_legacy_mode(pf->dev);
+ fn = mlx5_lag_fn(ldev, i);
+ roce_lag = roce_lag && is_mdev_legacy_mode(fn->dev);
}
#endif
@@ -1557,15 +1559,15 @@ static int mlx5_lag_get_devices_oper_speed(struct mlx5_lag *ldev,
mlx5_ldev_for_each(pf_idx, 0, ldev) {
u8 opmod = MLX5_VPORT_STATE_OP_MOD_VNIC_VPORT;
struct mlx5_core_dev *pf_mdev;
- struct lag_func *pf;
+ struct lag_fn *fn;
u32 speed;
u8 state;
int ret;
- pf = mlx5_lag_pf(ldev, pf_idx);
- if (!pf)
+ fn = mlx5_lag_fn(ldev, pf_idx);
+ if (!fn)
continue;
- pf_mdev = pf->dev;
+ pf_mdev = fn->dev;
if (!pf_mdev)
continue;
ret = mlx5_query_vport_max_tx_speed(pf_mdev, opmod, 0, 0,
@@ -1604,14 +1606,14 @@ static int mlx5_lag_get_devices_max_speed(struct mlx5_lag *ldev, u32 *max_speed)
*max_speed = 0;
mlx5_ldev_for_each(pf_idx, 0, ldev) {
struct mlx5_core_dev *pf_mdev;
- struct lag_func *pf;
+ struct lag_fn *fn;
u32 speed;
int ret;
- pf = mlx5_lag_pf(ldev, pf_idx);
- if (!pf)
+ fn = mlx5_lag_fn(ldev, pf_idx);
+ if (!fn)
continue;
- pf_mdev = pf->dev;
+ pf_mdev = fn->dev;
if (!pf_mdev)
continue;
@@ -1671,7 +1673,7 @@ static void mlx5_lag_modify_device_vports_speed(struct mlx5_core_dev *mdev,
void mlx5_lag_set_vports_agg_speed(struct mlx5_lag *ldev)
{
struct mlx5_core_dev *mdev;
- struct lag_func *pf;
+ struct lag_fn *fn;
u32 speed;
int pf_idx;
@@ -1691,10 +1693,10 @@ void mlx5_lag_set_vports_agg_speed(struct mlx5_lag *ldev)
speed = speed / MLX5_MAX_TX_SPEED_UNIT;
mlx5_ldev_for_each(pf_idx, 0, ldev) {
- pf = mlx5_lag_pf(ldev, pf_idx);
- if (!pf)
+ fn = mlx5_lag_fn(ldev, pf_idx);
+ if (!fn)
continue;
- mdev = pf->dev;
+ mdev = fn->dev;
if (!mdev)
continue;
@@ -1705,16 +1707,16 @@ void mlx5_lag_set_vports_agg_speed(struct mlx5_lag *ldev)
void mlx5_lag_reset_vports_speed(struct mlx5_lag *ldev)
{
struct mlx5_core_dev *mdev;
- struct lag_func *pf;
+ struct lag_fn *fn;
u32 speed;
int pf_idx;
int ret;
mlx5_ldev_for_each(pf_idx, 0, ldev) {
- pf = mlx5_lag_pf(ldev, pf_idx);
- if (!pf)
+ fn = mlx5_lag_fn(ldev, pf_idx);
+ if (!fn)
continue;
- mdev = pf->dev;
+ mdev = fn->dev;
if (!mdev)
continue;
@@ -1745,7 +1747,7 @@ static void mlx5_do_bond(struct mlx5_lag *ldev)
if (idx < 0)
return;
- dev0 = mlx5_lag_pf(ldev, idx)->dev;
+ dev0 = mlx5_lag_fn(ldev, idx)->dev;
if (!mlx5_lag_is_ready(ldev)) {
do_bond = false;
} else {
@@ -1790,7 +1792,7 @@ static void mlx5_do_bond(struct mlx5_lag *ldev)
mlx5_ldev_for_each(i, 0, ldev) {
if (i == idx)
continue;
- dev = mlx5_lag_pf(ldev, i)->dev;
+ dev = mlx5_lag_fn(ldev, i)->dev;
if (mlx5_get_roce_state(dev))
mlx5_nic_vport_enable_roce(dev);
}
@@ -1824,7 +1826,7 @@ static void mlx5_do_bond(struct mlx5_lag *ldev)
struct mlx5_devcom_comp_dev *mlx5_lag_get_devcom_comp(struct mlx5_lag *ldev)
{
struct mlx5_devcom_comp_dev *devcom = NULL;
- struct lag_func *pf;
+ struct lag_fn *fn;
u32 filter;
int i;
@@ -1832,9 +1834,9 @@ struct mlx5_devcom_comp_dev *mlx5_lag_get_devcom_comp(struct mlx5_lag *ldev)
filter = ldev->virt_lag ? MLX5_LAG_FILTER_ALL :
MLX5_LAG_FILTER_PORTS;
i = mlx5_get_next_lag_func(ldev, 0, filter);
- if (i < ldev->max_funcs) {
- pf = mlx5_lag_pf(ldev, i);
- devcom = pf->dev->priv.hca_devcom_comp;
+ if (i < ldev->max_fns) {
+ fn = mlx5_lag_fn(ldev, i);
+ devcom = fn->dev->priv.hca_devcom_comp;
}
mutex_unlock(&ldev->lock);
return devcom;
@@ -1842,7 +1844,7 @@ struct mlx5_devcom_comp_dev *mlx5_lag_get_devcom_comp(struct mlx5_lag *ldev)
static int mlx5_lag_demux_ft_fg_init(struct mlx5_core_dev *dev,
struct mlx5_flow_table_attr *ft_attr,
- struct lag_func *pf)
+ struct lag_fn *fn)
{
#ifdef CONFIG_MLX5_ESWITCH
struct mlx5_flow_namespace *ns;
@@ -1853,20 +1855,20 @@ static int mlx5_lag_demux_ft_fg_init(struct mlx5_core_dev *dev,
if (!ns)
return 0;
- pf->lag_demux_ft = mlx5_create_flow_table(ns, ft_attr);
- if (IS_ERR(pf->lag_demux_ft))
- return PTR_ERR(pf->lag_demux_ft);
+ fn->lag_demux_ft = mlx5_create_flow_table(ns, ft_attr);
+ if (IS_ERR(fn->lag_demux_ft))
+ return PTR_ERR(fn->lag_demux_ft);
fg = mlx5_esw_lag_demux_fg_create(dev->priv.eswitch,
- pf->lag_demux_ft);
+ fn->lag_demux_ft);
if (IS_ERR(fg)) {
err = PTR_ERR(fg);
- mlx5_destroy_flow_table(pf->lag_demux_ft);
- pf->lag_demux_ft = NULL;
+ mlx5_destroy_flow_table(fn->lag_demux_ft);
+ fn->lag_demux_ft = NULL;
return err;
}
- pf->lag_demux_fg = fg;
+ fn->lag_demux_fg = fg;
return 0;
#else
return -EOPNOTSUPP;
@@ -1875,7 +1877,7 @@ static int mlx5_lag_demux_ft_fg_init(struct mlx5_core_dev *dev,
static int mlx5_lag_demux_fw_init(struct mlx5_core_dev *dev,
struct mlx5_flow_table_attr *ft_attr,
- struct lag_func *pf)
+ struct lag_fn *fn)
{
struct mlx5_flow_namespace *ns;
int err;
@@ -1884,12 +1886,12 @@ static int mlx5_lag_demux_fw_init(struct mlx5_core_dev *dev,
if (!ns)
return 0;
- pf->lag_demux_fg = NULL;
+ fn->lag_demux_fg = NULL;
ft_attr->max_fte = 1;
- pf->lag_demux_ft = mlx5_create_lag_demux_flow_table(ns, ft_attr);
- if (IS_ERR(pf->lag_demux_ft)) {
- err = PTR_ERR(pf->lag_demux_ft);
- pf->lag_demux_ft = NULL;
+ fn->lag_demux_ft = mlx5_create_lag_demux_flow_table(ns, ft_attr);
+ if (IS_ERR(fn->lag_demux_ft)) {
+ err = PTR_ERR(fn->lag_demux_ft);
+ fn->lag_demux_ft = NULL;
return err;
}
@@ -1900,7 +1902,7 @@ int mlx5_lag_demux_init(struct mlx5_core_dev *dev,
struct mlx5_flow_table_attr *ft_attr)
{
struct mlx5_lag *ldev;
- struct lag_func *pf;
+ struct lag_fn *fn;
if (!ft_attr)
return -EINVAL;
@@ -1909,16 +1911,16 @@ int mlx5_lag_demux_init(struct mlx5_core_dev *dev,
if (!ldev)
return -ENODEV;
- pf = mlx5_lag_pf_by_dev(ldev, dev);
- if (!pf)
+ fn = mlx5_lag_fn_by_dev(ldev, dev);
+ if (!fn)
return -ENODEV;
- xa_init(&pf->lag_demux_rules);
+ xa_init(&fn->lag_demux_rules);
if (mlx5_lag_is_sw_managed(dev))
- return mlx5_lag_demux_ft_fg_init(dev, ft_attr, pf);
+ return mlx5_lag_demux_ft_fg_init(dev, ft_attr, fn);
- return mlx5_lag_demux_fw_init(dev, ft_attr, pf);
+ return mlx5_lag_demux_fw_init(dev, ft_attr, fn);
}
EXPORT_SYMBOL(mlx5_lag_demux_init);
@@ -1927,31 +1929,31 @@ void mlx5_lag_demux_cleanup(struct mlx5_core_dev *dev)
struct mlx5_flow_handle *rule;
struct mlx5_lag *ldev;
unsigned long vport_num;
- struct lag_func *pf;
+ struct lag_fn *fn;
ldev = mlx5_lag_dev(dev);
if (!ldev)
return;
- pf = mlx5_lag_pf_by_dev(ldev, dev);
- if (!pf)
+ fn = mlx5_lag_fn_by_dev(ldev, dev);
+ if (!fn)
return;
- xa_for_each(&pf->lag_demux_rules, vport_num, rule)
+ xa_for_each(&fn->lag_demux_rules, vport_num, rule)
mlx5_del_flow_rules(rule);
- xa_destroy(&pf->lag_demux_rules);
+ xa_destroy(&fn->lag_demux_rules);
- if (pf->lag_demux_fg)
- mlx5_destroy_flow_group(pf->lag_demux_fg);
- if (pf->lag_demux_ft)
- mlx5_destroy_flow_table(pf->lag_demux_ft);
- pf->lag_demux_fg = NULL;
- pf->lag_demux_ft = NULL;
+ if (fn->lag_demux_fg)
+ mlx5_destroy_flow_group(fn->lag_demux_fg);
+ if (fn->lag_demux_ft)
+ mlx5_destroy_flow_table(fn->lag_demux_ft);
+ fn->lag_demux_fg = NULL;
+ fn->lag_demux_ft = NULL;
}
EXPORT_SYMBOL(mlx5_lag_demux_cleanup);
-static struct lag_func *mlx5_lag_dev_get_master_pf(struct mlx5_lag *ldev,
- struct mlx5_core_dev *dev)
+static struct lag_fn *mlx5_lag_dev_get_master_fn(struct mlx5_lag *ldev,
+ struct mlx5_core_dev *dev)
{
u32 filter = mlx5_lag_get_filter(ldev, dev);
int idx;
@@ -1960,14 +1962,14 @@ static struct lag_func *mlx5_lag_dev_get_master_pf(struct mlx5_lag *ldev,
if (idx < 0)
return NULL;
- return mlx5_lag_pf(ldev, idx);
+ return mlx5_lag_fn(ldev, idx);
}
int mlx5_lag_demux_rule_add(struct mlx5_core_dev *vport_dev, u16 vport_num,
int index)
{
struct mlx5_flow_handle *rule;
- struct lag_func *master;
+ struct lag_fn *master;
struct mlx5_lag *ldev;
int err;
@@ -1975,7 +1977,7 @@ int mlx5_lag_demux_rule_add(struct mlx5_core_dev *vport_dev, u16 vport_num,
if (!ldev)
return 0;
- master = mlx5_lag_dev_get_master_pf(ldev, vport_dev);
+ master = mlx5_lag_dev_get_master_fn(ldev, vport_dev);
if (!master || !master->lag_demux_fg)
return 0;
@@ -2008,18 +2010,18 @@ EXPORT_SYMBOL(mlx5_lag_demux_rule_add);
void mlx5_lag_demux_rule_del(struct mlx5_core_dev *dev, int index)
{
struct mlx5_flow_handle *rule;
- struct lag_func *master_pf;
+ struct lag_fn *master_fn;
struct mlx5_lag *ldev;
ldev = mlx5_lag_dev(dev);
if (!ldev)
return;
- master_pf = mlx5_lag_dev_get_master_pf(ldev, dev);
- if (!master_pf || !master_pf->lag_demux_fg)
+ master_fn = mlx5_lag_dev_get_master_fn(ldev, dev);
+ if (!master_fn || !master_fn->lag_demux_fg)
return;
- rule = xa_erase(&master_pf->lag_demux_rules, index);
+ rule = xa_erase(&master_fn->lag_demux_rules, index);
if (rule)
mlx5_del_flow_rules(rule);
}
@@ -2069,7 +2071,7 @@ static int mlx5_handle_changeupper_event(struct mlx5_lag *ldev,
struct netdev_lag_upper_info *lag_upper_info = NULL;
bool is_bonded, is_in_lag, mode_supported;
bool has_inactive = 0;
- struct lag_func *pf;
+ struct lag_fn *fn;
struct slave *slave;
u8 bond_status = 0;
int num_slaves = 0;
@@ -2090,8 +2092,8 @@ static int mlx5_handle_changeupper_event(struct mlx5_lag *ldev,
rcu_read_lock();
for_each_netdev_in_bond_rcu(upper, ndev_tmp) {
mlx5_ldev_for_each(i, 0, ldev) {
- pf = mlx5_lag_pf(ldev, i);
- if (pf->netdev == ndev_tmp) {
+ fn = mlx5_lag_fn(ldev, i);
+ if (fn->netdev == ndev_tmp) {
idx++;
break;
}
@@ -2313,16 +2315,16 @@ static void mlx5_ldev_add_netdev(struct mlx5_lag *ldev,
struct mlx5_core_dev *dev,
struct net_device *netdev)
{
- struct lag_func *pf;
+ struct lag_fn *fn;
unsigned long flags;
int i;
spin_lock_irqsave(&lag_lock, flags);
- /* Find pf entry by matching dev pointer */
+ /* Find fn entry by matching dev pointer */
mlx5_ldev_for_each(i, 0, ldev) {
- pf = mlx5_lag_pf(ldev, i);
- if (pf->dev == dev) {
- pf->netdev = netdev;
+ fn = mlx5_lag_fn(ldev, i);
+ if (fn->dev == dev) {
+ fn->netdev = netdev;
ldev->tracker.netdev_state[i].link_up = 0;
ldev->tracker.netdev_state[i].tx_enabled = 0;
break;
@@ -2334,15 +2336,15 @@ static void mlx5_ldev_add_netdev(struct mlx5_lag *ldev,
static void mlx5_ldev_remove_netdev(struct mlx5_lag *ldev,
struct net_device *netdev)
{
- struct lag_func *pf;
+ struct lag_fn *fn;
unsigned long flags;
int i;
spin_lock_irqsave(&lag_lock, flags);
mlx5_ldev_for_each(i, 0, ldev) {
- pf = mlx5_lag_pf(ldev, i);
- if (pf->netdev == netdev) {
- pf->netdev = NULL;
+ fn = mlx5_lag_fn(ldev, i);
+ if (fn->netdev == netdev) {
+ fn->netdev = NULL;
break;
}
}
@@ -2353,37 +2355,37 @@ int mlx5_ldev_add_mdev(struct mlx5_lag *ldev,
struct mlx5_core_dev *dev,
u32 group_id)
{
- struct lag_func *pf;
+ struct lag_fn *fn;
u32 idx;
int err;
- pf = kzalloc_obj(*pf);
- if (!pf)
+ fn = kzalloc_obj(*fn);
+ if (!fn)
return -ENOMEM;
- err = xa_alloc(&ldev->pfs, &idx, pf, XA_LIMIT(0, U8_MAX - 1),
+ err = xa_alloc(&ldev->fns, &idx, fn, XA_LIMIT(0, U8_MAX - 1),
GFP_KERNEL);
if (err) {
- kfree(pf);
+ kfree(fn);
return err;
}
- /* max_funcs is the iteration ceiling; grow it, never shrink. */
- if (idx >= ldev->max_funcs)
- ldev->max_funcs = idx + 1;
- pf->idx = idx;
- pf->dev = dev;
- pf->group_id = group_id;
+ /* max_fns is the iteration ceiling; grow it, never shrink. */
+ if (idx >= ldev->max_fns)
+ ldev->max_fns = idx + 1;
+ fn->idx = idx;
+ fn->dev = dev;
+ fn->group_id = group_id;
dev->priv.lag = ldev;
if (group_id)
return 0;
- xa_set_mark(&ldev->pfs, idx, MLX5_LAG_XA_MARK_PORT);
+ xa_set_mark(&ldev->fns, idx, MLX5_LAG_XA_MARK_PORT);
- MLX5_NB_INIT(&pf->port_change_nb,
+ MLX5_NB_INIT(&fn->port_change_nb,
mlx5_lag_mpesw_port_change_event, PORT_CHANGE);
- mlx5_eq_notifier_register(dev, &pf->port_change_nb);
+ mlx5_eq_notifier_register(dev, &fn->port_change_nb);
return 0;
}
@@ -2391,24 +2393,24 @@ int mlx5_ldev_add_mdev(struct mlx5_lag *ldev,
void mlx5_ldev_remove_mdev(struct mlx5_lag *ldev,
struct mlx5_core_dev *dev)
{
- struct lag_func *pf;
+ struct lag_fn *fn;
int i;
mlx5_lag_for_each(i, 0, ldev, MLX5_LAG_FILTER_ALL) {
- pf = mlx5_lag_pf(ldev, i);
- if (pf->dev == dev)
+ fn = mlx5_lag_fn(ldev, i);
+ if (fn->dev == dev)
break;
}
- if (i >= ldev->max_funcs)
+ if (i >= ldev->max_fns)
return;
- if (pf->port_change_nb.nb.notifier_call)
- mlx5_eq_notifier_unregister(dev, &pf->port_change_nb);
+ if (fn->port_change_nb.nb.notifier_call)
+ mlx5_eq_notifier_unregister(dev, &fn->port_change_nb);
- pf->dev = NULL;
+ fn->dev = NULL;
dev->priv.lag = NULL;
- xa_erase(&ldev->pfs, pf->idx);
- kfree(pf);
+ xa_erase(&ldev->fns, fn->idx);
+ kfree(fn);
}
/* Must be called with HCA devcom component lock held */
@@ -2584,18 +2586,18 @@ void mlx5_lag_add_netdev(struct mlx5_core_dev *dev,
int mlx5_get_pre_lag_func(struct mlx5_lag *ldev, int start_idx, int end_idx,
u32 filter)
{
- struct lag_func *pf;
+ struct lag_fn *fn;
int i;
for (i = start_idx; i >= end_idx; i--) {
- pf = xa_load(&ldev->pfs, i);
- if (!pf || !pf->dev)
+ fn = xa_load(&ldev->fns, i);
+ if (!fn || !fn->dev)
continue;
if (filter == MLX5_LAG_FILTER_PORTS) {
- if (xa_get_mark(&ldev->pfs, i, MLX5_LAG_XA_MARK_PORT))
+ if (xa_get_mark(&ldev->fns, i, MLX5_LAG_XA_MARK_PORT))
return i;
} else if (filter == MLX5_LAG_FILTER_ALL ||
- filter == pf->group_id) {
+ filter == fn->group_id) {
return i;
}
}
@@ -2604,25 +2606,25 @@ int mlx5_get_pre_lag_func(struct mlx5_lag *ldev, int start_idx, int end_idx,
int mlx5_get_next_lag_func(struct mlx5_lag *ldev, int start_idx, u32 filter)
{
- struct lag_func *pf;
+ struct lag_fn *fn;
unsigned long idx;
if (filter == MLX5_LAG_FILTER_PORTS) {
- xa_for_each_marked_start(&ldev->pfs, idx, pf,
+ xa_for_each_marked_start(&ldev->fns, idx, fn,
MLX5_LAG_XA_MARK_PORT, start_idx)
- if (pf->dev)
+ if (fn->dev)
return idx;
- return ldev->max_funcs;
+ return ldev->max_fns;
}
- xa_for_each_start(&ldev->pfs, idx, pf, start_idx) {
- if (!pf->dev)
+ xa_for_each_start(&ldev->fns, idx, fn, start_idx) {
+ if (!fn->dev)
continue;
if (filter == MLX5_LAG_FILTER_ALL ||
- filter == pf->group_id)
+ filter == fn->group_id)
return idx;
}
- return ldev->max_funcs;
+ return ldev->max_fns;
}
bool mlx5_lag_is_roce(struct mlx5_core_dev *dev)
@@ -2676,7 +2678,7 @@ bool mlx5_lag_is_master(struct mlx5_core_dev *dev)
{
struct mlx5_lag *ldev;
unsigned long flags;
- struct lag_func *pf;
+ struct lag_fn *fn;
bool res = false;
int idx;
@@ -2690,8 +2692,8 @@ bool mlx5_lag_is_master(struct mlx5_core_dev *dev)
filter);
if ((__mlx5_lag_is_active(ldev) ||
__mlx5_lag_is_sd_active(ldev, dev)) && idx >= 0) {
- pf = mlx5_lag_pf(ldev, idx);
- res = pf && dev == pf->dev;
+ fn = mlx5_lag_fn(ldev, idx);
+ res = fn && dev == fn->dev;
}
}
spin_unlock_irqrestore(&lag_lock, flags);
@@ -2754,7 +2756,7 @@ void mlx5_lag_disable_change(struct mlx5_core_dev *dev)
struct mlx5_devcom_comp_dev *sd_devcom = mlx5_sd_get_devcom(dev);
struct mlx5_core_dev *primary = dev;
struct mlx5_lag *ldev;
- struct lag_func *pf;
+ struct lag_fn *fn;
bool mpesw;
int i;
@@ -2793,9 +2795,9 @@ void mlx5_lag_disable_change(struct mlx5_core_dev *dev)
mlx5_devcom_comp_lock(sd_devcom);
mutex_lock(&ldev->lock);
mlx5_lag_for_each(i, 0, ldev, MLX5_LAG_FILTER_ALL) {
- pf = mlx5_lag_pf(ldev, i);
- if (pf->dev == dev && pf->sd_fdb_active) {
- mlx5_lag_shared_fdb_destroy(ldev, pf->group_id);
+ fn = mlx5_lag_fn(ldev, i);
+ if (fn->dev == dev && fn->sd_fdb_active) {
+ mlx5_lag_shared_fdb_destroy(ldev, fn->group_id);
break;
}
}
@@ -2822,7 +2824,7 @@ u8 mlx5_lag_get_slave_port(struct mlx5_core_dev *dev,
{
struct mlx5_lag *ldev;
unsigned long flags;
- struct lag_func *pf;
+ struct lag_fn *fn;
u8 port = 0;
int i;
@@ -2832,8 +2834,8 @@ u8 mlx5_lag_get_slave_port(struct mlx5_core_dev *dev,
goto unlock;
mlx5_ldev_for_each(i, 0, ldev) {
- pf = mlx5_lag_pf(ldev, i);
- if (pf->netdev == slave) {
+ fn = mlx5_lag_fn(ldev, i);
+ if (fn->netdev == slave) {
port = i;
break;
}
@@ -2864,7 +2866,7 @@ struct mlx5_core_dev *mlx5_lag_get_next_peer_mdev(struct mlx5_core_dev *dev, int
struct mlx5_core_dev *peer_dev = NULL;
struct mlx5_lag *ldev;
unsigned long flags;
- struct lag_func *pf;
+ struct lag_fn *fn;
int idx;
spin_lock_irqsave(&lag_lock, flags);
@@ -2872,22 +2874,22 @@ struct mlx5_core_dev *mlx5_lag_get_next_peer_mdev(struct mlx5_core_dev *dev, int
if (!ldev)
goto unlock;
- if (*i == ldev->max_funcs)
+ if (*i == ldev->max_fns)
goto unlock;
mlx5_lag_for_each(idx, *i, ldev, mlx5_lag_get_filter(ldev, dev)) {
- pf = mlx5_lag_pf(ldev, idx);
- if (pf->dev != dev)
+ fn = mlx5_lag_fn(ldev, idx);
+ if (fn->dev != dev)
break;
}
- if (idx == ldev->max_funcs) {
+ if (idx == ldev->max_fns) {
*i = idx;
goto unlock;
}
*i = idx + 1;
- pf = mlx5_lag_pf(ldev, idx);
- peer_dev = pf->dev;
+ fn = mlx5_lag_fn(ldev, idx);
+ peer_dev = fn->dev;
unlock:
spin_unlock_irqrestore(&lag_lock, flags);
@@ -2905,7 +2907,7 @@ int mlx5_lag_query_cong_counters(struct mlx5_core_dev *dev,
int ret = 0, i, j, idx = 0;
struct mlx5_lag *ldev;
unsigned long flags;
- struct lag_func *pf;
+ struct lag_fn *fn;
int num_ports;
void *out;
@@ -2926,8 +2928,8 @@ int mlx5_lag_query_cong_counters(struct mlx5_core_dev *dev,
if (ldev && __mlx5_lag_is_active(ldev)) {
num_ports = ldev->ports;
mlx5_ldev_for_each(i, 0, ldev) {
- pf = mlx5_lag_pf(ldev, i);
- mdev[idx++] = pf->dev;
+ fn = mlx5_lag_fn(ldev, i);
+ mdev[idx++] = fn->dev;
}
} else {
num_ports = 1;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
index 479d9f42ff3f..cbe380ae8bf9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
@@ -51,7 +51,7 @@ enum mlx5_lag_mode {
MLX5_LAG_MODE_MPESW,
};
-struct lag_func {
+struct lag_fn {
struct mlx5_core_dev *dev;
struct net_device *netdev;
bool has_drop;
@@ -83,13 +83,13 @@ struct mlx5_lag {
unsigned long mode_flags;
unsigned long state_flags;
u8 ports;
- u8 max_funcs;
+ u8 max_fns;
u8 buckets;
bool virt_lag;
int mode_changes_in_progress;
u8 *v2p_map;
struct kref ref;
- struct xarray pfs;
+ struct xarray fns;
struct lag_tracker tracker;
struct workqueue_struct *wq;
struct delayed_work bond_work;
@@ -109,44 +109,44 @@ mlx5_lag_dev(struct mlx5_core_dev *dev)
return dev->priv.lag;
}
-static inline struct lag_func *
-mlx5_lag_pf(struct mlx5_lag *ldev, unsigned int idx)
+static inline struct lag_fn *
+mlx5_lag_fn(struct mlx5_lag *ldev, unsigned int idx)
{
- return xa_load(&ldev->pfs, idx);
+ return xa_load(&ldev->fns, idx);
}
/* Get device index (mlx5_get_dev_index) from xarray index */
static inline int mlx5_lag_xa_to_dev_idx(struct mlx5_lag *ldev, int xa_idx)
{
- struct lag_func *pf = mlx5_lag_pf(ldev, xa_idx);
+ struct lag_fn *fn = mlx5_lag_fn(ldev, xa_idx);
- return pf ? mlx5_get_dev_index(pf->dev) : -ENOENT;
+ return fn ? mlx5_get_dev_index(fn->dev) : -ENOENT;
}
-/* Find lag_func by device index (reverse lookup from mlx5_get_dev_index) */
-static inline struct lag_func *
-mlx5_lag_pf_by_dev_idx(struct mlx5_lag *ldev, int dev_idx)
+/* Find lag_fn by device index (reverse lookup from mlx5_get_dev_index) */
+static inline struct lag_fn *
+mlx5_lag_fn_by_dev_idx(struct mlx5_lag *ldev, int dev_idx)
{
- struct lag_func *pf;
+ struct lag_fn *fn;
unsigned long idx;
- xa_for_each(&ldev->pfs, idx, pf) {
- if (mlx5_get_dev_index(pf->dev) == dev_idx)
- return pf;
+ xa_for_each(&ldev->fns, idx, fn) {
+ if (mlx5_get_dev_index(fn->dev) == dev_idx)
+ return fn;
}
return NULL;
}
-/* Find lag_func by mlx5_core_dev pointer */
-static inline struct lag_func *
-mlx5_lag_pf_by_dev(struct mlx5_lag *ldev, struct mlx5_core_dev *dev)
+/* Find lag_fn by mlx5_core_dev pointer */
+static inline struct lag_fn *
+mlx5_lag_fn_by_dev(struct mlx5_lag *ldev, struct mlx5_core_dev *dev)
{
- struct lag_func *pf;
+ struct lag_fn *fn;
unsigned long idx;
- xa_for_each(&ldev->pfs, idx, pf) {
- if (pf->dev == dev)
- return pf;
+ xa_for_each(&ldev->fns, idx, fn) {
+ if (fn->dev == dev)
+ return fn;
}
return NULL;
}
@@ -154,17 +154,17 @@ mlx5_lag_pf_by_dev(struct mlx5_lag *ldev, struct mlx5_core_dev *dev)
static inline bool
__mlx5_lag_is_sd(struct mlx5_lag *ldev, struct mlx5_core_dev *dev)
{
- struct lag_func *pf = mlx5_lag_pf_by_dev(ldev, dev);
+ struct lag_fn *fn = mlx5_lag_fn_by_dev(ldev, dev);
- return pf && pf->group_id != 0;
+ return fn && fn->group_id != 0;
}
static inline bool
__mlx5_lag_dev_is_port(struct mlx5_lag *ldev, struct mlx5_core_dev *dev)
{
- struct lag_func *pf = mlx5_lag_pf_by_dev(ldev, dev);
+ struct lag_fn *fn = mlx5_lag_fn_by_dev(ldev, dev);
- return pf && xa_get_mark(&ldev->pfs, pf->idx, MLX5_LAG_XA_MARK_PORT);
+ return fn && xa_get_mark(&ldev->fns, fn->idx, MLX5_LAG_XA_MARK_PORT);
}
static inline bool
@@ -299,7 +299,7 @@ static inline bool mlx5_lag_is_supported(struct mlx5_core_dev *dev)
#define mlx5_lag_for_each(i, start_index, ldev, filter) \
for (int tmp = start_index; \
tmp = mlx5_get_next_lag_func(ldev, tmp, filter), \
- i = tmp, tmp < (ldev)->max_funcs; tmp++)
+ i = tmp, tmp < (ldev)->max_fns; tmp++)
#define mlx5_lag_for_each_reverse(i, start_index, end_index, ldev, filter) \
for (int tmp = start_index, tmp1 = end_index; \
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c
index 2077fc5d80c7..587638278f34 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c
@@ -26,15 +26,15 @@ static bool mlx5_lag_multipath_check_prereq(struct mlx5_lag *ldev)
if (__mlx5_lag_is_active(ldev) && !__mlx5_lag_is_multipath(ldev))
return false;
- if (mlx5_lag_is_sw_managed(mlx5_lag_pf(ldev, idx0)->dev) ||
- mlx5_lag_is_sw_managed(mlx5_lag_pf(ldev, idx1)->dev))
+ if (mlx5_lag_is_sw_managed(mlx5_lag_fn(ldev, idx0)->dev) ||
+ mlx5_lag_is_sw_managed(mlx5_lag_fn(ldev, idx1)->dev))
return false;
if (ldev->ports > MLX5_LAG_MULTIPATH_OFFLOADS_SUPPORTED_PORTS)
return false;
- return mlx5_esw_multipath_prereq(mlx5_lag_pf(ldev, idx0)->dev,
- mlx5_lag_pf(ldev, idx1)->dev);
+ return mlx5_esw_multipath_prereq(mlx5_lag_fn(ldev, idx0)->dev,
+ mlx5_lag_fn(ldev, idx1)->dev);
}
bool mlx5_lag_is_multipath(struct mlx5_core_dev *dev)
@@ -59,11 +59,15 @@ static void mlx5_lag_set_port_affinity(struct mlx5_lag *ldev,
{
int idx0 = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1);
int idx1 = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P2);
+ struct mlx5_core_dev *dev0, *dev1;
struct lag_tracker tracker = {};
if (idx0 < 0 || idx1 < 0 || !__mlx5_lag_is_multipath(ldev))
return;
+ dev0 = mlx5_lag_fn(ldev, idx0)->dev;
+ dev1 = mlx5_lag_fn(ldev, idx1)->dev;
+
switch (port) {
case MLX5_LAG_NORMAL_AFFINITY:
tracker.netdev_state[idx0].tx_enabled = true;
@@ -84,18 +88,17 @@ static void mlx5_lag_set_port_affinity(struct mlx5_lag *ldev,
tracker.netdev_state[idx1].link_up = true;
break;
default:
- mlx5_core_warn(mlx5_lag_pf(ldev, idx0)->dev,
- "Invalid affinity port %d", port);
+ mlx5_core_warn(dev0, "Invalid affinity port %d", port);
return;
}
if (tracker.netdev_state[idx0].tx_enabled)
- mlx5_notifier_call_chain(mlx5_lag_pf(ldev, idx0)->dev->priv.events,
+ mlx5_notifier_call_chain(dev0->priv.events,
MLX5_DEV_EVENT_PORT_AFFINITY,
(void *)0);
if (tracker.netdev_state[idx1].tx_enabled)
- mlx5_notifier_call_chain(mlx5_lag_pf(ldev, idx1)->dev->priv.events,
+ mlx5_notifier_call_chain(dev1->priv.events,
MLX5_DEV_EVENT_PORT_AFFINITY,
(void *)0);
@@ -150,7 +153,7 @@ mlx5_lag_get_next_fib_dev(struct mlx5_lag *ldev,
fib_dev = fib_info_nh(fi, i)->fib_nh_dev;
ldev_idx = mlx5_lag_dev_get_netdev_idx(ldev, fib_dev);
if (ldev_idx >= 0)
- return mlx5_lag_pf(ldev, ldev_idx)->netdev;
+ return mlx5_lag_fn(ldev, ldev_idx)->netdev;
}
return NULL;
@@ -182,7 +185,7 @@ static void mlx5_lag_fib_route_event(struct mlx5_lag *ldev, unsigned long event,
mp->fib.dst_len <= fen_info->dst_len &&
!(mp->fib.dst_len == fen_info->dst_len &&
fi->fib_priority < mp->fib.priority)) {
- mlx5_core_dbg(mlx5_lag_pf(ldev, idx)->dev,
+ mlx5_core_dbg(mlx5_lag_fn(ldev, idx)->dev,
"Multipath entry with lower priority was rejected\n");
return;
}
@@ -198,7 +201,7 @@ static void mlx5_lag_fib_route_event(struct mlx5_lag *ldev, unsigned long event,
}
if (nh_dev0 == nh_dev1) {
- mlx5_core_warn(mlx5_lag_pf(ldev, idx)->dev,
+ mlx5_core_warn(mlx5_lag_fn(ldev, idx)->dev,
"Multipath offload doesn't support routes with multiple nexthops of the same device");
return;
}
@@ -207,7 +210,7 @@ static void mlx5_lag_fib_route_event(struct mlx5_lag *ldev, unsigned long event,
if (__mlx5_lag_is_active(ldev)) {
mlx5_ldev_for_each(i, 0, ldev) {
dev_idx++;
- if (mlx5_lag_pf(ldev, i)->netdev == nh_dev0)
+ if (mlx5_lag_fn(ldev, i)->netdev == nh_dev0)
break;
}
mlx5_lag_set_port_affinity(ldev, dev_idx);
@@ -244,7 +247,7 @@ static void mlx5_lag_fib_nexthop_event(struct mlx5_lag *ldev,
/* nh added/removed */
if (event == FIB_EVENT_NH_DEL) {
mlx5_ldev_for_each(i, 0, ldev) {
- if (mlx5_lag_pf(ldev, i)->netdev == fib_nh->fib_nh_dev)
+ if (mlx5_lag_fn(ldev, i)->netdev == fib_nh->fib_nh_dev)
break;
dev_idx++;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
index 56faa1d498c7..6e3bef276611 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
@@ -16,7 +16,7 @@ static void mlx5_mpesw_metadata_cleanup(struct mlx5_lag *ldev)
int i;
mlx5_lag_for_each(i, 0, ldev, MLX5_LAG_FILTER_ALL) {
- dev = mlx5_lag_pf(ldev, i)->dev;
+ dev = mlx5_lag_fn(ldev, i)->dev;
esw = dev->priv.eswitch;
pf_metadata = ldev->lag_mpesw.pf_metadata[i];
if (!pf_metadata)
@@ -37,7 +37,7 @@ static int mlx5_mpesw_metadata_set(struct mlx5_lag *ldev)
int i, err;
mlx5_lag_for_each(i, 0, ldev, MLX5_LAG_FILTER_ALL) {
- dev = mlx5_lag_pf(ldev, i)->dev;
+ dev = mlx5_lag_fn(ldev, i)->dev;
esw = dev->priv.eswitch;
pf_metadata = mlx5_esw_match_metadata_alloc(esw);
if (!pf_metadata) {
@@ -53,7 +53,7 @@ static int mlx5_mpesw_metadata_set(struct mlx5_lag *ldev)
}
mlx5_lag_for_each(i, 0, ldev, MLX5_LAG_FILTER_ALL) {
- dev = mlx5_lag_pf(ldev, i)->dev;
+ dev = mlx5_lag_fn(ldev, i)->dev;
mlx5_notifier_call_chain(dev->priv.events, MLX5_DEV_EVENT_MULTIPORT_ESW,
(void *)0);
}
@@ -67,14 +67,14 @@ static int mlx5_mpesw_metadata_set(struct mlx5_lag *ldev)
static void mlx5_mpesw_restore_sd_fdb(struct mlx5_lag *ldev)
{
- struct lag_func *pf;
+ struct lag_fn *fn;
int err, i;
mlx5_ldev_for_each(i, 0, ldev) {
- pf = mlx5_lag_pf(ldev, i);
- err = mlx5_lag_shared_fdb_create(ldev, NULL, 0, pf->group_id);
+ fn = mlx5_lag_fn(ldev, i);
+ err = mlx5_lag_shared_fdb_create(ldev, NULL, 0, fn->group_id);
if (err)
- mlx5_core_warn(pf->dev,
+ mlx5_core_warn(fn->dev,
"Failed to restore SD shared FDB (%d)\n",
err);
}
@@ -82,26 +82,26 @@ static void mlx5_mpesw_restore_sd_fdb(struct mlx5_lag *ldev)
static int mlx5_mpesw_teardown_sd_fdb(struct mlx5_lag *ldev)
{
- struct lag_func *pf;
+ struct lag_fn *fn;
int i;
mlx5_ldev_for_each(i, 0, ldev) {
- pf = mlx5_lag_pf(ldev, i);
- if (!pf->sd_fdb_active)
+ fn = mlx5_lag_fn(ldev, i);
+ if (!fn->sd_fdb_active)
continue;
- mlx5_lag_shared_fdb_destroy(ldev, pf->group_id);
+ mlx5_lag_shared_fdb_destroy(ldev, fn->group_id);
}
return 0;
}
static bool mlx5_lag_has_sd_group(struct mlx5_lag *ldev)
{
- struct lag_func *pf;
+ struct lag_fn *fn;
int i;
mlx5_ldev_for_each(i, 0, ldev) {
- pf = mlx5_lag_pf(ldev, i);
- if (pf->group_id)
+ fn = mlx5_lag_fn(ldev, i);
+ if (fn->group_id)
return true;
}
return false;
@@ -155,7 +155,7 @@ static int mlx5_lag_enable_mpesw(struct mlx5_lag *ldev)
goto err_clear_master;
}
- dev0 = mlx5_lag_pf(ldev, idx)->dev;
+ dev0 = mlx5_lag_fn(ldev, idx)->dev;
valid = ldev->virt_lag ? mlx5_virt_mpesw_validate(ldev, dev0) :
mlx5_phys_mpesw_validate(ldev, dev0);
if (!valid) {
@@ -212,7 +212,7 @@ void mlx5_mpesw_sd_devcoms_lock(struct mlx5_lag *ldev)
int i;
mlx5_ldev_for_each(i, 0, ldev) {
- sd_devcom = mlx5_sd_get_devcom(mlx5_lag_pf(ldev, i)->dev);
+ sd_devcom = mlx5_sd_get_devcom(mlx5_lag_fn(ldev, i)->dev);
if (sd_devcom)
mlx5_devcom_comp_lock(sd_devcom);
}
@@ -223,8 +223,8 @@ void mlx5_mpesw_sd_devcoms_unlock(struct mlx5_lag *ldev)
struct mlx5_devcom_comp_dev *sd_devcom;
int i;
- mlx5_ldev_for_each_reverse(i, ldev->max_funcs, 0, ldev) {
- sd_devcom = mlx5_sd_get_devcom(mlx5_lag_pf(ldev, i)->dev);
+ mlx5_ldev_for_each_reverse(i, ldev->max_fns, 0, ldev) {
+ sd_devcom = mlx5_sd_get_devcom(mlx5_lag_fn(ldev, i)->dev);
if (sd_devcom)
mlx5_devcom_comp_unlock(sd_devcom);
}
@@ -348,10 +348,10 @@ int mlx5_lag_mpesw_port_change_event(struct notifier_block *nb,
unsigned long event, void *data)
{
struct mlx5_nb *mlx5_nb = container_of(nb, struct mlx5_nb, nb);
- struct lag_func *lag_func = container_of(mlx5_nb,
- struct lag_func,
+ struct lag_fn *lag_fn = container_of(mlx5_nb,
+ struct lag_fn,
port_change_nb);
- struct mlx5_core_dev *dev = lag_func->dev;
+ struct mlx5_core_dev *dev = lag_fn->dev;
struct mlx5_lag *ldev = dev->priv.lag;
struct mlx5_eqe *eqe = data;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/port_sel.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/port_sel.c
index 2a034b2a3eee..183e18910095 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/port_sel.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/port_sel.c
@@ -50,7 +50,7 @@ static int mlx5_lag_create_port_sel_table(struct mlx5_lag *ldev,
if (first_idx < 0)
return -EINVAL;
- dev = mlx5_lag_pf(ldev, first_idx)->dev;
+ dev = mlx5_lag_fn(ldev, first_idx)->dev;
ft_attr.max_fte = ldev->ports * ldev->buckets;
ft_attr.level = MLX5_LAG_FT_LEVEL_DEFINER;
@@ -79,6 +79,7 @@ static int mlx5_lag_create_port_sel_table(struct mlx5_lag *ldev,
flow_act.flags |= FLOW_ACT_NO_APPEND;
mlx5_ldev_for_each(i, 0, ldev) {
for (j = 0; j < ldev->buckets; j++) {
+ struct mlx5_core_dev *mdev;
u8 affinity;
idx = i * ldev->buckets + j;
@@ -87,9 +88,8 @@ static int mlx5_lag_create_port_sel_table(struct mlx5_lag *ldev,
/* affinity is 1-indexed device index,
* use reverse lookup.
*/
- dest.vport.vhca_id =
- MLX5_CAP_GEN(mlx5_lag_pf_by_dev_idx(ldev, affinity - 1)->dev,
- vhca_id);
+ mdev = mlx5_lag_fn_by_dev_idx(ldev, affinity - 1)->dev;
+ dest.vport.vhca_id = MLX5_CAP_GEN(mdev, vhca_id);
lag_definer->rules[idx] = mlx5_add_flow_rules(lag_definer->ft,
NULL, &flow_act,
&dest, 1);
@@ -311,7 +311,7 @@ mlx5_lag_create_definer(struct mlx5_lag *ldev, enum netdev_lag_hash hash,
if (first_idx < 0)
return ERR_PTR(-EINVAL);
- dev = mlx5_lag_pf(ldev, first_idx)->dev;
+ dev = mlx5_lag_fn(ldev, first_idx)->dev;
lag_definer = kzalloc_obj(*lag_definer);
if (!lag_definer)
return ERR_PTR(-ENOMEM);
@@ -360,7 +360,7 @@ static void mlx5_lag_destroy_definer(struct mlx5_lag *ldev,
if (first_idx < 0)
return;
- dev = mlx5_lag_pf(ldev, first_idx)->dev;
+ dev = mlx5_lag_fn(ldev, first_idx)->dev;
mlx5_ldev_for_each(i, 0, ldev) {
for (j = 0; j < ldev->buckets; j++) {
idx = i * ldev->buckets + j;
@@ -524,7 +524,7 @@ static int mlx5_lag_create_ttc_table(struct mlx5_lag *ldev)
if (first_idx < 0)
return -EINVAL;
- dev = mlx5_lag_pf(ldev, first_idx)->dev;
+ dev = mlx5_lag_fn(ldev, first_idx)->dev;
mlx5_lag_set_outer_ttc_params(ldev, &ttc_params);
port_sel->outer.ttc = mlx5_create_ttc_table(dev, &ttc_params);
return PTR_ERR_OR_ZERO(port_sel->outer.ttc);
@@ -540,7 +540,7 @@ static int mlx5_lag_create_inner_ttc_table(struct mlx5_lag *ldev)
if (first_idx < 0)
return -EINVAL;
- dev = mlx5_lag_pf(ldev, first_idx)->dev;
+ dev = mlx5_lag_fn(ldev, first_idx)->dev;
mlx5_lag_set_inner_ttc_params(ldev, &ttc_params);
port_sel->inner.ttc = mlx5_create_inner_ttc_table(dev, &ttc_params);
return PTR_ERR_OR_ZERO(port_sel->inner.ttc);
@@ -594,6 +594,9 @@ static int __mlx5_lag_modify_definers_destinations(struct mlx5_lag *ldev,
mlx5_ldev_for_each(i, 0, ldev) {
for (j = 0; j < ldev->buckets; j++) {
+ struct mlx5_core_dev *mdev;
+ u8 affinity;
+
idx = i * ldev->buckets + j;
if (ldev->v2p_map[idx] == ports[idx])
continue;
@@ -601,9 +604,9 @@ static int __mlx5_lag_modify_definers_destinations(struct mlx5_lag *ldev,
/* ports[] contains 1-indexed device indices,
* use reverse lookup.
*/
- dest.vport.vhca_id =
- MLX5_CAP_GEN(mlx5_lag_pf_by_dev_idx(ldev, ports[idx] - 1)->dev,
- vhca_id);
+ affinity = ports[idx];
+ mdev = mlx5_lag_fn_by_dev_idx(ldev, affinity - 1)->dev;
+ dest.vport.vhca_id = MLX5_CAP_GEN(mdev, vhca_id);
err = mlx5_modify_rule_destination(def->rules[idx], &dest, NULL);
if (err)
return err;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c
index 29048b0c2797..404278a15ef7 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c
@@ -19,11 +19,11 @@ bool mlx5_lag_shared_fdb_supported_filter(struct mlx5_lag *ldev, u32 filter)
if (idx < 0)
return false;
- dev0 = mlx5_lag_pf(ldev, idx)->dev;
+ dev0 = mlx5_lag_fn(ldev, idx)->dev;
mlx5_lag_for_each(i, 0, ldev, filter) {
if (i == idx)
continue;
- dev = mlx5_lag_pf(ldev, i)->dev;
+ dev = mlx5_lag_fn(ldev, i)->dev;
if (is_mdev_switchdev_mode(dev) &&
mlx5_eswitch_vport_match_metadata_enabled(dev->priv.eswitch) &&
MLX5_CAP_GEN(dev, lag_native_fdb_selection) &&
@@ -59,7 +59,7 @@ static int mlx5_lag_create_single_fdb_filter(struct mlx5_lag *ldev, u32 filter)
if (master_idx < 0)
return -EINVAL;
- dev0 = mlx5_lag_pf(ldev, master_idx)->dev;
+ dev0 = mlx5_lag_fn(ldev, master_idx)->dev;
master_esw = dev0->priv.eswitch;
mlx5_lag_for_each(i, 0, ldev, filter) {
struct mlx5_eswitch *slave_esw;
@@ -67,11 +67,11 @@ static int mlx5_lag_create_single_fdb_filter(struct mlx5_lag *ldev, u32 filter)
if (i == master_idx)
continue;
- slave_esw = mlx5_lag_pf(ldev, i)->dev->priv.eswitch;
+ slave_esw = mlx5_lag_fn(ldev, i)->dev->priv.eswitch;
err = mlx5_eswitch_offloads_single_fdb_add_one(master_esw,
slave_esw,
- ldev->max_funcs);
+ ldev->max_fns);
if (err)
goto err;
}
@@ -82,7 +82,7 @@ static int mlx5_lag_create_single_fdb_filter(struct mlx5_lag *ldev, u32 filter)
if (j == master_idx)
continue;
- slave_esw = mlx5_lag_pf(ldev, j)->dev->priv.eswitch;
+ slave_esw = mlx5_lag_fn(ldev, j)->dev->priv.eswitch;
mlx5_eswitch_offloads_single_fdb_del_one(master_esw, slave_esw);
}
return err;
@@ -101,7 +101,7 @@ int mlx5_lag_create_vport_lag(struct mlx5_lag *ldev, u32 group_id)
if (master_idx < 0)
return -EINVAL;
- dev0 = mlx5_lag_pf(ldev, master_idx)->dev;
+ dev0 = mlx5_lag_fn(ldev, master_idx)->dev;
master_esw = dev0->priv.eswitch;
mlx5_lag_for_each(i, 0, ldev, filter) {
@@ -110,7 +110,7 @@ int mlx5_lag_create_vport_lag(struct mlx5_lag *ldev, u32 group_id)
if (i == master_idx)
continue;
- slave_esw = mlx5_lag_pf(ldev, i)->dev->priv.eswitch;
+ slave_esw = mlx5_lag_fn(ldev, i)->dev->priv.eswitch;
err = mlx5_eswitch_offloads_vport_lag_add_one(master_esw,
slave_esw);
if (err)
@@ -125,7 +125,7 @@ int mlx5_lag_create_vport_lag(struct mlx5_lag *ldev, u32 group_id)
if (j == master_idx)
continue;
- slave_esw = mlx5_lag_pf(ldev, j)->dev->priv.eswitch;
+ slave_esw = mlx5_lag_fn(ldev, j)->dev->priv.eswitch;
mlx5_eswitch_offloads_vport_lag_del_one(master_esw, slave_esw);
}
return err;
@@ -143,7 +143,7 @@ int mlx5_lag_destroy_vport_lag(struct mlx5_lag *ldev, u32 group_id)
if (master_idx < 0)
return 0;
- dev0 = mlx5_lag_pf(ldev, master_idx)->dev;
+ dev0 = mlx5_lag_fn(ldev, master_idx)->dev;
master_esw = dev0->priv.eswitch;
mlx5_lag_for_each(i, 0, ldev, filter) {
@@ -151,7 +151,7 @@ int mlx5_lag_destroy_vport_lag(struct mlx5_lag *ldev, u32 group_id)
if (i == master_idx)
continue;
- dev = mlx5_lag_pf(ldev, i)->dev;
+ dev = mlx5_lag_fn(ldev, i)->dev;
mlx5_eswitch_offloads_vport_lag_del_one(master_esw,
dev->priv.eswitch);
}
@@ -170,12 +170,12 @@ static void mlx5_lag_destroy_single_fdb_filter(struct mlx5_lag *ldev,
if (master_idx < 0)
return;
- master_esw = mlx5_lag_pf(ldev, master_idx)->dev->priv.eswitch;
+ master_esw = mlx5_lag_fn(ldev, master_idx)->dev->priv.eswitch;
mlx5_lag_for_each(i, 0, ldev, filter) {
if (i == master_idx)
continue;
- peer_esw = mlx5_lag_pf(ldev, i)->dev->priv.eswitch;
+ peer_esw = mlx5_lag_fn(ldev, i)->dev->priv.eswitch;
mlx5_eswitch_offloads_single_fdb_del_one(master_esw, peer_esw);
}
}
@@ -214,14 +214,14 @@ int mlx5_lag_shared_fdb_create(struct mlx5_lag *ldev,
int idx = mlx5_lag_get_dev_index_by_seq_filter(ldev, MLX5_LAG_P1,
filter);
struct mlx5_core_dev *dev0;
- struct lag_func *pf;
+ struct lag_fn *fn;
int err;
int i;
if (idx < 0)
return -EINVAL;
- dev0 = mlx5_lag_pf(ldev, idx)->dev;
+ dev0 = mlx5_lag_fn(ldev, idx)->dev;
mlx5_lag_remove_devices_filter(ldev, filter);
@@ -242,8 +242,8 @@ int mlx5_lag_shared_fdb_create(struct mlx5_lag *ldev,
goto err_add_devices;
}
mlx5_lag_for_each(i, 0, ldev, filter) {
- pf = mlx5_lag_pf(ldev, i);
- pf->sd_fdb_active = true;
+ fn = mlx5_lag_fn(ldev, i);
+ fn->sd_fdb_active = true;
}
BLOCKING_INIT_NOTIFIER_HEAD(&dev0->priv.lag_nh);
}
@@ -265,8 +265,8 @@ int mlx5_lag_shared_fdb_create(struct mlx5_lag *ldev,
mlx5_deactivate_lag(ldev);
} else {
mlx5_lag_for_each(i, 0, ldev, filter) {
- pf = mlx5_lag_pf(ldev, i);
- pf->sd_fdb_active = false;
+ fn = mlx5_lag_fn(ldev, i);
+ fn->sd_fdb_active = false;
}
mlx5_lag_destroy_single_fdb_filter(ldev, group_id);
mlx5_lag_unload_reps_from_locked(ldev, filter);
@@ -280,7 +280,7 @@ int mlx5_lag_shared_fdb_create(struct mlx5_lag *ldev,
void mlx5_lag_shared_fdb_destroy(struct mlx5_lag *ldev, u32 group_id)
{
u32 filter = group_id ? group_id : MLX5_LAG_FILTER_ALL;
- struct lag_func *pf;
+ struct lag_fn *fn;
int err;
int i;
@@ -292,8 +292,8 @@ void mlx5_lag_shared_fdb_destroy(struct mlx5_lag *ldev, u32 group_id)
return;
} else {
mlx5_lag_for_each(i, 0, ldev, filter) {
- pf = mlx5_lag_pf(ldev, i);
- pf->sd_fdb_active = false;
+ fn = mlx5_lag_fn(ldev, i);
+ fn->sd_fdb_active = false;
}
mlx5_lag_destroy_single_fdb_filter(ldev, group_id);
mlx5_lag_unload_reps_from_locked(ldev, filter);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/sd.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/sd.c
index 4cdc50cd6f03..f843efbca660 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/sd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/sd.c
@@ -300,7 +300,7 @@ static int sd_lag_state_show(struct seq_file *file, void *priv)
{
struct mlx5_core_dev *dev = file->private;
struct mlx5_lag *ldev;
- struct lag_func *pf;
+ struct lag_fn *fn;
bool active = false;
int i;
@@ -310,9 +310,9 @@ static int sd_lag_state_show(struct seq_file *file, void *priv)
mutex_lock(&ldev->lock);
mlx5_ldev_for_each(i, 0, ldev) {
- pf = mlx5_lag_pf(ldev, i);
- if (pf->dev == dev) {
- active = pf->sd_fdb_active;
+ fn = mlx5_lag_fn(ldev, i);
+ if (fn->dev == dev) {
+ active = fn->sd_fdb_active;
break;
}
}
@@ -334,7 +334,7 @@ static void sd_lag_init(struct mlx5_core_dev *dev)
struct mlx5_sd *sd = mlx5_get_sd(primary);
struct mlx5_core_dev *pos, *to;
struct mlx5_lag *ldev;
- struct lag_func *pf;
+ struct lag_fn *fn;
int err;
int i;
@@ -346,14 +346,14 @@ static void sd_lag_init(struct mlx5_core_dev *dev)
}
mutex_lock(&ldev->lock);
- pf = mlx5_lag_pf_by_dev(ldev, primary);
- if (!pf) {
+ fn = mlx5_lag_fn_by_dev(ldev, primary);
+ if (!fn) {
sd_warn(primary, "%s: primary not registered in ldev, skipping\n",
__func__);
goto out;
}
- pf->group_id = sd->group_id;
+ fn->group_id = sd->group_id;
mlx5_sd_for_each_secondary(i, primary, pos) {
err = mlx5_ldev_add_mdev(ldev, pos, sd->group_id);
@@ -372,7 +372,7 @@ static void sd_lag_init(struct mlx5_core_dev *dev)
to = pos;
mlx5_sd_for_each_secondary_to(i, primary, to, pos)
mlx5_ldev_remove_mdev(ldev, pos);
- pf->group_id = 0;
+ fn->group_id = 0;
mutex_unlock(&ldev->lock);
}
@@ -381,7 +381,7 @@ static void sd_lag_cleanup(struct mlx5_core_dev *dev)
struct mlx5_core_dev *primary = mlx5_sd_get_primary(dev);
struct mlx5_core_dev *pos;
struct mlx5_lag *ldev;
- struct lag_func *pf;
+ struct lag_fn *fn;
int i;
ldev = mlx5_lag_dev(primary);
@@ -392,9 +392,9 @@ static void sd_lag_cleanup(struct mlx5_core_dev *dev)
mlx5_sd_for_each_secondary(i, primary, pos)
mlx5_ldev_remove_mdev(ldev, pos);
- pf = mlx5_lag_pf_by_dev(ldev, primary);
- if (pf)
- pf->group_id = 0;
+ fn = mlx5_lag_fn_by_dev(ldev, primary);
+ if (fn)
+ fn->group_id = 0;
mutex_unlock(&ldev->lock);
}
@@ -989,7 +989,7 @@ static void mlx5_sd_activate_shared_fdb(struct mlx5_core_dev *primary)
struct mlx5_sd *sd = mlx5_get_sd(primary);
struct mlx5_core_dev *pos;
struct mlx5_lag *ldev;
- struct lag_func *pf;
+ struct lag_fn *fn;
int err;
int i;
@@ -1009,8 +1009,8 @@ static void mlx5_sd_activate_shared_fdb(struct mlx5_core_dev *primary)
/* Check if SD FDB is already active for this group */
mlx5_lag_for_each(i, 0, ldev, sd->group_id) {
- pf = mlx5_lag_pf(ldev, i);
- if (pf->sd_fdb_active)
+ fn = mlx5_lag_fn(ldev, i);
+ if (fn->sd_fdb_active)
goto unlock;
break;
}
--
2.44.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net-next 07/15] net/mlx5: LAG, resolve affinity indices only in queue-affinity mode
2026-11-03 17:09 [PATCH net-next 00/15] net/mlx5: LAG over VFs/SFs (virtual LAG) Tariq Toukan
` (5 preceding siblings ...)
2026-11-03 17:10 ` [PATCH net-next 06/15] net/mlx5: LAG, rename PF naming to fn Tariq Toukan
@ 2026-11-03 17:10 ` Tariq Toukan
2026-11-03 17:10 ` [PATCH net-next 08/15] net/mlx5: LAG: replace fixed MLX5_MAX_PORTS arrays with dynamic allocation Tariq Toukan
` (7 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tariq Toukan @ 2026-11-03 17:10 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Carolina Jubran, Cosmin Ratiu, Edward Srouji,
Gal Pressman, Leon Romanovsky, open list, linux-rdma, Mark Bloch,
Moshe Shemesh, Or Har-Toov, Patrisious Haddad, Saeed Mahameed,
Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
mlx5_cmd_create_lag() resolved the first two members up front via
mlx5_lag_get_dev_index_by_seq() and returned -EINVAL if either failed,
but only the queue-affinity mode uses them.
Move the lookup into that case.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../net/ethernet/mellanox/mlx5/core/lag/lag.c | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
index 1b065033a2a1..2b76d119cfa6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
@@ -95,23 +95,25 @@ static int mlx5_cmd_create_lag(struct mlx5_core_dev *dev, struct mlx5_lag *ldev,
int port_sel_mode = get_port_sel_mode(mode, flags);
u32 in[MLX5_ST_SZ_DW(create_lag_in)] = {};
u8 *ports = ldev->v2p_map;
- int idx0, idx1;
void *lag_ctx;
lag_ctx = MLX5_ADDR_OF(create_lag_in, in, ctx);
MLX5_SET(create_lag_in, in, opcode, MLX5_CMD_OP_CREATE_LAG);
MLX5_SET(lagc, lag_ctx, fdb_selection_mode, fdb_sel_mode);
- idx0 = mlx5_lag_get_dev_index_by_seq(ldev, 0);
- idx1 = mlx5_lag_get_dev_index_by_seq(ldev, 1);
+ switch (port_sel_mode) {
+ case MLX5_LAG_PORT_SELECT_MODE_QUEUE_AFFINITY: {
+ int idx0, idx1;
- if (idx0 < 0 || idx1 < 0)
- return -EINVAL;
+ idx0 = mlx5_lag_get_dev_index_by_seq(ldev, 0);
+ idx1 = mlx5_lag_get_dev_index_by_seq(ldev, 1);
+
+ if (idx0 < 0 || idx1 < 0)
+ return -EINVAL;
- switch (port_sel_mode) {
- case MLX5_LAG_PORT_SELECT_MODE_QUEUE_AFFINITY:
MLX5_SET(lagc, lag_ctx, tx_remap_affinity_1, ports[idx0]);
MLX5_SET(lagc, lag_ctx, tx_remap_affinity_2, ports[idx1]);
break;
+ }
case MLX5_LAG_PORT_SELECT_MODE_PORT_SELECT_FT: {
u8 active_port;
int ret;
--
2.44.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net-next 08/15] net/mlx5: LAG: replace fixed MLX5_MAX_PORTS arrays with dynamic allocation
2026-11-03 17:09 [PATCH net-next 00/15] net/mlx5: LAG over VFs/SFs (virtual LAG) Tariq Toukan
` (6 preceding siblings ...)
2026-11-03 17:10 ` [PATCH net-next 07/15] net/mlx5: LAG, resolve affinity indices only in queue-affinity mode Tariq Toukan
@ 2026-11-03 17:10 ` Tariq Toukan
2026-11-03 17:10 ` [PATCH net-next 09/15] net/mlx5: LAG, drop MLX5_MAX_PORTS scratch array from device rescan Tariq Toukan
` (6 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tariq Toukan @ 2026-11-03 17:10 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Carolina Jubran, Cosmin Ratiu, Edward Srouji,
Gal Pressman, Leon Romanovsky, open list, linux-rdma, Mark Bloch,
Moshe Shemesh, Or Har-Toov, Patrisious Haddad, Saeed Mahameed,
Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
Converts two fixed-size arrays sized to MLX5_MAX_PORTS into
dynamically allocated pointers:
- lag_mpesw.pf_metadata in mpesw.c/mpesw.h, sized by ldev->max_fns
- mdev array in mlx5_lag_query_cong_counters(), sized by ldev->ports
The cong-counters array is sized by ldev->ports, which is fixed at ldev
allocation, rather than by the LAG mode, so a mode change between the
allocation and filling the array cannot overflow it. The query loop is
bounded by the number of entries actually filled. A virt LAG is not
aggregated and queries only the given device, as its members are not
LAG ports.
Thus, removes the hard dependency on MLX5_MAX_PORTS.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c | 15 +++++++--------
.../net/ethernet/mellanox/mlx5/core/lag/mpesw.c | 12 ++++++++++++
.../net/ethernet/mellanox/mlx5/core/lag/mpesw.h | 2 +-
3 files changed, 20 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
index 2b76d119cfa6..b873eb91fd0d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
@@ -2917,7 +2917,9 @@ int mlx5_lag_query_cong_counters(struct mlx5_core_dev *dev,
if (!out)
return -ENOMEM;
- mdev = kvzalloc(sizeof(mdev[0]) * MLX5_MAX_PORTS, GFP_KERNEL);
+ ldev = mlx5_lag_dev(dev);
+ num_ports = ldev ? max_t(int, ldev->ports, 1) : 1;
+ mdev = kcalloc(num_ports, sizeof(mdev[0]), GFP_KERNEL);
if (!mdev) {
ret = -ENOMEM;
goto free_out;
@@ -2926,20 +2928,17 @@ int mlx5_lag_query_cong_counters(struct mlx5_core_dev *dev,
memset(values, 0, sizeof(*values) * num_counters);
spin_lock_irqsave(&lag_lock, flags);
- ldev = mlx5_lag_dev(dev);
- if (ldev && __mlx5_lag_is_active(ldev)) {
- num_ports = ldev->ports;
+ if (ldev && __mlx5_lag_is_active(ldev) && !ldev->virt_lag) {
mlx5_ldev_for_each(i, 0, ldev) {
fn = mlx5_lag_fn(ldev, i);
mdev[idx++] = fn->dev;
}
} else {
- num_ports = 1;
- mdev[MLX5_LAG_P1] = dev;
+ mdev[idx++] = dev;
}
spin_unlock_irqrestore(&lag_lock, flags);
- for (i = 0; i < num_ports; ++i) {
+ for (i = 0; i < idx; ++i) {
u32 in[MLX5_ST_SZ_DW(query_cong_statistics_in)] = {};
MLX5_SET(query_cong_statistics_in, in, opcode,
@@ -2954,7 +2953,7 @@ int mlx5_lag_query_cong_counters(struct mlx5_core_dev *dev,
}
free_mdev:
- kvfree(mdev);
+ kfree(mdev);
free_out:
kvfree(out);
return ret;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
index 6e3bef276611..584436668a5c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
@@ -15,6 +15,9 @@ static void mlx5_mpesw_metadata_cleanup(struct mlx5_lag *ldev)
u32 pf_metadata;
int i;
+ if (!ldev->lag_mpesw.pf_metadata)
+ return;
+
mlx5_lag_for_each(i, 0, ldev, MLX5_LAG_FILTER_ALL) {
dev = mlx5_lag_fn(ldev, i)->dev;
esw = dev->priv.eswitch;
@@ -27,6 +30,9 @@ static void mlx5_mpesw_metadata_cleanup(struct mlx5_lag *ldev)
mlx5_esw_match_metadata_free(esw, pf_metadata);
ldev->lag_mpesw.pf_metadata[i] = 0;
}
+
+ kfree(ldev->lag_mpesw.pf_metadata);
+ ldev->lag_mpesw.pf_metadata = NULL;
}
static int mlx5_mpesw_metadata_set(struct mlx5_lag *ldev)
@@ -36,6 +42,12 @@ static int mlx5_mpesw_metadata_set(struct mlx5_lag *ldev)
u32 pf_metadata;
int i, err;
+ ldev->lag_mpesw.pf_metadata =
+ kcalloc(ldev->max_fns, sizeof(*ldev->lag_mpesw.pf_metadata),
+ GFP_KERNEL);
+ if (!ldev->lag_mpesw.pf_metadata)
+ return -ENOMEM;
+
mlx5_lag_for_each(i, 0, ldev, MLX5_LAG_FILTER_ALL) {
dev = mlx5_lag_fn(ldev, i)->dev;
esw = dev->priv.eswitch;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.h b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.h
index 5099723ba0f7..6296e3edd38c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.h
@@ -9,7 +9,7 @@
struct lag_mpesw {
struct work_struct mpesw_work;
- u32 pf_metadata[MLX5_MAX_PORTS];
+ u32 *pf_metadata;
};
enum mpesw_op {
--
2.44.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net-next 09/15] net/mlx5: LAG, drop MLX5_MAX_PORTS scratch array from device rescan
2026-11-03 17:09 [PATCH net-next 00/15] net/mlx5: LAG over VFs/SFs (virtual LAG) Tariq Toukan
` (7 preceding siblings ...)
2026-11-03 17:10 ` [PATCH net-next 08/15] net/mlx5: LAG: replace fixed MLX5_MAX_PORTS arrays with dynamic allocation Tariq Toukan
@ 2026-11-03 17:10 ` Tariq Toukan
2026-11-03 17:10 ` [PATCH net-next 10/15] net/mlx5: LAG, do not add a device to an already-active LAG Tariq Toukan
` (5 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tariq Toukan @ 2026-11-03 17:10 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Carolina Jubran, Cosmin Ratiu, Edward Srouji,
Gal Pressman, Leon Romanovsky, open list, linux-rdma, Mark Bloch,
Moshe Shemesh, Or Har-Toov, Patrisious Haddad, Saeed Mahameed,
Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
mlx5_lag_rescan_devices_locked_filter() collected the participating LAG
members into a fixed-size devs[MLX5_MAX_PORTS] array only to iterate
over it a second time for the rescan calls. Drop the scratch array and
re-walk the members directly with mlx5_lag_for_each().
This removes another dependency on the compile-time MLX5_MAX_PORTS bound
with no functional change.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
index b873eb91fd0d..9bc4a929cef3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
@@ -1341,9 +1341,7 @@ void mlx5_lag_rescan_dev_locked(struct mlx5_lag *ldev,
static void mlx5_lag_rescan_devices_locked_filter(struct mlx5_lag *ldev,
bool enable, u32 filter)
{
- struct mlx5_core_dev *devs[MLX5_MAX_PORTS];
struct lag_fn *fn;
- int num_devs = 0;
int i;
mlx5_lag_assert_locked_transition(ldev, filter);
@@ -1357,12 +1355,16 @@ static void mlx5_lag_rescan_devices_locked_filter(struct mlx5_lag *ldev,
fn->dev->priv.flags &= ~MLX5_PRIV_FLAGS_DISABLE_IB_ADEV;
else
fn->dev->priv.flags |= MLX5_PRIV_FLAGS_DISABLE_IB_ADEV;
- devs[num_devs++] = fn->dev;
}
mlx5_lag_drop_lock_for_reps(ldev, filter);
- for (i = 0; i < num_devs; i++)
- mlx5_rescan_drivers_locked(devs[i]);
+ mlx5_lag_for_each(i, 0, ldev, filter) {
+ fn = mlx5_lag_fn(ldev, i);
+ if (fn->dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV)
+ continue;
+
+ mlx5_rescan_drivers_locked(fn->dev);
+ }
mlx5_lag_retake_lock_after_reps(ldev);
}
--
2.44.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net-next 10/15] net/mlx5: LAG, do not add a device to an already-active LAG
2026-11-03 17:09 [PATCH net-next 00/15] net/mlx5: LAG over VFs/SFs (virtual LAG) Tariq Toukan
` (8 preceding siblings ...)
2026-11-03 17:10 ` [PATCH net-next 09/15] net/mlx5: LAG, drop MLX5_MAX_PORTS scratch array from device rescan Tariq Toukan
@ 2026-11-03 17:10 ` Tariq Toukan
2026-11-03 17:10 ` [PATCH net-next 11/15] net/mlx5: E-switch, add match-metadata allocator for nested VF/SF eswitches Tariq Toukan
` (4 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tariq Toukan @ 2026-11-03 17:10 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Carolina Jubran, Cosmin Ratiu, Edward Srouji,
Gal Pressman, Leon Romanovsky, open list, linux-rdma, Mark Bloch,
Moshe Shemesh, Or Har-Toov, Patrisious Haddad, Saeed Mahameed,
Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
mlx5_ldev_add_mdev() would add a newly probed device to the LAG even
when the LAG is already active, mutating membership while getters may be
iterating it and while the active mapping assumes a fixed member set.
Reject the join when the group's LAG is active:
__mlx5_lag_dev_add_mdev() returns -EOPNOTSUPP, and mlx5_lag_add_mdev()
treats that as terminal - unregister the HCA devcom component and leave
the device standalone, rather than the -EAGAIN retry used for the
bounded mode-change window.
The device stays out of the LAG until it is reprobed.
This keeps LAG membership stable while active. It is a no-op for
existing configurations, where no device is added to a LAG once it is
active.
In addition, do not register the eswitch devcom component of such a
device, so it does not pair with the eswitches of the LAG members.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 4 ++++
drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c | 9 +++++++++
drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h | 5 +++++
3 files changed, 18 insertions(+)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index c712848b202d..70e6dd9561a6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -3573,6 +3573,10 @@ void mlx5_esw_offloads_devcom_init(struct mlx5_eswitch *esw,
xa_init(&esw->offloads.peer_flows);
mutex_init(&esw->offloads.peer_mutex);
+ /* do not pair a virt LAG capable VF/SF that is not part of a LAG */
+ if (!mlx5_core_is_pf(esw->dev) && mlx5_virt_lag_nonmember(esw->dev))
+ return;
+
if (!MLX5_CAP_ESW(esw->dev, merged_eswitch))
return;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
index 9bc4a929cef3..d73bac8441f7 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
@@ -2449,6 +2449,11 @@ static int __mlx5_lag_dev_add_mdev(struct mlx5_core_dev *dev)
mutex_unlock(&ldev->lock);
return -EAGAIN;
}
+
+ if (mlx5_virt_lag_is_supported(dev) && __mlx5_lag_is_active(ldev)) {
+ mutex_unlock(&ldev->lock);
+ return -EOPNOTSUPP;
+ }
mlx5_ldev_get(ldev);
err = mlx5_ldev_add_mdev(ldev, dev, 0);
if (err) {
@@ -2537,6 +2542,10 @@ void mlx5_lag_add_mdev(struct mlx5_core_dev *dev)
err = __mlx5_lag_dev_add_mdev(dev);
mlx5_devcom_comp_unlock(dev->priv.hca_devcom_comp);
+ if (err == -EOPNOTSUPP) {
+ mlx5_lag_unregister_hca_devcom_comp(dev);
+ return;
+ }
if (err) {
msleep(100);
goto recheck;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
index cbe380ae8bf9..385c767e24ae 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
@@ -280,6 +280,11 @@ static inline bool mlx5_virt_lag_is_supported(const struct mlx5_core_dev *dev)
return true;
}
+static inline bool mlx5_virt_lag_nonmember(struct mlx5_core_dev *dev)
+{
+ return mlx5_virt_lag_is_supported(dev) && !mlx5_lag_dev(dev);
+}
+
static inline bool mlx5_lag_is_supported(struct mlx5_core_dev *dev)
{
if (!MLX5_CAP_GEN(dev, vport_group_manager) ||
--
2.44.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net-next 11/15] net/mlx5: E-switch, add match-metadata allocator for nested VF/SF eswitches
2026-11-03 17:09 [PATCH net-next 00/15] net/mlx5: LAG over VFs/SFs (virtual LAG) Tariq Toukan
` (9 preceding siblings ...)
2026-11-03 17:10 ` [PATCH net-next 10/15] net/mlx5: LAG, do not add a device to an already-active LAG Tariq Toukan
@ 2026-11-03 17:10 ` Tariq Toukan
2026-11-03 17:10 ` [PATCH net-next 12/15] net/mlx5: E-switch, match master egress rule by vport metadata Tariq Toukan
` (3 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tariq Toukan @ 2026-11-03 17:10 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Carolina Jubran, Cosmin Ratiu, Edward Srouji,
Gal Pressman, Leon Romanovsky, open list, linux-rdma, Mark Bloch,
Moshe Shemesh, Or Har-Toov, Patrisious Haddad, Saeed Mahameed,
Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
The eswitch source-port match metadata is laid out as 4 bits of PFNUM
and 12 bits of a unique id (ESW_SOURCE_PORT_METADATA_BITS). PFNUM is the
native_port_num reported in HCA_CAP, so all VFs/SFs of the same PF share
a single PFNUM. Each VF/SF eswitch allocates its id from its own
vport_metadata_ida, restarting from the lowest value, so two VFs/SFs of
the same PF can end up with identical metadata. Once their eswitches
share an FDB (virt LAG), that metadata no longer uniquely identifies the
source port.
Add a dedicated allocator for nested (virt LAG) eswitches that replaces
the PFNUM field with the VF/SF's slot in the LAG (its xarray index in
ldev->fns). That index is unique per function within the LAG, so
combined with a per-VF/SF id it yields unique metadata regardless of
which PF the VFs/SFs belong to. The split is 8 bits for the virt LAG
index - which fits the U8_MAX cap on the LAG xarray - and the remaining
8 bits for the id; the two still sum to ESW_SOURCE_PORT_METADATA_BITS,
so nothing downstream of the match changes.
The PFNUM value 0xf is reserved for internal port offload, which stamps
it into reg_c_0 and matches it with the same mask used for vport
metadata. That offload is gated on switchdev mode only, so it can be
used on a nested eswitch as well. Cap the LAG index accordingly.
Select the nested layout for any non-PF eswitch, so every PF keeps the
PFNUM layout regardless of its virt LAG capabilities.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../mellanox/mlx5/core/eswitch_offloads.c | 48 +++++++++++++++++++
.../net/ethernet/mellanox/mlx5/core/lag/lag.c | 17 +++++++
.../ethernet/mellanox/mlx5/core/mlx5_core.h | 1 +
3 files changed, 66 insertions(+)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index 70e6dd9561a6..ef1043517e9e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -3651,6 +3651,48 @@ static u32 mlx5_esw_match_metadata_reserved(struct mlx5_eswitch *esw)
return MLX5_ESW_METADATA_RSVD_UPLINK;
}
+/* Nested (virt LAG) source-port metadata layout: the upper ESW_NESTED_IDX_BITS
+ * hold the VF/SF's slot in the LAG and the lower ESW_NESTED_VPORT_BITS hold a
+ * vport id unique within its eswitch. The two fields still sum to
+ * ESW_SOURCE_PORT_METADATA_BITS. The LAG slot (0-254, per the xa_alloc() limit
+ * in mlx5_ldev_add_mdev()) fits in ESW_NESTED_IDX_BITS; slots 0xf0 and up would
+ * drive the PFNUM bits to the 0xf reserved by internal port offload, so only
+ * 0-239 are used.
+ */
+#define ESW_NESTED_VPORT_BITS 8
+#define ESW_NESTED_IDX_BITS (ESW_SOURCE_PORT_METADATA_BITS - ESW_NESTED_VPORT_BITS)
+
+static u32 mlx5_nested_esw_match_metadata_alloc(struct mlx5_eswitch *esw)
+{
+ u32 vport_end_ida = (1 << ESW_NESTED_VPORT_BITS) - 1;
+ u32 max_idx = (1 << ESW_NESTED_IDX_BITS) -
+ (1 << (ESW_NESTED_IDX_BITS - ESW_PFNUM_BITS)) - 1;
+ int idx;
+ int id;
+
+ idx = mlx5_lag_get_member_idx(esw->dev);
+ if (idx < 0 || idx > max_idx)
+ return 0;
+
+ /* Use only non-zero id's (2-255). */
+ id = ida_alloc_range(&esw->offloads.vport_metadata_ida,
+ MLX5_ESW_METADATA_RSVD_UPLINK + 1,
+ vport_end_ida, GFP_KERNEL);
+ if (id < 0)
+ return 0;
+ id = (idx << ESW_NESTED_VPORT_BITS) | id;
+ return id;
+}
+
+static void mlx5_nested_esw_match_metadata_free(struct mlx5_eswitch *esw,
+ u32 metadata)
+{
+ u32 vport_bit_mask = (1 << ESW_NESTED_VPORT_BITS) - 1;
+
+ /* Metadata holds only ESW_NESTED_VPORT_BITS of actual ida id. */
+ ida_free(&esw->offloads.vport_metadata_ida, metadata & vport_bit_mask);
+}
+
u32 mlx5_esw_match_metadata_alloc(struct mlx5_eswitch *esw)
{
u32 vport_end_ida = (1 << ESW_VPORT_BITS) - 1;
@@ -3659,6 +3701,9 @@ u32 mlx5_esw_match_metadata_alloc(struct mlx5_eswitch *esw)
int pf_num;
int id;
+ if (!mlx5_core_is_pf(esw->dev) && !mlx5_virt_lag_nonmember(esw->dev))
+ return mlx5_nested_esw_match_metadata_alloc(esw);
+
/* Only 4 bits of pf_num */
pf_num = mlx5_sd_pf_num_get(esw->dev);
if (pf_num < 0 || pf_num > max_pf_num)
@@ -3679,6 +3724,9 @@ void mlx5_esw_match_metadata_free(struct mlx5_eswitch *esw, u32 metadata)
{
u32 vport_bit_mask = (1 << ESW_VPORT_BITS) - 1;
+ if (!mlx5_core_is_pf(esw->dev) && !mlx5_virt_lag_nonmember(esw->dev))
+ return mlx5_nested_esw_match_metadata_free(esw, metadata);
+
/* Metadata contains only 12 bits of actual ida id */
ida_free(&esw->offloads.vport_metadata_ida, metadata & vport_bit_mask);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
index d73bac8441f7..4e15e16ae6e8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
@@ -516,6 +516,23 @@ int mlx5_lag_get_dev_seq(struct mlx5_core_dev *dev)
}
EXPORT_SYMBOL(mlx5_lag_get_dev_seq);
+int mlx5_lag_get_member_idx(struct mlx5_core_dev *dev)
+{
+ struct mlx5_lag *ldev = mlx5_lag_dev(dev);
+ struct lag_fn *fn;
+ int idx;
+
+ if (!ldev)
+ return -ENOENT;
+
+ xa_lock(&ldev->fns);
+ fn = mlx5_lag_fn_by_dev(ldev, dev);
+ idx = fn ? fn->idx : -ENOENT;
+ xa_unlock(&ldev->fns);
+
+ return idx;
+}
+
/* seq 0 = master, then all remaining devices */
static int mlx5_lag_get_dev_index_by_seq_all(struct mlx5_lag *ldev, int seq)
{
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
index d84d0424d04e..f5f105762d88 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
@@ -275,6 +275,7 @@ void mlx5_lag_add_mdev(struct mlx5_core_dev *dev);
void mlx5_lag_remove_mdev(struct mlx5_core_dev *dev);
void mlx5_lag_disable_change(struct mlx5_core_dev *dev);
void mlx5_lag_enable_change(struct mlx5_core_dev *dev);
+int mlx5_lag_get_member_idx(struct mlx5_core_dev *dev);
int mlx5_events_init(struct mlx5_core_dev *dev);
void mlx5_events_cleanup(struct mlx5_core_dev *dev);
--
2.44.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net-next 12/15] net/mlx5: E-switch, match master egress rule by vport metadata
2026-11-03 17:09 [PATCH net-next 00/15] net/mlx5: LAG over VFs/SFs (virtual LAG) Tariq Toukan
` (10 preceding siblings ...)
2026-11-03 17:10 ` [PATCH net-next 11/15] net/mlx5: E-switch, add match-metadata allocator for nested VF/SF eswitches Tariq Toukan
@ 2026-11-03 17:10 ` Tariq Toukan
2026-11-03 17:10 ` [PATCH net-next 13/15] net/mlx5: E-switch, drop master egress rule under a SW vport LAG Tariq Toukan
` (2 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tariq Toukan @ 2026-11-03 17:10 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Carolina Jubran, Cosmin Ratiu, Edward Srouji,
Gal Pressman, Leon Romanovsky, open list, linux-rdma, Mark Bloch,
Moshe Shemesh, Or Har-Toov, Patrisious Haddad, Saeed Mahameed,
Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
The master egress-ACL bounce group and rule matched the slave uplink by
source_port + source_eswitch_owner_vhca_id. Virt LAG master cannot match
that way; it must match by vport metadata (reg_c_0).
Virt LAG only supports MPESW, where every uplink has a unique metadata.
Hence, use metadata matching when LAG is virt LAG, and keep the
source_port + source_eswitch_owner_vhca_id match otherwise.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Akiva Goldberger <agoldberger@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../mellanox/mlx5/core/eswitch_offloads.c | 78 +++++++++++++------
1 file changed, 55 insertions(+), 23 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index ef1043517e9e..d633c63b309b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -3000,6 +3000,26 @@ static int esw_set_slave_root_fdb(struct mlx5_core_dev *master,
return err;
}
+static void mlx5_esw_set_spec_source_port_vhca(struct mlx5_flow_spec *spec,
+ u16 vport, u16 vhca_id)
+{
+ void *misc;
+
+ spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
+
+ misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
+ misc_parameters);
+ MLX5_SET(fte_match_set_misc, misc, source_port, vport);
+ MLX5_SET(fte_match_set_misc, misc, source_eswitch_owner_vhca_id,
+ vhca_id);
+
+ misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
+ misc_parameters);
+ MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
+ MLX5_SET_TO_ONES(fte_match_set_misc, misc,
+ source_eswitch_owner_vhca_id);
+}
+
static int __esw_set_master_egress_rule(struct mlx5_core_dev *master,
struct mlx5_core_dev *slave,
struct mlx5_vport *vport,
@@ -3011,22 +3031,22 @@ static int __esw_set_master_egress_rule(struct mlx5_core_dev *master,
struct mlx5_flow_act flow_act = {};
struct mlx5_flow_spec *spec;
int err = 0;
- void *misc;
+
+ if (mlx5_virt_lag_is_supported(master) &&
+ !mlx5_eswitch_vport_match_metadata_enabled(slave->priv.eswitch))
+ return -EINVAL;
spec = kvzalloc_obj(*spec);
if (!spec)
return -ENOMEM;
- spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
- misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
- misc_parameters);
- MLX5_SET(fte_match_set_misc, misc, source_port, MLX5_VPORT_UPLINK);
- MLX5_SET(fte_match_set_misc, misc, source_eswitch_owner_vhca_id, slave_index);
-
- misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
- MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
- MLX5_SET_TO_ONES(fte_match_set_misc, misc,
- source_eswitch_owner_vhca_id);
+ if (mlx5_virt_lag_is_supported(master) &&
+ mlx5_eswitch_vport_match_metadata_enabled(slave->priv.eswitch))
+ mlx5_esw_set_spec_source_port(slave->priv.eswitch,
+ MLX5_VPORT_UPLINK, spec);
+ else
+ mlx5_esw_set_spec_source_port_vhca(spec, MLX5_VPORT_UPLINK,
+ slave_index);
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
@@ -3179,6 +3199,21 @@ static void esw_unset_slave_egress_rule(struct mlx5_core_dev *master,
esw_slave_egress_destroy_resources(slave_vport);
}
+static void mlx5_esw_set_flow_group_source_port_vhca(u32 *flow_group_in)
+{
+ void *match_criteria = MLX5_ADDR_OF(create_flow_group_in,
+ flow_group_in, match_criteria);
+
+ MLX5_SET_TO_ONES(fte_match_param, match_criteria,
+ misc_parameters.source_port);
+ MLX5_SET_TO_ONES(fte_match_param, match_criteria,
+ misc_parameters.source_eswitch_owner_vhca_id);
+ MLX5_SET(create_flow_group_in, flow_group_in,
+ match_criteria_enable, MLX5_MATCH_MISC_PARAMETERS);
+ MLX5_SET(create_flow_group_in, flow_group_in,
+ source_eswitch_owner_vhca_id_valid, 1);
+}
+
static int esw_master_egress_create_resources(struct mlx5_eswitch *esw,
struct mlx5_flow_namespace *egress_ns,
struct mlx5_vport *vport, size_t count)
@@ -3189,13 +3224,16 @@ static int esw_master_egress_create_resources(struct mlx5_eswitch *esw,
};
struct mlx5_flow_table *acl;
struct mlx5_flow_group *g;
- void *match_criteria;
u32 *flow_group_in;
int err;
if (vport->egress.acl)
return 0;
+ if (mlx5_virt_lag_is_supported(esw->dev) &&
+ !mlx5_eswitch_vport_match_metadata_enabled(esw))
+ return -EINVAL;
+
flow_group_in = kvzalloc(inlen, GFP_KERNEL);
if (!flow_group_in)
return -ENOMEM;
@@ -3209,17 +3247,11 @@ static int esw_master_egress_create_resources(struct mlx5_eswitch *esw,
goto out;
}
- match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in,
- match_criteria);
- MLX5_SET_TO_ONES(fte_match_param, match_criteria,
- misc_parameters.source_port);
- MLX5_SET_TO_ONES(fte_match_param, match_criteria,
- misc_parameters.source_eswitch_owner_vhca_id);
- MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
- MLX5_MATCH_MISC_PARAMETERS);
-
- MLX5_SET(create_flow_group_in, flow_group_in,
- source_eswitch_owner_vhca_id_valid, 1);
+ if (mlx5_virt_lag_is_supported(esw->dev) &&
+ mlx5_eswitch_vport_match_metadata_enabled(esw))
+ mlx5_esw_set_flow_group_source_port(esw, flow_group_in, 0);
+ else
+ mlx5_esw_set_flow_group_source_port_vhca(flow_group_in);
MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, count);
--
2.44.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net-next 13/15] net/mlx5: E-switch, drop master egress rule under a SW vport LAG
2026-11-03 17:09 [PATCH net-next 00/15] net/mlx5: LAG over VFs/SFs (virtual LAG) Tariq Toukan
` (11 preceding siblings ...)
2026-11-03 17:10 ` [PATCH net-next 12/15] net/mlx5: E-switch, match master egress rule by vport metadata Tariq Toukan
@ 2026-11-03 17:10 ` Tariq Toukan
2026-11-03 17:10 ` [PATCH net-next 14/15] net/mlx5e: Register eswitch-manager VF/SF self-port with switch-id Tariq Toukan
2026-11-03 17:10 ` [PATCH net-next 15/15] net/mlx5: LAG, enable LAG over functions that do not represent a physical port Tariq Toukan
14 siblings, 0 replies; 16+ messages in thread
From: Tariq Toukan @ 2026-11-03 17:10 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Carolina Jubran, Cosmin Ratiu, Edward Srouji,
Gal Pressman, Leon Romanovsky, open list, linux-rdma, Mark Bloch,
Moshe Shemesh, Or Har-Toov, Patrisious Haddad, Saeed Mahameed,
Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
VPORT_LAG steers all traffic of a LAG slave to the LAG master. The
eswitch master egress rule does the opposite direction: it bounces
traffic that reached the master's manager vport into the slave eswitch.
With a FW vport LAG the FW steers that bounced packet to the LAG master,
so the two coexist.
The software vport LAG emulation cannot. It is a catch-all rule in the
slave eswitch's egress ACL that forwards to the master's manager vport,
while the master egress rule redirects the packet after the FDB - past
the point where the slave egress rule is evaluated - so the bounced
packet never reaches it.
The two therefore cannot coexist: drop the master egress rule when the
software vport LAG is installed, and restore it when it is removed. Both
rules are keyed by the peer vhca_id, so each slave swaps its own pair
independently. Restoring needs the ACL size, so pass ldev->max_funcs
down to mlx5_eswitch_offloads_vport_lag_del_one(), as the single FDB
path already does.
Also, release the MPESW metadata after the shared FDB is destroyed,
mirroring the creation order. Releasing it first makes all slaves fall
back to the same default uplink metadata, so the restored master egress
rules collide.
Note that vport LAG on its own only gets traffic to the LAG master; the
distribution to the other slaves esw managers, which was managed by
master egress rules, is done by the LAG demux
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../net/ethernet/mellanox/mlx5/core/eswitch.h | 3 ++-
.../mellanox/mlx5/core/eswitch_offloads.c | 24 +++++++++++++++++--
.../ethernet/mellanox/mlx5/core/lag/mpesw.c | 2 +-
.../mellanox/mlx5/core/lag/shared_fdb.c | 6 +++--
4 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
index e9cbcd73b23f..55f5ea522d46 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -957,7 +957,8 @@ bool mlx5_esw_offloads_controller_valid(const struct mlx5_eswitch *esw, u32 cont
int mlx5_eswitch_offloads_vport_lag_add_one(struct mlx5_eswitch *master_esw,
struct mlx5_eswitch *slave_esw);
void mlx5_eswitch_offloads_vport_lag_del_one(struct mlx5_eswitch *master_esw,
- struct mlx5_eswitch *slave_esw);
+ struct mlx5_eswitch *slave_esw,
+ int max_slaves);
int mlx5_eswitch_offloads_single_fdb_add_one(struct mlx5_eswitch *master_esw,
struct mlx5_eswitch *slave_esw, int max_slaves);
void mlx5_eswitch_offloads_single_fdb_del_one(struct mlx5_eswitch *master_esw,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index d633c63b309b..f1a5d7d036cb 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -3381,12 +3381,32 @@ void mlx5_eswitch_offloads_single_fdb_del_one(struct mlx5_eswitch *master_esw,
int mlx5_eswitch_offloads_vport_lag_add_one(struct mlx5_eswitch *master_esw,
struct mlx5_eswitch *slave_esw)
{
- return esw_set_slave_egress_rule(master_esw->dev, slave_esw->dev);
+ int err;
+
+ err = esw_set_slave_egress_rule(master_esw->dev, slave_esw->dev);
+ if (err)
+ return err;
+
+ esw_unset_master_egress_rule(master_esw->dev, slave_esw->dev);
+
+ return 0;
}
void mlx5_eswitch_offloads_vport_lag_del_one(struct mlx5_eswitch *master_esw,
- struct mlx5_eswitch *slave_esw)
+ struct mlx5_eswitch *slave_esw,
+ int max_slaves)
{
+ int err;
+
+ if (mlx5_sd_is_primary(slave_esw->dev)) {
+ err = esw_set_master_egress_rule(master_esw->dev,
+ slave_esw->dev, max_slaves);
+ if (err)
+ esw_warn(master_esw->dev,
+ "Failed to restore master egress rule (%d)\n",
+ err);
+ }
+
esw_unset_slave_egress_rule(master_esw->dev, slave_esw->dev);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
index 584436668a5c..3dd7fa8de66c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
@@ -208,10 +208,10 @@ void mlx5_lag_disable_mpesw(struct mlx5_lag *ldev)
if (ldev->mode != MLX5_LAG_MODE_MPESW)
return;
- mlx5_mpesw_metadata_cleanup(ldev);
mlx5_lag_shared_fdb_destroy(ldev, MLX5_LAG_FILTER_ALL);
if (mlx5_lag_has_sd_group(ldev))
mlx5_mpesw_restore_sd_fdb(ldev);
+ mlx5_mpesw_metadata_cleanup(ldev);
/* Pair with the master mark taken at MPESW create for VFs. */
if (ldev->virt_lag)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c
index 404278a15ef7..90209e4b99f7 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c
@@ -126,7 +126,8 @@ int mlx5_lag_create_vport_lag(struct mlx5_lag *ldev, u32 group_id)
if (j == master_idx)
continue;
slave_esw = mlx5_lag_fn(ldev, j)->dev->priv.eswitch;
- mlx5_eswitch_offloads_vport_lag_del_one(master_esw, slave_esw);
+ mlx5_eswitch_offloads_vport_lag_del_one(master_esw, slave_esw,
+ ldev->max_fns);
}
return err;
}
@@ -153,7 +154,8 @@ int mlx5_lag_destroy_vport_lag(struct mlx5_lag *ldev, u32 group_id)
continue;
dev = mlx5_lag_fn(ldev, i)->dev;
mlx5_eswitch_offloads_vport_lag_del_one(master_esw,
- dev->priv.eswitch);
+ dev->priv.eswitch,
+ ldev->max_fns);
}
return 0;
}
--
2.44.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net-next 14/15] net/mlx5e: Register eswitch-manager VF/SF self-port with switch-id
2026-11-03 17:09 [PATCH net-next 00/15] net/mlx5: LAG over VFs/SFs (virtual LAG) Tariq Toukan
` (12 preceding siblings ...)
2026-11-03 17:10 ` [PATCH net-next 13/15] net/mlx5: E-switch, drop master egress rule under a SW vport LAG Tariq Toukan
@ 2026-11-03 17:10 ` Tariq Toukan
2026-11-03 17:10 ` [PATCH net-next 15/15] net/mlx5: LAG, enable LAG over functions that do not represent a physical port Tariq Toukan
14 siblings, 0 replies; 16+ messages in thread
From: Tariq Toukan @ 2026-11-03 17:10 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Carolina Jubran, Cosmin Ratiu, Edward Srouji,
Gal Pressman, Leon Romanovsky, open list, linux-rdma, Mark Bloch,
Moshe Shemesh, Or Har-Toov, Patrisious Haddad, Saeed Mahameed,
Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
A non-PF function's self-port (its own uplink netdev) was always
registered with DEVLINK_PORT_FLAVOUR_VIRTUAL, which doesn't carries
switch_id. Consequently a function that acts as an eswitch manager - a
VF (or SF) running its own nested eswitch - exposed no phys_switch_id on
its uplink netdev, so it could not be grouped with the representors it
manages.
When the function is an eswitch manager, register its self-port with the
switch_id taken from the system image guid. The uplink netdev is already
bound to this devlink port, so phys_switch_id is derived by the core,
and the managed representors - which stamp the same switch_id - group
with it.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
drivers/net/ethernet/mellanox/mlx5/core/en/devlink.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/en/devlink.c
index 8818f65d1fbc..79adb1ecc450 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/devlink.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/devlink.c
@@ -63,6 +63,11 @@ int mlx5e_devlink_port_register(struct mlx5e_dev *mlx5e_dev,
dl_port_index = mlx5_esw_vport_to_devlink_port_index(mdev,
MLX5_VPORT_UPLINK);
} else {
+ if (MLX5_ESWITCH_MANAGER(mdev)) {
+ mlx5e_devlink_get_port_parent_id(mdev, &ppid);
+ memcpy(attrs.switch_id.id, ppid.id, ppid.id_len);
+ attrs.switch_id.id_len = ppid.id_len;
+ }
attrs.flavour = DEVLINK_PORT_FLAVOUR_VIRTUAL;
dl_port_index = mlx5_esw_vport_to_devlink_port_index(mdev, 0);
}
--
2.44.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net-next 15/15] net/mlx5: LAG, enable LAG over functions that do not represent a physical port
2026-11-03 17:09 [PATCH net-next 00/15] net/mlx5: LAG over VFs/SFs (virtual LAG) Tariq Toukan
` (13 preceding siblings ...)
2026-11-03 17:10 ` [PATCH net-next 14/15] net/mlx5e: Register eswitch-manager VF/SF self-port with switch-id Tariq Toukan
@ 2026-11-03 17:10 ` Tariq Toukan
14 siblings, 0 replies; 16+ messages in thread
From: Tariq Toukan @ 2026-11-03 17:10 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Carolina Jubran, Cosmin Ratiu, Edward Srouji,
Gal Pressman, Leon Romanovsky, open list, linux-rdma, Mark Bloch,
Moshe Shemesh, Or Har-Toov, Patrisious Haddad, Saeed Mahameed,
Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
LAG membership assumes every member represents a physical port.
A nested LAG of VFs/SFs does not fit that assumption; its member
functions sit behind a multi_uplink_eswitch and each reports
num_lag_ports < 2, so they do not represent a physical port.
Detect this with mlx5_virt_lag_is_supported(): let such a function join
the LAG in mlx5_lag_add_mdev(), and skip the MLX5_LAG_XA_MARK_PORT mark
in mlx5_ldev_add_mdev(), since it is not a physical port.
These function only support MPESW, and netdevs addition to LAG is only
needed for linux bond. Hence, don't allow such a lag to add netdevs to
itself. For the same reason, don't register the LAG netdev notifier for
it.
Such a function may report num_lag_ports == 0, which ldev->ports keeps
as is. Report at least one port from mlx5_lag_get_num_ports(), so RDMA,
which uses it as the TX-affinity divisor, sees the function's own port
rather than dividing by zero.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../net/ethernet/mellanox/mlx5/core/lag/lag.c | 21 +++++++++++++------
.../ethernet/mellanox/mlx5/core/lag/mpesw.c | 2 +-
2 files changed, 16 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
index 4e15e16ae6e8..5532b2505161 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
@@ -366,6 +366,7 @@ static struct mlx5_lag *mlx5_lag_dev_alloc(struct mlx5_core_dev *dev)
ldev->ports = MLX5_CAP_GEN(dev, num_lag_ports);
ldev->buckets = 1;
+ ldev->virt_lag = mlx5_virt_lag_is_supported(dev);
ldev->v2p_map = kcalloc(ldev->ports * MLX5_LAG_MAX_HASH_BUCKETS,
sizeof(*ldev->v2p_map), GFP_KERNEL);
if (!ldev->v2p_map)
@@ -381,7 +382,7 @@ static struct mlx5_lag *mlx5_lag_dev_alloc(struct mlx5_core_dev *dev)
INIT_DELAYED_WORK(&ldev->bond_work, mlx5_do_bond_work);
INIT_WORK(&ldev->speed_update_work, mlx5_mpesw_speed_update_work);
- if (!mlx5_sd_is_supported(dev)) {
+ if (!mlx5_sd_is_supported(dev) && !ldev->virt_lag) {
ldev->nb.notifier_call = mlx5_lag_netdev_event;
write_pnet(&ldev->net, mlx5_core_net(dev));
if (register_netdevice_notifier_net(read_pnet(&ldev->net),
@@ -468,7 +469,9 @@ int mlx5_lag_get_dev_index_by_seq(struct mlx5_lag *ldev, int seq)
/* Return the appropriate iterator filter for a device in LAG:
* - SD shared FDB active: iterate only the device's SD group
* - SD group exists but shared FDB not active: iterate all devices
- * - No SD: iterate ports only
+ * - Virt LAG: iterate all devices, since its members are not marked as
+ * ports, as they do not represent a physical port
+ * - Otherwise: iterate ports only
*/
static u32 mlx5_lag_get_filter(struct mlx5_lag *ldev, struct mlx5_core_dev *dev)
{
@@ -476,7 +479,7 @@ static u32 mlx5_lag_get_filter(struct mlx5_lag *ldev, struct mlx5_core_dev *dev)
if (fn && fn->sd_fdb_active)
return fn->group_id;
- if (fn && fn->group_id)
+ if (fn && (fn->group_id || ldev->virt_lag))
return MLX5_LAG_FILTER_ALL;
return MLX5_LAG_FILTER_PORTS;
}
@@ -2399,7 +2402,7 @@ int mlx5_ldev_add_mdev(struct mlx5_lag *ldev,
fn->group_id = group_id;
dev->priv.lag = ldev;
- if (group_id)
+ if (group_id || ldev->virt_lag)
return 0;
xa_set_mark(&ldev->fns, idx, MLX5_LAG_XA_MARK_PORT);
@@ -2548,7 +2551,7 @@ void mlx5_lag_add_mdev(struct mlx5_core_dev *dev)
{
int err;
- if (!mlx5_lag_is_supported(dev))
+ if (!mlx5_lag_is_supported(dev) && !mlx5_virt_lag_is_supported(dev))
return;
if (mlx5_lag_register_hca_devcom_comp(dev))
@@ -2583,6 +2586,9 @@ void mlx5_lag_remove_netdev(struct mlx5_core_dev *dev,
if (!ldev)
return;
+ if (ldev->virt_lag)
+ return;
+
mutex_lock(&ldev->lock);
mlx5_ldev_remove_netdev(ldev, netdev);
clear_bit(MLX5_LAG_FLAG_NDEVS_READY, &ldev->state_flags);
@@ -2604,6 +2610,9 @@ void mlx5_lag_add_netdev(struct mlx5_core_dev *dev,
if (!ldev)
return;
+ if (ldev->virt_lag)
+ return;
+
mutex_lock(&ldev->lock);
mlx5_ldev_add_netdev(ldev, dev, netdev);
num = mlx5_lag_num_netdevs(ldev);
@@ -2887,7 +2896,7 @@ u8 mlx5_lag_get_num_ports(struct mlx5_core_dev *dev)
if (!ldev)
return 0;
- return ldev->ports;
+ return max_t(u8, ldev->ports, 1);
}
EXPORT_SYMBOL(mlx5_lag_get_num_ports);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
index 3dd7fa8de66c..6f575750e403 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
@@ -336,7 +336,7 @@ bool mlx5_lag_is_mpesw(struct mlx5_core_dev *dev)
struct mlx5_lag *ldev = mlx5_lag_dev(dev);
return ldev && ldev->mode == MLX5_LAG_MODE_MPESW &&
- __mlx5_lag_dev_is_port(ldev, dev);
+ (ldev->virt_lag || __mlx5_lag_dev_is_port(ldev, dev));
}
EXPORT_SYMBOL(mlx5_lag_is_mpesw);
--
2.44.0
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2026-11-03 17:13 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-03 17:09 [PATCH net-next 00/15] net/mlx5: LAG over VFs/SFs (virtual LAG) Tariq Toukan
2026-11-03 17:09 ` [PATCH net-next 01/15] net/mlx5: Distinguish VFs/SFs in the SW system image GUID for LAG grouping Tariq Toukan
2026-11-03 17:09 ` [PATCH net-next 02/15] net/mlx5: LAG, select the MPESW master from the live member snapshot Tariq Toukan
2026-11-03 17:09 ` [PATCH net-next 03/15] net/mlx5: LAG, skip phys LAG prerequisites for a virt LAG Tariq Toukan
2026-11-03 17:09 ` [PATCH net-next 04/15] net/mlx5: LAG, treat virt LAG as a software managed LAG Tariq Toukan
2026-11-03 17:09 ` [PATCH net-next 05/15] net/mlx5: LAG, decouple iteration end-of-walk from MLX5_MAX_PORTS Tariq Toukan
2026-11-03 17:10 ` [PATCH net-next 06/15] net/mlx5: LAG, rename PF naming to fn Tariq Toukan
2026-11-03 17:10 ` [PATCH net-next 07/15] net/mlx5: LAG, resolve affinity indices only in queue-affinity mode Tariq Toukan
2026-11-03 17:10 ` [PATCH net-next 08/15] net/mlx5: LAG: replace fixed MLX5_MAX_PORTS arrays with dynamic allocation Tariq Toukan
2026-11-03 17:10 ` [PATCH net-next 09/15] net/mlx5: LAG, drop MLX5_MAX_PORTS scratch array from device rescan Tariq Toukan
2026-11-03 17:10 ` [PATCH net-next 10/15] net/mlx5: LAG, do not add a device to an already-active LAG Tariq Toukan
2026-11-03 17:10 ` [PATCH net-next 11/15] net/mlx5: E-switch, add match-metadata allocator for nested VF/SF eswitches Tariq Toukan
2026-11-03 17:10 ` [PATCH net-next 12/15] net/mlx5: E-switch, match master egress rule by vport metadata Tariq Toukan
2026-11-03 17:10 ` [PATCH net-next 13/15] net/mlx5: E-switch, drop master egress rule under a SW vport LAG Tariq Toukan
2026-11-03 17:10 ` [PATCH net-next 14/15] net/mlx5e: Register eswitch-manager VF/SF self-port with switch-id Tariq Toukan
2026-11-03 17:10 ` [PATCH net-next 15/15] net/mlx5: LAG, enable LAG over functions that do not represent a physical port Tariq Toukan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®