git: aae9d87526e1 - stable/15 - mlx5en: Report SR-IOV VF status
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 31 Oct 2026 18:58:49 UTC
The branch stable/15 has been updated by kbowling:
URL: https://cgit.FreeBSD.org/src/commit/?id=aae9d87526e183395469a9901da3106ef7454af0
commit aae9d87526e183395469a9901da3106ef7454af0
Author: Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-08 17:50:12 +0000
Commit: Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-10-31 18:57:04 +0000
mlx5en: Report SR-IOV VF status
Query each enabled eswitch vport to report its effective MAC and VLAN
configuration and administrative link-state policy. Serialize the
query with vport enable and disable, and hold the interface state lock
so teardown joins an in-progress report.
Propagate firmware errors from MAC, administrative link-state, and
supported VLAN queries instead of returning a partially initialized
configuration. When the hardware lacks CVLAN enforcement, report the
remaining status with no imposed access VLAN.
Keep the existing caller-owned vport-info structure unchanged on
stable/15. Return the additional CVLAN state through a new helper,
and retain the original query entry point as a compatibility wrapper.
Reviewed by: kib
Differential Revision: https://reviews.freebsd.org/D58740
(cherry picked from commit 0c08d85c99b7b57e45816d011685d349b240a3e3)
---
sys/dev/mlx5/mlx5_core/eswitch.h | 2 +
sys/dev/mlx5/mlx5_core/mlx5_eswitch.c | 38 +++++++---
sys/dev/mlx5/mlx5_core/mlx5_vport.c | 20 +++++-
sys/dev/mlx5/mlx5_en/mlx5_en_main.c | 127 ++++++++++++++++++++++++++++++++++
sys/dev/mlx5/vport.h | 2 +
5 files changed, 177 insertions(+), 12 deletions(-)
diff --git a/sys/dev/mlx5/mlx5_core/eswitch.h b/sys/dev/mlx5/mlx5_core/eswitch.h
index 50d06951bf07..8ab5bb122162 100644
--- a/sys/dev/mlx5/mlx5_core/eswitch.h
+++ b/sys/dev/mlx5/mlx5_core/eswitch.h
@@ -165,5 +165,7 @@ int mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw,
int vport, u16 vlan, u8 qos);
int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
int vport, struct mlx5_esw_vport_info *evi);
+int mlx5_eswitch_get_vport_config_cvlan(struct mlx5_eswitch *esw,
+ int vport, struct mlx5_esw_vport_info *evi, bool *cvlan_enabled);
#endif /* __MLX5_ESWITCH_H__ */
diff --git a/sys/dev/mlx5/mlx5_core/mlx5_eswitch.c b/sys/dev/mlx5/mlx5_core/mlx5_eswitch.c
index 30f04144502b..89b5fa3f7ed1 100644
--- a/sys/dev/mlx5/mlx5_core/mlx5_eswitch.c
+++ b/sys/dev/mlx5/mlx5_core/mlx5_eswitch.c
@@ -130,7 +130,7 @@ static int query_esw_vport_context_cmd(struct mlx5_core_dev *mdev, u32 vport,
}
static int query_esw_vport_cvlan(struct mlx5_core_dev *dev, u32 vport,
- u16 *vlan, u8 *qos)
+ u16 *vlan, u8 *qos, bool *enabled)
{
u32 out[MLX5_ST_SZ_DW(query_esw_vport_context_out)] = {0};
int err;
@@ -139,6 +139,7 @@ static int query_esw_vport_cvlan(struct mlx5_core_dev *dev, u32 vport,
*vlan = 0;
*qos = 0;
+ *enabled = false;
if (!MLX5_CAP_ESW(dev, vport_cvlan_strip) ||
!MLX5_CAP_ESW(dev, vport_cvlan_insert_if_not_exist))
@@ -154,7 +155,8 @@ static int query_esw_vport_cvlan(struct mlx5_core_dev *dev, u32 vport,
cvlan_insert = MLX5_GET(query_esw_vport_context_out, out,
esw_vport_context.vport_cvlan_insert);
- if (cvlan_strip || cvlan_insert) {
+ *enabled = cvlan_strip || cvlan_insert;
+ if (*enabled) {
*vlan = MLX5_GET(query_esw_vport_context_out, out,
esw_vport_context.cvlan_id);
*qos = MLX5_GET(query_esw_vport_context_out, out,
@@ -1218,9 +1220,20 @@ int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw,
int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
int vport, struct mlx5_esw_vport_info *ivi)
+{
+ bool cvlan_enabled;
+
+ return mlx5_eswitch_get_vport_config_cvlan(esw, vport, ivi,
+ &cvlan_enabled);
+}
+
+/* Preserve the existing caller-supplied structure size on stable/15. */
+int mlx5_eswitch_get_vport_config_cvlan(struct mlx5_eswitch *esw,
+ int vport, struct mlx5_esw_vport_info *ivi, bool *cvlan_enabled)
{
u16 vlan;
- u8 qos;
+ u8 linkstate, qos;
+ int err;
if (!ESW_ALLOWED(esw))
return -EPERM;
@@ -1230,11 +1243,19 @@ int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
memset(ivi, 0, sizeof(*ivi));
ivi->vf = vport - 1;
- mlx5_query_nic_vport_mac_address(esw->dev, vport, ivi->mac);
- ivi->linkstate = mlx5_query_vport_admin_state(esw->dev,
- MLX5_QUERY_VPORT_STATE_IN_OP_MOD_ESW_VPORT,
- vport);
- query_esw_vport_cvlan(esw->dev, vport, &vlan, &qos);
+ err = mlx5_query_nic_vport_mac_address(esw->dev, vport, ivi->mac);
+ if (err != 0)
+ return err;
+ err = mlx5_query_vport_admin_state_checked(esw->dev,
+ MLX5_QUERY_VPORT_STATE_IN_OP_MOD_ESW_VPORT, vport,
+ &linkstate);
+ if (err != 0)
+ return err;
+ ivi->linkstate = linkstate;
+ err = query_esw_vport_cvlan(esw->dev, vport, &vlan, &qos,
+ cvlan_enabled);
+ if (err != 0 && err != -ENOTSUPP)
+ return err;
ivi->vlan = vlan;
ivi->qos = qos;
ivi->spoofchk = 0;
@@ -1273,4 +1294,3 @@ int mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw,
mutex_unlock(&evport->state_lock);
return err;
}
-
diff --git a/sys/dev/mlx5/mlx5_core/mlx5_vport.c b/sys/dev/mlx5/mlx5_core/mlx5_vport.c
index 67893360044e..9d3e3c752111 100644
--- a/sys/dev/mlx5/mlx5_core/mlx5_vport.c
+++ b/sys/dev/mlx5/mlx5_core/mlx5_vport.c
@@ -64,13 +64,27 @@ u8 mlx5_query_vport_state(struct mlx5_core_dev *mdev, u8 opmod, u16 vport)
}
EXPORT_SYMBOL_GPL(mlx5_query_vport_state);
-u8 mlx5_query_vport_admin_state(struct mlx5_core_dev *mdev, u8 opmod, u16 vport)
+int
+mlx5_query_vport_admin_state_checked(struct mlx5_core_dev *mdev, u8 opmod,
+ u16 vport, u8 *state)
{
u32 out[MLX5_ST_SZ_DW(query_vport_state_out)] = {0};
+ int err;
- _mlx5_query_vport_state(mdev, opmod, vport, out, sizeof(out));
+ err = _mlx5_query_vport_state(mdev, opmod, vport, out, sizeof(out));
+ if (err != 0)
+ return err;
+ *state = MLX5_GET(query_vport_state_out, out, admin_state);
+ return 0;
+}
+
+u8 mlx5_query_vport_admin_state(struct mlx5_core_dev *mdev, u8 opmod, u16 vport)
+{
+ u8 state;
- return MLX5_GET(query_vport_state_out, out, admin_state);
+ state = 0;
+ (void)mlx5_query_vport_admin_state_checked(mdev, opmod, vport, &state);
+ return (state);
}
EXPORT_SYMBOL(mlx5_query_vport_admin_state);
diff --git a/sys/dev/mlx5/mlx5_en/mlx5_en_main.c b/sys/dev/mlx5/mlx5_en/mlx5_en_main.c
index c565c22c6028..c12cecb1064d 100644
--- a/sys/dev/mlx5/mlx5_en/mlx5_en_main.c
+++ b/sys/dev/mlx5/mlx5_en/mlx5_en_main.c
@@ -37,14 +37,19 @@
#include <machine/atomic.h>
#include <net/debugnet.h>
+#include <net/if_vf_status.h>
#include <netinet/tcp_ratelimit.h>
#include <netipsec/keydb.h>
#include <netipsec/ipsec_offload.h>
+#include <dev/mlx5/mlx5_core/eswitch.h>
+
static int mlx5e_get_wqe_sz(struct mlx5e_priv *priv, u32 *wqe_sz, u32 *nsegs);
static if_snd_tag_query_t mlx5e_ul_snd_tag_query;
static if_snd_tag_free_t mlx5e_ul_snd_tag_free;
+static int mlx5e_vf_status(if_t, struct if_vf_status **);
+
struct mlx5e_channel_param {
struct mlx5e_rq_param rq;
struct mlx5e_sq_param sq;
@@ -3516,6 +3521,127 @@ mlx5e_is_tlsrx_capable(struct mlx5_core_dev *mdev)
return (false);
}
+static int
+mlx5e_vf_status(if_t ifp, struct if_vf_status **statusp)
+{
+ struct mlx5e_vf_status {
+ u8 mac[ETH_ALEN];
+ u16 vlan;
+ u8 qos;
+ bool cvlan_enabled;
+ u32 vf;
+ u32 linkstate;
+ } *snapshot;
+ struct mlx5_esw_vport_info info;
+ struct mlx5_eswitch *esw;
+ struct mlx5_vport *vport;
+ struct if_vf_info *vf;
+ struct if_vf_status *status;
+ struct mlx5e_priv *priv;
+ int error, i, num_vfs;
+
+ priv = if_getsoftc(ifp);
+ PRIV_LOCK(priv);
+ if (priv->gone != 0) {
+ PRIV_UNLOCK(priv);
+ return (EOPNOTSUPP);
+ }
+ esw = priv->mdev->priv.eswitch;
+ if (!priv->mdev->iov_pf || esw == NULL || esw->total_vports <= 1) {
+ PRIV_UNLOCK(priv);
+ return (EOPNOTSUPP);
+ }
+ snapshot = mallocarray(esw->total_vports - 1, sizeof(*snapshot),
+ M_DEVBUF, M_WAITOK | M_ZERO);
+ num_vfs = 0;
+ for (i = 1; i < esw->total_vports; i++) {
+ vport = &esw->vports[i];
+ mutex_lock(&vport->state_lock);
+ if (!vport->enabled) {
+ mutex_unlock(&vport->state_lock);
+ continue;
+ }
+ /*
+ * The eswitch does not cache all effective vport policy. Query
+ * firmware while the vport is stable and return errors rather than
+ * publishing a partial snapshot.
+ */
+ error = mlx5_eswitch_get_vport_config_cvlan(esw, i, &info,
+ &snapshot[num_vfs].cvlan_enabled);
+ mutex_unlock(&vport->state_lock);
+ if (error != 0) {
+ PRIV_UNLOCK(priv);
+ free(snapshot, M_DEVBUF);
+ return (-error);
+ }
+ snapshot[num_vfs].vf = info.vf;
+ snapshot[num_vfs].vlan = info.vlan;
+ snapshot[num_vfs].qos = info.qos;
+ snapshot[num_vfs].linkstate = info.linkstate;
+ memcpy(snapshot[num_vfs].mac, info.mac, ETH_ALEN);
+ num_vfs++;
+ }
+ PRIV_UNLOCK(priv);
+ if (num_vfs == 0) {
+ free(snapshot, M_DEVBUF);
+ status = if_vf_status_alloc(0);
+ if (status == NULL)
+ return (ENOMEM);
+ *statusp = status;
+ return (0);
+ }
+
+ status = if_vf_status_alloc(num_vfs);
+ if (status == NULL) {
+ free(snapshot, M_DEVBUF);
+ return (ENOMEM);
+ }
+ for (i = 0; i < num_vfs; i++) {
+ vf = &status->vfs[i];
+ vf->fields = IFVF_F_CONFIGURED | IFVF_F_VLAN_MODE;
+ vf->index = snapshot[i].vf;
+ vf->configured = true;
+ /* An active priority policy may have both VID and PCP zero. */
+ if (snapshot[i].cvlan_enabled) {
+ vf->vlan_pcp = snapshot[i].qos;
+ vf->fields |= IFVF_F_VLAN_PCP;
+ }
+ if (!ETHER_IS_ZERO(snapshot[i].mac)) {
+ memcpy(vf->mac, snapshot[i].mac, sizeof(vf->mac));
+ vf->fields |= IFVF_F_MAC;
+ }
+ /* A priority-only tag does not impose an access VLAN. */
+ if (snapshot[i].vlan == 0)
+ vf->vlan_mode = IFVF_VLAN_TRUNK;
+ else {
+ vf->vlan_mode = IFVF_VLAN_ACCESS;
+ vf->vlan = snapshot[i].vlan;
+ vf->vlan_proto = ETHERTYPE_VLAN;
+ vf->vlan_count = 1;
+ vf->fields |= IFVF_F_VLAN | IFVF_F_VLAN_PROTO |
+ IFVF_F_VLAN_COUNT;
+ }
+ switch (snapshot[i].linkstate) {
+ case MLX5_ESW_VPORT_ADMIN_STATE_DOWN:
+ vf->link_state_policy = IFVF_LINK_DOWN;
+ break;
+ case MLX5_ESW_VPORT_ADMIN_STATE_UP:
+ vf->link_state_policy = IFVF_LINK_UP;
+ break;
+ case MLX5_ESW_VPORT_ADMIN_STATE_AUTO:
+ vf->link_state_policy = IFVF_LINK_AUTO;
+ break;
+ default:
+ vf->link_state_policy = IFVF_LINK_UNKNOWN;
+ break;
+ }
+ vf->fields |= IFVF_F_LINK_STATE_POLICY;
+ }
+ free(snapshot, M_DEVBUF);
+ *statusp = status;
+ return (0);
+}
+
static int
mlx5e_ioctl(if_t ifp, u_long command, caddr_t data)
{
@@ -4643,6 +4769,7 @@ mlx5e_create_ifp(struct mlx5_core_dev *mdev)
if_setinitfn(ifp, mlx5e_open);
if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
if_setioctlfn(ifp, mlx5e_ioctl);
+ if_setvfstatusfn(ifp, mlx5e_vf_status);
if_settransmitfn(ifp, mlx5e_xmit);
if_setqflushfn(ifp, if_qflush);
if_setgetcounterfn(ifp, mlx5e_get_counter);
diff --git a/sys/dev/mlx5/vport.h b/sys/dev/mlx5/vport.h
index fbb24773c128..335374cd4b49 100644
--- a/sys/dev/mlx5/vport.h
+++ b/sys/dev/mlx5/vport.h
@@ -61,6 +61,8 @@ int mlx5_nic_vport_modify_local_lb(struct mlx5_core_dev *mdev,
u8 mlx5_query_vport_state(struct mlx5_core_dev *mdev, u8 opmod, u16 vport);
u8 mlx5_query_vport_admin_state(struct mlx5_core_dev *mdev, u8 opmod,
u16 vport);
+int mlx5_query_vport_admin_state_checked(struct mlx5_core_dev *mdev,
+ u8 opmod, u16 vport, u8 *state);
int mlx5_modify_vport_admin_state(struct mlx5_core_dev *mdev, u8 opmod,
u16 vport, u8 state);