From: wei.fang@oss.nxp.com
To: claudiu.manoil@nxp.com, vladimir.oltean@nxp.com,
xiaoning.wang@nxp.com, andrew@lunn.ch, olteanv@gmail.com,
andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
kuba@kernel.org, pabeni@redhat.com, linux@armlinux.org.uk
Cc: wei.fang@nxp.com, imx@lists.linux.dev, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH v4 net-next 13/15] net: enetc: implement ndo_set_rx_mode_async for ENETC v4 VF
Date: Wed, 9 Sep 2026 18:07:31 +0800 [thread overview]
Message-ID: <20260909100733.1139689-14-wei.fang@oss.nxp.com> (raw)
In-Reply-To: <20260909100733.1139689-1-wei.fang@oss.nxp.com>
From: Wei Fang <wei.fang@nxp.com>
An ENETC VF sends MAC filter changes to the PF over the VSI mailbox,
whose send path may sleep for up to 200ms waiting for completion. Since
the legacy ndo_set_rx_mode runs in atomic context, use
ndo_set_rx_mode_async instead, which runs from a workqueue under
rtnl_lock and receives pre-snapshotted unicast and multicast address
lists from the core.
Add two helpers built on the VSI mailbox:
- enetc_vf_set_mac_promisc() sends a promiscuous mode message for a
given filter type (unicast, multicast or both).
- enetc_vf_set_mac_hash_filter() sends the 64-bit MAC hash filter table,
built from the snapshotted address lists.
The callback picks the configuration from the current netdev flags:
- IFF_PROMISC: enable 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 promiscuous mode and apply both unicast and
multicast hash filters.
These requests are subject to the PF-side ENETC_VF_FLAG_TRUSTED check.
For an untrusted VF (the default) the PF denies promiscuous mode and
unicast hash filtering, so only the multicast hash filter is applied,
limited to ENETC_VF_MC_HASH_BITS_MAX buckets. Mark a VF trusted via
'ip link set <pf> vf N trust on' for the full behaviour.
Set IFF_UNICAST_FLT for ENETC v4 VFs so the stack does not needlessly
fall back to full promiscuous mode; whether a unicast hash filter is
actually programmed still depends on the PF trust policy.
Since a denied request always fails, map -EOPNOTSUPP, -EACCES and -EPERM
to 0 so the core does not retry an operation that can never succeed.
ENETC v1 (LS1028A) does not support VF-to-PF MAC filter messaging and
keeps using the legacy ndev ops.
On VF removal, disable promiscuous mode and clear the MAC filters, so
that stale configuration does not persist if the VF is later bound to
another driver.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
.../net/ethernet/freescale/enetc/enetc_vf.c | 214 +++++++++++++++++-
1 file changed, 213 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_vf.c b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
index 322705202d49..8cf38c426dae 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_vf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
@@ -213,6 +213,193 @@ static int enetc_vf_setup_tc(struct net_device *ndev, enum tc_setup_type type,
}
}
+static int enetc_vf_set_mac_promisc(struct enetc_si *si, int type,
+ bool promisc, bool flush_macs)
+{
+ struct enetc_msg_mac_promisc_mode *msg;
+ struct device *dev = &si->pdev->dev;
+ 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(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, promisc);
+ msg->config |= FIELD_PREP(ENETC_MSG_MAC_FLUSH_MACS, flush_macs);
+ 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(si, &msg_swbd);
+}
+
+static int enetc_vf_set_mac_hash_filter(struct enetc_si *si,
+ struct netdev_hw_addr_list *uc,
+ struct netdev_hw_addr_list *mc)
+{
+ struct enetc_msg_mac_hash_filter *msg;
+ struct enetc_mac_filter *mac_filter;
+ struct device *dev = &si->pdev->dev;
+ struct enetc_msg_swbd msg_swbd;
+ struct netdev_hw_addr *ha;
+ int mac_filter_type = 0;
+ u32 tbl_cnt = 0;
+ u32 msg_size;
+ int i = 0;
+
+ if (!uc && !mc)
+ return 0;
+
+ if (uc) {
+ tbl_cnt += 2;
+ mac_filter_type |= ENETC_MAC_FILTER_TYPE_UC;
+ }
+
+ if (mc) {
+ tbl_cnt += 2;
+ mac_filter_type |= ENETC_MAC_FILTER_TYPE_MC;
+ }
+
+ msg_size = struct_size(msg, hash_tbl, tbl_cnt);
+ msg_swbd.size = ALIGN(msg_size, ENETC_MSG_ALIGN);
+ msg_swbd.vaddr = dma_alloc_coherent(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 (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);
+
+ bitmap_to_arr32(&msg->hash_tbl[i], mac_filter->mac_hash_table,
+ ENETC_MADDR_HASH_TBL_SZ);
+ i += 2;
+ }
+
+ if (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);
+
+ bitmap_to_arr32(&msg->hash_tbl[i], mac_filter->mac_hash_table,
+ ENETC_MADDR_HASH_TBL_SZ);
+ }
+
+ 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 int enetc_vf_enable_iff_promisc(struct enetc_si *si)
+{
+ int err;
+
+ err = enetc_vf_set_mac_promisc(si, ENETC_MAC_FILTER_TYPE_ALL,
+ true, true);
+ if (err)
+ dev_err(&si->pdev->dev,
+ "Failed to enable promiscuous mode, err: %pe\n",
+ ERR_PTR(err));
+
+ return err;
+}
+
+static int enetc_vf_disable_iff_promisc(struct enetc_si *si,
+ struct netdev_hw_addr_list *uc,
+ struct netdev_hw_addr_list *mc)
+{
+ int err;
+
+ err = enetc_vf_set_mac_hash_filter(si, uc, mc);
+ if (err) {
+ dev_err_once(&si->pdev->dev,
+ "Failed to set MAC hash filters, err: %pe\n",
+ ERR_PTR(err));
+ return err;
+ }
+
+ err = enetc_vf_set_mac_promisc(si, ENETC_MAC_FILTER_TYPE_ALL,
+ false, false);
+ if (err)
+ dev_err_once(&si->pdev->dev,
+ "Failed to disable promiscuous mode, err: %pe\n",
+ ERR_PTR(err));
+
+ return err;
+}
+
+static int enetc_vf_enable_iff_allmulti(struct enetc_si *si,
+ struct netdev_hw_addr_list *uc)
+{
+ int err;
+
+ err = enetc_vf_set_mac_promisc(si, ENETC_MAC_FILTER_TYPE_MC,
+ true, true);
+ if (err) {
+ dev_err(&si->pdev->dev,
+ "Failed to enable multicast promiscuous mode, err: %pe\n",
+ ERR_PTR(err));
+ return err;
+ }
+
+ err = enetc_vf_set_mac_hash_filter(si, uc, NULL);
+ if (err) {
+ dev_err(&si->pdev->dev,
+ "Failed to set unicast filter, err: %pe\n",
+ ERR_PTR(err));
+ return err;
+ }
+
+ err = enetc_vf_set_mac_promisc(si, ENETC_MAC_FILTER_TYPE_UC,
+ false, false);
+ if (err)
+ dev_err(&si->pdev->dev,
+ "Failed to disable unicast promiscuous mode, err: %pe\n",
+ ERR_PTR(err));
+
+ return err;
+}
+
+static int 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;
+ int err;
+
+ if (ndev->flags & IFF_PROMISC)
+ err = enetc_vf_enable_iff_promisc(si);
+ else if (ndev->flags & IFF_ALLMULTI)
+ err = enetc_vf_enable_iff_allmulti(si, uc);
+ else
+ err = enetc_vf_disable_iff_promisc(si, uc, mc);
+
+ /* If the error code is -EOPNOTSUPP or -EACCES or -EPERM, return 0
+ * directly to avoid meaningless retries.
+ */
+ if (err == -EOPNOTSUPP || err == -EACCES || err == -EPERM)
+ return 0;
+
+ return err;
+}
+
/* Probing/ Init */
static const struct net_device_ops enetc_ndev_ops = {
.ndo_open = enetc_open,
@@ -227,6 +414,20 @@ static const struct net_device_ops enetc_ndev_ops = {
.ndo_hwtstamp_set = enetc_hwtstamp_set,
};
+static const struct net_device_ops enetc4_ndev_ops = {
+ .ndo_open = enetc_open,
+ .ndo_stop = enetc_close,
+ .ndo_start_xmit = enetc_xmit,
+ .ndo_get_stats = enetc_get_stats,
+ .ndo_set_mac_address = enetc_vf_set_mac_addr,
+ .ndo_set_features = enetc_vf_set_features,
+ .ndo_eth_ioctl = enetc_ioctl,
+ .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)
{
int ip_mn;
@@ -280,6 +481,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;
@@ -352,7 +556,10 @@ static int enetc_vf_probe(struct pci_dev *pdev,
goto err_alloc_netdev;
}
- enetc_vf_netdev_setup(si, ndev, &enetc_ndev_ops);
+ if (is_enetc_rev1(si))
+ enetc_vf_netdev_setup(si, ndev, &enetc_ndev_ops);
+ else
+ enetc_vf_netdev_setup(si, ndev, &enetc4_ndev_ops);
priv = netdev_priv(ndev);
@@ -416,6 +623,11 @@ static void enetc_vf_remove(struct pci_dev *pdev)
priv = netdev_priv(si->ndev);
unregister_netdev(si->ndev);
+ /* Disable promiscuous mode and clear MAC filters */
+ if (!is_enetc_rev1(si))
+ enetc_vf_set_mac_promisc(si, ENETC_MAC_FILTER_TYPE_ALL,
+ false, true);
+
enetc_free_msix(priv);
enetc_free_si_resources(priv);
--
2.34.1
next prev parent reply other threads:[~2026-09-09 10:37 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-09 10:07 [PATCH v4 net-next 00/15] net: enetc: SR-IOV improvements and ENETC v4 VF support wei.fang
2026-09-09 10:07 ` [PATCH v4 net-next 01/15] net: enetc: add trusted " wei.fang
2026-09-10 11:20 ` netdev-bot+sashiko
2026-09-11 2:29 ` Wei Fang
2026-09-09 10:07 ` [PATCH v4 net-next 02/15] net: enetc: move msg_task and msg_int_name to struct enetc_si wei.fang
2026-09-11 20:14 ` Claudiu Manoil
2026-09-09 10:07 ` [PATCH v4 net-next 03/15] net: enetc: add link status message support to PF driver wei.fang
2026-09-10 11:20 ` netdev-bot+sashiko
2026-09-11 5:55 ` Wei Fang
2026-09-11 20:15 ` Claudiu Manoil
2026-09-09 10:07 ` [PATCH v4 net-next 04/15] net: enetc: add link speed " wei.fang
2026-09-10 11:20 ` netdev-bot+sashiko
2026-09-11 2:56 ` Wei Fang
2026-09-11 20:16 ` Claudiu Manoil
2026-09-09 10:07 ` [PATCH v4 net-next 05/15] net: enetc: use enetc_set_si_hw_addr() to set VF MAC address wei.fang
2026-09-09 10:07 ` [PATCH v4 net-next 06/15] net: enetc: relocate enetc_pf_set_vf_mac() for common PF support wei.fang
2026-09-09 10:07 ` [PATCH v4 net-next 07/15] net: enetc: add .ndo_set_vf_mac() to the enetc v4 driver wei.fang
2026-09-09 10:07 ` [PATCH v4 net-next 08/15] net: enetc: move mac_filter from struct enetc_pf to struct enetc_si wei.fang
2026-09-09 10:07 ` [PATCH v4 net-next 09/15] net: enetc: add MAC address filtering support for VFs of ENETC v4 wei.fang
2026-09-10 11:21 ` netdev-bot+sashiko
2026-09-11 6:13 ` Wei Fang
2026-09-09 10:07 ` [PATCH v4 net-next 10/15] net: enetc: simplify and rename PSIIER enable/disable helpers wei.fang
2026-09-09 10:07 ` [PATCH v4 net-next 11/15] net: enetc: restore VF MAC promiscuous mode after FLR for ENETC v4 wei.fang
2026-09-10 11:21 ` netdev-bot+sashiko
2026-09-11 6:23 ` Wei Fang
2026-09-11 20:17 ` Claudiu Manoil
2026-09-09 10:07 ` [PATCH v4 net-next 12/15] net: enetc: add VF support for i.MX94 and i.MX95 wei.fang
2026-09-09 10:07 ` wei.fang [this message]
2026-09-10 11:21 ` [PATCH v4 net-next 13/15] net: enetc: implement ndo_set_rx_mode_async for ENETC v4 VF netdev-bot+sashiko
2026-09-11 7:17 ` Wei Fang
2026-09-09 10:07 ` [PATCH v4 net-next 14/15] net: enetc: add PSI-to-VSI link status notification support for VF wei.fang
2026-09-09 10:07 ` [PATCH v4 net-next 15/15] net: enetc: add ndo_get_vf_config() support wei.fang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260909100733.1139689-14-wei.fang@oss.nxp.com \
--to=wei.fang@oss.nxp.com \
--cc=andrew+netdev@lunn.ch \
--cc=andrew@lunn.ch \
--cc=claudiu.manoil@nxp.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=imx@lists.linux.dev \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=netdev@vger.kernel.org \
--cc=olteanv@gmail.com \
--cc=pabeni@redhat.com \
--cc=vladimir.oltean@nxp.com \
--cc=wei.fang@nxp.com \
--cc=xiaoning.wang@nxp.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®