* [PATCH net-next 00/15] net: enetc: SR-IOV improvements and ENETC v4 VF support
@ 2026-06-05 6:55 wei.fang
2026-06-05 6:55 ` [PATCH net-next 01/15] net: enetc: add trusted " wei.fang
` (14 more replies)
0 siblings, 15 replies; 30+ messages in thread
From: wei.fang @ 2026-06-05 6:55 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang
Cc: imx, netdev, linux-kernel
From: Wei Fang <wei.fang@nxp.com>
This series enhances SR-IOV support for ENETC v1 and adds VF support
for ENETC v4. For ENETC v1, the trusted VF management and per-VF
configuration query via ndo_get_vf_config() are added. For ENETC v4,
preliminary VF support is introduced for i.MX94 and i.MX95 platforms.
On the PF side, the series introduces trust level management and MAC
address assignment for VFs, and implements ndo_get_vf_config() so that
userspace tools such as 'ip link show' can query the current per-VF
configuration. The PSI-to-VSI messaging infrastructure is extended to
handle link status and link speed queries from VFs, enabling DPDK-owned
VFs to obtain accurate link information from the PF.
On the VF side, MAC address filtering is implemented via the VSI-to-PSI
mailbox, supporting both unicast/multicast hash filters and promiscuous
mode control. Since the ndo_set_rx_mode callback is invoked with BH
disabled and is incompatible with the mailbox polling path,
ndo_set_rx_mode_async is used instead. Link status notifications are also
supported: the VF registers with the PF and receives PSI-to-VSI messages
on every PF link transition, keeping the VF carrier state in sync without
polling.
VF Function Level Reset is handled explicitly to restore the PF-managed
MAC promiscuous policy after each reset, since the hardware default after
FLR enables promiscuous mode regardless of the policy set by the PF
driver.
Several preparatory refactors are included to share infrastructure
between the PF and VF drivers, such as moving msg_task and mac_filter
from struct enetc_pf into the common struct enetc_si.
Claudiu Manoil (1):
net: enetc: add trusted VF support
Wei Fang (14):
net: enetc: move msg_task and msg_int_name to struct enetc_si
net: enetc: add link status message support to PF driver
net: enetc: add link speed message support to PF driver
net: enetc: use enetc_set_si_hw_addr() to set VF MAC address
net: enetc: relocate enetc_pf_set_vf_mac() for common PF support
net: enetc: add .ndo_set_vf_mac() to the enetc v4 driver
net: enetc: move mac_filter from struct enetc_pf to struct enetc_si
net: enetc: add MAC address filtering support for VFs of ENETC v4
net: enetc: simplify and rename PSIIER enable/disable helpers
net: enetc: restore VF MAC promiscuous mode after FLR for ENETC v4
net: enetc: add VF support for i.MX94 and i.MX95
net: enetc: implement ndo_set_rx_mode_async for ENETC v4 VF
net: enetc: add PSI-to-VSI link status notification support for VF
net: enetc: add ndo_get_vf_config() support
drivers/net/ethernet/freescale/enetc/Kconfig | 1 +
drivers/net/ethernet/freescale/enetc/enetc.c | 26 +
drivers/net/ethernet/freescale/enetc/enetc.h | 10 +-
.../net/ethernet/freescale/enetc/enetc4_hw.h | 1 +
.../net/ethernet/freescale/enetc/enetc4_pf.c | 81 +++-
.../ethernet/freescale/enetc/enetc_ethtool.c | 6 +
.../net/ethernet/freescale/enetc/enetc_hw.h | 25 +
.../ethernet/freescale/enetc/enetc_mailbox.h | 86 ++++
.../net/ethernet/freescale/enetc/enetc_msg.c | 459 ++++++++++++++++--
.../net/ethernet/freescale/enetc/enetc_pf.c | 60 +--
.../net/ethernet/freescale/enetc/enetc_pf.h | 21 +-
.../freescale/enetc/enetc_pf_common.c | 98 ++++
.../freescale/enetc/enetc_pf_common.h | 13 +
.../net/ethernet/freescale/enetc/enetc_vf.c | 325 ++++++++++++-
14 files changed, 1119 insertions(+), 93 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH net-next 01/15] net: enetc: add trusted VF support
2026-06-05 6:55 [PATCH net-next 00/15] net: enetc: SR-IOV improvements and ENETC v4 VF support wei.fang
@ 2026-06-05 6:55 ` wei.fang
2026-06-06 7:24 ` sashiko-bot
2026-06-05 6:55 ` [PATCH net-next 02/15] net: enetc: move msg_task and msg_int_name to struct enetc_si wei.fang
` (13 subsequent siblings)
14 siblings, 1 reply; 30+ messages in thread
From: wei.fang @ 2026-06-05 6:55 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang
Cc: imx, netdev, linux-kernel
From: Claudiu Manoil <claudiu.manoil@nxp.com>
Some mailbox messages require a higher privilege level to be executed
on behalf of the requesting VF. Introduce a trusted VF flag
(ENETC_VF_FLAG_TRUSTED) and wire up the ndo_set_vf_trust callback via
enetc_pf_set_vf_trust(), which is shared between the enetc and enetc4
PF drivers.
The first message gated on trust is the VF primary MAC address change.
An untrusted VF that attempts to set its own MAC address will receive a
ENETC_MSG_CLASS_ID_PERMISSION_DENY response and the hardware will not
be programmed.
Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
.../net/ethernet/freescale/enetc/enetc4_pf.c | 1 +
.../net/ethernet/freescale/enetc/enetc_msg.c | 30 +++++++++++++------
.../net/ethernet/freescale/enetc/enetc_pf.c | 1 +
.../net/ethernet/freescale/enetc/enetc_pf.h | 1 +
.../freescale/enetc/enetc_pf_common.c | 23 ++++++++++++++
.../freescale/enetc/enetc_pf_common.h | 1 +
6 files changed, 48 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index 4e771f852358..ee52ff929576 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -570,6 +570,7 @@ static const struct net_device_ops enetc4_ndev_ops = {
.ndo_eth_ioctl = enetc_ioctl,
.ndo_hwtstamp_get = enetc_hwtstamp_get,
.ndo_hwtstamp_set = enetc_hwtstamp_set,
+ .ndo_set_vf_trust = enetc_pf_set_vf_trust,
};
static struct phylink_pcs *
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_msg.c b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
index edc1277bb586..156333ef26bf 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_msg.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
@@ -7,6 +7,8 @@
ENETC_MSG_CLASS_ID_CMD_SUCCESS)
#define ENETC_PF_MSG_NOTSUPP FIELD_PREP(ENETC_PF_MSG_CLASS_ID, \
ENETC_MSG_CLASS_ID_CMD_NOT_SUPPORT)
+#define ENETC_PF_MSG_PERM_DENY FIELD_PREP(ENETC_PF_MSG_CLASS_ID, \
+ ENETC_MSG_CLASS_ID_PERMISSION_DENY)
static void enetc_msg_disable_mr_int(struct enetc_pf *pf)
{
@@ -61,31 +63,41 @@ static u16 enetc_msg_set_vf_primary_mac_addr(struct enetc_pf *pf, int vf_id,
struct enetc_vf_state *vf_state = &pf->vf_state[vf_id];
struct enetc_msg_mac_exact_filter *msg = vf_msg;
struct device *dev = &pf->si->pdev->dev;
+ u16 pf_msg = ENETC_PF_MSG_SUCCESS;
char *addr = msg->mac[0].addr;
+ mutex_lock(&vf_state->lock);
+
+ if (!(vf_state->flags & ENETC_VF_FLAG_TRUSTED)) {
+ pf_msg = ENETC_PF_MSG_PERM_DENY;
+ goto vf_state_unlock;
+ }
+
if (!is_valid_ether_addr(addr)) {
dev_err_ratelimited(dev, "VF%d attempted to set invalid MAC\n",
vf_id);
- return (FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
- ENETC_MSG_CLASS_ID_MAC_FILTER) |
- FIELD_PREP(ENETC_PF_MSG_CLASS_CODE,
- ENETC_MF_CLASS_CODE_INVALID_MAC));
+ pf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
+ ENETC_MSG_CLASS_ID_MAC_FILTER) |
+ FIELD_PREP(ENETC_PF_MSG_CLASS_CODE,
+ ENETC_MF_CLASS_CODE_INVALID_MAC);
+ goto vf_state_unlock;
}
- mutex_lock(&vf_state->lock);
if (vf_state->flags & ENETC_VF_FLAG_PF_SET_MAC) {
- mutex_unlock(&vf_state->lock);
dev_err_ratelimited(dev,
"VF%d attempted to override PF set MAC\n",
vf_id);
- return FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
- ENETC_MSG_CLASS_ID_CMD_NOT_PERMITTED);
+ pf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
+ ENETC_MSG_CLASS_ID_CMD_NOT_PERMITTED);
+ goto vf_state_unlock;
}
enetc_set_si_hw_addr(pf, vf_id + 1, addr);
+
+vf_state_unlock:
mutex_unlock(&vf_state->lock);
- return ENETC_PF_MSG_SUCCESS;
+ return pf_msg;
}
static u16 enetc_msg_handle_mac_filter(struct enetc_pf *pf, int vf_id,
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index 2d687bb8c3a0..8957e74314d1 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -540,6 +540,7 @@ static const struct net_device_ops enetc_ndev_ops = {
.ndo_set_rx_mode = enetc_pf_set_rx_mode,
.ndo_vlan_rx_add_vid = enetc_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = enetc_vlan_rx_del_vid,
+ .ndo_set_vf_trust = enetc_pf_set_vf_trust,
.ndo_set_vf_mac = enetc_pf_set_vf_mac,
.ndo_set_vf_vlan = enetc_pf_set_vf_vlan,
.ndo_set_vf_spoofchk = enetc_pf_set_vf_spoofchk,
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
index 285b7e5c48fd..eb977da2be71 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
@@ -9,6 +9,7 @@
enum enetc_vf_flags {
ENETC_VF_FLAG_PF_SET_MAC = BIT(0),
+ ENETC_VF_FLAG_TRUSTED = BIT(1),
};
struct enetc_vf_state {
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
index 6e5d2f869915..44c546b77d3f 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
@@ -462,5 +462,28 @@ int enetc_init_sriov_resources(struct enetc_pf *pf)
}
EXPORT_SYMBOL_GPL(enetc_init_sriov_resources);
+int enetc_pf_set_vf_trust(struct net_device *ndev, int vf, bool setting)
+{
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ struct enetc_pf *pf = enetc_si_priv(priv->si);
+ struct enetc_vf_state *vf_state;
+
+ if (vf >= pf->total_vfs)
+ return -EINVAL;
+
+ vf_state = &pf->vf_state[vf];
+ mutex_lock(&vf_state->lock);
+
+ if (setting)
+ vf_state->flags |= ENETC_VF_FLAG_TRUSTED;
+ else
+ vf_state->flags &= ~ENETC_VF_FLAG_TRUSTED;
+
+ mutex_unlock(&vf_state->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(enetc_pf_set_vf_trust);
+
MODULE_DESCRIPTION("NXP ENETC PF common functionality driver");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
index 57d2e0ebd2b0..5bf7c20aba42 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
@@ -17,6 +17,7 @@ void enetc_set_default_rss_key(struct enetc_pf *pf);
int enetc_vlan_rx_add_vid(struct net_device *ndev, __be16 prot, u16 vid);
int enetc_vlan_rx_del_vid(struct net_device *ndev, __be16 prot, u16 vid);
int enetc_init_sriov_resources(struct enetc_pf *pf);
+int enetc_pf_set_vf_trust(struct net_device *ndev, int vf, bool setting);
static inline u16 enetc_get_ip_revision(struct enetc_hw *hw)
{
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 02/15] net: enetc: move msg_task and msg_int_name to struct enetc_si
2026-06-05 6:55 [PATCH net-next 00/15] net: enetc: SR-IOV improvements and ENETC v4 VF support wei.fang
2026-06-05 6:55 ` [PATCH net-next 01/15] net: enetc: add trusted " wei.fang
@ 2026-06-05 6:55 ` wei.fang
2026-06-05 6:55 ` [PATCH net-next 03/15] net: enetc: add link status message support to PF driver wei.fang
` (12 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: wei.fang @ 2026-06-05 6:55 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang
Cc: imx, netdev, linux-kernel
From: Wei Fang <wei.fang@nxp.com>
The ENETC PF currently uses msg_task and msg_int_name in struct enetc_pf
to handle VSI-to-PSI mailbox messages via a workqueue and a dedicated
interrupt.
PSI-to-VSI message support will be added to the VF driver, which will
require the same mechanism: a message interrupt and a workqueue handler.
Since struct enetc_si is the common structure shared between PF and VF,
move msg_task and msg_int_name from struct enetc_pf to struct enetc_si
to allow both drivers to use them without duplication.
Also relocate the ENETC_INT_NAME_MAX macro definition ahead of struct
enetc_si so it can be used for the msg_int_name array declaration.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
drivers/net/ethernet/freescale/enetc/enetc.h | 5 ++++-
.../net/ethernet/freescale/enetc/enetc_msg.c | 19 ++++++++++---------
.../net/ethernet/freescale/enetc/enetc_pf.h | 3 ---
3 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index 04a5dd5ea6c7..2cd035773aca 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -25,6 +25,7 @@
#define ENETC_CBD_DATA_MEM_ALIGN 64
#define ENETC_MADDR_HASH_TBL_SZ 64
+#define ENETC_INT_NAME_MAX (IFNAMSIZ + 8)
enum enetc_mac_addr_type {UC, MC, MADDR_TYPE};
@@ -328,6 +329,9 @@ struct enetc_si {
struct work_struct rx_mode_task;
struct dentry *debugfs_root;
struct enetc_msg_swbd msg; /* Only valid for VSI */
+
+ struct work_struct msg_task;
+ char msg_int_name[ENETC_INT_NAME_MAX];
};
#define ENETC_SI_ALIGN 32
@@ -369,7 +373,6 @@ static inline bool enetc_is_pseudo_mac(struct enetc_si *si)
}
#define ENETC_MAX_NUM_TXQS 8
-#define ENETC_INT_NAME_MAX (IFNAMSIZ + 8)
struct enetc_int_vector {
void __iomem *rbier;
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_msg.c b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
index 156333ef26bf..8d4d0689807d 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_msg.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
@@ -37,7 +37,7 @@ static irqreturn_t enetc_msg_psi_msix(int irq, void *data)
struct enetc_pf *pf = enetc_si_priv(si);
enetc_msg_disable_mr_int(pf);
- schedule_work(&pf->msg_task);
+ schedule_work(&si->msg_task);
return IRQ_HANDLED;
}
@@ -215,12 +215,13 @@ static void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id,
static void enetc_msg_task(struct work_struct *work)
{
- struct enetc_pf *pf = container_of(work, struct enetc_pf, msg_task);
- u32 mr_mask = ENETC_PSIMR_MASK(pf->num_vfs);
- struct enetc_hw *hw = &pf->si->hw;
- u32 mr_status;
+ struct enetc_si *si = container_of(work, struct enetc_si, msg_task);
+ struct enetc_pf *pf = enetc_si_priv(si);
+ struct enetc_hw *hw = &si->hw;
+ u32 mr_status, mr_mask;
int i;
+ mr_mask = ENETC_PSIMR_MASK(pf->num_vfs);
mr_status = (enetc_rd(hw, ENETC_PSIMSGRR) & mr_mask) |
(enetc_rd(hw, ENETC_PSIIDR) & mr_mask);
if (!mr_status)
@@ -303,13 +304,13 @@ static int enetc_msg_psi_init(struct enetc_pf *pf)
}
/* initialize PSI mailbox */
- INIT_WORK(&pf->msg_task, enetc_msg_task);
+ INIT_WORK(&si->msg_task, enetc_msg_task);
/* register message passing interrupt handler */
- snprintf(pf->msg_int_name, sizeof(pf->msg_int_name), "%s-vfmsg",
+ snprintf(si->msg_int_name, sizeof(si->msg_int_name), "%s-vfmsg",
si->ndev->name);
vector = pci_irq_vector(si->pdev, ENETC_SI_INT_IDX);
- err = request_irq(vector, enetc_msg_psi_msix, 0, pf->msg_int_name, si);
+ err = request_irq(vector, enetc_msg_psi_msix, 0, si->msg_int_name, si);
if (err) {
dev_err(&si->pdev->dev,
"PSI messaging: request_irq() failed!\n");
@@ -342,7 +343,7 @@ static void enetc_msg_psi_free(struct enetc_pf *pf)
/* de-register message passing interrupt handler */
free_irq(pci_irq_vector(si->pdev, ENETC_SI_INT_IDX), si);
- cancel_work_sync(&pf->msg_task);
+ cancel_work_sync(&si->msg_task);
/* MR interrupts may be re-enabled by workqueue */
enetc_msg_disable_mr_int(pf);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
index eb977da2be71..07bb9aab89aa 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
@@ -43,10 +43,7 @@ struct enetc_pf {
struct enetc_vf_state *vf_state;
struct enetc_mac_filter mac_filter[MADDR_TYPE];
-
struct enetc_msg_swbd *rxmsg;
- struct work_struct msg_task;
- char msg_int_name[ENETC_INT_NAME_MAX];
char vlan_promisc_simap; /* bitmap of SIs in VLAN promisc mode */
DECLARE_BITMAP(vlan_ht_filter, ENETC_VLAN_HT_SIZE);
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 03/15] net: enetc: add link status message support to PF driver
2026-06-05 6:55 [PATCH net-next 00/15] net: enetc: SR-IOV improvements and ENETC v4 VF support wei.fang
2026-06-05 6:55 ` [PATCH net-next 01/15] net: enetc: add trusted " wei.fang
2026-06-05 6:55 ` [PATCH net-next 02/15] net: enetc: move msg_task and msg_int_name to struct enetc_si wei.fang
@ 2026-06-05 6:55 ` wei.fang
2026-06-06 7:24 ` sashiko-bot
2026-06-05 6:55 ` [PATCH net-next 04/15] net: enetc: add link speed " wei.fang
` (11 subsequent siblings)
14 siblings, 1 reply; 30+ messages in thread
From: wei.fang @ 2026-06-05 6:55 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang
Cc: imx, netdev, linux-kernel
From: Wei Fang <wei.fang@nxp.com>
Add link status message support to the PF driver using three command IDs
under message class 0x80 (ENETC_MSG_CLASS_ID_LINK_STATUS):
1. ENETC_MSG_GET_CURRENT_LINK_STATUS
The VF queries the current PF link status synchronously. This command is
not used by the Linux VF driver but is intended for DPDK-owned VFs.
2. ENETC_MSG_REGISTER_LINK_CHANGE_NOTIFIER
The VF registers for link change notification. Upon registration, the PF
immediately notifies the VF of the current link status via a PSI-to-VSI
message, and continues to do so on every subsequent link state change.
3. ENETC_MSG_UNREGISTER_LINK_CHANGE_NOTIFIER
The VF unregisters from link change notification.
PSI-to-VSI notifications are sent via the ENETC_PSIMSGSR register. A new
msg_lock mutex is introduced in struct enetc_pf to protect concurrent
access between the phylink callbacks and the VSI-to-PSI message handler.
The bitmask link_status_ms_mask tracks which VFs have registered for
notifications and is cleared when SR-IOV is disabled.
Two functions are exported for use by PF drivers:
enetc_pf_notify_vf_link_up()
enetc_pf_notify_vf_link_down()
Through this mechanism, VFs can accurately perceive the link status and
report it to upper layers such as the kernel network stack, containers,
and virtual machines.
Note that currently only the ENETC v4 driver supports this feature, while
v1 does not.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
.../net/ethernet/freescale/enetc/enetc4_pf.c | 2 +
.../net/ethernet/freescale/enetc/enetc_hw.h | 4 +
.../ethernet/freescale/enetc/enetc_mailbox.h | 18 +++
.../net/ethernet/freescale/enetc/enetc_msg.c | 152 +++++++++++++++++-
.../net/ethernet/freescale/enetc/enetc_pf.h | 4 +
.../freescale/enetc/enetc_pf_common.c | 2 +
.../freescale/enetc/enetc_pf_common.h | 9 ++
7 files changed, 185 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index ee52ff929576..ad211eefd9d4 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -940,6 +940,7 @@ static void enetc4_pl_mac_link_up(struct phylink_config *config,
enetc4_set_rx_pause(pf, rx_pause);
enetc4_mac_tx_enable(pf);
enetc4_mac_rx_enable(pf);
+ enetc_pf_notify_vf_link_up(pf);
}
static void enetc4_pl_mac_link_down(struct phylink_config *config,
@@ -950,6 +951,7 @@ static void enetc4_pl_mac_link_down(struct phylink_config *config,
enetc4_mac_rx_graceful_stop(pf);
enetc4_mac_tx_graceful_stop(pf);
+ enetc_pf_notify_vf_link_down(pf);
}
static const struct phylink_mac_ops enetc_pl_mac_ops = {
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
index bf99b65d7598..37c6060ccc82 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
@@ -80,6 +80,10 @@ static inline u32 enetc_vsi_set_msize(u32 size)
#define ENETC_SIMSGSR_SET_MC(val) ((val) << 16)
#define ENETC_SIMSGSR_GET_MC(val) ((val) >> 16)
+#define ENETC_PSIMSGSR 0x208
+#define PSIMSGSR_MS(n) BIT((n) + 1) /* n is VF index */
+#define PSIMSGSR_MC GENMASK(31, 16)
+
/* SI statistics */
#define ENETC_SIROCT 0x300
#define ENETC_SIRFRM 0x308
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h b/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h
index d9677da38989..43b9ee2ab3e4 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h
@@ -107,6 +107,7 @@ enum enetc_msg_class_id {
/* Common Class ID for PSI-to-VSI and VSI-to-PSI messages */
ENETC_MSG_CLASS_ID_MAC_FILTER = 0x20,
+ ENETC_MSG_CLASS_ID_LINK_STATUS = 0x80,
ENETC_MSG_CLASS_ID_IP_REVISION = 0xf0,
};
@@ -118,11 +119,23 @@ enum enetc_msg_ip_revision_cmd_id {
ENETC_MSG_GET_IP_MN = 1,
};
+enum enetc_msg_link_status_cmd_id {
+ ENETC_MSG_GET_CURRENT_LINK_STATUS,
+ ENETC_MSG_REGISTER_LINK_CHANGE_NOTIFIER,
+ ENETC_MSG_UNREGISTER_LINK_CHANGE_NOTIFIER,
+};
+
/* Class-specific error return codes of MAC filter */
enum enetc_mac_filter_class_code {
ENETC_MF_CLASS_CODE_INVALID_MAC,
};
+/* Class-specific notifications/codes of link status */
+enum enetc_link_status_class_code {
+ ENETC_LINK_STATUS_CLASS_CODE_UP,
+ ENETC_LINK_STATUS_CLASS_CODE_DOWN,
+};
+
struct enetc_msg_swbd {
void *vaddr;
dma_addr_t dma;
@@ -161,6 +174,11 @@ struct enetc_msg_mac_exact_filter {
/* The generic message format applies to the following messages:
* Get IP revision message, class_id 0xf0.
* cmd_id 1: get IP minor revision
+ *
+ * Link status message, class id 0x80.
+ * cmd_id 0x0: get the current link status
+ * cmd_id 0x1: register link status change notification
+ * cmd_id 0x2: unregister link status change notification
*/
struct enetc_msg_generic {
struct enetc_msg_header hdr;
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_msg.c b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
index 8d4d0689807d..c93b4e6913d8 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_msg.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
@@ -128,6 +128,113 @@ static u16 enetc_msg_handle_ip_revision(struct enetc_pf *pf, void *vf_msg)
}
}
+static u16 enetc_msg_get_link_status(struct enetc_pf *pf)
+{
+ struct net_device *ndev = pf->si->ndev;
+ u16 pf_msg;
+
+ pf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
+ ENETC_MSG_CLASS_ID_LINK_STATUS);
+
+ if (netif_carrier_ok(ndev))
+ pf_msg |= FIELD_PREP(ENETC_PF_MSG_CLASS_CODE,
+ ENETC_LINK_STATUS_CLASS_CODE_UP);
+ else
+ pf_msg |= FIELD_PREP(ENETC_PF_MSG_CLASS_CODE,
+ ENETC_LINK_STATUS_CLASS_CODE_DOWN);
+
+ return pf_msg;
+}
+
+static int enetc_pf_send_msg(struct enetc_pf *pf, u32 msg_code, u16 ms_mask)
+{
+ struct enetc_si *si = pf->si;
+ u32 val;
+
+ enetc_wr(&si->hw, ENETC_PSIMSGSR,
+ FIELD_PREP(PSIMSGSR_MC, msg_code) | ms_mask);
+
+ return read_poll_timeout(enetc_rd, val, !(val & ms_mask), 1000,
+ 200000, false, &si->hw, ENETC_PSIMSGSR);
+}
+
+static void enetc_msg_notify_vf_link_status(struct enetc_pf *pf, u16 ms_mask,
+ bool link_up)
+{
+ u16 pf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
+ ENETC_MSG_CLASS_ID_LINK_STATUS);
+
+ if (link_up)
+ pf_msg |= FIELD_PREP(ENETC_PF_MSG_CLASS_CODE,
+ ENETC_LINK_STATUS_CLASS_CODE_UP);
+ else
+ pf_msg |= FIELD_PREP(ENETC_PF_MSG_CLASS_CODE,
+ ENETC_LINK_STATUS_CLASS_CODE_DOWN);
+
+ if (enetc_pf_send_msg(pf, pf_msg, ms_mask))
+ dev_err_ratelimited(&pf->si->pdev->dev,
+ "PF notifies link status failed\n");
+}
+
+static void enetc_pf_reply_msg(struct enetc_hw *hw, int vf_id, u16 pf_msg)
+{
+ /* w1c to clear the corresponding VF MR bit */
+ enetc_wr(hw, ENETC_PSIIDR, ENETC_PSIMR_BIT(vf_id));
+ enetc_wr(hw, ENETC_PSIMSGRR, ENETC_SIMSGSR_SET_MC(pf_msg) |
+ ENETC_PSIMR_BIT(vf_id));
+}
+
+static void enetc_msg_register_link_status_notifier(struct enetc_pf *pf,
+ int vf_id)
+{
+ u16 pf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
+ ENETC_MSG_CLASS_ID_CMD_SUCCESS);
+
+ mutex_lock(&pf->msg_lock);
+
+ pf->link_status_ms_mask |= PSIMSGSR_MS(vf_id);
+ enetc_pf_reply_msg(&pf->si->hw, vf_id, pf_msg);
+
+ /* Notify VF the current link status */
+ enetc_msg_notify_vf_link_status(pf, PSIMSGSR_MS(vf_id),
+ netif_carrier_ok(pf->si->ndev));
+
+ mutex_unlock(&pf->msg_lock);
+}
+
+static void enetc_msg_unregister_link_status_notifier(struct enetc_pf *pf,
+ int vf_id)
+{
+ u16 pf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
+ ENETC_MSG_CLASS_ID_CMD_SUCCESS);
+
+ mutex_lock(&pf->msg_lock);
+
+ pf->link_status_ms_mask &= ~PSIMSGSR_MS(vf_id);
+ enetc_pf_reply_msg(&pf->si->hw, vf_id, pf_msg);
+
+ mutex_unlock(&pf->msg_lock);
+}
+
+static u16 enetc_msg_handle_link_status(struct enetc_pf *pf, int vf_id,
+ void *vf_msg)
+{
+ struct enetc_msg_header *msg_hdr = vf_msg;
+
+ switch (msg_hdr->cmd_id) {
+ case ENETC_MSG_GET_CURRENT_LINK_STATUS:
+ return enetc_msg_get_link_status(pf);
+ case ENETC_MSG_REGISTER_LINK_CHANGE_NOTIFIER:
+ enetc_msg_register_link_status_notifier(pf, vf_id);
+ return 0;
+ case ENETC_MSG_UNREGISTER_LINK_CHANGE_NOTIFIER:
+ enetc_msg_unregister_link_status_notifier(pf, vf_id);
+ return 0;
+ default:
+ return ENETC_PF_MSG_NOTSUPP;
+ }
+}
+
static void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id,
u16 *pf_msg)
{
@@ -203,6 +310,9 @@ static void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id,
case ENETC_MSG_CLASS_ID_IP_REVISION:
*pf_msg = enetc_msg_handle_ip_revision(pf, msg);
break;
+ case ENETC_MSG_CLASS_ID_LINK_STATUS:
+ *pf_msg = enetc_msg_handle_link_status(pf, vf_id, msg);
+ break;
default:
dev_err_ratelimited(dev,
"Unsupported message class ID: 0x%x\n",
@@ -228,7 +338,6 @@ static void enetc_msg_task(struct work_struct *work)
goto out;
for (i = 0; i < pf->num_vfs; i++) {
- u32 psimsgrr;
u16 msg_code;
if (!(ENETC_PSIMR_BIT(i) & mr_status))
@@ -236,12 +345,13 @@ static void enetc_msg_task(struct work_struct *work)
enetc_msg_handle_rxmsg(pf, i, &msg_code);
- /* w1c to clear the corresponding VF MR bit */
- enetc_wr(hw, ENETC_PSIIDR, ENETC_PSIMR_BIT(i));
+ /* If msg_code is 0, it means that PF has responded to
+ * VF in enetc_msg_handle_rxmsg.
+ */
+ if (!msg_code)
+ continue;
- psimsgrr = ENETC_SIMSGSR_SET_MC(msg_code);
- psimsgrr |= ENETC_PSIMR_BIT(i); /* w1c */
- enetc_wr(hw, ENETC_PSIMSGRR, psimsgrr);
+ enetc_pf_reply_msg(hw, i, msg_code);
}
out:
@@ -361,6 +471,7 @@ int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)
if (!num_vfs) {
pci_disable_sriov(pdev);
enetc_msg_psi_free(pf);
+ pf->link_status_ms_mask = 0;
pf->num_vfs = 0;
} else {
pf->num_vfs = num_vfs;
@@ -388,3 +499,32 @@ int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)
return err;
}
EXPORT_SYMBOL_GPL(enetc_sriov_configure);
+
+static void enetc_pf_notify_vf_link_status(struct enetc_pf *pf,
+ bool link_up)
+{
+ u16 ms_mask;
+
+ mutex_lock(&pf->msg_lock);
+
+ ms_mask = pf->link_status_ms_mask;
+ if (!ms_mask)
+ goto msg_unlock;
+
+ enetc_msg_notify_vf_link_status(pf, ms_mask, link_up);
+
+msg_unlock:
+ mutex_unlock(&pf->msg_lock);
+}
+
+void enetc_pf_notify_vf_link_up(struct enetc_pf *pf)
+{
+ enetc_pf_notify_vf_link_status(pf, true);
+}
+EXPORT_SYMBOL_GPL(enetc_pf_notify_vf_link_up);
+
+void enetc_pf_notify_vf_link_down(struct enetc_pf *pf)
+{
+ enetc_pf_notify_vf_link_status(pf, false);
+}
+EXPORT_SYMBOL_GPL(enetc_pf_notify_vf_link_down);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
index 07bb9aab89aa..549ea3f4b5cb 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
@@ -60,6 +60,10 @@ struct enetc_pf {
const struct enetc_pf_ops *ops;
int num_mfe; /* number of mac address filter table entries */
+ /* Message lock, prevent concurrent access */
+ struct mutex msg_lock;
+ u16 link_status_ms_mask;
+
};
#define phylink_to_enetc_pf(config) \
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
index 44c546b77d3f..e3bed5580d17 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
@@ -458,6 +458,8 @@ int enetc_init_sriov_resources(struct enetc_pf *pf)
for (int i = 0; i < pf->total_vfs; i++)
mutex_init(&pf->vf_state[i].lock);
+ mutex_init(&pf->msg_lock);
+
return 0;
}
EXPORT_SYMBOL_GPL(enetc_init_sriov_resources);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
index 5bf7c20aba42..bbe21c739cf7 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
@@ -26,9 +26,18 @@ static inline u16 enetc_get_ip_revision(struct enetc_hw *hw)
#if IS_ENABLED(CONFIG_PCI_IOV)
int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs);
+void enetc_pf_notify_vf_link_up(struct enetc_pf *pf);
+void enetc_pf_notify_vf_link_down(struct enetc_pf *pf);
#else
static inline int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)
{
return 0;
}
+
+static inline void enetc_pf_notify_vf_link_up(struct enetc_pf *pf)
+{
+}
+
+static inline void enetc_pf_notify_vf_link_down(struct enetc_pf *pf)
+{}
#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 04/15] net: enetc: add link speed message support to PF driver
2026-06-05 6:55 [PATCH net-next 00/15] net: enetc: SR-IOV improvements and ENETC v4 VF support wei.fang
` (2 preceding siblings ...)
2026-06-05 6:55 ` [PATCH net-next 03/15] net: enetc: add link status message support to PF driver wei.fang
@ 2026-06-05 6:55 ` wei.fang
2026-06-06 7:24 ` sashiko-bot
2026-06-05 6:55 ` [PATCH net-next 05/15] net: enetc: use enetc_set_si_hw_addr() to set VF MAC address wei.fang
` (10 subsequent siblings)
14 siblings, 1 reply; 30+ messages in thread
From: wei.fang @ 2026-06-05 6:55 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang
Cc: imx, netdev, linux-kernel
From: Wei Fang <wei.fang@nxp.com>
When a VF is driven by DPDK, the VF relies on the PF to provide accurate
link speed information so that the VF-side user space application can
make correct forwarding and configuration decisions.
Therefore, add link speed message support for DPDK-owned VF. The PF will
reply the current link speed when it receives the get link speed message
from VF.
With this enhancement, VFs controlled by DPDK can obtain real-time link
speed information from the PF, improving overall link state visibility,
synchronization between PF/VF, and enabling more accurate performance
adjustments in VF-side applications.
Note that currently the link speed change notification is not supported.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
.../ethernet/freescale/enetc/enetc_mailbox.h | 29 +++++++
.../net/ethernet/freescale/enetc/enetc_msg.c | 77 +++++++++++++++++++
2 files changed, 106 insertions(+)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h b/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h
index 43b9ee2ab3e4..44c8196accaa 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h
@@ -108,6 +108,7 @@ enum enetc_msg_class_id {
/* Common Class ID for PSI-to-VSI and VSI-to-PSI messages */
ENETC_MSG_CLASS_ID_MAC_FILTER = 0x20,
ENETC_MSG_CLASS_ID_LINK_STATUS = 0x80,
+ ENETC_MSG_CLASS_ID_LINK_SPEED,
ENETC_MSG_CLASS_ID_IP_REVISION = 0xf0,
};
@@ -125,6 +126,13 @@ enum enetc_msg_link_status_cmd_id {
ENETC_MSG_UNREGISTER_LINK_CHANGE_NOTIFIER,
};
+enum enetc_msg_link_speed_cmd_id {
+ ENETC_MSG_GET_CURRENT_LINK_SPEED,
+ /* The following command IDs are not currently supported */
+ ENETC_MSG_REGISTER_SPEED_CHANGE_NOTIFIER,
+ ENETC_MSG_UNREGISTER_SPEED_CHANGE_NOTIFIER,
+};
+
/* Class-specific error return codes of MAC filter */
enum enetc_mac_filter_class_code {
ENETC_MF_CLASS_CODE_INVALID_MAC,
@@ -136,6 +144,22 @@ enum enetc_link_status_class_code {
ENETC_LINK_STATUS_CLASS_CODE_DOWN,
};
+/* Class-specific notifcaitons/codes of link speed */
+enum enetc_link_speed_class_code {
+ ENETC_MSG_SPEED_UNKNOWN,
+ ENETC_MSG_SPEED_10M_HD,
+ ENETC_MSG_SPEED_10M_FD,
+ ENETC_MSG_SPEED_100M_HD,
+ ENETC_MSG_SPEED_100M_FD,
+ ENETC_MSG_SPEED_1000M,
+ ENETC_MSG_SPEED_2500M,
+ ENETC_MSG_SPEED_5G,
+ ENETC_MSG_SPEED_10G,
+ ENETC_MSG_SPEED_25G,
+ ENETC_MSG_SPEED_50G,
+ ENETC_MSG_SPEED_100G,
+};
+
struct enetc_msg_swbd {
void *vaddr;
dma_addr_t dma;
@@ -179,6 +203,11 @@ struct enetc_msg_mac_exact_filter {
* cmd_id 0x0: get the current link status
* cmd_id 0x1: register link status change notification
* cmd_id 0x2: unregister link status change notification
+ *
+ * Link speed message, class_id 0x81.
+ * cmd_id 0x0: get the current link speed.
+ * cmd_id 0x1: register link speed change notification
+ * cmd_id 0x2: unregister link speed change notification
*/
struct enetc_msg_generic {
struct enetc_msg_header hdr;
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_msg.c b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
index c93b4e6913d8..49c1ca14735c 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_msg.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
@@ -9,6 +9,7 @@
ENETC_MSG_CLASS_ID_CMD_NOT_SUPPORT)
#define ENETC_PF_MSG_PERM_DENY FIELD_PREP(ENETC_PF_MSG_CLASS_ID, \
ENETC_MSG_CLASS_ID_PERMISSION_DENY)
+#define ENETC_PF_MSG_SPEED(s) FIELD_PREP(ENETC_PF_MSG_CLASS_CODE, (s))
static void enetc_msg_disable_mr_int(struct enetc_pf *pf)
{
@@ -235,6 +236,79 @@ static u16 enetc_msg_handle_link_status(struct enetc_pf *pf, int vf_id,
}
}
+static u16 enetc_msg_get_link_speed(struct enetc_pf *pf)
+{
+ struct enetc_ndev_priv *priv = netdev_priv(pf->si->ndev);
+ struct ethtool_link_ksettings link_info = {};
+ u16 pf_msg;
+
+ pf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
+ ENETC_MSG_CLASS_ID_LINK_SPEED);
+
+ rtnl_lock();
+ if (phylink_ethtool_ksettings_get(priv->phylink, &link_info)) {
+ pf_msg |= ENETC_PF_MSG_SPEED(ENETC_MSG_SPEED_UNKNOWN);
+ rtnl_unlock();
+
+ return pf_msg;
+ }
+ rtnl_unlock();
+
+ switch (link_info.base.speed) {
+ case SPEED_10:
+ if (link_info.base.duplex == DUPLEX_HALF)
+ pf_msg |= ENETC_PF_MSG_SPEED(ENETC_MSG_SPEED_10M_HD);
+ else
+ pf_msg |= ENETC_PF_MSG_SPEED(ENETC_MSG_SPEED_10M_FD);
+ break;
+ case SPEED_100:
+ if (link_info.base.duplex == DUPLEX_HALF)
+ pf_msg |= ENETC_PF_MSG_SPEED(ENETC_MSG_SPEED_100M_HD);
+ else
+ pf_msg |= ENETC_PF_MSG_SPEED(ENETC_MSG_SPEED_100M_FD);
+ break;
+ case SPEED_1000:
+ pf_msg |= ENETC_PF_MSG_SPEED(ENETC_MSG_SPEED_1000M);
+ break;
+ case SPEED_2500:
+ pf_msg |= ENETC_PF_MSG_SPEED(ENETC_MSG_SPEED_2500M);
+ break;
+ case SPEED_5000:
+ pf_msg |= ENETC_PF_MSG_SPEED(ENETC_MSG_SPEED_5G);
+ break;
+ case SPEED_10000:
+ pf_msg |= ENETC_PF_MSG_SPEED(ENETC_MSG_SPEED_10G);
+ break;
+ case SPEED_25000:
+ pf_msg |= ENETC_PF_MSG_SPEED(ENETC_MSG_SPEED_25G);
+ break;
+ case SPEED_50000:
+ pf_msg |= ENETC_PF_MSG_SPEED(ENETC_MSG_SPEED_50G);
+ break;
+ case SPEED_100000:
+ pf_msg |= ENETC_PF_MSG_SPEED(ENETC_MSG_SPEED_100G);
+ break;
+ default:
+ pf_msg |= ENETC_PF_MSG_SPEED(ENETC_MSG_SPEED_UNKNOWN);
+ }
+
+ return pf_msg;
+}
+
+static u16 enetc_msg_handle_link_speed(struct enetc_pf *pf, void *vf_msg)
+{
+ struct enetc_msg_header *msg_hdr = vf_msg;
+
+ switch (msg_hdr->cmd_id) {
+ case ENETC_MSG_GET_CURRENT_LINK_SPEED:
+ return enetc_msg_get_link_speed(pf);
+ case ENETC_MSG_REGISTER_SPEED_CHANGE_NOTIFIER:
+ case ENETC_MSG_UNREGISTER_SPEED_CHANGE_NOTIFIER:
+ default:
+ return ENETC_PF_MSG_NOTSUPP;
+ }
+}
+
static void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id,
u16 *pf_msg)
{
@@ -313,6 +387,9 @@ static void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id,
case ENETC_MSG_CLASS_ID_LINK_STATUS:
*pf_msg = enetc_msg_handle_link_status(pf, vf_id, msg);
break;
+ case ENETC_MSG_CLASS_ID_LINK_SPEED:
+ *pf_msg = enetc_msg_handle_link_speed(pf, msg);
+ break;
default:
dev_err_ratelimited(dev,
"Unsupported message class ID: 0x%x\n",
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 05/15] net: enetc: use enetc_set_si_hw_addr() to set VF MAC address
2026-06-05 6:55 [PATCH net-next 00/15] net: enetc: SR-IOV improvements and ENETC v4 VF support wei.fang
` (3 preceding siblings ...)
2026-06-05 6:55 ` [PATCH net-next 04/15] net: enetc: add link speed " wei.fang
@ 2026-06-05 6:55 ` wei.fang
2026-06-05 6:55 ` [PATCH net-next 06/15] net: enetc: relocate enetc_pf_set_vf_mac() for common PF support wei.fang
` (9 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: wei.fang @ 2026-06-05 6:55 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang
Cc: imx, netdev, linux-kernel
From: Wei Fang <wei.fang@nxp.com>
Prepare for moving enetc_pf_set_vf_mac() into the enetc-pf-common driver
by replacing enetc_pf_set_primary_mac_addr() with enetc_set_si_hw_addr().
This makes the VF primary MAC configuration path generic and allows
future enetc v4 PF driver to reuse the same interface.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
drivers/net/ethernet/freescale/enetc/enetc_pf.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index 8957e74314d1..4a16bc49312b 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -255,7 +255,7 @@ static int enetc_pf_set_vf_mac(struct net_device *ndev, int vf, u8 *mac)
mutex_lock(&vf_state->lock);
vf_state->flags |= ENETC_VF_FLAG_PF_SET_MAC;
- enetc_pf_set_primary_mac_addr(&priv->si->hw, vf + 1, mac);
+ enetc_set_si_hw_addr(pf, vf + 1, mac);
mutex_unlock(&vf_state->lock);
return 0;
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 06/15] net: enetc: relocate enetc_pf_set_vf_mac() for common PF support
2026-06-05 6:55 [PATCH net-next 00/15] net: enetc: SR-IOV improvements and ENETC v4 VF support wei.fang
` (4 preceding siblings ...)
2026-06-05 6:55 ` [PATCH net-next 05/15] net: enetc: use enetc_set_si_hw_addr() to set VF MAC address wei.fang
@ 2026-06-05 6:55 ` wei.fang
2026-06-05 6:55 ` [PATCH net-next 07/15] net: enetc: add .ndo_set_vf_mac() to the enetc v4 driver wei.fang
` (8 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: wei.fang @ 2026-06-05 6:55 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang
Cc: imx, netdev, linux-kernel
From: Wei Fang <wei.fang@nxp.com>
Move enetc_pf_set_vf_mac() into enetc-pf-common driver as a generic
interface for both ENETC v1 and v4 PF driver to use.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
.../net/ethernet/freescale/enetc/enetc_pf.c | 22 ------------------
.../freescale/enetc/enetc_pf_common.c | 23 +++++++++++++++++++
.../freescale/enetc/enetc_pf_common.h | 1 +
3 files changed, 24 insertions(+), 22 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index 4a16bc49312b..38fcc7b5fc6d 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -239,28 +239,6 @@ static void enetc_set_loopback(struct net_device *ndev, bool en)
}
}
-static int enetc_pf_set_vf_mac(struct net_device *ndev, int vf, u8 *mac)
-{
- struct enetc_ndev_priv *priv = netdev_priv(ndev);
- struct enetc_pf *pf = enetc_si_priv(priv->si);
- struct enetc_vf_state *vf_state;
-
- if (vf >= pf->total_vfs)
- return -EINVAL;
-
- if (!is_valid_ether_addr(mac))
- return -EADDRNOTAVAIL;
-
- vf_state = &pf->vf_state[vf];
-
- mutex_lock(&vf_state->lock);
- vf_state->flags |= ENETC_VF_FLAG_PF_SET_MAC;
- enetc_set_si_hw_addr(pf, vf + 1, mac);
- mutex_unlock(&vf_state->lock);
-
- return 0;
-}
-
static int enetc_pf_set_vf_vlan(struct net_device *ndev, int vf, u16 vlan,
u8 qos, __be16 proto)
{
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
index e3bed5580d17..85e1efa6a8ce 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
@@ -487,5 +487,28 @@ int enetc_pf_set_vf_trust(struct net_device *ndev, int vf, bool setting)
}
EXPORT_SYMBOL_GPL(enetc_pf_set_vf_trust);
+int enetc_pf_set_vf_mac(struct net_device *ndev, int vf, u8 *mac)
+{
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ struct enetc_pf *pf = enetc_si_priv(priv->si);
+ struct enetc_vf_state *vf_state;
+
+ if (vf >= pf->total_vfs)
+ return -EINVAL;
+
+ if (!is_valid_ether_addr(mac))
+ return -EADDRNOTAVAIL;
+
+ vf_state = &pf->vf_state[vf];
+
+ mutex_lock(&vf_state->lock);
+ vf_state->flags |= ENETC_VF_FLAG_PF_SET_MAC;
+ enetc_set_si_hw_addr(pf, vf + 1, mac);
+ mutex_unlock(&vf_state->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(enetc_pf_set_vf_mac);
+
MODULE_DESCRIPTION("NXP ENETC PF common functionality driver");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
index bbe21c739cf7..b2a2b06c794a 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
@@ -18,6 +18,7 @@ int enetc_vlan_rx_add_vid(struct net_device *ndev, __be16 prot, u16 vid);
int enetc_vlan_rx_del_vid(struct net_device *ndev, __be16 prot, u16 vid);
int enetc_init_sriov_resources(struct enetc_pf *pf);
int enetc_pf_set_vf_trust(struct net_device *ndev, int vf, bool setting);
+int enetc_pf_set_vf_mac(struct net_device *ndev, int vf, u8 *mac);
static inline u16 enetc_get_ip_revision(struct enetc_hw *hw)
{
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 07/15] net: enetc: add .ndo_set_vf_mac() to the enetc v4 driver
2026-06-05 6:55 [PATCH net-next 00/15] net: enetc: SR-IOV improvements and ENETC v4 VF support wei.fang
` (5 preceding siblings ...)
2026-06-05 6:55 ` [PATCH net-next 06/15] net: enetc: relocate enetc_pf_set_vf_mac() for common PF support wei.fang
@ 2026-06-05 6:55 ` wei.fang
2026-06-05 6:55 ` [PATCH net-next 08/15] net: enetc: move mac_filter from struct enetc_pf to struct enetc_si wei.fang
` (7 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: wei.fang @ 2026-06-05 6:55 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang
Cc: imx, netdev, linux-kernel
From: Wei Fang <wei.fang@nxp.com>
Add .ndo_set_vf_mac() to the enetc v4 driver to configure the MAC
addresses of VFs.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
drivers/net/ethernet/freescale/enetc/enetc4_pf.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index ad211eefd9d4..4cff2f1237f1 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -571,6 +571,7 @@ static const struct net_device_ops enetc4_ndev_ops = {
.ndo_hwtstamp_get = enetc_hwtstamp_get,
.ndo_hwtstamp_set = enetc_hwtstamp_set,
.ndo_set_vf_trust = enetc_pf_set_vf_trust,
+ .ndo_set_vf_mac = enetc_pf_set_vf_mac,
};
static struct phylink_pcs *
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 08/15] net: enetc: move mac_filter from struct enetc_pf to struct enetc_si
2026-06-05 6:55 [PATCH net-next 00/15] net: enetc: SR-IOV improvements and ENETC v4 VF support wei.fang
` (6 preceding siblings ...)
2026-06-05 6:55 ` [PATCH net-next 07/15] net: enetc: add .ndo_set_vf_mac() to the enetc v4 driver wei.fang
@ 2026-06-05 6:55 ` wei.fang
2026-06-06 7:24 ` sashiko-bot
2026-06-05 6:55 ` [PATCH net-next 09/15] net: enetc: add MAC address filtering support for VFs of ENETC v4 wei.fang
` (6 subsequent siblings)
14 siblings, 1 reply; 30+ messages in thread
From: wei.fang @ 2026-06-05 6:55 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang
Cc: imx, netdev, linux-kernel
From: Wei Fang <wei.fang@nxp.com>
The mac_filter array currently resides in struct enetc_pf and is used to
track unicast and multicast MAC address filters for the PF. Since struct
enetc_si is the common structure shared between the PF and VF drivers,
move mac_filter into struct enetc_si to prepare for MAC filter support
in the VF driver.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
drivers/net/ethernet/freescale/enetc/enetc.h | 1 +
drivers/net/ethernet/freescale/enetc/enetc4_pf.c | 5 +++--
drivers/net/ethernet/freescale/enetc/enetc_pf.c | 15 +++++++--------
drivers/net/ethernet/freescale/enetc/enetc_pf.h | 2 --
4 files changed, 11 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index 2cd035773aca..24d9f89aee73 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -332,6 +332,7 @@ struct enetc_si {
struct work_struct msg_task;
char msg_int_name[ENETC_INT_NAME_MAX];
+ struct enetc_mac_filter mac_filter[MADDR_TYPE];
};
#define ENETC_SI_ALIGN 32
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index 4cff2f1237f1..f6920ded9f7e 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -225,11 +225,12 @@ static void enetc4_pf_set_mac_hash_filter(struct enetc_pf *pf, int type)
struct net_device *ndev = pf->si->ndev;
struct enetc_mac_filter *mac_filter;
struct enetc_hw *hw = &pf->si->hw;
+ struct enetc_si *si = pf->si;
struct netdev_hw_addr *ha;
netif_addr_lock_bh(ndev);
if (type & ENETC_MAC_FILTER_TYPE_UC) {
- mac_filter = &pf->mac_filter[UC];
+ mac_filter = &si->mac_filter[UC];
enetc_reset_mac_addr_filter(mac_filter);
netdev_for_each_uc_addr(ha, ndev)
enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
@@ -239,7 +240,7 @@ static void enetc4_pf_set_mac_hash_filter(struct enetc_pf *pf, int type)
}
if (type & ENETC_MAC_FILTER_TYPE_MC) {
- mac_filter = &pf->mac_filter[MC];
+ mac_filter = &si->mac_filter[MC];
enetc_reset_mac_addr_filter(mac_filter);
netdev_for_each_mc_addr(ha, ndev)
enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index 38fcc7b5fc6d..209a3503609f 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -111,10 +111,9 @@ static void enetc_set_mac_ht_flt(struct enetc_si *si, int si_idx, int type,
}
}
-static void enetc_sync_mac_filters(struct enetc_pf *pf)
+static void enetc_sync_mac_filters(struct enetc_si *si)
{
- struct enetc_mac_filter *f = pf->mac_filter;
- struct enetc_si *si = pf->si;
+ struct enetc_mac_filter *f = si->mac_filter;
int i, pos;
pos = EMETC_MAC_ADDR_FILT_RES;
@@ -158,10 +157,10 @@ static void enetc_sync_mac_filters(struct enetc_pf *pf)
static void enetc_pf_set_rx_mode(struct net_device *ndev)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
- struct enetc_pf *pf = enetc_si_priv(priv->si);
- struct enetc_hw *hw = &priv->si->hw;
bool uprom = false, mprom = false;
struct enetc_mac_filter *filter;
+ struct enetc_si *si = priv->si;
+ struct enetc_hw *hw = &si->hw;
struct netdev_hw_addr *ha;
u32 psipmr = 0;
bool em;
@@ -180,7 +179,7 @@ static void enetc_pf_set_rx_mode(struct net_device *ndev)
/* first 2 filter entries belong to PF */
if (!uprom) {
/* Update unicast filters */
- filter = &pf->mac_filter[UC];
+ filter = &si->mac_filter[UC];
enetc_reset_mac_addr_filter(filter);
em = (netdev_uc_count(ndev) == 1);
@@ -196,7 +195,7 @@ static void enetc_pf_set_rx_mode(struct net_device *ndev)
if (!mprom) {
/* Update multicast filters */
- filter = &pf->mac_filter[MC];
+ filter = &si->mac_filter[MC];
enetc_reset_mac_addr_filter(filter);
netdev_for_each_mc_addr(ha, ndev) {
@@ -209,7 +208,7 @@ static void enetc_pf_set_rx_mode(struct net_device *ndev)
if (!uprom || !mprom)
/* update PF entries */
- enetc_sync_mac_filters(pf);
+ enetc_sync_mac_filters(si);
psipmr |= enetc_port_rd(hw, ENETC_PSIPMR) &
~(ENETC_PSIPMR_SET_UP(0) | ENETC_PSIPMR_SET_MP(0));
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
index 549ea3f4b5cb..b90a3d24d854 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
@@ -41,8 +41,6 @@ struct enetc_pf {
int num_vfs; /* number of active VFs, after sriov_init */
int total_vfs; /* max number of VFs, set for PF at probe */
struct enetc_vf_state *vf_state;
-
- struct enetc_mac_filter mac_filter[MADDR_TYPE];
struct enetc_msg_swbd *rxmsg;
char vlan_promisc_simap; /* bitmap of SIs in VLAN promisc mode */
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 09/15] net: enetc: add MAC address filtering support for VFs of ENETC v4
2026-06-05 6:55 [PATCH net-next 00/15] net: enetc: SR-IOV improvements and ENETC v4 VF support wei.fang
` (7 preceding siblings ...)
2026-06-05 6:55 ` [PATCH net-next 08/15] net: enetc: move mac_filter from struct enetc_pf to struct enetc_si wei.fang
@ 2026-06-05 6:55 ` wei.fang
2026-06-06 7:24 ` sashiko-bot
2026-06-05 6:55 ` [PATCH net-next 10/15] net: enetc: simplify and rename PSIIER enable/disable helpers wei.fang
` (5 subsequent siblings)
14 siblings, 1 reply; 30+ messages in thread
From: wei.fang @ 2026-06-05 6:55 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang
Cc: imx, netdev, linux-kernel
From: Wei Fang <wei.fang@nxp.com>
The ENETC v4 VF hardware supports MAC address filtering, but the
underlying hardware resources (PSIPMMR register and per-SI hash filter
tables) are owned and managed exclusively by the PF driver. Add
VSI-to-PSI mailbox message support so that VFs can request MAC filter
configuration from the PF.
Two new command IDs are introduced under the existing MAC filter message
class (0x20):
1. ENETC_MSG_SET_MAC_HASH_TABLE (cmd_id 3): allows a trusted VF to
program its unicast and/or multicast MAC hash filter table. The PF
validates that the hardware-supported 64-bit table size is requested
before applying the configuration via the per-SI hash filter registers.
2. ENETC_MSG_SET_MAC_PROMISC_MODE (cmd_id 5): allows a VF to enable or
disable unicast/multicast promiscuous mode, and optionally flush the
associated hash filter table. Enabling promiscuous mode requires the VF
to be marked as trusted, since it widens the traffic received by the VF.
Flushing the hash table without enabling promiscuous mode does not
require elevated privilege.
To accommodate independent per-type control, refactor
enetc4_pf_set_si_mac_promisc() to accept an enetc_mac_addr_type enum
and a single enable flag instead of two separate boolean parameters.
This allows callers to set unicast and multicast promiscuous modes in
separate steps.
The PSIPMMR register holds promiscuous mode bits for all SIs and is
modified by both the PF rx_mode workqueue (enetc4_psi_do_set_rx_mode)
and the VF message handler workqueue (enetc_msg_task). Since both
workqueues can run concurrently on SMP systems and
enetc4_pf_set_si_mac_promisc() performs a non-atomic read-modify-write,
protect all accesses to this register with pf->msg_lock to prevent lost
updates.
When a VF loses trusted status via ndo_set_vf_trust(), its unicast and
multicast MAC hash filters are cleared and promiscuous mode is disabled
to prevent it from receiving traffic beyond its allowed scope.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
.../net/ethernet/freescale/enetc/enetc4_pf.c | 40 +++++--
.../ethernet/freescale/enetc/enetc_mailbox.h | 39 ++++++
.../net/ethernet/freescale/enetc/enetc_msg.c | 113 ++++++++++++++++++
.../net/ethernet/freescale/enetc/enetc_pf.h | 4 +
.../freescale/enetc/enetc_pf_common.c | 21 +++-
5 files changed, 204 insertions(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index f6920ded9f7e..2e081a59154e 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -76,19 +76,22 @@ static void enetc4_pf_get_si_primary_mac(struct enetc_hw *hw, int si,
}
static void enetc4_pf_set_si_mac_promisc(struct enetc_hw *hw, int si,
- bool uc_promisc, bool mc_promisc)
+ enum enetc_mac_addr_type type,
+ bool en)
{
u32 val = enetc_port_rd(hw, ENETC4_PSIPMMR);
- if (uc_promisc)
- val |= PSIPMMR_SI_MAC_UP(si);
- else
- val &= ~PSIPMMR_SI_MAC_UP(si);
-
- if (mc_promisc)
- val |= PSIPMMR_SI_MAC_MP(si);
- else
- val &= ~PSIPMMR_SI_MAC_MP(si);
+ if (type == UC) {
+ if (en)
+ val |= PSIPMMR_SI_MAC_UP(si);
+ else
+ val &= ~PSIPMMR_SI_MAC_UP(si);
+ } else if (type == MC) {
+ if (en)
+ val |= PSIPMMR_SI_MAC_MP(si);
+ else
+ val &= ~PSIPMMR_SI_MAC_MP(si);
+ }
enetc_port_wr(hw, ENETC4_PSIPMMR, val);
}
@@ -107,6 +110,16 @@ static void enetc4_pf_set_si_mc_hash_filter(struct enetc_hw *hw, int si,
enetc_port_wr(hw, ENETC4_PSIMMHFR1(si), upper_32_bits(hash));
}
+static void enetc4_pf_set_si_mac_hash_filter(struct enetc_hw *hw, int si,
+ enum enetc_mac_addr_type type,
+ u64 hash)
+{
+ if (type == UC)
+ enetc4_pf_set_si_uc_hash_filter(hw, si, hash);
+ else if (type == MC)
+ enetc4_pf_set_si_mc_hash_filter(hw, si, hash);
+}
+
static void enetc4_pf_set_loopback(struct net_device *ndev, bool en)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
@@ -273,6 +286,8 @@ static void enetc4_pf_set_mac_filter(struct enetc_pf *pf, int type)
static const struct enetc_pf_ops enetc4_pf_ops = {
.set_si_primary_mac = enetc4_pf_set_si_primary_mac,
.get_si_primary_mac = enetc4_pf_get_si_primary_mac,
+ .set_si_mac_promisc = enetc4_pf_set_si_mac_promisc,
+ .set_si_mac_hash_filter = enetc4_pf_set_si_mac_hash_filter,
};
static int enetc4_pf_struct_init(struct enetc_si *si)
@@ -513,7 +528,10 @@ static void enetc4_psi_do_set_rx_mode(struct work_struct *work)
type = ENETC_MAC_FILTER_TYPE_ALL;
}
- enetc4_pf_set_si_mac_promisc(hw, 0, uc_promisc, mc_promisc);
+ mutex_lock(&pf->msg_lock);
+ enetc4_pf_set_si_mac_promisc(hw, 0, UC, uc_promisc);
+ enetc4_pf_set_si_mac_promisc(hw, 0, MC, mc_promisc);
+ mutex_unlock(&pf->msg_lock);
if (uc_promisc) {
enetc4_pf_set_si_uc_hash_filter(hw, 0, 0);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h b/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h
index 44c8196accaa..9e23499e290f 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h
@@ -91,6 +91,17 @@
#define ENETC_PF_MSG_CLASS_CODE_U8 GENMASK(7, 0)
#define ENETC_PF_MSG_CLASS_ID GENMASK(15, 8)
+#define ENETC_MAC_HASH_TABLE_SIZE_64 0
+#define ENETC_MSG_MAC_HASH_SIZE GENMASK(5, 0)
+#define ENETC_MSG_MAC_TYPE GENMASK(7, 6)
+#define ENETC_MAC_FILTER_TYPE_UC BIT(0)
+#define ENETC_MAC_FILTER_TYPE_MC BIT(1)
+#define ENETC_MAC_FILTER_TYPE_ALL (ENETC_MAC_FILTER_TYPE_UC | \
+ ENETC_MAC_FILTER_TYPE_MC)
+
+#define ENETC_MSG_MAC_FLUSH_MACS BIT(0)
+#define ENETC_MSG_MAC_PROMISC_MODE BIT(1)
+
enum enetc_msg_class_id {
/* Class ID for PSI-to-VSI messages */
ENETC_MSG_CLASS_ID_CMD_SUCCESS = 1,
@@ -114,6 +125,8 @@ enum enetc_msg_class_id {
enum enetc_msg_mac_filter_cmd_id {
ENETC_MSG_SET_PRIMARY_MAC,
+ ENETC_MSG_SET_MAC_HASH_TABLE = 3,
+ ENETC_MSG_SET_MAC_PROMISC_MODE = 5,
};
enum enetc_msg_ip_revision_cmd_id {
@@ -195,6 +208,32 @@ struct enetc_msg_mac_exact_filter {
struct enetc_mac_addr mac[];
};
+/* message format of class_id 0x20 for hash MAC filter.
+ * cmd_id 0x3: set MAC hash table
+ */
+struct enetc_msg_mac_hash_filter {
+ struct enetc_msg_header hdr;
+ /* bit 0 ~ 5: ENETC_MSG_MAC_HASH_SIZE
+ * bit 6~7: ENETC_MSG_MAC_TYPE
+ */
+ u8 sz_type;
+ u8 resv[3];
+ u32 hash_tbl[];
+};
+
+/* message format of class_id 0x20 for MAC promiscuous mode.
+ * cmd_id 0x5: set MAC promiscuous mode
+ */
+struct enetc_msg_mac_promisc_mode {
+ struct enetc_msg_header hdr;
+ /* bit 0: ENETC_MSG_MAC_FLUSH_MACS
+ * bit 1: ENETC_MSG_MAC_PROMISC_MODE
+ * bit 6~7: ENETC_MSG_MAC_TYPE
+ */
+ u8 config;
+ u8 resv[15];
+};
+
/* The generic message format applies to the following messages:
* Get IP revision message, class_id 0xf0.
* cmd_id 1: get IP minor revision
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_msg.c b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
index 49c1ca14735c..7dcb1dcdec84 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_msg.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
@@ -101,6 +101,115 @@ static u16 enetc_msg_set_vf_primary_mac_addr(struct enetc_pf *pf, int vf_id,
return pf_msg;
}
+static u16 enetc_msg_set_vf_mac_hash_filter(struct enetc_pf *pf, int vf_id,
+ void *vf_msg)
+{
+ struct enetc_vf_state *vf_state = &pf->vf_state[vf_id];
+ struct enetc_msg_mac_hash_filter *msg = vf_msg;
+ struct enetc_hw *hw = &pf->si->hw;
+ u16 pf_msg = ENETC_PF_MSG_SUCCESS;
+ int si_id = vf_id + 1;
+ u64 hash_tbl;
+ int type;
+
+ mutex_lock(&vf_state->lock);
+
+ if (!(vf_state->flags & ENETC_VF_FLAG_TRUSTED)) {
+ pf_msg = ENETC_PF_MSG_PERM_DENY;
+ goto vf_state_unlock;
+ }
+
+ if (!pf->ops->set_si_mac_hash_filter) {
+ pf_msg = ENETC_PF_MSG_NOTSUPP;
+ goto vf_state_unlock;
+ }
+
+ /* Currently, hardware only supports 64 bits table size */
+ if (FIELD_GET(ENETC_MSG_MAC_HASH_SIZE, msg->sz_type) !=
+ ENETC_MAC_HASH_TABLE_SIZE_64) {
+ pf_msg = ENETC_PF_MSG_NOTSUPP;
+ goto vf_state_unlock;
+ }
+
+ type = FIELD_GET(ENETC_MSG_MAC_TYPE, msg->sz_type);
+ hash_tbl = (u64)msg->hash_tbl[1] << 32 | msg->hash_tbl[0];
+ if (type == ENETC_MAC_FILTER_TYPE_UC) {
+ pf->ops->set_si_mac_hash_filter(hw, si_id, UC, hash_tbl);
+ } else if (type == ENETC_MAC_FILTER_TYPE_MC) {
+ pf->ops->set_si_mac_hash_filter(hw, si_id, MC, hash_tbl);
+ } else if (type == ENETC_MAC_FILTER_TYPE_ALL) {
+ if (!msg->hdr.len) {
+ pf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
+ ENETC_MSG_CLASS_ID_INVALID_MSG_LEN);
+ goto vf_state_unlock;
+ }
+
+ pf->ops->set_si_mac_hash_filter(hw, si_id, UC, hash_tbl);
+ hash_tbl = (u64)msg->hash_tbl[3] << 32 | msg->hash_tbl[2];
+ pf->ops->set_si_mac_hash_filter(hw, si_id, MC, hash_tbl);
+ }
+
+vf_state_unlock:
+ mutex_unlock(&vf_state->lock);
+
+ return pf_msg;
+}
+
+static u16 enetc_msg_set_vf_mac_promisc_mode(struct enetc_pf *pf, int vf_id,
+ void *vf_msg)
+{
+ struct enetc_vf_state *vf_state = &pf->vf_state[vf_id];
+ struct enetc_msg_mac_promisc_mode *msg = vf_msg;
+ u16 pf_msg = ENETC_PF_MSG_SUCCESS;
+ struct enetc_hw *hw = &pf->si->hw;
+ bool promisc, flush_macs;
+ int si_id = vf_id + 1;
+ int type;
+
+ mutex_lock(&vf_state->lock);
+ if (msg->config & ENETC_MSG_MAC_PROMISC_MODE) {
+ if (!(vf_state->flags & ENETC_VF_FLAG_TRUSTED)) {
+ pf_msg = ENETC_PF_MSG_PERM_DENY;
+ goto vf_state_unlock;
+ }
+ }
+
+ if (!pf->ops->set_si_mac_promisc) {
+ pf_msg = ENETC_PF_MSG_NOTSUPP;
+ goto vf_state_unlock;
+ }
+
+ flush_macs = !!(msg->config & ENETC_MSG_MAC_FLUSH_MACS);
+ if (flush_macs && !pf->ops->set_si_mac_hash_filter) {
+ pf_msg = ENETC_PF_MSG_NOTSUPP;
+ goto vf_state_unlock;
+ }
+
+ type = FIELD_GET(ENETC_MSG_MAC_TYPE, msg->config);
+ promisc = !!(msg->config & ENETC_MSG_MAC_PROMISC_MODE);
+
+ mutex_lock(&pf->msg_lock);
+
+ if (type & ENETC_MAC_FILTER_TYPE_UC)
+ pf->ops->set_si_mac_promisc(hw, si_id, UC, promisc);
+
+ if (type & ENETC_MAC_FILTER_TYPE_MC)
+ pf->ops->set_si_mac_promisc(hw, si_id, MC, promisc);
+
+ mutex_unlock(&pf->msg_lock);
+
+ if ((type & ENETC_MAC_FILTER_TYPE_UC) && flush_macs)
+ pf->ops->set_si_mac_hash_filter(hw, si_id, UC, 0);
+
+ if ((type & ENETC_MAC_FILTER_TYPE_MC) && flush_macs)
+ pf->ops->set_si_mac_hash_filter(hw, si_id, MC, 0);
+
+vf_state_unlock:
+ mutex_unlock(&vf_state->lock);
+
+ return pf_msg;
+}
+
static u16 enetc_msg_handle_mac_filter(struct enetc_pf *pf, int vf_id,
void *vf_msg)
{
@@ -109,6 +218,10 @@ static u16 enetc_msg_handle_mac_filter(struct enetc_pf *pf, int vf_id,
switch (msg_hdr->cmd_id) {
case ENETC_MSG_SET_PRIMARY_MAC:
return enetc_msg_set_vf_primary_mac_addr(pf, vf_id, vf_msg);
+ case ENETC_MSG_SET_MAC_HASH_TABLE:
+ return enetc_msg_set_vf_mac_hash_filter(pf, vf_id, vf_msg);
+ case ENETC_MSG_SET_MAC_PROMISC_MODE:
+ return enetc_msg_set_vf_mac_promisc_mode(pf, vf_id, vf_msg);
default:
return ENETC_PF_MSG_NOTSUPP;
}
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
index b90a3d24d854..7ca85731d6cc 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
@@ -34,6 +34,10 @@ struct enetc_pf_ops {
struct phylink_pcs *(*create_pcs)(struct enetc_pf *pf, struct mii_bus *bus);
void (*destroy_pcs)(struct phylink_pcs *pcs);
int (*enable_psfp)(struct enetc_ndev_priv *priv);
+ void (*set_si_mac_promisc)(struct enetc_hw *hw, int si,
+ enum enetc_mac_addr_type type, bool en);
+ void (*set_si_mac_hash_filter)(struct enetc_hw *hw, int si,
+ enum enetc_mac_addr_type type, u64 hash);
};
struct enetc_pf {
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
index 85e1efa6a8ce..66a9a734d18e 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
@@ -468,6 +468,7 @@ int enetc_pf_set_vf_trust(struct net_device *ndev, int vf, bool setting)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct enetc_pf *pf = enetc_si_priv(priv->si);
+ struct enetc_hw *hw = &pf->si->hw;
struct enetc_vf_state *vf_state;
if (vf >= pf->total_vfs)
@@ -476,11 +477,27 @@ int enetc_pf_set_vf_trust(struct net_device *ndev, int vf, bool setting)
vf_state = &pf->vf_state[vf];
mutex_lock(&vf_state->lock);
- if (setting)
+ if (setting) {
vf_state->flags |= ENETC_VF_FLAG_TRUSTED;
- else
+ } else {
vf_state->flags &= ~ENETC_VF_FLAG_TRUSTED;
+ /* Clear MAC hash filters and disable MAC promiscuous modes
+ * if the VF is untrusted.
+ */
+ if (pf->ops->set_si_mac_hash_filter) {
+ pf->ops->set_si_mac_hash_filter(hw, vf + 1, UC, 0);
+ pf->ops->set_si_mac_hash_filter(hw, vf + 1, MC, 0);
+ }
+
+ mutex_lock(&pf->msg_lock);
+ if (pf->ops->set_si_mac_promisc) {
+ pf->ops->set_si_mac_promisc(hw, vf + 1, UC, false);
+ pf->ops->set_si_mac_promisc(hw, vf + 1, MC, false);
+ }
+ mutex_unlock(&pf->msg_lock);
+ }
+
mutex_unlock(&vf_state->lock);
return 0;
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 10/15] net: enetc: simplify and rename PSIIER enable/disable helpers
2026-06-05 6:55 [PATCH net-next 00/15] net: enetc: SR-IOV improvements and ENETC v4 VF support wei.fang
` (8 preceding siblings ...)
2026-06-05 6:55 ` [PATCH net-next 09/15] net: enetc: add MAC address filtering support for VFs of ENETC v4 wei.fang
@ 2026-06-05 6:55 ` wei.fang
2026-06-05 6:55 ` [PATCH net-next 11/15] net: enetc: restore VF MAC promiscuous mode after FLR for ENETC v4 wei.fang
` (4 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: wei.fang @ 2026-06-05 6:55 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang
Cc: imx, netdev, linux-kernel
From: Wei Fang <wei.fang@nxp.com>
The PSIIER register controls two categories of interrupt sources:
message-receive (MR) interrupts, which fire when a VF sends a mailbox
message to the PSI, and VF FLR interrupts, which fire when a VF
performs a Function Level Reset.
The current helpers enetc_msg_enable_mr_int() and
enetc_msg_disable_mr_int() use a read-modify-write sequence to update
only the MR bits in PSIIER, intending to preserve any other bits that
may be set. However, VF FLR interrupt support is not yet implemented,
so PSIIER only ever holds MR interrupt bits at this point. The
read-modify-write is therefore unnecessary overhead.
Simplify enetc_disable_psiier_interrupts() to write 0 directly to
PSIIER, disabling all interrupt sources at once, and simplify
enetc_enable_psiier_interrupts() to write the MR mask directly without
reading the current register value first.
Rename both helpers from the MR-specific names to names that reflect
their true scope, i.e. managing all PSIIER interrupt sources rather
than just the MR bits. This prepares the code for a future patch that
adds VF FLR interrupt support, at which point
enetc_enable_psiier_interrupts() will be extended to also set the
corresponding FLR bits.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
.../net/ethernet/freescale/enetc/enetc_msg.c | 30 ++++++++-----------
1 file changed, 12 insertions(+), 18 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_msg.c b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
index 7dcb1dcdec84..d9560e2c5385 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_msg.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
@@ -11,23 +11,17 @@
ENETC_MSG_CLASS_ID_PERMISSION_DENY)
#define ENETC_PF_MSG_SPEED(s) FIELD_PREP(ENETC_PF_MSG_CLASS_CODE, (s))
-static void enetc_msg_disable_mr_int(struct enetc_pf *pf)
+static void enetc_disable_psiier_interrupts(struct enetc_pf *pf)
{
struct enetc_hw *hw = &pf->si->hw;
- u32 psiier;
- psiier = enetc_rd(hw, ENETC_PSIIER) & ~ENETC_PSIMR_MASK(pf->num_vfs);
-
- /* disable MR int source(s) */
- enetc_wr(hw, ENETC_PSIIER, psiier);
+ enetc_wr(hw, ENETC_PSIIER, 0);
}
-static void enetc_msg_enable_mr_int(struct enetc_pf *pf)
+static void enetc_enable_psiier_interrupts(struct enetc_pf *pf)
{
+ u32 psiier = ENETC_PSIMR_MASK(pf->num_vfs);
struct enetc_hw *hw = &pf->si->hw;
- u32 psiier;
-
- psiier = enetc_rd(hw, ENETC_PSIIER) | ENETC_PSIMR_MASK(pf->num_vfs);
enetc_wr(hw, ENETC_PSIIER, psiier);
}
@@ -37,7 +31,7 @@ static irqreturn_t enetc_msg_psi_msix(int irq, void *data)
struct enetc_si *si = (struct enetc_si *)data;
struct enetc_pf *pf = enetc_si_priv(si);
- enetc_msg_disable_mr_int(pf);
+ enetc_disable_psiier_interrupts(pf);
schedule_work(&si->msg_task);
return IRQ_HANDLED;
@@ -545,7 +539,7 @@ static void enetc_msg_task(struct work_struct *work)
}
out:
- enetc_msg_enable_mr_int(pf);
+ enetc_enable_psiier_interrupts(pf);
}
/* Init */
@@ -620,8 +614,8 @@ static int enetc_msg_psi_init(struct enetc_pf *pf)
/* set one IRQ entry for PSI message receive notification (SI int) */
enetc_wr(&si->hw, ENETC_SIMSIVR, ENETC_SI_INT_IDX);
- /* enable MR interrupts */
- enetc_msg_enable_mr_int(pf);
+ /* enable PSIIER interrupts */
+ enetc_enable_psiier_interrupts(pf);
return 0;
@@ -637,16 +631,16 @@ static void enetc_msg_psi_free(struct enetc_pf *pf)
struct enetc_si *si = pf->si;
int i;
- /* disable MR interrupts */
- enetc_msg_disable_mr_int(pf);
+ /* disable PSIIER interrupts */
+ enetc_disable_psiier_interrupts(pf);
/* de-register message passing interrupt handler */
free_irq(pci_irq_vector(si->pdev, ENETC_SI_INT_IDX), si);
cancel_work_sync(&si->msg_task);
- /* MR interrupts may be re-enabled by workqueue */
- enetc_msg_disable_mr_int(pf);
+ /* PSIIER interrupts may be re-enabled by workqueue */
+ enetc_disable_psiier_interrupts(pf);
for (i = 0; i < pf->num_vfs; i++)
enetc_msg_free_mbx(si, i);
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 11/15] net: enetc: restore VF MAC promiscuous mode after FLR for ENETC v4
2026-06-05 6:55 [PATCH net-next 00/15] net: enetc: SR-IOV improvements and ENETC v4 VF support wei.fang
` (9 preceding siblings ...)
2026-06-05 6:55 ` [PATCH net-next 10/15] net: enetc: simplify and rename PSIIER enable/disable helpers wei.fang
@ 2026-06-05 6:55 ` wei.fang
2026-06-06 7:24 ` sashiko-bot
2026-06-05 6:55 ` [PATCH net-next 12/15] net: enetc: add VF support for i.MX94 and i.MX95 wei.fang
` (3 subsequent siblings)
14 siblings, 1 reply; 30+ messages in thread
From: wei.fang @ 2026-06-05 6:55 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang
Cc: imx, netdev, linux-kernel
From: Wei Fang <wei.fang@nxp.com>
On ENETC v4, a PCIe VF Function Level Reset (FLR) resets certain bits in
PF register space, including PSIPMMR[SIn_MAC_UP] and PSIPMMR[SIn_MAC_MP],
which control the unicast and multicast promiscuous mode for the
corresponding SI. The reset (default) value of these bits enables
promiscuous mode, meaning that after a VF FLR, the SI is left in
promiscuous mode regardless of the configuration set by the PF driver
prior to the reset.
This is a potential security vulnerability: a malicious VM could
deliberately trigger a VF FLR to force promiscuous mode on its SI,
allowing it to capture network traffic not destined for that VF.
To mitigate this, make the following changes:
- Add ENETC_VF_FLAG_UC_PROMISC and ENETC_VF_FLAG_MC_PROMISC to
enetc_vf_flags to track the PF-managed promiscuous mode state for each
VF.
- Update enetc_msg_set_vf_mac_promisc_mode() to keep these flags in sync
whenever a VF requests a promiscuous mode change via messaging.
- Update enetc_pf_set_vf_trust() to clear both promisc flags when a VF
is untrusted, so that a subsequent FLR cannot restore promiscuous mode
that the PF has already revoked.
- Add a vf_flr_handler callback to enetc_pf_ops. The ENETC v4
implementation re-applies the tracked UC/MC promiscuous mode settings
to the hardware after each FLR, ensuring the hardware state matches
the PF-managed policy rather than the insecure reset default.
- Add enetc_vf_flr_handler() in enetc_msg.c to detect FLR events via the
PSIIDR register and dispatch to the vf_flr_handler callback. Invoke it
at the start of enetc_msg_task() before processing VF messages.
- Enable FLR interrupts in PSIIER only when a vf_flr_handler callback is
registered, keeping ENETC v1 behavior unchanged.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
.../net/ethernet/freescale/enetc/enetc4_pf.c | 21 +++++++++
.../net/ethernet/freescale/enetc/enetc_hw.h | 12 +++++
.../net/ethernet/freescale/enetc/enetc_msg.c | 44 ++++++++++++++++++-
.../net/ethernet/freescale/enetc/enetc_pf.h | 3 ++
.../freescale/enetc/enetc_pf_common.c | 4 +-
5 files changed, 81 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index 2e081a59154e..15c8b704b2b7 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -283,11 +283,32 @@ static void enetc4_pf_set_mac_filter(struct enetc_pf *pf, int type)
enetc4_pf_set_mac_hash_filter(pf, ENETC_MAC_FILTER_TYPE_MC);
}
+static void enetc4_pf_vf_flr_handler(struct enetc_pf *pf, int vf_id)
+{
+ struct enetc_hw *hw = &pf->si->hw;
+ struct enetc_vf_state *vf_state;
+ bool uc_promisc, mc_promisc;
+
+ vf_state = &pf->vf_state[vf_id];
+ mutex_lock(&vf_state->lock);
+
+ uc_promisc = !!(vf_state->flags & ENETC_VF_FLAG_UC_PROMISC);
+ mc_promisc = !!(vf_state->flags & ENETC_VF_FLAG_MC_PROMISC);
+
+ mutex_lock(&pf->msg_lock);
+ enetc4_pf_set_si_mac_promisc(hw, vf_id + 1, UC, uc_promisc);
+ enetc4_pf_set_si_mac_promisc(hw, vf_id + 1, MC, mc_promisc);
+ mutex_unlock(&pf->msg_lock);
+
+ mutex_unlock(&vf_state->lock);
+}
+
static const struct enetc_pf_ops enetc4_pf_ops = {
.set_si_primary_mac = enetc4_pf_set_si_primary_mac,
.get_si_primary_mac = enetc4_pf_get_si_primary_mac,
.set_si_mac_promisc = enetc4_pf_set_si_mac_promisc,
.set_si_mac_hash_filter = enetc4_pf_set_si_mac_hash_filter,
+ .vf_flr_handler = enetc4_pf_vf_flr_handler,
};
static int enetc4_pf_struct_init(struct enetc_si *si)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
index 37c6060ccc82..62844344ff29 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
@@ -109,6 +109,18 @@ static inline u32 enetc_vsi_set_msize(u32 size)
#define ENETC_PSIIER 0xa00
#define ENETC_PSIIDR 0xa08
+
+/* VF FLR interrupt mask, n is the active number of VSIs.
+ * It is available for ENETC_PSIIER and ENETC_PSIIDR registers.
+ */
+#define ENETC_VFFLR_MASK(n) \
+ ({ typeof(n) _n = (n); (_n) ? GENMASK(16 + (_n), 17) : 0; })
+
+/* VF FLR interrupt bit, n is VSI index. It is available
+ * for ENETC_PSIIER and ENETC_PSIIDR registers.
+ */
+#define ENETC_VFFLR_BIT(n) BIT(17 + (n))
+
#define ENETC_SITXIDR 0xa18
#define ENETC_SIRXIDR 0xa28
#define ENETC_SIMSIVR 0xa30
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_msg.c b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
index d9560e2c5385..6aacb22cfa82 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_msg.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
@@ -23,6 +23,9 @@ static void enetc_enable_psiier_interrupts(struct enetc_pf *pf)
u32 psiier = ENETC_PSIMR_MASK(pf->num_vfs);
struct enetc_hw *hw = &pf->si->hw;
+ if (pf->ops->vf_flr_handler)
+ psiier |= ENETC_VFFLR_MASK(pf->num_vfs);
+
enetc_wr(hw, ENETC_PSIIER, psiier);
}
@@ -184,11 +187,23 @@ static u16 enetc_msg_set_vf_mac_promisc_mode(struct enetc_pf *pf, int vf_id,
mutex_lock(&pf->msg_lock);
- if (type & ENETC_MAC_FILTER_TYPE_UC)
+ if (type & ENETC_MAC_FILTER_TYPE_UC) {
+ if (promisc)
+ vf_state->flags |= ENETC_VF_FLAG_UC_PROMISC;
+ else
+ vf_state->flags &= ~ENETC_VF_FLAG_UC_PROMISC;
+
pf->ops->set_si_mac_promisc(hw, si_id, UC, promisc);
+ }
+
+ if (type & ENETC_MAC_FILTER_TYPE_MC) {
+ if (promisc)
+ vf_state->flags |= ENETC_VF_FLAG_MC_PROMISC;
+ else
+ vf_state->flags &= ~ENETC_VF_FLAG_MC_PROMISC;
- if (type & ENETC_MAC_FILTER_TYPE_MC)
pf->ops->set_si_mac_promisc(hw, si_id, MC, promisc);
+ }
mutex_unlock(&pf->msg_lock);
@@ -507,6 +522,29 @@ static void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id,
kfree(msg);
}
+static void enetc_vf_flr_handler(struct enetc_pf *pf)
+{
+ u32 flr_mask = ENETC_VFFLR_MASK(pf->num_vfs);
+ struct enetc_hw *hw = &pf->si->hw;
+ u32 flr_status;
+
+ if (!pf->ops->vf_flr_handler)
+ return;
+
+ flr_status = enetc_rd(hw, ENETC_PSIIDR) & flr_mask;
+ if (!flr_status)
+ return;
+
+ for (int i = 0; i < pf->num_vfs; i++) {
+ if (!(ENETC_VFFLR_BIT(i) & flr_status))
+ continue;
+
+ /* Clear FLR interrupt status, W1C */
+ enetc_wr(hw, ENETC_PSIIDR, ENETC_VFFLR_BIT(i));
+ pf->ops->vf_flr_handler(pf, i);
+ }
+}
+
static void enetc_msg_task(struct work_struct *work)
{
struct enetc_si *si = container_of(work, struct enetc_si, msg_task);
@@ -515,6 +553,8 @@ static void enetc_msg_task(struct work_struct *work)
u32 mr_status, mr_mask;
int i;
+ enetc_vf_flr_handler(pf);
+
mr_mask = ENETC_PSIMR_MASK(pf->num_vfs);
mr_status = (enetc_rd(hw, ENETC_PSIMSGRR) & mr_mask) |
(enetc_rd(hw, ENETC_PSIIDR) & mr_mask);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
index 7ca85731d6cc..650735a7de81 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
@@ -10,6 +10,8 @@
enum enetc_vf_flags {
ENETC_VF_FLAG_PF_SET_MAC = BIT(0),
ENETC_VF_FLAG_TRUSTED = BIT(1),
+ ENETC_VF_FLAG_UC_PROMISC = BIT(2),
+ ENETC_VF_FLAG_MC_PROMISC = BIT(3),
};
struct enetc_vf_state {
@@ -38,6 +40,7 @@ struct enetc_pf_ops {
enum enetc_mac_addr_type type, bool en);
void (*set_si_mac_hash_filter)(struct enetc_hw *hw, int si,
enum enetc_mac_addr_type type, u64 hash);
+ void (*vf_flr_handler)(struct enetc_pf *pf, int vf_id);
};
struct enetc_pf {
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
index 66a9a734d18e..1aecaba04cfd 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
@@ -480,7 +480,9 @@ int enetc_pf_set_vf_trust(struct net_device *ndev, int vf, bool setting)
if (setting) {
vf_state->flags |= ENETC_VF_FLAG_TRUSTED;
} else {
- vf_state->flags &= ~ENETC_VF_FLAG_TRUSTED;
+ vf_state->flags &= ~(ENETC_VF_FLAG_TRUSTED |
+ ENETC_VF_FLAG_UC_PROMISC |
+ ENETC_VF_FLAG_MC_PROMISC);
/* Clear MAC hash filters and disable MAC promiscuous modes
* if the VF is untrusted.
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 12/15] net: enetc: add VF support for i.MX94 and i.MX95
2026-06-05 6:55 [PATCH net-next 00/15] net: enetc: SR-IOV improvements and ENETC v4 VF support wei.fang
` (10 preceding siblings ...)
2026-06-05 6:55 ` [PATCH net-next 11/15] net: enetc: restore VF MAC promiscuous mode after FLR for ENETC v4 wei.fang
@ 2026-06-05 6:55 ` wei.fang
2026-06-06 7:24 ` sashiko-bot
2026-06-05 6:55 ` [PATCH net-next 13/15] net: enetc: implement ndo_set_rx_mode_async for ENETC v4 VF wei.fang
` (2 subsequent siblings)
14 siblings, 1 reply; 30+ messages in thread
From: wei.fang @ 2026-06-05 6:55 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang
Cc: imx, netdev, linux-kernel
From: Wei Fang <wei.fang@nxp.com>
This patch adds VF support for i.MX94 and i.MX95 platforms. Compared to
the LS1028A ENETC, the VF device ID has been updated to 0xef00.
On i.MX95 (v4.1), each ENETC instance supports 2 VFs.
The i.MX94 (v4.3) has two types of ENETC with different VF capabilities:
- standalone ENETC (same as i.MX95): does not support VFs
- internal ENETC connected to the CPU port of NETC switch: supports 3
VFs
The driver is updated to recognize these SoC-specific VF capabilities
and handle each ENETC instance accordingly.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
drivers/net/ethernet/freescale/enetc/Kconfig | 1 +
drivers/net/ethernet/freescale/enetc/enetc.c | 15 ++++++++++++++
.../net/ethernet/freescale/enetc/enetc4_hw.h | 1 +
.../net/ethernet/freescale/enetc/enetc4_pf.c | 10 +++++++++-
.../ethernet/freescale/enetc/enetc_ethtool.c | 6 ++++++
.../net/ethernet/freescale/enetc/enetc_vf.c | 20 ++++++++++++++++++-
6 files changed, 51 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig b/drivers/net/ethernet/freescale/enetc/Kconfig
index db5c17a44613..f425f82a6213 100644
--- a/drivers/net/ethernet/freescale/enetc/Kconfig
+++ b/drivers/net/ethernet/freescale/enetc/Kconfig
@@ -69,6 +69,7 @@ config FSL_ENETC_VF
depends on PCI_MSI
select FSL_ENETC_CORE
select FSL_ENETC_MDIO
+ select NXP_NTMP
select PHYLINK
select DIMLIB
select CRC_ITU_T
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index aa8a87124b10..fdceaf36daa7 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -3745,6 +3745,13 @@ static const struct enetc_drvdata enetc_vf_data = {
.eth_ops = &enetc_vf_ethtool_ops,
};
+static const struct enetc_drvdata enetc4_vf_data = {
+ .sysclk_freq = ENETC_CLK_333M,
+ .tx_csum = true,
+ .max_frags = ENETC4_MAX_SKB_FRAGS,
+ .eth_ops = &enetc_vf_ethtool_ops,
+};
+
static const struct enetc_platform_info enetc_info[] = {
{ .revision = ENETC_REV_1_0,
.dev_id = ENETC_DEV_ID_PF,
@@ -3758,6 +3765,10 @@ static const struct enetc_platform_info enetc_info[] = {
.dev_id = ENETC_DEV_ID_VF,
.data = &enetc_vf_data,
},
+ { .revision = ENETC_REV_4_1,
+ .dev_id = NXP_ENETC_VF_DEV_ID,
+ .data = &enetc4_vf_data,
+ },
{
.revision = ENETC_REV_4_3,
.dev_id = NXP_ENETC_PPM_DEV_ID,
@@ -3767,6 +3778,10 @@ static const struct enetc_platform_info enetc_info[] = {
.dev_id = NXP_ENETC_PF_DEV_ID,
.data = &enetc4_pf_data,
},
+ { .revision = ENETC_REV_4_3,
+ .dev_id = NXP_ENETC_VF_DEV_ID,
+ .data = &enetc4_vf_data,
+ },
};
int enetc_get_driver_data(struct enetc_si *si)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
index f18437556a0e..7595c7d80d0d 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
@@ -12,6 +12,7 @@
#define NXP_ENETC_VENDOR_ID 0x1131
#define NXP_ENETC_PF_DEV_ID 0xe101
#define NXP_ENETC_PPM_DEV_ID 0xe110
+#define NXP_ENETC_VF_DEV_ID 0xef00
/**********************Station interface registers************************/
/* Station interface LSO segmentation flag mask register 0/1 */
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index 15c8b704b2b7..868ed694e120 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -314,11 +314,15 @@ static const struct enetc_pf_ops enetc4_pf_ops = {
static int enetc4_pf_struct_init(struct enetc_si *si)
{
struct enetc_pf *pf = enetc_si_priv(si);
+ int err;
pf->si = si;
- pf->total_vfs = pci_sriov_get_totalvfs(si->pdev);
pf->ops = &enetc4_pf_ops;
+ err = enetc_init_sriov_resources(pf);
+ if (err)
+ return err;
+
enetc4_get_port_caps(pf);
enetc4_get_psi_hw_features(si);
@@ -1208,6 +1212,9 @@ static void enetc4_pf_remove(struct pci_dev *pdev)
struct enetc_si *si = pci_get_drvdata(pdev);
struct enetc_pf *pf = enetc_si_priv(si);
+ if (pf->num_vfs)
+ enetc_sriov_configure(pdev, 0);
+
enetc_remove_debugfs(si);
enetc4_pf_netdev_destroy(si);
enetc4_pf_free(pf);
@@ -1225,6 +1232,7 @@ static struct pci_driver enetc4_pf_driver = {
.id_table = enetc4_pf_id_table,
.probe = enetc4_pf_probe,
.remove = enetc4_pf_remove,
+ .sriov_configure = enetc_sriov_configure,
};
module_pci_driver(enetc4_pf_driver);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
index 71f376ef1be1..246852e453a0 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
@@ -859,6 +859,9 @@ static int enetc_get_rxnfc(struct net_device *ndev, struct ethtool_rxnfc *rxnfc,
struct enetc_ndev_priv *priv = netdev_priv(ndev);
int i, j;
+ if (!is_enetc_rev1(priv->si))
+ return -EOPNOTSUPP;
+
switch (rxnfc->cmd) {
case ETHTOOL_GRXCLSRLCNT:
/* total number of entries */
@@ -903,6 +906,9 @@ static int enetc_set_rxnfc(struct net_device *ndev, struct ethtool_rxnfc *rxnfc)
struct enetc_ndev_priv *priv = netdev_priv(ndev);
int err;
+ if (!is_enetc_rev1(priv->si))
+ return -EOPNOTSUPP;
+
switch (rxnfc->cmd) {
case ETHTOOL_SRXCLSRLINS:
if (rxnfc->fs.location >= priv->si->num_fs_entries)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_vf.c b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
index 9cdb0a4d6baf..9b16226602aa 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_vf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
@@ -281,6 +281,12 @@ static void enetc_vf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
ndev->features |= NETIF_F_RXHASH;
}
+ if (si->drvdata->tx_csum)
+ priv->active_offloads |= ENETC_F_TXCSUM;
+
+ if (si->hw_features & ENETC_SI_F_LSO)
+ priv->active_offloads |= ENETC_F_LSO;
+
/* pick up primary MAC address from SI */
enetc_load_primary_mac_addr(&si->hw, ndev);
}
@@ -292,6 +298,13 @@ static const struct enetc_si_ops enetc_vsi_ops = {
.teardown_cbdr = enetc_teardown_cbdr,
};
+static const struct enetc_si_ops enetc4_vsi_ops = {
+ .get_rss_table = enetc4_get_rss_table,
+ .set_rss_table = enetc4_set_rss_table,
+ .setup_cbdr = enetc4_setup_cbdr,
+ .teardown_cbdr = enetc4_teardown_cbdr,
+};
+
static int enetc_vf_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -307,7 +320,11 @@ static int enetc_vf_probe(struct pci_dev *pdev,
si = pci_get_drvdata(pdev);
enetc_vf_get_revision(si);
- si->ops = &enetc_vsi_ops;
+ if (is_enetc_rev1(si))
+ si->ops = &enetc_vsi_ops;
+ else
+ si->ops = &enetc4_vsi_ops;
+
err = enetc_get_driver_data(si);
if (err) {
dev_err_probe(&pdev->dev, err,
@@ -402,6 +419,7 @@ static void enetc_vf_remove(struct pci_dev *pdev)
static const struct pci_device_id enetc_vf_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_VF) },
+ { PCI_DEVICE(NXP_ENETC_VENDOR_ID, NXP_ENETC_VF_DEV_ID) },
{ 0, } /* End of table. */
};
MODULE_DEVICE_TABLE(pci, enetc_vf_id_table);
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 13/15] net: enetc: implement ndo_set_rx_mode_async for ENETC v4 VF
2026-06-05 6:55 [PATCH net-next 00/15] net: enetc: SR-IOV improvements and ENETC v4 VF support wei.fang
` (11 preceding siblings ...)
2026-06-05 6:55 ` [PATCH net-next 12/15] net: enetc: add VF support for i.MX94 and i.MX95 wei.fang
@ 2026-06-05 6:55 ` wei.fang
2026-06-06 7:24 ` sashiko-bot
2026-06-05 6:55 ` [PATCH net-next 14/15] net: enetc: add PSI-to-VSI link status notification support for VF wei.fang
2026-06-05 6:55 ` [PATCH net-next 15/15] net: enetc: add ndo_get_vf_config() support wei.fang
14 siblings, 1 reply; 30+ messages in thread
From: wei.fang @ 2026-06-05 6:55 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang
Cc: imx, netdev, linux-kernel
From: Wei Fang <wei.fang@nxp.com>
The ENETC VF communicates MAC filter changes to the PF driver via a VSI
mailbox interface. The message send path in enetc_msg_vsi_send() polls
for completion with a timeout up to 200ms, which requires a sleepable
context.
The legacy ndo_set_rx_mode callback is invoked with netif_addr_lock_bh
held and BH disabled, making it incompatible with the VSI messaging path.
Implement ndo_set_rx_mode_async instead, which runs from a workqueue with
rtnl_lock held in a fully sleepable context, and receives pre-snapshotted
unicast and multicast address lists from the networking core.
Add enetc_vf_set_mac_promisc() to send a MAC promiscuous mode message to
the PF. The message specifies the filter type (unicast, multicast, or
both) and whether to enable promiscuous mode and clear existing MAC hash
filter.
Add enetc_vf_set_mac_hash_filter() to send a 64-bit Bloom filter hash
table to the PF. Each filter type (UC or MC) contributes two u32 entries
representing the low and high halves of its 64-bit hash bitmap. The
function accepts pre-snapshotted address lists from the framework and
iterates them with netdev_hw_addr_list_for_each(). When IFF_PROMISC is
active, hash filter programming is skipped since promiscuous mode already
accepts all frames.
The ndo_set_rx_mode_async callback selects the appropriate filter
configuration based on the current netdev flags:
- IFF_PROMISC: enable full promiscuous mode for both unicast and
multicast
- IFF_ALLMULTI: enable multicast promiscuous mode, disable unicast
promiscuous mode, and apply a unicast hash filter
- otherwise: disable all promiscuous modes and apply both
unicast and multicast hash filters
Set IFF_UNICAST_FLT in priv_flags for ENETC v4 VFs so the network stack
does not fall back to full promiscuous mode unnecessarily when unicast
address filtering is supported by the hardware.
This feature applies to ENETC v4 hardware only. ENETC v1 (LS1028A) does
not support VF-PF MAC filter messaging and the callback returns early
for such devices.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
.../net/ethernet/freescale/enetc/enetc_vf.c | 120 ++++++++++++++++++
1 file changed, 120 insertions(+)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_vf.c b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
index 9b16226602aa..418ee98da17d 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_vf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
@@ -209,6 +209,122 @@ static int enetc_vf_setup_tc(struct net_device *ndev, enum tc_setup_type type,
}
}
+static int enetc_vf_set_mac_promisc(struct enetc_ndev_priv *priv,
+ int type, bool en)
+{
+ struct enetc_msg_mac_promisc_mode *msg;
+ struct enetc_msg_swbd msg_swbd;
+
+ if (!(type & ENETC_MAC_FILTER_TYPE_ALL))
+ return -EINVAL;
+
+ msg_swbd.size = ALIGN(sizeof(*msg), ENETC_MSG_ALIGN);
+ msg_swbd.vaddr = dma_alloc_coherent(priv->dev, msg_swbd.size,
+ &msg_swbd.dma, GFP_KERNEL);
+ if (!msg_swbd.vaddr)
+ return -ENOMEM;
+
+ msg = (struct enetc_msg_mac_promisc_mode *)msg_swbd.vaddr;
+ msg->config = FIELD_PREP(ENETC_MSG_MAC_TYPE,
+ type & ENETC_MAC_FILTER_TYPE_ALL);
+ msg->config |= FIELD_PREP(ENETC_MSG_MAC_PROMISC_MODE, en);
+ msg->config |= FIELD_PREP(ENETC_MSG_MAC_FLUSH_MACS, en);
+ enetc_msg_fill_common_hdr(&msg_swbd, ENETC_MSG_CLASS_ID_MAC_FILTER,
+ ENETC_MSG_SET_MAC_PROMISC_MODE, 0, 0);
+
+ return enetc_msg_vsi_send(priv->si, &msg_swbd);
+}
+
+static int enetc_vf_set_mac_hash_filter(struct enetc_ndev_priv *priv,
+ struct netdev_hw_addr_list *uc,
+ struct netdev_hw_addr_list *mc)
+{
+ struct enetc_msg_mac_hash_filter *msg;
+ struct net_device *ndev = priv->ndev;
+ struct enetc_mac_filter *mac_filter;
+ struct enetc_msg_swbd msg_swbd;
+ struct enetc_si *si = priv->si;
+ struct netdev_hw_addr *ha;
+ u32 msg_size, tbl_cnt;
+ int mac_filter_type;
+ u64 hash_val;
+ int i = 0;
+
+ if (ndev->flags & IFF_PROMISC)
+ return 0;
+
+ if (ndev->flags & IFF_ALLMULTI) {
+ tbl_cnt = 2;
+ mac_filter_type = ENETC_MAC_FILTER_TYPE_UC;
+ } else {
+ tbl_cnt = 4;
+ mac_filter_type = ENETC_MAC_FILTER_TYPE_ALL;
+ }
+
+ msg_size = struct_size(msg, hash_tbl, tbl_cnt);
+ msg_swbd.size = ALIGN(msg_size, ENETC_MSG_ALIGN);
+ msg_swbd.vaddr = dma_alloc_coherent(priv->dev, msg_swbd.size,
+ &msg_swbd.dma, GFP_KERNEL);
+ if (!msg_swbd.vaddr)
+ return -ENOMEM;
+
+ msg = (struct enetc_msg_mac_hash_filter *)msg_swbd.vaddr;
+ msg->sz_type = FIELD_PREP(ENETC_MSG_MAC_TYPE, mac_filter_type);
+ msg->sz_type |= FIELD_PREP(ENETC_MSG_MAC_HASH_SIZE,
+ ENETC_MAC_HASH_TABLE_SIZE_64);
+
+ if (mac_filter_type & ENETC_MAC_FILTER_TYPE_UC) {
+ mac_filter = &si->mac_filter[UC];
+ enetc_reset_mac_addr_filter(mac_filter);
+ netdev_hw_addr_list_for_each(ha, uc)
+ enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
+
+ memcpy(&hash_val, mac_filter->mac_hash_table,
+ sizeof(hash_val));
+ msg->hash_tbl[i++] = hash_val & GENMASK(31, 0);
+ msg->hash_tbl[i++] = hash_val >> 32;
+ }
+
+ if (mac_filter_type & ENETC_MAC_FILTER_TYPE_MC) {
+ mac_filter = &si->mac_filter[MC];
+ enetc_reset_mac_addr_filter(mac_filter);
+ netdev_hw_addr_list_for_each(ha, mc)
+ enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
+
+ memcpy(&hash_val, mac_filter->mac_hash_table,
+ sizeof(hash_val));
+ msg->hash_tbl[i++] = hash_val & GENMASK(31, 0);
+ msg->hash_tbl[i++] = hash_val >> 32;
+ }
+
+ enetc_msg_fill_common_hdr(&msg_swbd, ENETC_MSG_CLASS_ID_MAC_FILTER,
+ ENETC_MSG_SET_MAC_HASH_TABLE, 0, 0);
+
+ return enetc_msg_vsi_send(si, &msg_swbd);
+}
+
+static void enetc_vf_set_rx_mode(struct net_device *ndev,
+ struct netdev_hw_addr_list *uc,
+ struct netdev_hw_addr_list *mc)
+{
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ struct enetc_si *si = priv->si;
+
+ if (is_enetc_rev1(si))
+ return;
+
+ if (ndev->flags & IFF_PROMISC) {
+ enetc_vf_set_mac_promisc(priv, ENETC_MAC_FILTER_TYPE_ALL, true);
+ } else if (ndev->flags & IFF_ALLMULTI) {
+ enetc_vf_set_mac_promisc(priv, ENETC_MAC_FILTER_TYPE_MC, true);
+ enetc_vf_set_mac_promisc(priv, ENETC_MAC_FILTER_TYPE_UC, false);
+ } else {
+ enetc_vf_set_mac_promisc(priv, ENETC_MAC_FILTER_TYPE_ALL, false);
+ }
+
+ enetc_vf_set_mac_hash_filter(priv, uc, mc);
+}
+
/* Probing/ Init */
static const struct net_device_ops enetc_ndev_ops = {
.ndo_open = enetc_open,
@@ -221,6 +337,7 @@ static const struct net_device_ops enetc_ndev_ops = {
.ndo_setup_tc = enetc_vf_setup_tc,
.ndo_hwtstamp_get = enetc_hwtstamp_get,
.ndo_hwtstamp_set = enetc_hwtstamp_set,
+ .ndo_set_rx_mode_async = enetc_vf_set_rx_mode,
};
static void enetc_vf_get_revision(struct enetc_si *si)
@@ -276,6 +393,9 @@ static void enetc_vf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
ndev->vlan_features = NETIF_F_SG | NETIF_F_HW_CSUM |
NETIF_F_TSO | NETIF_F_TSO6;
+ if (!is_enetc_rev1(si))
+ ndev->priv_flags |= IFF_UNICAST_FLT;
+
if (si->num_rss) {
ndev->hw_features |= NETIF_F_RXHASH;
ndev->features |= NETIF_F_RXHASH;
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 14/15] net: enetc: add PSI-to-VSI link status notification support for VF
2026-06-05 6:55 [PATCH net-next 00/15] net: enetc: SR-IOV improvements and ENETC v4 VF support wei.fang
` (12 preceding siblings ...)
2026-06-05 6:55 ` [PATCH net-next 13/15] net: enetc: implement ndo_set_rx_mode_async for ENETC v4 VF wei.fang
@ 2026-06-05 6:55 ` wei.fang
2026-06-06 7:24 ` sashiko-bot
2026-06-05 6:55 ` [PATCH net-next 15/15] net: enetc: add ndo_get_vf_config() support wei.fang
14 siblings, 1 reply; 30+ messages in thread
From: wei.fang @ 2026-06-05 6:55 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang
Cc: imx, netdev, linux-kernel
From: Wei Fang <wei.fang@nxp.com>
Add infrastructure for ENETC v4 VFs to track PF link status changes via
the PSI-to-VSI messaging channel. Two new ops,
vf_reg_link_status_notifier and vf_unreg_link_status_notifier, are added
to enetc_si_ops and wired into enetc_phylink_connect() and enetc_close()
for the phy-less path. The feature is populated only in enetc4_vsi_ops;
rev1 hardware is not affected.
On enetc_open(), the VF sends a REGISTER_LINK_CHANGE_NOTIFIER message to
the PF through the VSI-to-PSI messaging channel. The PF records the VF
in link_status_ms_mask, and immediately sends the current link status so
that the VF carrier reflects reality as soon as the interface comes up.
On every subsequent PF link transition the PF broadcasts a 16-bit
notification to all registered VFs.
On the VF side, a dedicated MSI-X vector handles incoming PSI-to-VSI
messages. The interrupt handler schedules a work item which parses the
notification and updates the carrier state via netif_carrier_on() or
netif_carrier_off() accordingly.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
drivers/net/ethernet/freescale/enetc/enetc.c | 11 ++
drivers/net/ethernet/freescale/enetc/enetc.h | 4 +
.../net/ethernet/freescale/enetc/enetc_hw.h | 9 +
.../net/ethernet/freescale/enetc/enetc_vf.c | 185 +++++++++++++++++-
4 files changed, 208 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index fdceaf36daa7..a1a8a1551cd8 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -2892,11 +2892,15 @@ static void enetc_clear_interrupts(struct enetc_ndev_priv *priv)
static int enetc_phylink_connect(struct net_device *ndev)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ struct enetc_si *si = priv->si;
struct ethtool_keee edata;
int err;
if (!priv->phylink) {
/* phy-less mode */
+ if (si->ops->vf_reg_link_status_notifier)
+ return si->ops->vf_reg_link_status_notifier(si);
+
netif_carrier_on(ndev);
return 0;
}
@@ -2968,6 +2972,7 @@ int enetc_open(struct net_device *ndev)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct enetc_bdr_resource *tx_res, *rx_res;
+ struct enetc_si *si = priv->si;
bool extended;
int err;
@@ -3010,6 +3015,8 @@ int enetc_open(struct net_device *ndev)
err_alloc_tx:
if (priv->phylink)
phylink_disconnect_phy(priv->phylink);
+ else if (si->ops->vf_unreg_link_status_notifier)
+ si->ops->vf_unreg_link_status_notifier(si);
err_phy_connect:
enetc_free_irqs(priv);
err_setup_irqs:
@@ -3050,6 +3057,7 @@ EXPORT_SYMBOL_GPL(enetc_stop);
int enetc_close(struct net_device *ndev)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ struct enetc_si *si = priv->si;
enetc_stop(ndev);
@@ -3057,6 +3065,9 @@ int enetc_close(struct net_device *ndev)
phylink_stop(priv->phylink);
phylink_disconnect_phy(priv->phylink);
} else {
+ if (si->ops->vf_unreg_link_status_notifier)
+ si->ops->vf_unreg_link_status_notifier(si);
+
netif_carrier_off(ndev);
}
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index 24d9f89aee73..1666dfe81cbb 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -300,6 +300,10 @@ struct enetc_si_ops {
int (*set_rss_table)(struct enetc_si *si, const u32 *table, int count);
int (*setup_cbdr)(struct enetc_si *si);
void (*teardown_cbdr)(struct enetc_si *si);
+
+ /* VSI-specific hooks */
+ int (*vf_reg_link_status_notifier)(struct enetc_si *si);
+ int (*vf_unreg_link_status_notifier)(struct enetc_si *si);
};
/* PCI IEP device data */
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
index 62844344ff29..5dc4532607b3 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
@@ -84,6 +84,9 @@ static inline u32 enetc_vsi_set_msize(u32 size)
#define PSIMSGSR_MS(n) BIT((n) + 1) /* n is VF index */
#define PSIMSGSR_MC GENMASK(31, 16)
+#define ENETC_VSIMSGRR 0x208
+#define VSIMSGRR_MC GENMASK(31, 16)
+
/* SI statistics */
#define ENETC_SIROCT 0x300
#define ENETC_SIRFRM 0x308
@@ -107,6 +110,12 @@ static inline u32 enetc_vsi_set_msize(u32 size)
#define ENETC_SICAPR0 0x900
#define ENETC_SICAPR1 0x904
+#define ENETC_VSIIER 0xa00
+#define VSIIER_MRIE BIT(9)
+
+#define ENETC_VSIIDR 0xa08
+#define VSIIDR_MR BIT(9)
+
#define ENETC_PSIIER 0xa00
#define ENETC_PSIIDR 0xa08
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_vf.c b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
index 418ee98da17d..9cace77110b8 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_vf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
@@ -131,6 +131,37 @@ static int enetc_msg_vsi_send(struct enetc_si *si, struct enetc_msg_swbd *msg)
return err;
}
+static int enetc_msg_link_status_notifier(struct enetc_si *si, bool reg)
+{
+ struct device *dev = &si->pdev->dev;
+ struct enetc_msg_swbd msg_swbd;
+ u8 cmd_id;
+
+ msg_swbd.size = ALIGN(sizeof(struct enetc_msg_generic),
+ ENETC_MSG_ALIGN);
+ msg_swbd.vaddr = dma_alloc_coherent(dev, msg_swbd.size,
+ &msg_swbd.dma, GFP_KERNEL);
+ if (!msg_swbd.vaddr)
+ return -ENOMEM;
+
+ cmd_id = reg ? ENETC_MSG_REGISTER_LINK_CHANGE_NOTIFIER :
+ ENETC_MSG_UNREGISTER_LINK_CHANGE_NOTIFIER;
+ enetc_msg_fill_common_hdr(&msg_swbd, ENETC_MSG_CLASS_ID_LINK_STATUS,
+ cmd_id, 0, 0);
+
+ return enetc_msg_vsi_send(si, &msg_swbd);
+}
+
+static int enetc_vf_reg_link_status_notifier(struct enetc_si *si)
+{
+ return enetc_msg_link_status_notifier(si, true);
+}
+
+static int enetc_vf_unreg_link_status_notifier(struct enetc_si *si)
+{
+ return enetc_msg_link_status_notifier(si, false);
+}
+
static int enetc_msg_vsi_set_primary_mac_addr(struct enetc_ndev_priv *priv,
struct sockaddr *saddr)
{
@@ -411,6 +442,113 @@ static void enetc_vf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
enetc_load_primary_mac_addr(&si->hw, ndev);
}
+static void enetc_vf_enable_mr_int(struct enetc_hw *hw)
+{
+ u32 val = enetc_rd(hw, ENETC_VSIIER) | VSIIER_MRIE;
+
+ enetc_wr(hw, ENETC_VSIIER, val);
+}
+
+static void enetc_vf_disable_mr_int(struct enetc_hw *hw)
+{
+ u32 val = enetc_rd(hw, ENETC_VSIIER) & (~VSIIER_MRIE);
+
+ enetc_wr(hw, ENETC_VSIIER, val);
+}
+
+static void enetc_vf_msg_handle_link_status(struct enetc_si *si, u8 class_code)
+{
+ struct net_device *ndev = si->ndev;
+
+ switch (class_code) {
+ case ENETC_LINK_STATUS_CLASS_CODE_UP:
+ if (!netif_carrier_ok(ndev)) {
+ netif_carrier_on(ndev);
+ netdev_info(ndev, "Link is Up\n");
+ }
+ break;
+ case ENETC_LINK_STATUS_CLASS_CODE_DOWN:
+ if (netif_carrier_ok(ndev)) {
+ netif_carrier_off(ndev);
+ netdev_info(ndev, "Link is Down\n");
+ }
+ break;
+ }
+}
+
+static void enetc_vf_msg_task(struct work_struct *work)
+{
+ struct enetc_si *si = container_of(work, struct enetc_si, msg_task);
+ struct enetc_hw *hw = &si->hw;
+ u8 class_id, class_code;
+ u16 pf_msg;
+
+ pf_msg = FIELD_GET(VSIMSGRR_MC, enetc_rd(hw, ENETC_VSIMSGRR));
+ /* W1C to clear the message received interrupt event */
+ enetc_wr(hw, ENETC_VSIIDR, VSIIDR_MR);
+
+ class_id = FIELD_GET(ENETC_PF_MSG_CLASS_ID, pf_msg);
+ class_code = FIELD_GET(ENETC_PF_MSG_CLASS_CODE, pf_msg);
+
+ switch (class_id) {
+ case ENETC_MSG_CLASS_ID_LINK_STATUS:
+ enetc_vf_msg_handle_link_status(si, class_code);
+ break;
+ default:
+ dev_err(&si->pdev->dev,
+ "Unsupported Message Class ID (0x%02x) from PF\n",
+ class_id);
+ }
+
+ enetc_vf_enable_mr_int(hw);
+}
+
+static irqreturn_t enetc_vf_msg_msix_handler(int irq, void *data)
+{
+ struct enetc_si *si = (struct enetc_si *)data;
+
+ enetc_vf_disable_mr_int(&si->hw);
+ queue_work(si->workqueue, &si->msg_task);
+
+ return IRQ_HANDLED;
+}
+
+static int enetc_vf_register_msg_msix(struct enetc_si *si)
+{
+ int irq, err;
+
+ if (is_enetc_rev1(si))
+ return 0;
+
+ snprintf(si->msg_int_name, sizeof(si->msg_int_name), "%s-pfmsg",
+ pci_name(si->pdev));
+ irq = pci_irq_vector(si->pdev, ENETC_SI_INT_IDX);
+ err = request_irq(irq, enetc_vf_msg_msix_handler, 0,
+ si->msg_int_name, si);
+ if (err) {
+ dev_err(&si->pdev->dev,
+ "VF messaging: request_irq() failed!\n");
+ return err;
+ }
+
+ /* set one IRQ entry for PSI-to-VSI messaging */
+ enetc_wr(&si->hw, ENETC_SIMSIVR, ENETC_SI_INT_IDX);
+
+ /* Enable message received interrupt */
+ enetc_vf_enable_mr_int(&si->hw);
+
+ return 0;
+}
+
+static void enetc_vf_free_msg_msix(struct enetc_si *si)
+{
+ if (is_enetc_rev1(si))
+ return;
+
+ enetc_vf_disable_mr_int(&si->hw);
+ free_irq(pci_irq_vector(si->pdev, ENETC_SI_INT_IDX), si);
+}
+
static const struct enetc_si_ops enetc_vsi_ops = {
.get_rss_table = enetc_get_rss_table,
.set_rss_table = enetc_set_rss_table,
@@ -423,8 +561,36 @@ static const struct enetc_si_ops enetc4_vsi_ops = {
.set_rss_table = enetc4_set_rss_table,
.setup_cbdr = enetc4_setup_cbdr,
.teardown_cbdr = enetc4_teardown_cbdr,
+ .vf_reg_link_status_notifier = enetc_vf_reg_link_status_notifier,
+ .vf_unreg_link_status_notifier = enetc_vf_unreg_link_status_notifier,
};
+static int enetc_vf_wq_task_init(struct enetc_si *si)
+{
+ char wq_name[24];
+
+ if (is_enetc_rev1(si))
+ return 0;
+
+ snprintf(wq_name, sizeof(wq_name), "enetc-%s", pci_name(si->pdev));
+ si->workqueue = create_singlethread_workqueue(wq_name);
+ if (!si->workqueue)
+ return -ENOMEM;
+
+ INIT_WORK(&si->msg_task, enetc_vf_msg_task);
+
+ return 0;
+}
+
+static void enetc_vf_wq_task_destroy(struct enetc_si *si)
+{
+ if (!si->workqueue)
+ return;
+
+ disable_work_sync(&si->msg_task);
+ destroy_workqueue(si->workqueue);
+}
+
static int enetc_vf_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -489,6 +655,18 @@ static int enetc_vf_probe(struct pci_dev *pdev,
goto err_alloc_msix;
}
+ err = enetc_vf_wq_task_init(si);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to init workqueue\n");
+ goto err_wq_init;
+ }
+
+ err = enetc_vf_register_msg_msix(si);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to register msg irq\n");
+ goto err_register_msg_msix;
+ }
+
err = register_netdev(ndev);
if (err)
goto err_reg_netdev;
@@ -498,6 +676,10 @@ static int enetc_vf_probe(struct pci_dev *pdev,
return 0;
err_reg_netdev:
+ enetc_vf_free_msg_msix(si);
+err_register_msg_msix:
+ enetc_vf_wq_task_destroy(si);
+err_wq_init:
enetc_free_msix(priv);
err_config_si:
err_alloc_msix:
@@ -524,7 +706,8 @@ static void enetc_vf_remove(struct pci_dev *pdev)
priv = netdev_priv(si->ndev);
unregister_netdev(si->ndev);
-
+ enetc_vf_free_msg_msix(si);
+ enetc_vf_wq_task_destroy(si);
enetc_free_msix(priv);
enetc_free_si_resources(priv);
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH net-next 15/15] net: enetc: add ndo_get_vf_config() support
2026-06-05 6:55 [PATCH net-next 00/15] net: enetc: SR-IOV improvements and ENETC v4 VF support wei.fang
` (13 preceding siblings ...)
2026-06-05 6:55 ` [PATCH net-next 14/15] net: enetc: add PSI-to-VSI link status notification support for VF wei.fang
@ 2026-06-05 6:55 ` wei.fang
14 siblings, 0 replies; 30+ messages in thread
From: wei.fang @ 2026-06-05 6:55 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang
Cc: imx, netdev, linux-kernel
From: Wei Fang <wei.fang@nxp.com>
Without ndo_get_vf_config(), userspace tools such as 'ip link show'
cannot query the current VF configuration from the PF.
To support this, extend struct enetc_vf_state to track the per-VF VLAN
and spoofchk settings, and update the corresponding setter callbacks to
persist their state when the hardware is programmed.
enetc_pf_get_vf_config() reads back the persisted state and reports MAC
address, VLAN parameters, spoofchk, and trust state through struct
ifla_vf_info.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
.../net/ethernet/freescale/enetc/enetc4_pf.c | 1 +
.../net/ethernet/freescale/enetc/enetc_pf.c | 22 +++++++++++++
.../net/ethernet/freescale/enetc/enetc_pf.h | 4 +++
.../freescale/enetc/enetc_pf_common.c | 31 +++++++++++++++++++
.../freescale/enetc/enetc_pf_common.h | 2 ++
5 files changed, 60 insertions(+)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index 868ed694e120..a3edf5fc930e 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -616,6 +616,7 @@ static const struct net_device_ops enetc4_ndev_ops = {
.ndo_hwtstamp_set = enetc_hwtstamp_set,
.ndo_set_vf_trust = enetc_pf_set_vf_trust,
.ndo_set_vf_mac = enetc_pf_set_vf_mac,
+ .ndo_get_vf_config = enetc_pf_get_vf_config,
};
static struct phylink_pcs *
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index 209a3503609f..fa09c875d09b 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -243,6 +243,7 @@ static int enetc_pf_set_vf_vlan(struct net_device *ndev, int vf, u16 vlan,
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct enetc_pf *pf = enetc_si_priv(priv->si);
+ struct enetc_vf_state *vf_state;
if (priv->si->errata & ENETC_ERR_VLAN_ISOL)
return -EOPNOTSUPP;
@@ -255,6 +256,15 @@ static int enetc_pf_set_vf_vlan(struct net_device *ndev, int vf, u16 vlan,
return -EPROTONOSUPPORT;
enetc_set_isol_vlan(&priv->si->hw, vf + 1, vlan, qos);
+
+ vf_state = &pf->vf_state[vf];
+ /* Currently only C-tags is susupported, so tpid is always 0,
+ * which indicates ETH_P_8021Q.
+ */
+ vf_state->tpid = 0;
+ vf_state->qos = qos;
+ vf_state->vid = vlan;
+
return 0;
}
@@ -262,6 +272,7 @@ static int enetc_pf_set_vf_spoofchk(struct net_device *ndev, int vf, bool en)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct enetc_pf *pf = enetc_si_priv(priv->si);
+ struct enetc_vf_state *vf_state;
u32 cfgr;
if (vf >= pf->total_vfs)
@@ -271,6 +282,16 @@ static int enetc_pf_set_vf_spoofchk(struct net_device *ndev, int vf, bool en)
cfgr = (cfgr & ~ENETC_PSICFGR0_ASE) | (en ? ENETC_PSICFGR0_ASE : 0);
enetc_port_wr(&priv->si->hw, ENETC_PSICFGR0(vf + 1), cfgr);
+ vf_state = &pf->vf_state[vf];
+ mutex_lock(&vf_state->lock);
+
+ if (en)
+ vf_state->flags |= ENETC_VF_FLAG_SPOOFCHK;
+ else
+ vf_state->flags &= ~ENETC_VF_FLAG_SPOOFCHK;
+
+ mutex_unlock(&vf_state->lock);
+
return 0;
}
@@ -528,6 +549,7 @@ static const struct net_device_ops enetc_ndev_ops = {
.ndo_xdp_xmit = enetc_xdp_xmit,
.ndo_hwtstamp_get = enetc_hwtstamp_get,
.ndo_hwtstamp_set = enetc_hwtstamp_set,
+ .ndo_get_vf_config = enetc_pf_get_vf_config,
};
static struct phylink_pcs *
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
index 650735a7de81..faead2bf684a 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
@@ -12,11 +12,15 @@ enum enetc_vf_flags {
ENETC_VF_FLAG_TRUSTED = BIT(1),
ENETC_VF_FLAG_UC_PROMISC = BIT(2),
ENETC_VF_FLAG_MC_PROMISC = BIT(3),
+ ENETC_VF_FLAG_SPOOFCHK = BIT(4),
};
struct enetc_vf_state {
struct mutex lock; /* Prevent concurrent access */
enum enetc_vf_flags flags;
+ u8 tpid; /* SI-based VLAN TPID (0: 0x8100, 1: 0x88a8) */
+ u8 qos; /* SI-based VLAN QOS (priority) bits */
+ u16 vid; /* SI-based VLAN ID */
};
struct enetc_port_caps {
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
index 1aecaba04cfd..559eddfbba9e 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
@@ -529,5 +529,36 @@ int enetc_pf_set_vf_mac(struct net_device *ndev, int vf, u8 *mac)
}
EXPORT_SYMBOL_GPL(enetc_pf_set_vf_mac);
+int enetc_pf_get_vf_config(struct net_device *ndev, int vf,
+ struct ifla_vf_info *ivi)
+{
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ struct enetc_pf *pf = enetc_si_priv(priv->si);
+ struct enetc_vf_state *vf_state;
+
+ if (vf >= pf->total_vfs)
+ return -EINVAL;
+
+ vf_state = &pf->vf_state[vf];
+ mutex_lock(&vf_state->lock);
+
+ ivi->vf = vf;
+ ivi->spoofchk = !!(vf_state->flags & ENETC_VF_FLAG_SPOOFCHK);
+ ivi->trusted = !!(vf_state->flags & ENETC_VF_FLAG_TRUSTED);
+ enetc_get_si_hw_addr(pf, vf + 1, ivi->mac);
+
+ if (vf_state->vid) {
+ ivi->vlan = vf_state->vid;
+ ivi->qos = vf_state->qos;
+ ivi->vlan_proto = vf_state->tpid ? htons(ETH_P_8021AD) :
+ htons(ETH_P_8021Q);
+ }
+
+ mutex_unlock(&vf_state->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(enetc_pf_get_vf_config);
+
MODULE_DESCRIPTION("NXP ENETC PF common functionality driver");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
index b2a2b06c794a..0e487ea9c0a5 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
@@ -19,6 +19,8 @@ int enetc_vlan_rx_del_vid(struct net_device *ndev, __be16 prot, u16 vid);
int enetc_init_sriov_resources(struct enetc_pf *pf);
int enetc_pf_set_vf_trust(struct net_device *ndev, int vf, bool setting);
int enetc_pf_set_vf_mac(struct net_device *ndev, int vf, u8 *mac);
+int enetc_pf_get_vf_config(struct net_device *ndev, int vf,
+ struct ifla_vf_info *ivi);
static inline u16 enetc_get_ip_revision(struct enetc_hw *hw)
{
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 01/15] net: enetc: add trusted VF support
2026-06-05 6:55 ` [PATCH net-next 01/15] net: enetc: add trusted " wei.fang
@ 2026-06-06 7:24 ` sashiko-bot
2026-06-06 13:37 ` Wei Fang (OSS)
0 siblings, 1 reply; 30+ messages in thread
From: sashiko-bot @ 2026-06-06 7:24 UTC (permalink / raw)
To: wei.fang; +Cc: imx, Frank.Li
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] UAPI Breakage: The patch unconditionally denies MAC address changes for untrusted VFs and fails to implement correct trusted VF override semantics.
--
commit 6f75af6dda440eac57a8d16c81c6cc7d3ceba0b9
Author: Claudiu Manoil <claudiu.manoil@nxp.com>
net: enetc: add trusted VF support
Some mailbox messages require a higher privilege level to be executed
on behalf of the requesting VF. Introduce a trusted VF flag
(ENETC_VF_FLAG_TRUSTED) and wire up the ndo_set_vf_trust callback via
enetc_pf_set_vf_trust().
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_msg.c b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
> index edc1277bb5860..156333ef26bf3 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc_msg.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
[ ... ]
> @@ -61,31 +63,41 @@ static u16 enetc_msg_set_vf_primary_mac_addr(struct enetc_pf *pf, int vf_id,
> struct enetc_vf_state *vf_state = &pf->vf_state[vf_id];
> struct enetc_msg_mac_exact_filter *msg = vf_msg;
> struct device *dev = &pf->si->pdev->dev;
> + u16 pf_msg = ENETC_PF_MSG_SUCCESS;
> char *addr = msg->mac[0].addr;
>
> + mutex_lock(&vf_state->lock);
> +
> + if (!(vf_state->flags & ENETC_VF_FLAG_TRUSTED)) {
> + pf_msg = ENETC_PF_MSG_PERM_DENY;
> + goto vf_state_unlock;
> + }
[Severity: High]
Under standard Linux SR-IOV semantics, untrusted VFs are allowed to set their
own MAC address provided the PF has not administratively locked it (i.e. when
PF_SET_MAC is false). Does this check unconditionally deny all MAC changes from
untrusted VFs? If so, couldn't this break backward compatibility and break guest
OSes that attempt to assign a random MAC on boot?
> +
> if (!is_valid_ether_addr(addr)) {
> dev_err_ratelimited(dev, "VF%d attempted to set invalid MAC\n",
> vf_id);
> - return (FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
> - ENETC_MSG_CLASS_ID_MAC_FILTER) |
> - FIELD_PREP(ENETC_PF_MSG_CLASS_CODE,
> - ENETC_MF_CLASS_CODE_INVALID_MAC));
> + pf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
> + ENETC_MSG_CLASS_ID_MAC_FILTER) |
> + FIELD_PREP(ENETC_PF_MSG_CLASS_CODE,
> + ENETC_MF_CLASS_CODE_INVALID_MAC);
> + goto vf_state_unlock;
> }
>
> - mutex_lock(&vf_state->lock);
> if (vf_state->flags & ENETC_VF_FLAG_PF_SET_MAC) {
> - mutex_unlock(&vf_state->lock);
> dev_err_ratelimited(dev,
> "VF%d attempted to override PF set MAC\n",
> vf_id);
> - return FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
> - ENETC_MSG_CLASS_ID_CMD_NOT_PERMITTED);
> + pf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
> + ENETC_MSG_CLASS_ID_CMD_NOT_PERMITTED);
> + goto vf_state_unlock;
> }
[Severity: High]
Does this incorrectly deny MAC changes from trusted VFs if the PF has assigned
a MAC? Since this ENETC_VF_FLAG_PF_SET_MAC check happens after the TRUSTED check
and unconditionally rejects the operation, it appears to violate the standard
semantics that trusted VFs can override a PF-set MAC.
>
> enetc_set_si_hw_addr(pf, vf_id + 1, addr);
> +
> +vf_state_unlock:
> mutex_unlock(&vf_state->lock);
>
> - return ENETC_PF_MSG_SUCCESS;
> + return pf_msg;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260605065550.3038579-1-wei.fang@oss.nxp.com?part=1
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 03/15] net: enetc: add link status message support to PF driver
2026-06-05 6:55 ` [PATCH net-next 03/15] net: enetc: add link status message support to PF driver wei.fang
@ 2026-06-06 7:24 ` sashiko-bot
2026-06-06 14:05 ` Wei Fang (OSS)
0 siblings, 1 reply; 30+ messages in thread
From: sashiko-bot @ 2026-06-06 7:24 UTC (permalink / raw)
To: wei.fang; +Cc: imx, Frank.Li
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] The `msg_lock` mutex is used uninitialized if the device does not support SR-IOV or if the PF initializes with 0 VFs, leading to a kernel panic or lockdep splat on link up/down.
- [High] A malicious or unresponsive VF can stall the PF's shared message handler for 200ms per request, causing a Denial of Service (DoS).
- [Medium] Data race on `pf->link_status_ms_mask` during SR-IOV teardown causes a 200ms timeout on concurrent link state changes.
--
commit 7d8f9f9cc2f3db8a098f8342c6d804d1aeb36a72
Author: Wei Fang <wei.fang@nxp.com>
Date: Fri Jun 5 06:55:38 2026 +0000
net: enetc: add link status message support to PF driver
Add link status message support to the PF driver using three command IDs
under message class 0x80 (ENETC_MSG_CLASS_ID_LINK_STATUS).
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
> --- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
> @@ -458,6 +458,8 @@ int enetc_init_sriov_resources(struct enetc_pf *pf)
> for (int i = 0; i < pf->total_vfs; i++)
> mutex_init(&pf->vf_state[i].lock);
>
> + mutex_init(&pf->msg_lock);
> +
> return 0;
> }
[Severity: High]
If the device does not support SR-IOV or total_vfs is 0,
enetc_init_sriov_resources() returns early:
pf->total_vfs = pci_sriov_get_totalvfs(pf->si->pdev);
if (!pf->total_vfs)
return 0;
This skips the mutex_init() for msg_lock.
However, the phylink callbacks enetc4_pl_mac_link_up() and
enetc4_pl_mac_link_down() unconditionally call enetc_pf_notify_vf_link_up()
and enetc_pf_notify_vf_link_down().
These functions eventually reach enetc_pf_notify_vf_link_status(), which
attempts to acquire this uninitialized lock:
enetc_pf_notify_vf_link_status()
mutex_lock(&pf->msg_lock);
Could this cause a lockdep warning or a crash when the device link comes
up or goes down and total_vfs is 0?
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_msg.c b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
> --- a/drivers/net/ethernet/freescale/enetc/enetc_msg.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
[ ... ]
> +static int enetc_pf_send_msg(struct enetc_pf *pf, u32 msg_code, u16 ms_mask)
> +{
> + struct enetc_si *si = pf->si;
> + u32 val;
> +
> + enetc_wr(&si->hw, ENETC_PSIMSGSR,
> + FIELD_PREP(PSIMSGSR_MC, msg_code) | ms_mask);
> +
> + return read_poll_timeout(enetc_rd, val, !(val & ms_mask), 1000,
> + 200000, false, &si->hw, ENETC_PSIMSGSR);
> +}
> +
> +static void enetc_msg_notify_vf_link_status(struct enetc_pf *pf, u16 ms_mask,
> + bool link_up)
> +{
[ ... ]
> + if (enetc_pf_send_msg(pf, pf_msg, ms_mask))
> + dev_err_ratelimited(&pf->si->pdev->dev,
> + "PF notifies link status failed\n");
> +}
[Severity: High]
If a VF is malicious, crashed, or improperly configured and fails to clear
its bit in ENETC_PSIMSGSR, enetc_pf_send_msg() will block the phylink worker
thread for its maximum 200ms polling timeout.
Because enetc_msg_notify_vf_link_status() only logs an error and does not
remove the unresponsive VF from pf->link_status_ms_mask, won't every
subsequent link state change also incur this 200ms stall?
Additionally, a malicious VF could spam ENETC_MSG_REGISTER_LINK_CHANGE_NOTIFIER
messages, forcing the PF to repeatedly call enetc_pf_send_msg() while holding
pf->msg_lock. Could this stall the shared msg_task workqueue and starve
other VFs?
> @@ -361,6 +471,7 @@ int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)
> if (!num_vfs) {
> pci_disable_sriov(pdev);
> enetc_msg_psi_free(pf);
> + pf->link_status_ms_mask = 0;
> pf->num_vfs = 0;
> } else {
[Severity: Medium]
When disabling SR-IOV, pf->link_status_ms_mask is cleared outside of
pf->msg_lock and after the VFs have been disabled via pci_disable_sriov().
If a physical link state change occurs concurrently, could
enetc_pf_notify_vf_link_status() acquire the lock, observe a stale non-zero
ms_mask, and attempt to notify destroyed VFs?
Since the VFs are no longer active, they wouldn't clear their bits, causing
enetc_pf_send_msg() to inevitably timeout after 200ms. Should this mask be
cleared under the msg_lock before disabling SR-IOV?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260605065550.3038579-1-wei.fang@oss.nxp.com?part=3
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 04/15] net: enetc: add link speed message support to PF driver
2026-06-05 6:55 ` [PATCH net-next 04/15] net: enetc: add link speed " wei.fang
@ 2026-06-06 7:24 ` sashiko-bot
0 siblings, 0 replies; 30+ messages in thread
From: sashiko-bot @ 2026-06-06 7:24 UTC (permalink / raw)
To: wei.fang; +Cc: imx, Frank.Li
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] An unprivileged VF can flood the PF with `ENETC_MSG_GET_CURRENT_LINK_SPEED` messages to cause global `rtnl_lock` contention, leading to a host-wide control-plane Denial of Service.
--
commit 3eea0a03e4cdfef39b34f0bcd2ee86ea5e1372eb
Author: Wei Fang <wei.fang@nxp.com>
net: enetc: add link speed message support to PF driver
This commit adds link speed message support to the PF driver for DPDK-owned
VFs. The PF can now reply with the current link speed when queried by a VF,
improving synchronization and performance adjustments in the VF-side
applications.
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_msg.c b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
> index c93b4e6913d86..49c1ca14735c9 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc_msg.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
[ ... ]
> +static u16 enetc_msg_get_link_speed(struct enetc_pf *pf)
> +{
> + struct enetc_ndev_priv *priv = netdev_priv(pf->si->ndev);
> + struct ethtool_link_ksettings link_info = {};
> + u16 pf_msg;
> +
> + pf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
> + ENETC_MSG_CLASS_ID_LINK_SPEED);
> +
> + rtnl_lock();
> + if (phylink_ethtool_ksettings_get(priv->phylink, &link_info)) {
> + pf_msg |= ENETC_PF_MSG_SPEED(ENETC_MSG_SPEED_UNKNOWN);
> + rtnl_unlock();
> +
> + return pf_msg;
> + }
> + rtnl_unlock();
[Severity: High]
Can an unprivileged VF flood the PF with ENETC_MSG_GET_CURRENT_LINK_SPEED
messages to cause global rtnl_lock contention?
Because enetc_msg_get_link_speed() unconditionally acquires the global
rtnl_lock() to query link settings in response to a VF request, a malicious
or malfunctioning guest could potentially spam these messages in a tight
loop.
Could this severely starve other processes and VMs on the host that require
rtnl_lock for routine network configuration, resulting in a system-wide
control-plane denial of service?
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260605065550.3038579-1-wei.fang@oss.nxp.com?part=4
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 08/15] net: enetc: move mac_filter from struct enetc_pf to struct enetc_si
2026-06-05 6:55 ` [PATCH net-next 08/15] net: enetc: move mac_filter from struct enetc_pf to struct enetc_si wei.fang
@ 2026-06-06 7:24 ` sashiko-bot
2026-06-07 2:52 ` Wei Fang (OSS)
0 siblings, 1 reply; 30+ messages in thread
From: sashiko-bot @ 2026-06-06 7:24 UTC (permalink / raw)
To: wei.fang; +Cc: Frank.Li, imx
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] On 32-bit platforms, the 64-bit MAC hash table is truncated to 32 bits when programming the hardware, causing MAC addresses that hash to the upper 32 bits of the table to be silently dropped.
--
commit 3178ee41440e498f50696b0d334e000fdca4eaa7
Author: Wei Fang <wei.fang@nxp.com>
net: enetc: move mac_filter from struct enetc_pf to struct enetc_si
The mac_filter array currently resides in struct enetc_pf and is used to
track unicast and multicast MAC address filters for the PF. Since struct
enetc_si is the common structure shared between the PF and VF drivers,
move mac_filter into struct enetc_si to prepare for MAC filter support
in the VF driver.
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> index 4cff2f1237f18..f6920ded9f7ef 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> @@ -225,11 +225,12 @@ static void enetc4_pf_set_mac_hash_filter(struct enetc_pf *pf, int type)
> struct net_device *ndev = pf->si->ndev;
> struct enetc_mac_filter *mac_filter;
> struct enetc_hw *hw = &pf->si->hw;
> + struct enetc_si *si = pf->si;
> struct netdev_hw_addr *ha;
>
> netif_addr_lock_bh(ndev);
> if (type & ENETC_MAC_FILTER_TYPE_UC) {
> - mac_filter = &pf->mac_filter[UC];
> + mac_filter = &si->mac_filter[UC];
[Severity: High]
This isn't a bug introduced by this patch, but on 32-bit platforms, does
dereferencing mac_hash_table truncate the 64-bit filter down to 32 bits?
The mac_hash_table is declared as DECLARE_BITMAP(mac_hash_table, 64),
which evaluates to an array of two unsigned long elements on 32-bit systems.
When configuring the hardware later in this function:
enetc4_pf_set_mac_hash_filter() {
...
enetc4_pf_set_si_uc_hash_filter(hw, 0, *mac_filter->mac_hash_table);
}
Dereferencing mac_hash_table directly like this only passes the first
unsigned long. Since enetc4_pf_set_si_uc_hash_filter() takes a u64
parameter, the 32-bit value will be zero-extended, effectively losing the
upper 32 bits of the MAC hash.
[ ... ]
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
> index 38fcc7b5fc6da..209a3503609f5 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
> @@ -111,10 +111,9 @@ static void enetc_set_mac_ht_flt(struct enetc_si *si, int si_idx, int type,
> }
> }
>
> -static void enetc_sync_mac_filters(struct enetc_pf *pf)
> +static void enetc_sync_mac_filters(struct enetc_si *si)
> {
> - struct enetc_mac_filter *f = pf->mac_filter;
> - struct enetc_si *si = pf->si;
> + struct enetc_mac_filter *f = si->mac_filter;
> int i, pos;
[Severity: High]
This is a pre-existing issue, but does enetc_sync_mac_filters() also truncate
the hash table on 32-bit architectures?
enetc_sync_mac_filters() {
...
enetc_set_mac_ht_flt(si, 0, i, *f->mac_hash_table);
}
Like in enetc4_pf_set_mac_hash_filter(), passing *f->mac_hash_table only
provides the first 32 bits on 32-bit platforms. Furthermore,
enetc_set_mac_ht_flt() accepts an unsigned long for the hash:
static void enetc_set_mac_ht_flt(struct enetc_si *si, int si_idx, int type,
unsigned long hash)
{
...
enetc_port_wr(&si->hw, ENETC_PSIUMHFR1(si_idx),
upper_32_bits(hash));
}
Since hash is an unsigned long, upper_32_bits(hash) will always evaluate to 0
on 32-bit platforms. Is there a risk that any unicast or multicast MAC
addresses that hash to bits 32-63 will be silently dropped by the hardware
filter?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260605065550.3038579-1-wei.fang@oss.nxp.com?part=8
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 09/15] net: enetc: add MAC address filtering support for VFs of ENETC v4
2026-06-05 6:55 ` [PATCH net-next 09/15] net: enetc: add MAC address filtering support for VFs of ENETC v4 wei.fang
@ 2026-06-06 7:24 ` sashiko-bot
0 siblings, 0 replies; 30+ messages in thread
From: sashiko-bot @ 2026-06-06 7:24 UTC (permalink / raw)
To: wei.fang; +Cc: imx, Frank.Li
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] A Time-Of-Check to Time-Of-Use (TOCTOU) race condition in `enetc_msg_handle_rxmsg` allows a malicious VF to trigger a heap out-of-bounds read in `enetc_msg_set_vf_mac_hash_filter` by changing the message length between allocation and use.
--
commit 46d6bb311e4a8bcc15dcd4d622db8e4c46a5ec75
Author: Wei Fang <wei.fang@nxp.com>
net: enetc: add MAC address filtering support for VFs of ENETC v4
Adds VSI-to-PSI mailbox message support to allow VFs to request MAC filter
configuration from the PF on ENETC v4. Introduces two new command IDs to
program the MAC hash filter table and configure promiscuous mode.
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_msg.c b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
> index 49c1ca14735c9..7dcb1dcdec84d 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc_msg.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
[ ... ]
> @@ -101,6 +101,115 @@ static u16 enetc_msg_set_vf_primary_mac_addr(struct enetc_pf *pf, int vf_id,
[ ... ]
> +static u16 enetc_msg_set_vf_mac_hash_filter(struct enetc_pf *pf, int vf_id,
> + void *vf_msg)
> +{
[ ... ]
> + } else if (type == ENETC_MAC_FILTER_TYPE_ALL) {
> + if (!msg->hdr.len) {
> + pf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
> + ENETC_MSG_CLASS_ID_INVALID_MSG_LEN);
> + goto vf_state_unlock;
> + }
> +
> + pf->ops->set_si_mac_hash_filter(hw, si_id, UC, hash_tbl);
> + hash_tbl = (u64)msg->hash_tbl[3] << 32 | msg->hash_tbl[2];
[Severity: High]
Can a malicious VF trigger a heap out-of-bounds read here?
Looking at enetc_msg_handle_rxmsg(), which handles the message allocation, it
reads msg_hdr->len from DMA memory to calculate the size:
u32 msg_size = ENETC_MSG_SIZE(msg_hdr->len);
...
msg = kzalloc_objs(*msg, msg_size);
...
memcpy(msg, msg_swbd->vaddr, msg_size);
If the VF modifies the length in DMA memory to a non-zero value between the
msg_size calculation and the memcpy, the copied msg->hdr.len will differ from
the size actually allocated.
If the buffer was allocated as 32 bytes (because the initial length was 0),
this check for !msg->hdr.len will pass, and the subsequent read of
msg->hash_tbl[3] (at offset 32) will read out of bounds.
If this object is placed at the end of a slab page next to an unmapped page,
could this cause a panic, leading to a guest-to-host denial of service?
Additionally, would the leaked kernel heap data be programmed into the MAC hash
filter, potentially creating an information leak?
> + pf->ops->set_si_mac_hash_filter(hw, si_id, MC, hash_tbl);
> + }
> +
> +vf_state_unlock:
> + mutex_unlock(&vf_state->lock);
> +
> + return pf_msg;
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260605065550.3038579-1-wei.fang@oss.nxp.com?part=9
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 11/15] net: enetc: restore VF MAC promiscuous mode after FLR for ENETC v4
2026-06-05 6:55 ` [PATCH net-next 11/15] net: enetc: restore VF MAC promiscuous mode after FLR for ENETC v4 wei.fang
@ 2026-06-06 7:24 ` sashiko-bot
0 siblings, 0 replies; 30+ messages in thread
From: sashiko-bot @ 2026-06-06 7:24 UTC (permalink / raw)
To: wei.fang; +Cc: Frank.Li, imx
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Critical] State leakage of VF configuration flags across SR-IOV disable/enable cycles leading to privilege escalation.
--
commit 4b3358f3b481a101e7878efe2d4cc289110ff9db
Author: Wei Fang <wei.fang@nxp.com>
net: enetc: restore VF MAC promiscuous mode after FLR for ENETC v4
This commit adds tracking for VF MAC promiscuous mode to mitigate a security
vulnerability where a VF Function Level Reset (FLR) defaults to enabling
promiscuous mode. It introduces a vf_flr_handler callback to restore the
hardware state based on PF-managed policies.
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> index 2e081a59154e1..15c8b704b2b75 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
[ ... ]
> @@ -283,11 +283,32 @@ static void enetc4_pf_set_mac_filter(struct enetc_pf *pf, int type)
> enetc4_pf_set_mac_hash_filter(pf, ENETC_MAC_FILTER_TYPE_MC);
> }
>
> +static void enetc4_pf_vf_flr_handler(struct enetc_pf *pf, int vf_id)
> +{
> + struct enetc_hw *hw = &pf->si->hw;
> + struct enetc_vf_state *vf_state;
> + bool uc_promisc, mc_promisc;
> +
> + vf_state = &pf->vf_state[vf_id];
> + mutex_lock(&vf_state->lock);
> +
> + uc_promisc = !!(vf_state->flags & ENETC_VF_FLAG_UC_PROMISC);
> + mc_promisc = !!(vf_state->flags & ENETC_VF_FLAG_MC_PROMISC);
> +
> + mutex_lock(&pf->msg_lock);
> + enetc4_pf_set_si_mac_promisc(hw, vf_id + 1, UC, uc_promisc);
[Severity: Critical]
Does this introduce a privilege escalation due to state leakage across SR-IOV
disable/enable cycles?
When SR-IOV is disabled, enetc_sriov_configure() drops pf->num_vfs but does
not appear to clear the pf->vf_state array. As a result, the state from the
previous session leaks into the next session.
If a previously trusted VF had these flags set, a newly created untrusted VF
would inherit them. The untrusted VM could then deliberately trigger a
Function Level Reset (FLR), causing this handler to explicitly restore the
hardware to promiscuous mode based on the leaked flags:
enetc4_pf_vf_flr_handler()
uc_promisc = !!(vf_state->flags & ENETC_VF_FLAG_UC_PROMISC);
...
enetc4_pf_set_si_mac_promisc(hw, vf_id + 1, UC, uc_promisc);
Could this allow an untrusted VM to sniff network traffic destined for other
VMs or the host? Should pf->vf_state be reinitialized when SR-IOV is
disabled or enabled?
> + enetc4_pf_set_si_mac_promisc(hw, vf_id + 1, MC, mc_promisc);
> + mutex_unlock(&pf->msg_lock);
> +
> + mutex_unlock(&vf_state->lock);
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260605065550.3038579-1-wei.fang@oss.nxp.com?part=11
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 12/15] net: enetc: add VF support for i.MX94 and i.MX95
2026-06-05 6:55 ` [PATCH net-next 12/15] net: enetc: add VF support for i.MX94 and i.MX95 wei.fang
@ 2026-06-06 7:24 ` sashiko-bot
2026-06-07 3:53 ` Wei Fang (OSS)
0 siblings, 1 reply; 30+ messages in thread
From: sashiko-bot @ 2026-06-06 7:24 UTC (permalink / raw)
To: wei.fang; +Cc: imx, Frank.Li
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The `pf->msg_lock` mutex is used uninitialized on standalone ENETC devices, leading to a panic or lockdep splat during RX mode configuration.
- [High] ENETC4 VF driver data uses `enetc_vf_ethtool_ops` which unconditionally reads ENETC 1.0 specific registers via `ethtool -d`, triggering out-of-bounds/reserved accesses.
--
commit aabc7a8de39df35b07517a53cac397ac5c0fb902
Author: Wei Fang <wei.fang@nxp.com>
net: enetc: add VF support for i.MX94 and i.MX95
This patch adds VF support for i.MX94 and i.MX95 platforms. Compared to
the LS1028A ENETC, the VF device ID has been updated to 0xef00.
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
> index aa8a87124b103..fdceaf36daa72 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc.c
> @@ -3745,6 +3745,13 @@ static const struct enetc_drvdata enetc_vf_data = {
> .eth_ops = &enetc_vf_ethtool_ops,
> };
>
> +static const struct enetc_drvdata enetc4_vf_data = {
> + .sysclk_freq = ENETC_CLK_333M,
> + .tx_csum = true,
> + .max_frags = ENETC4_MAX_SKB_FRAGS,
> + .eth_ops = &enetc_vf_ethtool_ops,
[Severity: High]
Does this safely support ENETC v4 hardware? The enetc_vf_ethtool_ops
implements the get_regs callback using enetc_get_regs(), which
unconditionally reads registers defined in the enetc_si_regs array.
This array includes ENETC 1.0 specific Control Ring (CBDR) registers like
ENETC_SICBDRMR. Since ENETC v4 hardware uses NTMP instead of CBDR, these
register offsets are invalid or reserved on i.MX94/i.MX95.
Reading reserved memory regions via ethtool -d can trigger a synchronous
external abort or kernel panic on some architectures. Should the driver
define an ENETC4-specific ethtool_ops for the VF or check hardware
revisions before reading these registers?
> +};
> +
[ ... ]
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> index 15c8b704b2b75..868ed694e1200 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> @@ -314,11 +314,15 @@ static const struct enetc_pf_ops enetc4_pf_ops = {
> static int enetc4_pf_struct_init(struct enetc_si *si)
> {
> struct enetc_pf *pf = enetc_si_priv(si);
> + int err;
>
> pf->si = si;
> - pf->total_vfs = pci_sriov_get_totalvfs(si->pdev);
> pf->ops = &enetc4_pf_ops;
>
> + err = enetc_init_sriov_resources(pf);
[Severity: High]
Can this lead to an uninitialized mutex being used on standalone ENETC v4
devices that do not support VFs?
In enetc_init_sriov_resources(), there is an early return if pf->total_vfs
is 0:
int enetc_init_sriov_resources(struct enetc_pf *pf)
{
...
pf->total_vfs = pci_sriov_get_totalvfs(pf->si->pdev);
if (!pf->total_vfs)
return 0;
...
mutex_init(&pf->msg_lock);
return 0;
}
If total_vfs is 0 (as is the case for standalone i.MX94 ENETC),
the msg_lock is not initialized. Later, when the network interface is
brought up or the promiscuous mode changes, enetc4_psi_do_set_rx_mode()
unconditionally locks this uninitialized mutex:
mutex_lock(&pf->msg_lock);
enetc4_pf_set_si_mac_promisc(hw, 0, UC, uc_promisc);
...
mutex_unlock(&pf->msg_lock);
Would it be better to initialize the mutex unconditionally, or condition
the locking on the device capabilities?
> + if (err)
> + return err;
> +
> enetc4_get_port_caps(pf);
> enetc4_get_psi_hw_features(si);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260605065550.3038579-1-wei.fang@oss.nxp.com?part=12
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 13/15] net: enetc: implement ndo_set_rx_mode_async for ENETC v4 VF
2026-06-05 6:55 ` [PATCH net-next 13/15] net: enetc: implement ndo_set_rx_mode_async for ENETC v4 VF wei.fang
@ 2026-06-06 7:24 ` sashiko-bot
2026-06-07 4:01 ` Wei Fang (OSS)
0 siblings, 1 reply; 30+ messages in thread
From: sashiko-bot @ 2026-06-06 7:24 UTC (permalink / raw)
To: wei.fang; +Cc: Frank.Li, imx
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Incorrect conversion of the MAC hash table bitmap to `u64` and missing endianness conversions corrupt the hardware mailbox payload on 32-bit big-endian architectures.
--
commit 0c4f7b4fe1b39fb9114ce4bf92f78fdf7e89d32d
Author: Wei Fang <wei.fang@nxp.com>
net: enetc: implement ndo_set_rx_mode_async for ENETC v4 VF
The ENETC VF communicates MAC filter changes to the PF driver via a VSI
mailbox interface. The message send path in enetc_msg_vsi_send() polls
for completion with a timeout up to 200ms, which requires a sleepable
context.
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_vf.c b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
> index 9b16226602aa9..418ee98da17d6 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc_vf.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
[ ... ]
> @@ -209,6 +209,122 @@ static int enetc_vf_setup_tc(struct net_device *ndev, enum tc_setup_type type,
> +static int enetc_vf_set_mac_hash_filter(struct enetc_ndev_priv *priv,
> + struct netdev_hw_addr_list *uc,
> + struct netdev_hw_addr_list *mc)
> +{
[ ... ]
> + if (mac_filter_type & ENETC_MAC_FILTER_TYPE_UC) {
> + mac_filter = &si->mac_filter[UC];
> + enetc_reset_mac_addr_filter(mac_filter);
> + netdev_hw_addr_list_for_each(ha, uc)
> + enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
> +
> + memcpy(&hash_val, mac_filter->mac_hash_table,
> + sizeof(hash_val));
> + msg->hash_tbl[i++] = hash_val & GENMASK(31, 0);
> + msg->hash_tbl[i++] = hash_val >> 32;
[Severity: High]
Does this memcpy() and bitwise shift logic correctly handle the bitmap
conversion on 32-bit big-endian systems?
Since mac_hash_table is declared with DECLARE_BITMAP(mac_hash_table, 64), it
is an array of unsigned long. On 32-bit architectures, this is an array of
two 32-bit words.
On 32-bit big-endian systems, memcpy() will place the first 32-bit word
(mac_hash_table[0], containing bits 0-31) into the most significant 32 bits
of the u64 hash_val, and the second word (mac_hash_table[1], containing bits
32-63) into the least significant 32 bits.
Then, hash_val & GENMASK(31, 0) grabs the lower 32 bits (which is actually
bits 32-63 of the bitmap) and assigns them to msg->hash_tbl[0]. This swaps
the halves of the bitmap and corrupts the hardware mailbox payload.
Additionally, this code appears to lack explicit cpu_to_le32() conversions
for serialization into shared memory. Could a helper like bitmap_to_arr32()
be used here instead to avoid these issues?
> + }
> +
> + if (mac_filter_type & ENETC_MAC_FILTER_TYPE_MC) {
> + mac_filter = &si->mac_filter[MC];
> + enetc_reset_mac_addr_filter(mac_filter);
> + netdev_hw_addr_list_for_each(ha, mc)
> + enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
> +
> + memcpy(&hash_val, mac_filter->mac_hash_table,
> + sizeof(hash_val));
> + msg->hash_tbl[i++] = hash_val & GENMASK(31, 0);
> + msg->hash_tbl[i++] = hash_val >> 32;
[Severity: High]
This block has the same 32-bit big-endian conversion and serialization issue
for the multicast bitmap as described above for the unicast bitmap.
> + }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260605065550.3038579-1-wei.fang@oss.nxp.com?part=13
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH net-next 14/15] net: enetc: add PSI-to-VSI link status notification support for VF
2026-06-05 6:55 ` [PATCH net-next 14/15] net: enetc: add PSI-to-VSI link status notification support for VF wei.fang
@ 2026-06-06 7:24 ` sashiko-bot
0 siblings, 0 replies; 30+ messages in thread
From: sashiko-bot @ 2026-06-06 7:24 UTC (permalink / raw)
To: wei.fang; +Cc: imx, Frank.Li
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Incorrect teardown sequence in device removal and probe error paths leads to Use-After-Free and hardware interrupt storms.
- [High] VF initialization fails completely on older host PF drivers due to unsupported link status registration command.
- [Medium] Missing workqueue flush in `enetc_close()` allows asynchronous carrier state modification on a down interface.
--
commit 24125d222c23303bc6d2d8db3f12047a510f7b92
Author: Wei Fang <wei.fang@nxp.com>
net: enetc: add PSI-to-VSI link status notification support for VF
Add infrastructure for ENETC v4 VFs to track PF link status changes via
the PSI-to-VSI messaging channel. Two new ops,
vf_reg_link_status_notifier and vf_unreg_link_status_notifier, are added
to enetc_si_ops and wired into enetc_phylink_connect() and enetc_close()
for the phy-less path.
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
> index fdceaf36daa72..a1a8a1551cd8e 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc.c
> @@ -2892,11 +2892,15 @@ static void enetc_clear_interrupts(struct enetc_ndev_priv *priv)
> static int enetc_phylink_connect(struct net_device *ndev)
> {
> struct enetc_ndev_priv *priv = netdev_priv(ndev);
> + struct enetc_si *si = priv->si;
> struct ethtool_keee edata;
> int err;
>
> if (!priv->phylink) {
> /* phy-less mode */
> + if (si->ops->vf_reg_link_status_notifier)
> + return si->ops->vf_reg_link_status_notifier(si);
> +
[Severity: High]
If an older PF driver rejects the ENETC_MSG_REGISTER_LINK_CHANGE_NOTIFIER
command and returns -EOPNOTSUPP, will propagating this error cause
enetc_open() to abort and completely break VF initialization on older host
kernels?
Would it be safer to intercept -EOPNOTSUPP and fall back to the legacy
netif_carrier_on() behavior?
> netif_carrier_on(ndev);
> return 0;
> }
[ ... ]
> @@ -3050,6 +3057,7 @@ EXPORT_SYMBOL_GPL(enetc_stop);
> int enetc_close(struct net_device *ndev)
> {
> struct enetc_ndev_priv *priv = netdev_priv(ndev);
> + struct enetc_si *si = priv->si;
>
> enetc_stop(ndev);
>
> @@ -3057,6 +3065,9 @@ int enetc_close(struct net_device *ndev)
> phylink_stop(priv->phylink);
> phylink_disconnect_phy(priv->phylink);
> } else {
> + if (si->ops->vf_unreg_link_status_notifier)
> + si->ops->vf_unreg_link_status_notifier(si);
> +
> netif_carrier_off(ndev);
> }
[Severity: Medium]
Since si->msg_task isn't flushed or canceled here, could a pending link status
interrupt execute asynchronously after the device is closed?
If enetc_vf_msg_task() runs after netif_carrier_off(), it might incorrectly
invoke netif_carrier_on() and turn the carrier state back on for a closed
interface. Does it make sense to add flush_work(&si->msg_task) here to ensure
proper synchronization?
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_vf.c b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
> index 418ee98da17d6..9cace77110b8a 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc_vf.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
[ ... ]
> @@ -524,7 +706,8 @@ static void enetc_vf_remove(struct pci_dev *pdev)
>
> priv = netdev_priv(si->ndev);
> unregister_netdev(si->ndev);
> -
> + enetc_vf_free_msg_msix(si);
> + enetc_vf_wq_task_destroy(si);
> enetc_free_msix(priv);
>
> enetc_free_si_resources(priv);
[Severity: High]
Could this teardown sequence result in an interrupt storm and a
use-after-free? This also appears to apply to the enetc_vf_probe() error
path.
During removal, enetc_vf_free_msg_msix() frees the OS-level IRQ handler. Then
enetc_vf_wq_task_destroy() waits for the workqueue to drain. If
enetc_vf_msg_task() executes during this time, it unconditionally calls
enetc_vf_enable_mr_int() at the end, re-enabling the interrupt in the
hardware. Since the OS handler is gone, this leaves the device generating
unhandled MSI-X interrupts, which might lead to an IRQ storm or IOMMU fault.
Additionally, unregister_netdev() has already completed before the workqueue
is destroyed. If the work item executes and calls netif_carrier_on() for the
unregistered device, it adds the device to the global linkwatch list. When the
linkwatch worker later processes the list, it accesses the freed net_device
memory.
Should the teardown order be adjusted so the workqueue is destroyed before the
interrupt is freed, and should both happen before the netdev is unregistered?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260605065550.3038579-1-wei.fang@oss.nxp.com?part=14
^ permalink raw reply [flat|nested] 30+ messages in thread
* RE: [PATCH net-next 01/15] net: enetc: add trusted VF support
2026-06-06 7:24 ` sashiko-bot
@ 2026-06-06 13:37 ` Wei Fang (OSS)
0 siblings, 0 replies; 30+ messages in thread
From: Wei Fang (OSS) @ 2026-06-06 13:37 UTC (permalink / raw)
To: sashiko-reviews@lists.linux.dev, Wei Fang (OSS)
Cc: imx@lists.linux.dev, Frank.Li@kernel.org, Networking
> > @@ -61,31 +63,41 @@ static u16
> enetc_msg_set_vf_primary_mac_addr(struct enetc_pf *pf, int vf_id,
> > struct enetc_vf_state *vf_state = &pf->vf_state[vf_id];
> > struct enetc_msg_mac_exact_filter *msg = vf_msg;
> > struct device *dev = &pf->si->pdev->dev;
> > + u16 pf_msg = ENETC_PF_MSG_SUCCESS;
> > char *addr = msg->mac[0].addr;
> >
> > + mutex_lock(&vf_state->lock);
> > +
> > + if (!(vf_state->flags & ENETC_VF_FLAG_TRUSTED)) {
> > + pf_msg = ENETC_PF_MSG_PERM_DENY;
> > + goto vf_state_unlock;
> > + }
>
> [Severity: High]
> Under standard Linux SR-IOV semantics, untrusted VFs are allowed to set their
> own MAC address provided the PF has not administratively locked it (i.e. when
> PF_SET_MAC is false). Does this check unconditionally deny all MAC changes
> from
> untrusted VFs? If so, couldn't this break backward compatibility and break
> guest
> OSes that attempt to assign a random MAC on boot?
I do not think an untrusted VF can set its own MAC. If so, it can set the
address to the address of another VF or PF, and eavesdrop on traffic sent
to other network interfaces. Furthermore, a malicious VM that arbitrarily
changes its MAC address can achieve MAC address spoofing and bypass
security policies.
>
> > +
> > if (!is_valid_ether_addr(addr)) {
> > dev_err_ratelimited(dev, "VF%d attempted to set invalid MAC\n",
> > vf_id);
> > - return (FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
> > - ENETC_MSG_CLASS_ID_MAC_FILTER) |
> > - FIELD_PREP(ENETC_PF_MSG_CLASS_CODE,
> > - ENETC_MF_CLASS_CODE_INVALID_MAC));
> > + pf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
> > + ENETC_MSG_CLASS_ID_MAC_FILTER) |
> > + FIELD_PREP(ENETC_PF_MSG_CLASS_CODE,
> > + ENETC_MF_CLASS_CODE_INVALID_MAC);
> > + goto vf_state_unlock;
> > }
> >
> > - mutex_lock(&vf_state->lock);
> > if (vf_state->flags & ENETC_VF_FLAG_PF_SET_MAC) {
> > - mutex_unlock(&vf_state->lock);
> > dev_err_ratelimited(dev,
> > "VF%d attempted to override PF set MAC\n",
> > vf_id);
> > - return FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
> > - ENETC_MSG_CLASS_ID_CMD_NOT_PERMITTED);
> > + pf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
> > + ENETC_MSG_CLASS_ID_CMD_NOT_PERMITTED);
> > + goto vf_state_unlock;
> > }
>
> [Severity: High]
> Does this incorrectly deny MAC changes from trusted VFs if the PF has
> assigned
> a MAC? Since this ENETC_VF_FLAG_PF_SET_MAC check happens after the
> TRUSTED check
> and unconditionally rejects the operation, it appears to violate the standard
> semantics that trusted VFs can override a PF-set MAC.
PF has higher privileges. If PF has already changed the MAC address for VF,
VF is not allowed to change the address via mailbox messages, even if it is
trusted. This is the original design intention.
These warninga are false positives.
^ permalink raw reply [flat|nested] 30+ messages in thread
* RE: [PATCH net-next 03/15] net: enetc: add link status message support to PF driver
2026-06-06 7:24 ` sashiko-bot
@ 2026-06-06 14:05 ` Wei Fang (OSS)
0 siblings, 0 replies; 30+ messages in thread
From: Wei Fang (OSS) @ 2026-06-06 14:05 UTC (permalink / raw)
To: sashiko-reviews@lists.linux.dev, Wei Fang (OSS)
Cc: imx@lists.linux.dev, Frank.Li@kernel.org, Networking
> > diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
> b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
> > --- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
> > +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
> > @@ -458,6 +458,8 @@ int enetc_init_sriov_resources(struct enetc_pf *pf)
> > for (int i = 0; i < pf->total_vfs; i++)
> > mutex_init(&pf->vf_state[i].lock);
> >
> > + mutex_init(&pf->msg_lock);
> > +
> > return 0;
> > }
>
> [Severity: High]
> If the device does not support SR-IOV or total_vfs is 0,
> enetc_init_sriov_resources() returns early:
>
> pf->total_vfs = pci_sriov_get_totalvfs(pf->si->pdev);
> if (!pf->total_vfs)
> return 0;
>
> This skips the mutex_init() for msg_lock.
>
> However, the phylink callbacks enetc4_pl_mac_link_up() and
> enetc4_pl_mac_link_down() unconditionally call enetc_pf_notify_vf_link_up()
> and enetc_pf_notify_vf_link_down().
>
> These functions eventually reach enetc_pf_notify_vf_link_status(), which
> attempts to acquire this uninitialized lock:
>
> enetc_pf_notify_vf_link_status()
> mutex_lock(&pf->msg_lock);
>
> Could this cause a lockdep warning or a crash when the device link comes
> up or goes down and total_vfs is 0?
This is a bug, will fix it in v2.
>
> > diff --git a/drivers/net/ethernet/freescale/enetc/enetc_msg.c
> b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
> > --- a/drivers/net/ethernet/freescale/enetc/enetc_msg.c
> > +++ b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
> [ ... ]
> > +static int enetc_pf_send_msg(struct enetc_pf *pf, u32 msg_code, u16
> ms_mask)
> > +{
> > + struct enetc_si *si = pf->si;
> > + u32 val;
> > +
> > + enetc_wr(&si->hw, ENETC_PSIMSGSR,
> > + FIELD_PREP(PSIMSGSR_MC, msg_code) | ms_mask);
> > +
> > + return read_poll_timeout(enetc_rd, val, !(val & ms_mask), 1000,
> > + 200000, false, &si->hw, ENETC_PSIMSGSR);
> > +}
> > +
> > +static void enetc_msg_notify_vf_link_status(struct enetc_pf *pf, u16
> ms_mask,
> > + bool link_up)
> > +{
> [ ... ]
> > + if (enetc_pf_send_msg(pf, pf_msg, ms_mask))
> > + dev_err_ratelimited(&pf->si->pdev->dev,
> > + "PF notifies link status failed\n");
> > +}
>
> [Severity: High]
> If a VF is malicious, crashed, or improperly configured and fails to clear
> its bit in ENETC_PSIMSGSR, enetc_pf_send_msg() will block the phylink worker
> thread for its maximum 200ms polling timeout.
>
> Because enetc_msg_notify_vf_link_status() only logs an error and does not
> remove the unresponsive VF from pf->link_status_ms_mask, won't every
> subsequent link state change also incur this 200ms stall?
This problem is unavoidable. We cannot determine whether VF is malicious
or simply not responding due to busy conditions. Removing it from
pf->link_status_ms_mask will cause VF to malfunction.
Please ignore this warning.
>
> Additionally, a malicious VF could spam
> ENETC_MSG_REGISTER_LINK_CHANGE_NOTIFIER
> messages, forcing the PF to repeatedly call enetc_pf_send_msg() while holding
> pf->msg_lock. Could this stall the shared msg_task workqueue and starve
> other VFs?
I don't think that's the case, since msg_task doesn't only handle messages from
malicious VFs.
>
> > @@ -361,6 +471,7 @@ int enetc_sriov_configure(struct pci_dev *pdev, int
> num_vfs)
> > if (!num_vfs) {
> > pci_disable_sriov(pdev);
> > enetc_msg_psi_free(pf);
> > + pf->link_status_ms_mask = 0;
> > pf->num_vfs = 0;
> > } else {
>
> [Severity: Medium]
> When disabling SR-IOV, pf->link_status_ms_mask is cleared outside of
> pf->msg_lock and after the VFs have been disabled via pci_disable_sriov().
>
> If a physical link state change occurs concurrently, could
> enetc_pf_notify_vf_link_status() acquire the lock, observe a stale non-zero
> ms_mask, and attempt to notify destroyed VFs?
>
> Since the VFs are no longer active, they wouldn't clear their bits, causing
> enetc_pf_send_msg() to inevitably timeout after 200ms. Should this mask be
> cleared under the msg_lock before disabling SR-IOV?
I don't think this needs to be improved. First, this kind of problem is very rare,
and second, the timeout is normal and will not have a functional impact.
And the problem could not be solved even before moving to
pci_disable_sriov(). Because VF may still set its mask via message during the
window between clearing the mask and VF actually closing.
--
pw-bot: cr
^ permalink raw reply [flat|nested] 30+ messages in thread
* RE: [PATCH net-next 08/15] net: enetc: move mac_filter from struct enetc_pf to struct enetc_si
2026-06-06 7:24 ` sashiko-bot
@ 2026-06-07 2:52 ` Wei Fang (OSS)
0 siblings, 0 replies; 30+ messages in thread
From: Wei Fang (OSS) @ 2026-06-07 2:52 UTC (permalink / raw)
To: sashiko-reviews@lists.linux.dev
Cc: Frank.Li@kernel.org, imx@lists.linux.dev, Networking
> > diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> > index 4cff2f1237f18..f6920ded9f7ef 100644
> > --- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> > +++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> > @@ -225,11 +225,12 @@ static void enetc4_pf_set_mac_hash_filter(struct
> enetc_pf *pf, int type)
> > struct net_device *ndev = pf->si->ndev;
> > struct enetc_mac_filter *mac_filter;
> > struct enetc_hw *hw = &pf->si->hw;
> > + struct enetc_si *si = pf->si;
> > struct netdev_hw_addr *ha;
> >
> > netif_addr_lock_bh(ndev);
> > if (type & ENETC_MAC_FILTER_TYPE_UC) {
> > - mac_filter = &pf->mac_filter[UC];
> > + mac_filter = &si->mac_filter[UC];
>
> [Severity: High]
> This isn't a bug introduced by this patch, but on 32-bit platforms, does
> dereferencing mac_hash_table truncate the 64-bit filter down to 32 bits?
>
> The mac_hash_table is declared as DECLARE_BITMAP(mac_hash_table, 64),
> which evaluates to an array of two unsigned long elements on 32-bit systems.
> When configuring the hardware later in this function:
>
> enetc4_pf_set_mac_hash_filter() {
> ...
> enetc4_pf_set_si_uc_hash_filter(hw, 0,
> *mac_filter->mac_hash_table);
> }
>
> Dereferencing mac_hash_table directly like this only passes the first
> unsigned long. Since enetc4_pf_set_si_uc_hash_filter() takes a u64
> parameter, the 32-bit value will be zero-extended, effectively losing the
> upper 32 bits of the MAC hash.
>
> [ ... ]
>
> > diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
> b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
> > index 38fcc7b5fc6da..209a3503609f5 100644
> > --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
> > +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
> > @@ -111,10 +111,9 @@ static void enetc_set_mac_ht_flt(struct enetc_si *si,
> int si_idx, int type,
> > }
> > }
> >
> > -static void enetc_sync_mac_filters(struct enetc_pf *pf)
> > +static void enetc_sync_mac_filters(struct enetc_si *si)
> > {
> > - struct enetc_mac_filter *f = pf->mac_filter;
> > - struct enetc_si *si = pf->si;
> > + struct enetc_mac_filter *f = si->mac_filter;
> > int i, pos;
>
> [Severity: High]
> This is a pre-existing issue, but does enetc_sync_mac_filters() also truncate
> the hash table on 32-bit architectures?
>
> enetc_sync_mac_filters() {
> ...
> enetc_set_mac_ht_flt(si, 0, i, *f->mac_hash_table);
> }
>
> Like in enetc4_pf_set_mac_hash_filter(), passing *f->mac_hash_table only
> provides the first 32 bits on 32-bit platforms. Furthermore,
> enetc_set_mac_ht_flt() accepts an unsigned long for the hash:
>
> static void enetc_set_mac_ht_flt(struct enetc_si *si, int si_idx, int type,
> unsigned long hash)
> {
> ...
> enetc_port_wr(&si->hw, ENETC_PSIUMHFR1(si_idx),
> upper_32_bits(hash));
> }
>
> Since hash is an unsigned long, upper_32_bits(hash) will always evaluate to 0
> on 32-bit platforms. Is there a risk that any unicast or multicast MAC
> addresses that hash to bits 32-63 will be silently dropped by the hardware
> filter?
LS1028A, i.MX95/94 and later i.MX series and S32N7 are all 64-bit architectures.
So this not a real issue.
^ permalink raw reply [flat|nested] 30+ messages in thread
* RE: [PATCH net-next 12/15] net: enetc: add VF support for i.MX94 and i.MX95
2026-06-06 7:24 ` sashiko-bot
@ 2026-06-07 3:53 ` Wei Fang (OSS)
0 siblings, 0 replies; 30+ messages in thread
From: Wei Fang (OSS) @ 2026-06-07 3:53 UTC (permalink / raw)
To: sashiko-reviews@lists.linux.dev
Cc: imx@lists.linux.dev, Frank.Li@kernel.org, Networking
> > diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c
> b/drivers/net/ethernet/freescale/enetc/enetc.c
> > index aa8a87124b103..fdceaf36daa72 100644
> > --- a/drivers/net/ethernet/freescale/enetc/enetc.c
> > +++ b/drivers/net/ethernet/freescale/enetc/enetc.c
> > @@ -3745,6 +3745,13 @@ static const struct enetc_drvdata enetc_vf_data
> = {
> > .eth_ops = &enetc_vf_ethtool_ops,
> > };
> >
> > +static const struct enetc_drvdata enetc4_vf_data = {
> > + .sysclk_freq = ENETC_CLK_333M,
> > + .tx_csum = true,
> > + .max_frags = ENETC4_MAX_SKB_FRAGS,
> > + .eth_ops = &enetc_vf_ethtool_ops,
>
> [Severity: High]
> Does this safely support ENETC v4 hardware? The enetc_vf_ethtool_ops
> implements the get_regs callback using enetc_get_regs(), which
> unconditionally reads registers defined in the enetc_si_regs array.
>
> This array includes ENETC 1.0 specific Control Ring (CBDR) registers like
> ENETC_SICBDRMR. Since ENETC v4 hardware uses NTMP instead of CBDR,
> these
> register offsets are invalid or reserved on i.MX94/i.MX95.
>
> Reading reserved memory regions via ethtool -d can trigger a synchronous
> external abort or kernel panic on some architectures. Should the driver
> define an ENETC4-specific ethtool_ops for the VF or check hardware
> revisions before reading these registers?
The VF registers of v1 and v4 are basically the same, so there is no such
issue.
>
> > +};
> > +
>
> [ ... ]
>
> > diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> > index 15c8b704b2b75..868ed694e1200 100644
> > --- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> > +++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> > @@ -314,11 +314,15 @@ static const struct enetc_pf_ops enetc4_pf_ops =
> {
> > static int enetc4_pf_struct_init(struct enetc_si *si)
> > {
> > struct enetc_pf *pf = enetc_si_priv(si);
> > + int err;
> >
> > pf->si = si;
> > - pf->total_vfs = pci_sriov_get_totalvfs(si->pdev);
> > pf->ops = &enetc4_pf_ops;
> >
> > + err = enetc_init_sriov_resources(pf);
>
> [Severity: High]
> Can this lead to an uninitialized mutex being used on standalone ENETC v4
> devices that do not support VFs?
>
> In enetc_init_sriov_resources(), there is an early return if pf->total_vfs
> is 0:
>
> int enetc_init_sriov_resources(struct enetc_pf *pf)
> {
> ...
> pf->total_vfs = pci_sriov_get_totalvfs(pf->si->pdev);
> if (!pf->total_vfs)
> return 0;
> ...
> mutex_init(&pf->msg_lock);
> return 0;
> }
>
> If total_vfs is 0 (as is the case for standalone i.MX94 ENETC),
> the msg_lock is not initialized. Later, when the network interface is
> brought up or the promiscuous mode changes, enetc4_psi_do_set_rx_mode()
> unconditionally locks this uninitialized mutex:
>
> mutex_lock(&pf->msg_lock);
> enetc4_pf_set_si_mac_promisc(hw, 0, UC, uc_promisc);
> ...
> mutex_unlock(&pf->msg_lock);
>
> Would it be better to initialize the mutex unconditionally, or condition
> the locking on the device capabilities?
Yes, this is a bug, will fix it in v2.
--
pw-bot: cr
^ permalink raw reply [flat|nested] 30+ messages in thread
* RE: [PATCH net-next 13/15] net: enetc: implement ndo_set_rx_mode_async for ENETC v4 VF
2026-06-06 7:24 ` sashiko-bot
@ 2026-06-07 4:01 ` Wei Fang (OSS)
0 siblings, 0 replies; 30+ messages in thread
From: Wei Fang (OSS) @ 2026-06-07 4:01 UTC (permalink / raw)
To: sashiko-reviews@lists.linux.dev
Cc: Frank.Li@kernel.org, imx@lists.linux.dev, Networking
> > @@ -209,6 +209,122 @@ static int enetc_vf_setup_tc(struct net_device
> > *ndev, enum tc_setup_type type,
> > +static int enetc_vf_set_mac_hash_filter(struct enetc_ndev_priv *priv,
> > + struct netdev_hw_addr_list *uc,
> > + struct netdev_hw_addr_list *mc)
> > +{
>
> [ ... ]
>
> > + if (mac_filter_type & ENETC_MAC_FILTER_TYPE_UC) {
> > + mac_filter = &si->mac_filter[UC];
> > + enetc_reset_mac_addr_filter(mac_filter);
> > + netdev_hw_addr_list_for_each(ha, uc)
> > + enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
> > +
> > + memcpy(&hash_val, mac_filter->mac_hash_table,
> > + sizeof(hash_val));
> > + msg->hash_tbl[i++] = hash_val & GENMASK(31, 0);
> > + msg->hash_tbl[i++] = hash_val >> 32;
>
> [Severity: High]
> Does this memcpy() and bitwise shift logic correctly handle the bitmap
> conversion on 32-bit big-endian systems?
>
> Since mac_hash_table is declared with DECLARE_BITMAP(mac_hash_table, 64),
> it is an array of unsigned long. On 32-bit architectures, this is an array of two
> 32-bit words.
>
> On 32-bit big-endian systems, memcpy() will place the first 32-bit word
> (mac_hash_table[0], containing bits 0-31) into the most significant 32 bits of
> the u64 hash_val, and the second word (mac_hash_table[1], containing bits
> 32-63) into the least significant 32 bits.
>
> Then, hash_val & GENMASK(31, 0) grabs the lower 32 bits (which is actually
> bits 32-63 of the bitmap) and assigns them to msg->hash_tbl[0]. This swaps
> the halves of the bitmap and corrupts the hardware mailbox payload.
>
> Additionally, this code appears to lack explicit cpu_to_le32() conversions for
> serialization into shared memory. Could a helper like bitmap_to_arr32() be
> used here instead to avoid these issues?
>
> > + }
> > +
> > + if (mac_filter_type & ENETC_MAC_FILTER_TYPE_MC) {
> > + mac_filter = &si->mac_filter[MC];
> > + enetc_reset_mac_addr_filter(mac_filter);
> > + netdev_hw_addr_list_for_each(ha, mc)
> > + enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
> > +
> > + memcpy(&hash_val, mac_filter->mac_hash_table,
> > + sizeof(hash_val));
> > + msg->hash_tbl[i++] = hash_val & GENMASK(31, 0);
> > + msg->hash_tbl[i++] = hash_val >> 32;
>
> [Severity: High]
> This block has the same 32-bit big-endian conversion and serialization issue for
> the multicast bitmap as described above for the unicast bitmap.
>
All platforms use ENETC are arm64 littler-endian systems, so this is no
such issue.
^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2026-06-07 4:01 UTC | newest]
Thread overview: 30+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-05 6:55 [PATCH net-next 00/15] net: enetc: SR-IOV improvements and ENETC v4 VF support wei.fang
2026-06-05 6:55 ` [PATCH net-next 01/15] net: enetc: add trusted " wei.fang
2026-06-06 7:24 ` sashiko-bot
2026-06-06 13:37 ` Wei Fang (OSS)
2026-06-05 6:55 ` [PATCH net-next 02/15] net: enetc: move msg_task and msg_int_name to struct enetc_si wei.fang
2026-06-05 6:55 ` [PATCH net-next 03/15] net: enetc: add link status message support to PF driver wei.fang
2026-06-06 7:24 ` sashiko-bot
2026-06-06 14:05 ` Wei Fang (OSS)
2026-06-05 6:55 ` [PATCH net-next 04/15] net: enetc: add link speed " wei.fang
2026-06-06 7:24 ` sashiko-bot
2026-06-05 6:55 ` [PATCH net-next 05/15] net: enetc: use enetc_set_si_hw_addr() to set VF MAC address wei.fang
2026-06-05 6:55 ` [PATCH net-next 06/15] net: enetc: relocate enetc_pf_set_vf_mac() for common PF support wei.fang
2026-06-05 6:55 ` [PATCH net-next 07/15] net: enetc: add .ndo_set_vf_mac() to the enetc v4 driver wei.fang
2026-06-05 6:55 ` [PATCH net-next 08/15] net: enetc: move mac_filter from struct enetc_pf to struct enetc_si wei.fang
2026-06-06 7:24 ` sashiko-bot
2026-06-07 2:52 ` Wei Fang (OSS)
2026-06-05 6:55 ` [PATCH net-next 09/15] net: enetc: add MAC address filtering support for VFs of ENETC v4 wei.fang
2026-06-06 7:24 ` sashiko-bot
2026-06-05 6:55 ` [PATCH net-next 10/15] net: enetc: simplify and rename PSIIER enable/disable helpers wei.fang
2026-06-05 6:55 ` [PATCH net-next 11/15] net: enetc: restore VF MAC promiscuous mode after FLR for ENETC v4 wei.fang
2026-06-06 7:24 ` sashiko-bot
2026-06-05 6:55 ` [PATCH net-next 12/15] net: enetc: add VF support for i.MX94 and i.MX95 wei.fang
2026-06-06 7:24 ` sashiko-bot
2026-06-07 3:53 ` Wei Fang (OSS)
2026-06-05 6:55 ` [PATCH net-next 13/15] net: enetc: implement ndo_set_rx_mode_async for ENETC v4 VF wei.fang
2026-06-06 7:24 ` sashiko-bot
2026-06-07 4:01 ` Wei Fang (OSS)
2026-06-05 6:55 ` [PATCH net-next 14/15] net: enetc: add PSI-to-VSI link status notification support for VF wei.fang
2026-06-06 7:24 ` sashiko-bot
2026-06-05 6:55 ` [PATCH net-next 15/15] net: enetc: add ndo_get_vf_config() support wei.fang
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.