* [PATCH net-next v9 0/7] Introduce async callback ndo_set_rx_mode_async
@ 2026-03-14 18:28 I Viswanath
2026-03-14 18:28 ` [PATCH net-next v9 1/7] net: core: Add state tracking for async netdev ops I Viswanath
` (7 more replies)
0 siblings, 8 replies; 18+ messages in thread
From: I Viswanath @ 2026-03-14 18:28 UTC (permalink / raw)
To: stfomichev, horms, edumazet, pabeni, andrew+netdev, kuba, davem,
eperezma, xuanzhuo, jasowang, mst, przemyslaw.kitszel,
anthony.l.nguyen, jacob.e.keller, ronak.doshi, pcnet32
Cc: bcm-kernel-feedback-list, netdev, virtualization, intel-wired-lan,
linux-kernel, I Viswanath
This is an implementation of the idea provided by Jakub here
https://lore.kernel.org/netdev/20250923163727.5e97abdb@kernel.org/
The set_rx_mode callback is invoked under the addr_lock spinlock which
makes it illegal to sleep. This means set_rx_mode is prone to
sleep-in-atomic bugs as drivers have a tendency to do the I/O directly
in the callback.
This problem can be avoided if set_rx_mode were done in 2 stages: snapshot
and commit. A handful of drivers implement this idea by implementing the
rx_mode setting as work and scheduling it in the set_rx_mode callback.
This series moves that work to net/core by introducing a new async
netdev op set_rx_mode_async.
In the process of doing this, I encountered problems described in the
the first patch of the series. In brief, the patch introduces a state
variable to keep track of the current netdev state. This should be
useful for async netdev ops in general as nothing about these problems
was specific to set_rx_mode_async.
The rx_mode refactor has the secondary benefit of preventing RX mode
update requests from building up as only the most recent request
(before the work has run) will be committed.
In brief, the new RX mode update flow will look something like:
set_rx_mode():
ndo_set_rx_mode();
prepare_snapshot();
set_rx_mode_async():
fetch_snapshot();
ndo_set_rx_mode_async();
ndo_set_rx_mode_async() is called from a work item and the handler
doesn't hold the netif_addr_lock spin lock during its execution
making execution sleepable in that part.
This model should work correctly if the following conditions hold:
1. ndo_set_rx_mode_async should use the rx_mode set by the most recent
call to prepare_rx_mode() before its execution.
2. If a prepare_snapshot() call happens during execution of the work,
the work should be rescheduled.
3. All calls to modify rx_mode should pass through a new helper
netif_set_rx_mode (which requires the instance lock or RTNL if the
driver doesn't use it).
1 is guaranteed by the implementation and 2 by workqueue properties.
Drivers need to ensure 3.
---
v1:
Link: https://lore.kernel.org/netdev/20251020134857.5820-1-viswanathiyyappan@gmail.com/
v2:
- Exported set_and_schedule_rx_config as a symbol for use in modules
- Fixed incorrect cleanup for the case of rx_work alloc failing in alloc_netdev_mqs
- Removed the locked version (cp_set_rx_mode) and renamed __cp_set_rx_mode to cp_set_rx_mode
Link: https://lore.kernel.org/netdev/20251026175445.1519537-1-viswanathiyyappan@gmail.com/
v3:
- Added RFT tag
- Corrected mangled patch
Link: https://lore.kernel.org/netdev/20251028174222.1739954-1-viswanathiyyappan@gmail.com/
v4:
- Completely reworked the snapshot mechanism as per v3 comments
- Implemented the callback for virtio-net instead of 8139cp driver
- Removed RFC tag
Link: https://lore.kernel.org/netdev/20251118164333.24842-1-viswanathiyyappan@gmail.com/
v5:
- Fix broken code and titles
- Remove RFT tag
Link: https://lore.kernel.org/netdev/20251120141354.355059-1-viswanathiyyappan@gmail.com/
v6:
- Added struct netif_deferred_work_cleanup and members needs_deferred_cleanup and deferred_work_cleanup in net_device
- Moved out ctrl bits from netif_rx_mode_config to netif_rx_mode_work_ctx
Link: https://lore.kernel.org/netdev/20251227174225.699975-1-viswanathiyyappan@gmail.com/
v7:
- Improved function, enum and struct names
Link: https://lore.kernel.org/netdev/20260102180530.1559514-1-viswanathiyyappan@gmail.com/
v8:
- Implemented the callback for drivers e1000, 8139cp, vmxnet3 and pcnet32
- Moved the rx_mode config set calls (for prom and allmulti) in prepare_rx_mode to the ndo_set_rx_mode callback for consistency
- Improved commit messages
Link: https://lore.kernel.org/netdev/20260112181626.20117-1-viswanathiyyappan@gmail.com/
v9:
- Removed cleanup_work and simplified resource cleanup
- Added netif_async_ctx (which includes netdev state tracking) for async ndo handling in general
- Converted netif_schedule_mode_work to a synchronous function netif_set_rx_mode
- Renamed *_write_rx_mode functions to *_set_rx_mode_async
I Viswanath (7):
net: core: Add state tracking for async netdev ops
net: core: Introduce callback ndo_set_rx_mode_async
virtio-net: Implement ndo_set_rx_mode_async callback
e1000: Implement ndo_set_rx_mode_async callback
8139cp: Implement ndo_set_rx_mode_async callback
vmxnet3: Implement ndo_set_rx_mode_async callback
pcnet32: Implement ndo_set_rx_mode_async callback
drivers/net/ethernet/amd/pcnet32.c | 65 +++-
drivers/net/ethernet/intel/e1000/e1000_main.c | 77 +++-
drivers/net/ethernet/realtek/8139cp.c | 49 ++-
drivers/net/virtio_net.c | 85 ++---
drivers/net/vmxnet3/vmxnet3_drv.c | 46 ++-
include/linux/netdevice.h | 123 ++++++-
include/net/netdev_lock.h | 8 +
net/core/dev.c | 335 +++++++++++++++++-
8 files changed, 663 insertions(+), 125 deletions(-)
--
2.47.3
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH net-next v9 1/7] net: core: Add state tracking for async netdev ops
2026-03-14 18:28 [PATCH net-next v9 0/7] Introduce async callback ndo_set_rx_mode_async I Viswanath
@ 2026-03-14 18:28 ` I Viswanath
2026-03-16 7:25 ` [Intel-wired-lan] " Loktionov, Aleksandr
2026-03-14 18:28 ` [PATCH net-next v9 2/7] net: core: Introduce callback ndo_set_rx_mode_async I Viswanath
` (6 subsequent siblings)
7 siblings, 1 reply; 18+ messages in thread
From: I Viswanath @ 2026-03-14 18:28 UTC (permalink / raw)
To: stfomichev, horms, edumazet, pabeni, andrew+netdev, kuba, davem,
eperezma, xuanzhuo, jasowang, mst, przemyslaw.kitszel,
anthony.l.nguyen, jacob.e.keller, ronak.doshi, pcnet32
Cc: bcm-kernel-feedback-list, netdev, virtualization, intel-wired-lan,
linux-kernel, I Viswanath
Async netdev ops are tricky because of the following problems:
1) Freeing the context associated with async netdev ops might require
waiting for completion of the associated work which might require the
rtnl lock or the instance lock. However this will deadlock in
__dev_close_many as the cleanup is done with those locks already held.
2) We need a way to enable/disable async netdev ops depending on the PM
state to allow/prevent hardware access as appropriate.
We solve these problems by introducing a state variable to track
the current state of netdev. This can take the following values:
- ACTIVE (up and normal operation)
- DOWN (down)
- INACTIVE (in suspend/shutdown)
To solve 1, we set the state to down in __dev_close_many. In the
associated op handler, we check for the current state and return if
the netdev is down.
To solve 2, the commit introduces the following functions:
- netif_enable_async_ops -> sets state to ACTIVE
- netif_disable_async_ops -> sets state to INACTIVE and cancels any
pending work as required.
The op implementation can use the state information to do the required
processing.
Signed-off-by: I Viswanath <viswanathiyyappan@gmail.com>
---
include/linux/netdevice.h | 29 ++++++++++++++
net/core/dev.c | 84 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 111 insertions(+), 2 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index ae269a2e7f4d..6d426dc66af9 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1062,6 +1062,16 @@ struct netdev_net_notifier {
struct notifier_block *nb;
};
+enum netif_async_state {
+ NETIF_ASYNC_ACTIVE,
+ NETIF_ASYNC_DOWN,
+ NETIF_ASYNC_INACTIVE
+};
+
+struct netif_async_ctx {
+ enum netif_async_state state;
+};
+
/*
* This structure defines the management hooks for network devices.
* The following hooks can be defined; unless noted otherwise, they are
@@ -2027,6 +2037,8 @@ enum netdev_reg_state {
* @sfp_bus: attached &struct sfp_bus structure.
*
* @qdisc_tx_busylock: lockdep class annotating Qdisc->busylock spinlock
+ * @async_ctx : Context required for async ops
+ * @needs_async_ctx : Does dev need async op context?
*
* @proto_down: protocol port state information can be sent to the
* switch driver and used to set the phys state of the
@@ -2454,6 +2466,8 @@ struct net_device {
struct phy_device *phydev;
struct sfp_bus *sfp_bus;
struct lock_class_key *qdisc_tx_busylock;
+ struct netif_async_ctx *async_ctx;
+ bool needs_async_ctx;
bool proto_down;
bool irq_affinity_auto;
bool rx_cpu_rmap_auto;
@@ -3376,6 +3390,21 @@ int dev_loopback_xmit(struct net *net, struct sock *sk, struct sk_buff *newskb);
u16 dev_pick_tx_zero(struct net_device *dev, struct sk_buff *skb,
struct net_device *sb_dev);
+void netif_disable_async_ops(struct net_device *dev);
+void netif_enable_async_ops(struct net_device *dev);
+
+static inline void netif_set_async_state(struct net_device *dev,
+ enum netif_async_state state)
+{
+ dev->async_ctx->state = state;
+}
+
+static inline enum netif_async_state
+netif_get_async_state(struct net_device *dev)
+{
+ return dev->async_ctx->state;
+}
+
int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev);
int __dev_direct_xmit(struct sk_buff *skb, u16 queue_id);
diff --git a/net/core/dev.c b/net/core/dev.c
index 200d44883fc1..b1797bd28a6b 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1664,6 +1664,33 @@ static int napi_kthread_create(struct napi_struct *n)
return err;
}
+static int __netif_alloc_async_ctx(struct net_device *dev)
+{
+ dev->async_ctx = kzalloc_obj(*dev->async_ctx);
+ if (!dev->async_ctx)
+ return -ENOMEM;
+
+ netif_set_async_state(dev, NETIF_ASYNC_ACTIVE);
+ return 0;
+}
+
+static int netif_alloc_async_ctx(struct net_device *dev)
+{
+ int ret;
+
+ ret = __netif_alloc_async_ctx(dev);
+ return ret;
+}
+
+static void netif_free_async_ctx(struct net_device *dev)
+{
+ if (!dev->async_ctx)
+ return;
+
+ kfree(dev->async_ctx);
+ dev->async_ctx = NULL;
+}
+
static int __dev_open(struct net_device *dev, struct netlink_ext_ack *extack)
{
const struct net_device_ops *ops = dev->netdev_ops;
@@ -1698,14 +1725,18 @@ static int __dev_open(struct net_device *dev, struct netlink_ext_ack *extack)
if (ops->ndo_validate_addr)
ret = ops->ndo_validate_addr(dev);
+ if (!ret && dev->needs_async_ctx)
+ ret = netif_alloc_async_ctx(dev);
+
if (!ret && ops->ndo_open)
ret = ops->ndo_open(dev);
netpoll_poll_enable(dev);
- if (ret)
+ if (ret) {
clear_bit(__LINK_STATE_START, &dev->state);
- else {
+ netif_free_async_ctx(dev);
+ } else {
netif_set_up(dev, true);
dev_set_rx_mode(dev);
dev_activate(dev);
@@ -1772,6 +1803,11 @@ static void __dev_close_many(struct list_head *head)
netdev_ops_assert_locked(dev);
+ if (dev->needs_async_ctx) {
+ netif_set_async_state(dev, NETIF_ASYNC_DOWN);
+ netif_free_async_ctx(dev);
+ }
+
if (ops->ndo_stop)
ops->ndo_stop(dev);
@@ -1821,6 +1857,50 @@ void netif_close(struct net_device *dev)
}
EXPORT_SYMBOL(netif_close);
+/* netif_disable_async_ops - disable execution of async NDOs.
+ *
+ * To be used in cases of the device shutting down, suspending or
+ * failing to resume.
+ *
+ * Should be called in the shutdown callback and in the PM suspend
+ * callbacks: @suspend(), @freeze(), @poweroff() and in the error
+ * path of PM resume callbacks.
+ */
+void netif_disable_async_ops(struct net_device *dev)
+{
+ netdev_lock_ops_compat(dev);
+
+ if (!dev->needs_async_ctx || !netif_running(dev)) {
+ netdev_unlock_ops_compat(dev);
+ return;
+ }
+
+ netif_set_async_state(dev, NETIF_ASYNC_INACTIVE);
+ netdev_unlock_ops_compat(dev);
+}
+EXPORT_SYMBOL(netif_disable_async_ops);
+
+/* netif_enable_async_ops - enable execution of async NDOs.
+ *
+ * To be used when the device attempts to resume or fails to suspend.
+ *
+ * Should be called in the PM resume callbacks: @resume(), @thaw(),
+ * @restore() and in the error path of PM suspend callbacks.
+ */
+void netif_enable_async_ops(struct net_device *dev)
+{
+ netdev_lock_ops_compat(dev);
+
+ if (!dev->needs_async_ctx || !netif_running(dev)) {
+ netdev_unlock_ops_compat(dev);
+ return;
+ }
+
+ netif_set_async_state(dev, NETIF_ASYNC_ACTIVE);
+ netdev_unlock_ops_compat(dev);
+}
+EXPORT_SYMBOL(netif_enable_async_ops);
+
void netif_disable_lro(struct net_device *dev)
{
struct net_device *lower_dev;
--
2.47.3
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v9 2/7] net: core: Introduce callback ndo_set_rx_mode_async
2026-03-14 18:28 [PATCH net-next v9 0/7] Introduce async callback ndo_set_rx_mode_async I Viswanath
2026-03-14 18:28 ` [PATCH net-next v9 1/7] net: core: Add state tracking for async netdev ops I Viswanath
@ 2026-03-14 18:28 ` I Viswanath
2026-03-16 7:29 ` [Intel-wired-lan] " Loktionov, Aleksandr
2026-03-14 18:28 ` [PATCH net-next v9 3/7] virtio-net: Implement ndo_set_rx_mode_async callback I Viswanath
` (5 subsequent siblings)
7 siblings, 1 reply; 18+ messages in thread
From: I Viswanath @ 2026-03-14 18:28 UTC (permalink / raw)
To: stfomichev, horms, edumazet, pabeni, andrew+netdev, kuba, davem,
eperezma, xuanzhuo, jasowang, mst, przemyslaw.kitszel,
anthony.l.nguyen, jacob.e.keller, ronak.doshi, pcnet32
Cc: bcm-kernel-feedback-list, netdev, virtualization, intel-wired-lan,
linux-kernel, I Viswanath
The set_rx_mode callback is invoked under the addr_lock spinlock which
makes it illegal to sleep. This means set_rx_mode is prone to
sleep-in-atomic bugs as drivers have a tendency to do the I/O directly
in the callback.
This problem can be avoided if set_rx_mode were done in 2 stages: snapshot
and commit. A handful of drivers implement this idea by implementing the
rx_mode update as work and scheduling it in the set_rx_mode callback.
Implement this idea in net/core as this is not driver specific. To
facilitate this transition, a new async callback set_rx_mode_async
is introduced.
When this callback is provided, the set_rx_mode callback customizes
the snapshot creation and the work behaviour as required while the
set_rx_mode_async callback is run async as work and commits the
prepared snapshot.
Apart from this, the drivers need to be updated to have all the RX mode
updates pass through the netif_set_rx_mode helper to ensure correctness.
Suggested-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: I Viswanath <viswanathiyyappan@gmail.com>
---
include/linux/netdevice.h | 94 +++++++++++++-
include/net/netdev_lock.h | 8 ++
net/core/dev.c | 251 +++++++++++++++++++++++++++++++++++++-
3 files changed, 347 insertions(+), 6 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 6d426dc66af9..a69377068f4a 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1068,7 +1068,36 @@ enum netif_async_state {
NETIF_ASYNC_INACTIVE
};
+enum netif_rx_mode_cfg {
+ NETIF_RX_MODE_CFG_ALLMULTI,
+ NETIF_RX_MODE_CFG_PROMISC,
+ NETIF_RX_MODE_CFG_BROADCAST
+};
+
+enum netif_rx_mode_flags {
+ NETIF_RX_MODE_READY,
+ NETIF_RX_MODE_UC_SKIP,
+ NETIF_RX_MODE_MC_SKIP
+};
+
+struct netif_rx_mode_config {
+ char *uc_addrs;
+ char *mc_addrs;
+ int uc_count;
+ int mc_count;
+ int cfg;
+};
+
+struct netif_rx_mode_work {
+ struct netif_rx_mode_config *pending;
+ struct netif_rx_mode_config *ready;
+ struct work_struct work;
+ struct net_device *dev;
+ int flags;
+};
+
struct netif_async_ctx {
+ struct netif_rx_mode_work *rx_mode_work;
enum netif_async_state state;
};
@@ -1124,9 +1153,15 @@ struct netif_async_ctx {
* changes to configuration when multicast or promiscuous is enabled.
*
* void (*ndo_set_rx_mode)(struct net_device *dev);
- * This function is called device changes address list filtering.
+ * This function is called when device changes address list filtering.
* If driver handles unicast address filtering, it should set
- * IFF_UNICAST_FLT in its priv_flags.
+ * IFF_UNICAST_FLT in its priv_flags. If the ndo_set_rx_mode_async
+ * callback is provided, This would be used to set up the
+ * rx mode snapshot that will be committed by ndo_set_rx_mode_async.
+ *
+ * void (*ndo_set_rx_mode_async)(struct net_device *dev);
+ * This function will be scheduled by dev_set_rx_mode and is
+ * responsible for committing the rx_mode snapshot to the hardware.
*
* int (*ndo_set_mac_address)(struct net_device *dev, void *addr);
* This function is called when the Media Access Control address
@@ -1447,6 +1482,7 @@ struct net_device_ops {
void (*ndo_change_rx_flags)(struct net_device *dev,
int flags);
void (*ndo_set_rx_mode)(struct net_device *dev);
+ void (*ndo_set_rx_mode_async)(struct net_device *dev);
int (*ndo_set_mac_address)(struct net_device *dev,
void *addr);
int (*ndo_validate_addr)(struct net_device *dev);
@@ -3405,6 +3441,60 @@ netif_get_async_state(struct net_device *dev)
return dev->async_ctx->state;
}
+void netif_set_rx_mode(struct net_device *dev);
+
+/* Helpers to be used in the set_rx_mode callback */
+static inline void netif_set_rx_mode_cfg(struct net_device *dev, int b,
+ bool val)
+{
+ if (val)
+ dev->async_ctx->rx_mode_work->pending->cfg |= BIT(b);
+ else
+ dev->async_ctx->rx_mode_work->pending->cfg &= ~BIT(b);
+}
+
+static inline void netif_set_rx_mode_flag(struct net_device *dev, int b,
+ bool val)
+{
+ if (val)
+ dev->async_ctx->rx_mode_work->flags |= BIT(b);
+ else
+ dev->async_ctx->rx_mode_work->flags &= ~BIT(b);
+}
+
+/* Helpers to be used in the set_rx_mode_async callback */
+static inline bool netif_get_rx_mode_cfg(struct net_device *dev, int b)
+{
+ return !!(dev->async_ctx->rx_mode_work->ready->cfg & BIT(b));
+}
+
+static inline bool netif_get_rx_mode_flag(struct net_device *dev, int b)
+{
+ return !!(dev->async_ctx->rx_mode_work->flags & BIT(b));
+}
+
+static inline int netif_rx_mode_uc_count(struct net_device *dev)
+{
+ return dev->async_ctx->rx_mode_work->ready->uc_count;
+}
+
+static inline int netif_rx_mode_mc_count(struct net_device *dev)
+{
+ return dev->async_ctx->rx_mode_work->ready->mc_count;
+}
+
+#define netif_rx_mode_for_each_uc_addr(ha_addr, dev, __i) \
+ for (__i = 0, \
+ ha_addr = (dev)->async_ctx->rx_mode_work->ready->uc_addrs; \
+ __i < (dev)->async_ctx->rx_mode_work->ready->uc_count; \
+ __i++, ha_addr += (dev)->addr_len)
+
+#define netif_rx_mode_for_each_mc_addr(ha_addr, dev, __i) \
+ for (__i = 0, \
+ ha_addr = (dev)->async_ctx->rx_mode_work->ready->mc_addrs; \
+ __i < (dev)->async_ctx->rx_mode_work->ready->mc_count; \
+ __i++, ha_addr += (dev)->addr_len)
+
int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev);
int __dev_direct_xmit(struct sk_buff *skb, u16 queue_id);
diff --git a/include/net/netdev_lock.h b/include/net/netdev_lock.h
index 3d3aef80beac..118fa89232a0 100644
--- a/include/net/netdev_lock.h
+++ b/include/net/netdev_lock.h
@@ -80,6 +80,14 @@ netdev_ops_assert_locked_or_invisible(const struct net_device *dev)
netdev_ops_assert_locked(dev);
}
+static inline bool netdev_trylock_ops_compat(struct net_device *dev)
+{
+ if (netdev_need_ops_lock(dev))
+ return netdev_trylock(dev);
+ else
+ return rtnl_trylock();
+}
+
static inline void netdev_lock_ops_compat(struct net_device *dev)
{
if (netdev_need_ops_lock(dev))
diff --git a/net/core/dev.c b/net/core/dev.c
index b1797bd28a6b..acf46a304d62 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1664,6 +1664,92 @@ static int napi_kthread_create(struct napi_struct *n)
return err;
}
+static void dev_set_rx_mode_async(struct work_struct *param)
+{
+ struct netif_rx_mode_work *ctx;
+ struct net_device *dev;
+
+ ctx = container_of(param, struct netif_rx_mode_work, work);
+ dev = ctx->dev;
+
+ /* This handler requires the instance lock and we cancel this work
+ * in dev_close where it is already held, resulting in a deadlock.
+ * Avoid that scenario by trying to acquire the lock and bailing
+ * out when we are in teardown.
+ */
+ while (!netdev_trylock_ops_compat(dev)) {
+ if (netif_get_async_state(dev) == NETIF_ASYNC_DOWN)
+ return;
+
+ msleep(20);
+ }
+
+ /* We could introduce a new lock for this but reusing the addr
+ * lock works well enough
+ */
+ netif_addr_lock_bh(dev);
+ if (!netif_get_rx_mode_flag(dev, NETIF_RX_MODE_READY)) {
+ netif_addr_unlock_bh(dev);
+ goto out;
+ }
+ swap(ctx->ready, ctx->pending);
+ netif_set_rx_mode_flag(dev, NETIF_RX_MODE_READY, false);
+ netif_addr_unlock_bh(dev);
+
+ dev->netdev_ops->ndo_set_rx_mode_async(dev);
+out:
+ netdev_unlock_ops_compat(dev);
+}
+
+static int netif_alloc_rx_mode_ctx(struct net_device *dev)
+{
+ struct netif_rx_mode_work *rx_mode_work;
+
+ rx_mode_work = kzalloc_obj(*rx_mode_work);
+ if (!rx_mode_work)
+ goto fail;
+
+ rx_mode_work->ready = kzalloc_obj(*rx_mode_work->ready);
+ if (!rx_mode_work->ready)
+ goto fail_ready;
+
+ rx_mode_work->pending = kzalloc_obj(*rx_mode_work->pending);
+ if (!rx_mode_work->pending)
+ goto fail_pending;
+
+ INIT_WORK(&rx_mode_work->work, dev_set_rx_mode_async);
+ rx_mode_work->dev = dev;
+
+ dev->async_ctx->rx_mode_work = rx_mode_work;
+ return 0;
+
+fail_pending:
+ kfree(rx_mode_work->ready);
+fail_ready:
+ kfree(rx_mode_work);
+fail:
+ return -ENOMEM;
+}
+
+static void netif_free_rx_mode_ctx(struct net_device *dev)
+{
+ if (!dev->async_ctx->rx_mode_work)
+ return;
+
+ cancel_work_sync(&dev->async_ctx->rx_mode_work->work);
+
+ kfree(dev->async_ctx->rx_mode_work->ready->uc_addrs);
+ kfree(dev->async_ctx->rx_mode_work->ready->mc_addrs);
+ kfree(dev->async_ctx->rx_mode_work->ready);
+
+ kfree(dev->async_ctx->rx_mode_work->pending->uc_addrs);
+ kfree(dev->async_ctx->rx_mode_work->pending->mc_addrs);
+ kfree(dev->async_ctx->rx_mode_work->pending);
+
+ kfree(dev->async_ctx->rx_mode_work);
+ dev->async_ctx->rx_mode_work = NULL;
+}
+
static int __netif_alloc_async_ctx(struct net_device *dev)
{
dev->async_ctx = kzalloc_obj(*dev->async_ctx);
@@ -1676,17 +1762,27 @@ static int __netif_alloc_async_ctx(struct net_device *dev)
static int netif_alloc_async_ctx(struct net_device *dev)
{
+ const struct net_device_ops *ops = dev->netdev_ops;
int ret;
ret = __netif_alloc_async_ctx(dev);
+
+ if (!ret && ops->ndo_set_rx_mode_async)
+ ret = netif_alloc_rx_mode_ctx(dev);
+
return ret;
}
static void netif_free_async_ctx(struct net_device *dev)
{
+ const struct net_device_ops *ops = dev->netdev_ops;
+
if (!dev->async_ctx)
return;
+ if (ops->ndo_set_rx_mode_async)
+ netif_free_rx_mode_ctx(dev);
+
kfree(dev->async_ctx);
dev->async_ctx = NULL;
}
@@ -1868,6 +1964,8 @@ EXPORT_SYMBOL(netif_close);
*/
void netif_disable_async_ops(struct net_device *dev)
{
+ const struct net_device_ops *ops = dev->netdev_ops;
+
netdev_lock_ops_compat(dev);
if (!dev->needs_async_ctx || !netif_running(dev)) {
@@ -1877,6 +1975,9 @@ void netif_disable_async_ops(struct net_device *dev)
netif_set_async_state(dev, NETIF_ASYNC_INACTIVE);
netdev_unlock_ops_compat(dev);
+
+ if (ops->ndo_set_rx_mode_async)
+ cancel_work_sync(&dev->async_ctx->rx_mode_work->work);
}
EXPORT_SYMBOL(netif_disable_async_ops);
@@ -9749,6 +9850,88 @@ int netif_set_allmulti(struct net_device *dev, int inc, bool notify)
return 0;
}
+static int __netif_prepare_rx_mode(struct net_device *dev)
+{
+ bool skip_uc = false, skip_mc = false;
+ struct netif_rx_mode_config *pending;
+ int uc_count = 0, mc_count = 0;
+ struct netdev_hw_addr *ha;
+ char *tmp;
+ int i;
+
+ pending = dev->async_ctx->rx_mode_work->pending;
+
+ skip_uc = netif_get_rx_mode_flag(dev, NETIF_RX_MODE_UC_SKIP);
+ skip_mc = netif_get_rx_mode_flag(dev, NETIF_RX_MODE_MC_SKIP);
+
+ /* The allocations need to be atomic since this will be called under
+ * netif_addr_lock_bh()
+ */
+ if (!skip_uc) {
+ uc_count = netdev_uc_count(dev);
+ tmp = krealloc(pending->uc_addrs, uc_count * dev->addr_len,
+ GFP_ATOMIC);
+ if (!tmp)
+ return -ENOMEM;
+
+ i = 0;
+ pending->uc_addrs = tmp;
+ pending->uc_count = uc_count;
+ netdev_for_each_uc_addr(ha, dev)
+ memcpy(pending->uc_addrs + (i++) * dev->addr_len,
+ ha->addr, dev->addr_len);
+ }
+
+ if (!skip_mc) {
+ mc_count = netdev_mc_count(dev);
+ tmp = krealloc(pending->mc_addrs, mc_count * dev->addr_len,
+ GFP_ATOMIC);
+ if (!tmp)
+ return -ENOMEM;
+
+ i = 0;
+ pending->mc_addrs = tmp;
+ pending->mc_count = mc_count;
+ netdev_for_each_mc_addr(ha, dev)
+ memcpy(pending->mc_addrs + (i++) * dev->addr_len,
+ ha->addr, dev->addr_len);
+ }
+
+ return 0;
+}
+
+/* Attempt to prepare the rx_mode snapshot and if successful,
+ * signal that it's ready.
+ */
+static int netif_prepare_rx_mode(struct net_device *dev)
+{
+ int rc;
+
+ lockdep_assert_held(&dev->addr_list_lock);
+ rc = __netif_prepare_rx_mode(dev);
+ netif_set_rx_mode_flag(dev, NETIF_RX_MODE_READY, (rc == 0));
+ return rc;
+}
+
+static void netif_schedule_rx_mode_work(struct net_device *dev)
+{
+ const struct net_device_ops *ops = dev->netdev_ops;
+
+ if (ops->ndo_set_rx_mode)
+ ops->ndo_set_rx_mode(dev);
+
+ if (!ops->ndo_set_rx_mode_async)
+ return;
+
+ if (netif_get_async_state(dev) == NETIF_ASYNC_INACTIVE)
+ return;
+
+ if (netif_prepare_rx_mode(dev))
+ return;
+
+ schedule_work(&dev->async_ctx->rx_mode_work->work);
+}
+
/*
* Upload unicast and multicast address lists to device and
* configure RX filtering. When the device doesn't support unicast
@@ -9757,8 +9940,6 @@ int netif_set_allmulti(struct net_device *dev, int inc, bool notify)
*/
void __dev_set_rx_mode(struct net_device *dev)
{
- const struct net_device_ops *ops = dev->netdev_ops;
-
/* dev_open will call this function so the list will stay sane. */
if (!(dev->flags&IFF_UP))
return;
@@ -9779,8 +9960,7 @@ void __dev_set_rx_mode(struct net_device *dev)
}
}
- if (ops->ndo_set_rx_mode)
- ops->ndo_set_rx_mode(dev);
+ netif_schedule_rx_mode_work(dev);
}
void dev_set_rx_mode(struct net_device *dev)
@@ -9790,6 +9970,66 @@ void dev_set_rx_mode(struct net_device *dev)
netif_addr_unlock_bh(dev);
}
+/* netif_set_rx_mode() - Helper to centralize RX mode requests in core.
+ *
+ * If ndo_set_rx_mode_async is provided, perform the required
+ * setup and invoke ndo_set_rx_mode_async callback. Otherwise this is the
+ * same as invoking the ndo_set_rx_mode callback.
+ *
+ * If ndo_set_rx_mode_async is implemented, the driver must perform all
+ * RX mode updates via this function and invoking the set_rx_mode callback
+ * directly is a bug.
+ */
+void netif_set_rx_mode(struct net_device *dev)
+{
+ const struct net_device_ops *ops = dev->netdev_ops;
+ struct netif_rx_mode_work *ctx;
+ bool netif_down;
+ int rc = 0;
+
+ if (WARN_ON(!ops->ndo_set_rx_mode))
+ return;
+
+ if (!ops->ndo_set_rx_mode_async) {
+ ops->ndo_set_rx_mode(dev);
+ return;
+ }
+
+ netdev_ops_assert_locked(dev);
+
+ netif_down = !netif_running(dev);
+ if (netif_down) {
+ rc = __netif_alloc_async_ctx(dev);
+ if (!rc)
+ rc = netif_alloc_rx_mode_ctx(dev);
+ if (rc)
+ goto out;
+ }
+
+ netif_addr_lock_bh(dev);
+ ops->ndo_set_rx_mode(dev);
+ rc = netif_prepare_rx_mode(dev);
+ if (rc) {
+ netif_addr_unlock_bh(dev);
+ goto out;
+ }
+
+ /* There might be a work scheduled by dev_set_rx_mode before
+ * this function's execution that could be using outdated
+ * config. Clear the ready bit to prevent that work's execution.
+ */
+ ctx = dev->async_ctx->rx_mode_work;
+ swap(ctx->ready, ctx->pending);
+ netif_set_rx_mode_flag(dev, NETIF_RX_MODE_READY, false);
+ netif_addr_unlock_bh(dev);
+
+ ops->ndo_set_rx_mode_async(dev);
+out:
+ if (netif_down)
+ netif_free_async_ctx(dev);
+}
+EXPORT_SYMBOL(netif_set_rx_mode);
+
/**
* netif_get_flags() - get flags reported to userspace
* @dev: device
@@ -11451,6 +11691,9 @@ int register_netdevice(struct net_device *dev)
}
}
+ if (dev->netdev_ops->ndo_set_rx_mode_async)
+ dev->needs_async_ctx = true;
+
if (((dev->hw_features | dev->features) &
NETIF_F_HW_VLAN_CTAG_FILTER) &&
(!dev->netdev_ops->ndo_vlan_rx_add_vid ||
--
2.47.3
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v9 3/7] virtio-net: Implement ndo_set_rx_mode_async callback
2026-03-14 18:28 [PATCH net-next v9 0/7] Introduce async callback ndo_set_rx_mode_async I Viswanath
2026-03-14 18:28 ` [PATCH net-next v9 1/7] net: core: Add state tracking for async netdev ops I Viswanath
2026-03-14 18:28 ` [PATCH net-next v9 2/7] net: core: Introduce callback ndo_set_rx_mode_async I Viswanath
@ 2026-03-14 18:28 ` I Viswanath
2026-03-16 7:30 ` [Intel-wired-lan] " Loktionov, Aleksandr
2026-03-14 18:28 ` [PATCH net-next v9 4/7] e1000: " I Viswanath
` (4 subsequent siblings)
7 siblings, 1 reply; 18+ messages in thread
From: I Viswanath @ 2026-03-14 18:28 UTC (permalink / raw)
To: stfomichev, horms, edumazet, pabeni, andrew+netdev, kuba, davem,
eperezma, xuanzhuo, jasowang, mst, przemyslaw.kitszel,
anthony.l.nguyen, jacob.e.keller, ronak.doshi, pcnet32
Cc: bcm-kernel-feedback-list, netdev, virtualization, intel-wired-lan,
linux-kernel, I Viswanath
Implement the ndo_set_rx_mode_async callback and update
the driver to use the snapshot/commit model for RX mode update.
Signed-off-by: I Viswanath <viswanathiyyappan@gmail.com>
---
There are no calls to netif_set_rx_mode in virtio-net
drivers/net/virtio_net.c | 85 ++++++++++++----------------------------
1 file changed, 25 insertions(+), 60 deletions(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 811b90da15a9..70255d09401c 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -448,12 +448,6 @@ struct virtnet_info {
/* Work struct for config space updates */
struct work_struct config_work;
- /* Work struct for setting rx mode */
- struct work_struct rx_mode_work;
-
- /* OK to queue work setting RX mode? */
- bool rx_mode_work_enabled;
-
/* Does the affinity hint is set for virtqueues? */
bool affinity_hint_set;
@@ -717,20 +711,6 @@ static void virtnet_rq_free_buf(struct virtnet_info *vi,
put_page(virt_to_head_page(buf));
}
-static void enable_rx_mode_work(struct virtnet_info *vi)
-{
- rtnl_lock();
- vi->rx_mode_work_enabled = true;
- rtnl_unlock();
-}
-
-static void disable_rx_mode_work(struct virtnet_info *vi)
-{
- rtnl_lock();
- vi->rx_mode_work_enabled = false;
- rtnl_unlock();
-}
-
static void virtqueue_napi_schedule(struct napi_struct *napi,
struct virtqueue *vq)
{
@@ -3802,33 +3782,30 @@ static int virtnet_close(struct net_device *dev)
return 0;
}
-static void virtnet_rx_mode_work(struct work_struct *work)
+static void virtnet_set_rx_mode_async(struct net_device *dev)
{
- struct virtnet_info *vi =
- container_of(work, struct virtnet_info, rx_mode_work);
+ struct virtnet_info *vi = netdev_priv(dev);
u8 *promisc_allmulti __free(kfree) = NULL;
- struct net_device *dev = vi->dev;
struct scatterlist sg[2];
struct virtio_net_ctrl_mac *mac_data;
- struct netdev_hw_addr *ha;
+ char *ha_addr;
int uc_count;
int mc_count;
void *buf;
- int i;
+ int i, ni;
- /* We can't dynamically set ndo_set_rx_mode, so return gracefully */
+ /* We can't dynamically set rx_mode, so return gracefully */
if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_RX))
return;
- promisc_allmulti = kzalloc_obj(*promisc_allmulti);
+ promisc_allmulti = kzalloc_obj(*promisc_allmulti, GFP_ATOMIC);
if (!promisc_allmulti) {
dev_warn(&dev->dev, "Failed to set RX mode, no memory.\n");
return;
}
- rtnl_lock();
-
- *promisc_allmulti = !!(dev->flags & IFF_PROMISC);
+ *promisc_allmulti = netif_get_rx_mode_cfg(dev,
+ NETIF_RX_MODE_CFG_PROMISC);
sg_init_one(sg, promisc_allmulti, sizeof(*promisc_allmulti));
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX,
@@ -3836,7 +3813,8 @@ static void virtnet_rx_mode_work(struct work_struct *work)
dev_warn(&dev->dev, "Failed to %sable promisc mode.\n",
*promisc_allmulti ? "en" : "dis");
- *promisc_allmulti = !!(dev->flags & IFF_ALLMULTI);
+ *promisc_allmulti = netif_get_rx_mode_cfg(dev,
+ NETIF_RX_MODE_CFG_ALLMULTI);
sg_init_one(sg, promisc_allmulti, sizeof(*promisc_allmulti));
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX,
@@ -3844,27 +3822,22 @@ static void virtnet_rx_mode_work(struct work_struct *work)
dev_warn(&dev->dev, "Failed to %sable allmulti mode.\n",
*promisc_allmulti ? "en" : "dis");
- netif_addr_lock_bh(dev);
-
- uc_count = netdev_uc_count(dev);
- mc_count = netdev_mc_count(dev);
+ uc_count = netif_rx_mode_uc_count(dev);
+ mc_count = netif_rx_mode_mc_count(dev);
/* MAC filter - use one buffer for both lists */
buf = kzalloc(((uc_count + mc_count) * ETH_ALEN) +
(2 * sizeof(mac_data->entries)), GFP_ATOMIC);
mac_data = buf;
- if (!buf) {
- netif_addr_unlock_bh(dev);
- rtnl_unlock();
+ if (!buf)
return;
- }
sg_init_table(sg, 2);
/* Store the unicast list and count in the front of the buffer */
mac_data->entries = cpu_to_virtio32(vi->vdev, uc_count);
i = 0;
- netdev_for_each_uc_addr(ha, dev)
- memcpy(&mac_data->macs[i++][0], ha->addr, ETH_ALEN);
+ netif_rx_mode_for_each_uc_addr(ha_addr, dev, ni)
+ memcpy(&mac_data->macs[i++][0], ha_addr, ETH_ALEN);
sg_set_buf(&sg[0], mac_data,
sizeof(mac_data->entries) + (uc_count * ETH_ALEN));
@@ -3874,10 +3847,8 @@ static void virtnet_rx_mode_work(struct work_struct *work)
mac_data->entries = cpu_to_virtio32(vi->vdev, mc_count);
i = 0;
- netdev_for_each_mc_addr(ha, dev)
- memcpy(&mac_data->macs[i++][0], ha->addr, ETH_ALEN);
-
- netif_addr_unlock_bh(dev);
+ netif_rx_mode_for_each_mc_addr(ha_addr, dev, ni)
+ memcpy(&mac_data->macs[i++][0], ha_addr, ETH_ALEN);
sg_set_buf(&sg[1], mac_data,
sizeof(mac_data->entries) + (mc_count * ETH_ALEN));
@@ -3886,17 +3857,16 @@ static void virtnet_rx_mode_work(struct work_struct *work)
VIRTIO_NET_CTRL_MAC_TABLE_SET, sg))
dev_warn(&dev->dev, "Failed to set MAC filter table.\n");
- rtnl_unlock();
-
kfree(buf);
}
static void virtnet_set_rx_mode(struct net_device *dev)
{
- struct virtnet_info *vi = netdev_priv(dev);
+ bool allmulti = !!(dev->flags & IFF_ALLMULTI);
+ bool promisc = !!(dev->flags & IFF_PROMISC);
- if (vi->rx_mode_work_enabled)
- schedule_work(&vi->rx_mode_work);
+ netif_set_rx_mode_cfg(dev, NETIF_RX_MODE_CFG_ALLMULTI, allmulti);
+ netif_set_rx_mode_cfg(dev, NETIF_RX_MODE_CFG_PROMISC, promisc);
}
static int virtnet_vlan_rx_add_vid(struct net_device *dev,
@@ -5711,8 +5681,6 @@ static void virtnet_freeze_down(struct virtio_device *vdev)
/* Make sure no work handler is accessing the device */
flush_work(&vi->config_work);
- disable_rx_mode_work(vi);
- flush_work(&vi->rx_mode_work);
if (netif_running(vi->dev)) {
rtnl_lock();
@@ -5738,8 +5706,6 @@ static int virtnet_restore_up(struct virtio_device *vdev)
virtio_device_ready(vdev);
- enable_rx_mode_work(vi);
-
if (netif_running(vi->dev)) {
rtnl_lock();
err = virtnet_open(vi->dev);
@@ -6214,6 +6180,7 @@ static const struct net_device_ops virtnet_netdev = {
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = virtnet_set_mac_address,
.ndo_set_rx_mode = virtnet_set_rx_mode,
+ .ndo_set_rx_mode_async = virtnet_set_rx_mode_async,
.ndo_get_stats64 = virtnet_stats,
.ndo_vlan_rx_add_vid = virtnet_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = virtnet_vlan_rx_kill_vid,
@@ -6834,7 +6801,6 @@ static int virtnet_probe(struct virtio_device *vdev)
vdev->priv = vi;
INIT_WORK(&vi->config_work, virtnet_config_changed_work);
- INIT_WORK(&vi->rx_mode_work, virtnet_rx_mode_work);
if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF)) {
vi->mergeable_rx_bufs = true;
@@ -6986,8 +6952,6 @@ static int virtnet_probe(struct virtio_device *vdev)
if (vi->has_rss || vi->has_rss_hash_report)
virtnet_init_default_rss(vi);
- enable_rx_mode_work(vi);
-
/* serialize netdev register + virtio_device_ready() with ndo_open() */
rtnl_lock();
@@ -7136,8 +7100,6 @@ static void virtnet_remove(struct virtio_device *vdev)
/* Make sure no work handler is accessing the device. */
flush_work(&vi->config_work);
- disable_rx_mode_work(vi);
- flush_work(&vi->rx_mode_work);
virtnet_free_irq_moder(vi);
@@ -7158,6 +7120,7 @@ static __maybe_unused int virtnet_freeze(struct virtio_device *vdev)
virtnet_freeze_down(vdev);
remove_vq_common(vi);
+ netif_disable_async_ops(vi->dev);
return 0;
}
@@ -7166,6 +7129,7 @@ static __maybe_unused int virtnet_restore(struct virtio_device *vdev)
struct virtnet_info *vi = vdev->priv;
int err;
+ netif_enable_async_ops(vi->dev);
err = virtnet_restore_up(vdev);
if (err)
return err;
@@ -7175,6 +7139,7 @@ static __maybe_unused int virtnet_restore(struct virtio_device *vdev)
if (err) {
virtnet_freeze_down(vdev);
remove_vq_common(vi);
+ netif_disable_async_ops(vi->dev);
return err;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v9 4/7] e1000: Implement ndo_set_rx_mode_async callback
2026-03-14 18:28 [PATCH net-next v9 0/7] Introduce async callback ndo_set_rx_mode_async I Viswanath
` (2 preceding siblings ...)
2026-03-14 18:28 ` [PATCH net-next v9 3/7] virtio-net: Implement ndo_set_rx_mode_async callback I Viswanath
@ 2026-03-14 18:28 ` I Viswanath
2026-03-16 7:30 ` [Intel-wired-lan] " Loktionov, Aleksandr
2026-03-14 18:28 ` [PATCH net-next v9 5/7] 8139cp: " I Viswanath
` (3 subsequent siblings)
7 siblings, 1 reply; 18+ messages in thread
From: I Viswanath @ 2026-03-14 18:28 UTC (permalink / raw)
To: stfomichev, horms, edumazet, pabeni, andrew+netdev, kuba, davem,
eperezma, xuanzhuo, jasowang, mst, przemyslaw.kitszel,
anthony.l.nguyen, jacob.e.keller, ronak.doshi, pcnet32
Cc: bcm-kernel-feedback-list, netdev, virtualization, intel-wired-lan,
linux-kernel, I Viswanath
Implement the ndo_set_rx_mode_async callback and update
the driver to use the snapshot/commit model for RX mode update.
Signed-off-by: I Viswanath <viswanathiyyappan@gmail.com>
---
Call paths involving netif_set_rx_mode in e1000
netif_set_rx_mode
|-- __e1000_shutdown (lock added)
|
`-- e1000_configure
|-- e1000_open (ndo_open, takes lock)
|
`-- e1000_up
|-- e1000_reinit_locked
| |-- e1000_set_features (ndo_set_features, takes lock)
| |-- e1000_reset_task (ethtool callback, takes lock)
| |-- e1000_mii_ioctl
| | `-- e1000_ioctl (ndo_do_ioctl, takes lock)
| `-- e1000_nway_reset (ethtool callback, takes lock)
|
|-- e1000_change_mtu (ndo_change_mtu, takes lock)
|-- e1000_resume (lock added)
|-- e1000_io_resume (lock added)
|
|-- e1000_set_link_ksettings (ethtool callback, takes lock)
|-- e1000_set_pauseparam (ethtool callback, takes lock)
`-- e1000_set_ringparam (ethtool callback, takes lock)
drivers/net/ethernet/intel/e1000/e1000_main.c | 77 ++++++++++++++-----
1 file changed, 59 insertions(+), 18 deletions(-)
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 9b09eb144b81..ec25b41c63b7 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -99,6 +99,7 @@ static void e1000_clean_tx_ring(struct e1000_adapter *adapter,
static void e1000_clean_rx_ring(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring);
static void e1000_set_rx_mode(struct net_device *netdev);
+static void e1000_set_rx_mode_async(struct net_device *netdev);
static void e1000_update_phy_info_task(struct work_struct *work);
static void e1000_watchdog(struct work_struct *work);
static void e1000_82547_tx_fifo_stall_task(struct work_struct *work);
@@ -359,7 +360,7 @@ static void e1000_configure(struct e1000_adapter *adapter)
struct net_device *netdev = adapter->netdev;
int i;
- e1000_set_rx_mode(netdev);
+ netif_set_rx_mode(netdev);
e1000_restore_vlan(adapter);
e1000_init_manageability(adapter);
@@ -823,6 +824,7 @@ static const struct net_device_ops e1000_netdev_ops = {
.ndo_stop = e1000_close,
.ndo_start_xmit = e1000_xmit_frame,
.ndo_set_rx_mode = e1000_set_rx_mode,
+ .ndo_set_rx_mode_async = e1000_set_rx_mode_async,
.ndo_set_mac_address = e1000_set_mac,
.ndo_tx_timeout = e1000_tx_timeout,
.ndo_change_mtu = e1000_change_mtu,
@@ -2223,23 +2225,44 @@ static int e1000_set_mac(struct net_device *netdev, void *p)
}
/**
- * e1000_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode set
+ * e1000_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode
+ * config.
* @netdev: network interface device structure
*
* The set_rx_mode entry point is called whenever the unicast or multicast
* address lists or the network interface flags are updated. This routine is
- * responsible for configuring the hardware for proper unicast, multicast,
- * promiscuous mode, and all-multi behavior.
+ * responsible for preparing the rx mode config and scheduling the rx_mode
+ * work which invokes the set_rx_mode_async callback.
**/
static void e1000_set_rx_mode(struct net_device *netdev)
+{
+ bool allmulti = !!(netdev->flags & IFF_ALLMULTI);
+ bool promisc = !!(netdev->flags & IFF_PROMISC);
+
+ netif_set_rx_mode_flag(netdev, NETIF_RX_MODE_UC_SKIP, promisc);
+
+ netif_set_rx_mode_cfg(netdev, NETIF_RX_MODE_CFG_ALLMULTI, allmulti);
+ netif_set_rx_mode_cfg(netdev, NETIF_RX_MODE_CFG_PROMISC, promisc);
+}
+
+/**
+ * e1000_set_rx_mode_async - Secondary Unicast, Multicast and Promiscuous mode
+ * confirm.
+ * @netdev: network interface device structure
+ *
+ * The set_rx_mode_async callback is responsible for actually updating the
+ * hardware. This routine is responsible for configuring the hardware for
+ * proper unicast, multicast, promiscuous mode, and all-multi behavior.
+ **/
+static void e1000_set_rx_mode_async(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
- struct netdev_hw_addr *ha;
bool use_uc = false;
+ char *ha_addr;
u32 rctl;
u32 hash_value;
- int i, rar_entries = E1000_RAR_ENTRIES;
+ int i, rar_entries = E1000_RAR_ENTRIES, ni;
int mta_reg_count = E1000_NUM_MTA_REGISTERS;
u32 *mcarray = kcalloc(mta_reg_count, sizeof(u32), GFP_ATOMIC);
@@ -2250,11 +2273,11 @@ static void e1000_set_rx_mode(struct net_device *netdev)
rctl = er32(RCTL);
- if (netdev->flags & IFF_PROMISC) {
+ if (netif_get_rx_mode_cfg(netdev, NETIF_RX_MODE_CFG_PROMISC)) {
rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
rctl &= ~E1000_RCTL_VFE;
} else {
- if (netdev->flags & IFF_ALLMULTI)
+ if (netif_get_rx_mode_cfg(netdev, NETIF_RX_MODE_CFG_ALLMULTI))
rctl |= E1000_RCTL_MPE;
else
rctl &= ~E1000_RCTL_MPE;
@@ -2263,9 +2286,9 @@ static void e1000_set_rx_mode(struct net_device *netdev)
rctl |= E1000_RCTL_VFE;
}
- if (netdev_uc_count(netdev) > rar_entries - 1) {
+ if (netif_rx_mode_uc_count(netdev) > rar_entries - 1) {
rctl |= E1000_RCTL_UPE;
- } else if (!(netdev->flags & IFF_PROMISC)) {
+ } else if (!netif_get_rx_mode_cfg(netdev, NETIF_RX_MODE_CFG_PROMISC)) {
rctl &= ~E1000_RCTL_UPE;
use_uc = true;
}
@@ -2286,23 +2309,23 @@ static void e1000_set_rx_mode(struct net_device *netdev)
*/
i = 1;
if (use_uc)
- netdev_for_each_uc_addr(ha, netdev) {
+ netif_rx_mode_for_each_uc_addr(ha_addr, netdev, ni) {
if (i == rar_entries)
break;
- e1000_rar_set(hw, ha->addr, i++);
+ e1000_rar_set(hw, ha_addr, i++);
}
- netdev_for_each_mc_addr(ha, netdev) {
+ netif_rx_mode_for_each_mc_addr(ha_addr, netdev, ni) {
if (i == rar_entries) {
/* load any remaining addresses into the hash table */
u32 hash_reg, hash_bit, mta;
- hash_value = e1000_hash_mc_addr(hw, ha->addr);
+ hash_value = e1000_hash_mc_addr(hw, ha_addr);
hash_reg = (hash_value >> 5) & 0x7F;
hash_bit = hash_value & 0x1F;
mta = (1 << hash_bit);
mcarray[hash_reg] |= mta;
} else {
- e1000_rar_set(hw, ha->addr, i++);
+ e1000_rar_set(hw, ha_addr, i++);
}
}
@@ -5092,7 +5115,10 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake)
if (wufc) {
e1000_setup_rctl(adapter);
- e1000_set_rx_mode(netdev);
+
+ rtnl_lock();
+ netif_set_rx_mode(netdev);
+ rtnl_unlock();
rctl = er32(RCTL);
@@ -5150,11 +5176,13 @@ static int e1000_suspend(struct device *dev)
{
int retval;
struct pci_dev *pdev = to_pci_dev(dev);
+ struct net_device *netdev = pci_get_drvdata(pdev);
bool wake;
retval = __e1000_shutdown(pdev, &wake);
device_set_wakeup_enable(dev, wake);
+ netif_disable_async_ops(netdev);
return retval;
}
@@ -5166,6 +5194,8 @@ static int e1000_resume(struct device *dev)
struct e1000_hw *hw = &adapter->hw;
u32 err;
+ netif_enable_async_ops(netdev);
+
if (adapter->need_ioport)
err = pci_enable_device(pdev);
else
@@ -5195,8 +5225,11 @@ static int e1000_resume(struct device *dev)
e1000_init_manageability(adapter);
- if (netif_running(netdev))
+ if (netif_running(netdev)) {
+ rtnl_lock();
e1000_up(adapter);
+ rtnl_unlock();
+ }
netif_device_attach(netdev);
@@ -5205,6 +5238,7 @@ static int e1000_resume(struct device *dev)
static void e1000_shutdown(struct pci_dev *pdev)
{
+ struct net_device *netdev = pci_get_drvdata(pdev);
bool wake;
__e1000_shutdown(pdev, &wake);
@@ -5213,6 +5247,8 @@ static void e1000_shutdown(struct pci_dev *pdev)
pci_wake_from_d3(pdev, wake);
pci_set_power_state(pdev, PCI_D3hot);
}
+
+ netif_disable_async_ops(netdev);
}
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -5312,11 +5348,16 @@ static void e1000_io_resume(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct e1000_adapter *adapter = netdev_priv(netdev);
+ int rc;
e1000_init_manageability(adapter);
if (netif_running(netdev)) {
- if (e1000_up(adapter)) {
+ rtnl_lock();
+ rc = e1000_up(adapter);
+ rtnl_unlock();
+
+ if (rc) {
pr_info("can't bring device back up after reset\n");
return;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v9 5/7] 8139cp: Implement ndo_set_rx_mode_async callback
2026-03-14 18:28 [PATCH net-next v9 0/7] Introduce async callback ndo_set_rx_mode_async I Viswanath
` (3 preceding siblings ...)
2026-03-14 18:28 ` [PATCH net-next v9 4/7] e1000: " I Viswanath
@ 2026-03-14 18:28 ` I Viswanath
2026-03-16 7:34 ` [Intel-wired-lan] " Loktionov, Aleksandr
2026-03-14 18:28 ` [PATCH net-next v9 6/7] vmxnet3: " I Viswanath
` (2 subsequent siblings)
7 siblings, 1 reply; 18+ messages in thread
From: I Viswanath @ 2026-03-14 18:28 UTC (permalink / raw)
To: stfomichev, horms, edumazet, pabeni, andrew+netdev, kuba, davem,
eperezma, xuanzhuo, jasowang, mst, przemyslaw.kitszel,
anthony.l.nguyen, jacob.e.keller, ronak.doshi, pcnet32
Cc: bcm-kernel-feedback-list, netdev, virtualization, intel-wired-lan,
linux-kernel, I Viswanath
Implement the ndo_set_rx_mode_async callback and update
the driver to use the snapshot/commit model for RX mode update.
Signed-off-by: I Viswanath <viswanathiyyappan@gmail.com>
---
Call paths involving netif_set_rx_mode in 8139cp
netif_set_rx_mode
|-- cp_init_hw
| |-- cp_open (ndo_open, takes lock)
| | `-- cp_change_mtu (ndo_change_mtu, takes lock)
| |
| `-- cp_resume (lock added)
|
`-- cp_tx_timeout (ndo_tx_timeout, takes lock)
drivers/net/ethernet/realtek/8139cp.c | 49 ++++++++++++++++++---------
1 file changed, 33 insertions(+), 16 deletions(-)
diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c
index 5652da8a178c..9651a0d9d8f0 100644
--- a/drivers/net/ethernet/realtek/8139cp.c
+++ b/drivers/net/ethernet/realtek/8139cp.c
@@ -372,7 +372,6 @@ struct cp_private {
} while (0)
-static void __cp_set_rx_mode (struct net_device *dev);
static void cp_tx (struct cp_private *cp);
static void cp_clean_rings (struct cp_private *cp);
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -885,30 +884,31 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
/* Set or clear the multicast filter for this adaptor.
This routine is not state sensitive and need not be SMP locked. */
-static void __cp_set_rx_mode (struct net_device *dev)
+static void cp_set_rx_mode_async(struct net_device *dev)
{
struct cp_private *cp = netdev_priv(dev);
u32 mc_filter[2]; /* Multicast hash filter */
+ char *ha_addr;
int rx_mode;
+ int ni;
/* Note: do not reorder, GCC is clever about common statements. */
- if (dev->flags & IFF_PROMISC) {
+ if (netif_get_rx_mode_cfg(dev, NETIF_RX_MODE_CFG_PROMISC)) {
/* Unconditionally log net taps. */
rx_mode =
AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
AcceptAllPhys;
mc_filter[1] = mc_filter[0] = 0xffffffff;
- } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
- (dev->flags & IFF_ALLMULTI)) {
+ } else if ((netif_rx_mode_mc_count(dev) > multicast_filter_limit) ||
+ netif_get_rx_mode_cfg(dev, NETIF_RX_MODE_CFG_ALLMULTI)) {
/* Too many to filter perfectly -- accept all multicasts. */
rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
mc_filter[1] = mc_filter[0] = 0xffffffff;
} else {
- struct netdev_hw_addr *ha;
rx_mode = AcceptBroadcast | AcceptMyPhys;
mc_filter[1] = mc_filter[0] = 0;
- netdev_for_each_mc_addr(ha, dev) {
- int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
+ netif_rx_mode_for_each_mc_addr(ha_addr, dev, ni) {
+ int bit_nr = ether_crc(ETH_ALEN, ha_addr) >> 26;
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
rx_mode |= AcceptMulticast;
@@ -925,12 +925,14 @@ static void __cp_set_rx_mode (struct net_device *dev)
static void cp_set_rx_mode (struct net_device *dev)
{
- unsigned long flags;
- struct cp_private *cp = netdev_priv(dev);
+ bool allmulti = !!(dev->flags & IFF_ALLMULTI);
+ bool promisc = !!(dev->flags & IFF_PROMISC);
- spin_lock_irqsave (&cp->lock, flags);
- __cp_set_rx_mode(dev);
- spin_unlock_irqrestore (&cp->lock, flags);
+ netif_set_rx_mode_flag(dev, NETIF_RX_MODE_UC_SKIP, true);
+ netif_set_rx_mode_flag(dev, NETIF_RX_MODE_MC_SKIP, promisc | allmulti);
+
+ netif_set_rx_mode_cfg(dev, NETIF_RX_MODE_CFG_ALLMULTI, allmulti);
+ netif_set_rx_mode_cfg(dev, NETIF_RX_MODE_CFG_PROMISC, promisc);
}
static void __cp_get_stats(struct cp_private *cp)
@@ -1040,7 +1042,7 @@ static void cp_init_hw (struct cp_private *cp)
cp_start_hw(cp);
cpw8(TxThresh, 0x06); /* XXX convert magic num to a constant */
- __cp_set_rx_mode(dev);
+ netif_set_rx_mode(dev);
cpw32_f (TxConfig, IFG | (TX_DMA_BURST << TxDMAShift));
cpw8(Config1, cpr8(Config1) | DriverLoaded | PMEnable);
@@ -1262,7 +1264,7 @@ static void cp_tx_timeout(struct net_device *dev, unsigned int txqueue)
cp_clean_rings(cp);
cp_init_rings(cp);
cp_start_hw(cp);
- __cp_set_rx_mode(dev);
+ netif_set_rx_mode(dev);
cpw16_f(IntrMask, cp_norx_intr_mask);
netif_wake_queue(dev);
@@ -1870,6 +1872,7 @@ static const struct net_device_ops cp_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = cp_set_mac_address,
.ndo_set_rx_mode = cp_set_rx_mode,
+ .ndo_set_rx_mode_async = cp_set_rx_mode_async,
.ndo_get_stats = cp_get_stats,
.ndo_eth_ioctl = cp_ioctl,
.ndo_start_xmit = cp_start_xmit,
@@ -2071,7 +2074,7 @@ static int __maybe_unused cp_suspend(struct device *device)
spin_unlock_irqrestore (&cp->lock, flags);
device_set_wakeup_enable(device, cp->wol_enabled);
-
+ netif_disable_async_ops(dev);
return 0;
}
@@ -2081,6 +2084,8 @@ static int __maybe_unused cp_resume(struct device *device)
struct cp_private *cp = netdev_priv(dev);
unsigned long flags;
+ netif_enable_async_ops(dev);
+
if (!netif_running(dev))
return 0;
@@ -2088,7 +2093,11 @@ static int __maybe_unused cp_resume(struct device *device)
/* FIXME: sh*t may happen if the Rx ring buffer is depleted */
cp_init_rings_index (cp);
+
+ rtnl_lock();
cp_init_hw (cp);
+ rtnl_unlock();
+
cp_enable_irq(cp);
netif_start_queue (dev);
@@ -2101,6 +2110,13 @@ static int __maybe_unused cp_resume(struct device *device)
return 0;
}
+static void cp_shutdown(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+
+ netif_disable_async_ops(dev);
+}
+
static const struct pci_device_id cp_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139), },
{ PCI_DEVICE(PCI_VENDOR_ID_TTTECH, PCI_DEVICE_ID_TTTECH_MC322), },
@@ -2116,6 +2132,7 @@ static struct pci_driver cp_driver = {
.probe = cp_init_one,
.remove = cp_remove_one,
.driver.pm = &cp_pm_ops,
+ .shutdown = &cp_shutdown
};
module_pci_driver(cp_driver);
--
2.47.3
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v9 6/7] vmxnet3: Implement ndo_set_rx_mode_async callback
2026-03-14 18:28 [PATCH net-next v9 0/7] Introduce async callback ndo_set_rx_mode_async I Viswanath
` (4 preceding siblings ...)
2026-03-14 18:28 ` [PATCH net-next v9 5/7] 8139cp: " I Viswanath
@ 2026-03-14 18:28 ` I Viswanath
2026-03-16 7:35 ` [Intel-wired-lan] " Loktionov, Aleksandr
2026-03-14 18:28 ` [PATCH net-next v9 7/7] pcnet32: " I Viswanath
2026-03-14 20:06 ` [PATCH net-next v9 0/7] Introduce async callback ndo_set_rx_mode_async Jakub Kicinski
7 siblings, 1 reply; 18+ messages in thread
From: I Viswanath @ 2026-03-14 18:28 UTC (permalink / raw)
To: stfomichev, horms, edumazet, pabeni, andrew+netdev, kuba, davem,
eperezma, xuanzhuo, jasowang, mst, przemyslaw.kitszel,
anthony.l.nguyen, jacob.e.keller, ronak.doshi, pcnet32
Cc: bcm-kernel-feedback-list, netdev, virtualization, intel-wired-lan,
linux-kernel, I Viswanath
Implement the ndo_set_rx_mode_async callback and update
the driver to use the snapshot/commit model for RX mode update.
Signed-off-by: I Viswanath <viswanathiyyappan@gmail.com>
---
Call paths involving netif_set_rx_mode in vmxnet3
netif_set_rx_mode
`-- vmxnet3_activate_dev
|-- vmxnet3_open (ndo_open, takes lock)
|-- vmxnet3_change_mtu (ndo_change_mtu, takes lock)
|-- vmxnet3_reset_work (takes lock)
|-- vmxnet3_resume (lock added)
|-- vmxnet3_set_ringparam (ethtool callback, takes lock)
`-- vmxnet3_xdp_set
`-- vmxnet3_xdp (ndo_bpf, takes lock)
drivers/net/vmxnet3/vmxnet3_drv.c | 46 +++++++++++++++++++++++--------
1 file changed, 35 insertions(+), 11 deletions(-)
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index 40522afc0532..350e44286c00 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -2775,18 +2775,18 @@ static u8 *
vmxnet3_copy_mc(struct net_device *netdev)
{
u8 *buf = NULL;
- u32 sz = netdev_mc_count(netdev) * ETH_ALEN;
+ u32 sz = netif_rx_mode_mc_count(netdev) * ETH_ALEN;
+ char *ha_addr;
+ int ni;
/* struct Vmxnet3_RxFilterConf.mfTableLen is u16. */
if (sz <= 0xffff) {
/* We may be called with BH disabled */
buf = kmalloc(sz, GFP_ATOMIC);
if (buf) {
- struct netdev_hw_addr *ha;
int i = 0;
-
- netdev_for_each_mc_addr(ha, netdev)
- memcpy(buf + i++ * ETH_ALEN, ha->addr,
+ netif_rx_mode_for_each_mc_addr(ha_addr, netdev, ni)
+ memcpy(buf + i++ * ETH_ALEN, ha_addr,
ETH_ALEN);
}
}
@@ -2796,8 +2796,23 @@ vmxnet3_copy_mc(struct net_device *netdev)
static void
vmxnet3_set_mc(struct net_device *netdev)
+{
+ bool allmulti = !!(netdev->flags & IFF_ALLMULTI);
+ bool promisc = !!(netdev->flags & IFF_PROMISC);
+ bool broadcast = !!(netdev->flags & IFF_BROADCAST);
+
+ netif_set_rx_mode_flag(netdev, NETIF_RX_MODE_UC_SKIP, true);
+ netif_set_rx_mode_flag(netdev, NETIF_RX_MODE_MC_SKIP, allmulti);
+
+ netif_set_rx_mode_cfg(netdev, NETIF_RX_MODE_CFG_ALLMULTI, allmulti);
+ netif_set_rx_mode_cfg(netdev, NETIF_RX_MODE_CFG_PROMISC, promisc);
+ netif_set_rx_mode_cfg(netdev, NETIF_RX_MODE_CFG_BROADCAST, broadcast);
+}
+
+static void vmxnet3_set_mc_async(struct net_device *netdev)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ int mc_count = netif_rx_mode_mc_count(netdev);
unsigned long flags;
struct Vmxnet3_RxFilterConf *rxConf =
&adapter->shared->devRead.rxFilterConf;
@@ -2806,7 +2821,7 @@ vmxnet3_set_mc(struct net_device *netdev)
bool new_table_pa_valid = false;
u32 new_mode = VMXNET3_RXM_UCAST;
- if (netdev->flags & IFF_PROMISC) {
+ if (netif_get_rx_mode_cfg(netdev, NETIF_RX_MODE_CFG_PROMISC)) {
u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
memset(vfTable, 0, VMXNET3_VFT_SIZE * sizeof(*vfTable));
@@ -2815,16 +2830,16 @@ vmxnet3_set_mc(struct net_device *netdev)
vmxnet3_restore_vlan(adapter);
}
- if (netdev->flags & IFF_BROADCAST)
+ if (netif_get_rx_mode_cfg(netdev, NETIF_RX_MODE_CFG_BROADCAST))
new_mode |= VMXNET3_RXM_BCAST;
- if (netdev->flags & IFF_ALLMULTI)
+ if (netif_get_rx_mode_cfg(netdev, NETIF_RX_MODE_CFG_ALLMULTI))
new_mode |= VMXNET3_RXM_ALL_MULTI;
else
- if (!netdev_mc_empty(netdev)) {
+ if (mc_count) {
new_table = vmxnet3_copy_mc(netdev);
if (new_table) {
- size_t sz = netdev_mc_count(netdev) * ETH_ALEN;
+ size_t sz = mc_count * ETH_ALEN;
rxConf->mfTableLen = cpu_to_le16(sz);
new_table_pa = dma_map_single(
@@ -3213,7 +3228,7 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
}
/* Apply the rx filter settins last. */
- vmxnet3_set_mc(adapter->netdev);
+ netif_set_rx_mode(adapter->netdev);
/*
* Check link state when first activating device. It will start the
@@ -3977,6 +3992,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
.ndo_get_stats64 = vmxnet3_get_stats64,
.ndo_tx_timeout = vmxnet3_tx_timeout,
.ndo_set_rx_mode = vmxnet3_set_mc,
+ .ndo_set_rx_mode_async = vmxnet3_set_mc_async,
.ndo_vlan_rx_add_vid = vmxnet3_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = vmxnet3_vlan_rx_kill_vid,
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -4400,6 +4416,7 @@ static void vmxnet3_shutdown_device(struct pci_dev *pdev)
vmxnet3_disable_all_intrs(adapter);
clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state);
+ netif_disable_async_ops(netdev);
}
@@ -4518,6 +4535,7 @@ vmxnet3_suspend(struct device *device)
pci_disable_device(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, PMSG_SUSPEND));
+ netif_disable_async_ops(netdev);
return 0;
}
@@ -4531,6 +4549,8 @@ vmxnet3_resume(struct device *device)
struct net_device *netdev = pci_get_drvdata(pdev);
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ netif_enable_async_ops(netdev);
+
if (!netif_running(netdev))
return 0;
@@ -4559,7 +4579,11 @@ vmxnet3_resume(struct device *device)
vmxnet3_rq_cleanup_all(adapter);
vmxnet3_reset_dev(adapter);
+
+ rtnl_lock();
err = vmxnet3_activate_dev(adapter);
+ rtnl_unlock();
+
if (err != 0) {
netdev_err(netdev,
"failed to re-activate on resume, error: %d", err);
--
2.47.3
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v9 7/7] pcnet32: Implement ndo_set_rx_mode_async callback
2026-03-14 18:28 [PATCH net-next v9 0/7] Introduce async callback ndo_set_rx_mode_async I Viswanath
` (5 preceding siblings ...)
2026-03-14 18:28 ` [PATCH net-next v9 6/7] vmxnet3: " I Viswanath
@ 2026-03-14 18:28 ` I Viswanath
2026-03-16 7:35 ` [Intel-wired-lan] " Loktionov, Aleksandr
2026-03-14 20:06 ` [PATCH net-next v9 0/7] Introduce async callback ndo_set_rx_mode_async Jakub Kicinski
7 siblings, 1 reply; 18+ messages in thread
From: I Viswanath @ 2026-03-14 18:28 UTC (permalink / raw)
To: stfomichev, horms, edumazet, pabeni, andrew+netdev, kuba, davem,
eperezma, xuanzhuo, jasowang, mst, przemyslaw.kitszel,
anthony.l.nguyen, jacob.e.keller, ronak.doshi, pcnet32
Cc: bcm-kernel-feedback-list, netdev, virtualization, intel-wired-lan,
linux-kernel, I Viswanath
Implement the ndo_set_rx_mode_async callback and update
the driver to use the snapshot/commit model for RX mode update.
Signed-off-by: I Viswanath <viswanathiyyappan@gmail.com>
---
There are no calls to netif_set_rx_mode in pcnet32
drivers/net/ethernet/amd/pcnet32.c | 65 ++++++++++++++++++++++++------
1 file changed, 53 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c
index 911808ab13a7..d5ad96985d68 100644
--- a/drivers/net/ethernet/amd/pcnet32.c
+++ b/drivers/net/ethernet/amd/pcnet32.c
@@ -314,8 +314,9 @@ static void pcnet32_tx_timeout(struct net_device *dev, unsigned int txqueue);
static irqreturn_t pcnet32_interrupt(int, void *);
static int pcnet32_close(struct net_device *);
static struct net_device_stats *pcnet32_get_stats(struct net_device *);
-static void pcnet32_load_multicast(struct net_device *dev);
+static void pcnet32_load_multicast(struct net_device *dev, bool is_open);
static void pcnet32_set_multicast_list(struct net_device *);
+static void pcnet32_set_multicast_list_async(struct net_device *);
static int pcnet32_ioctl(struct net_device *, struct ifreq *, int);
static void pcnet32_watchdog(struct timer_list *);
static int mdio_read(struct net_device *dev, int phy_id, int reg_num);
@@ -1580,6 +1581,7 @@ static const struct net_device_ops pcnet32_netdev_ops = {
.ndo_tx_timeout = pcnet32_tx_timeout,
.ndo_get_stats = pcnet32_get_stats,
.ndo_set_rx_mode = pcnet32_set_multicast_list,
+ .ndo_set_rx_mode_async = pcnet32_set_multicast_list_async,
.ndo_eth_ioctl = pcnet32_ioctl,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
@@ -2260,7 +2262,7 @@ static int pcnet32_open(struct net_device *dev)
lp->init_block->mode =
cpu_to_le16((lp->options & PCNET32_PORT_PORTSEL) << 7);
- pcnet32_load_multicast(dev);
+ pcnet32_load_multicast(dev, true);
if (pcnet32_init_ring(dev)) {
rc = -ENOMEM;
@@ -2676,18 +2678,26 @@ static struct net_device_stats *pcnet32_get_stats(struct net_device *dev)
}
/* taken from the sunlance driver, which it took from the depca driver */
-static void pcnet32_load_multicast(struct net_device *dev)
+static void pcnet32_load_multicast(struct net_device *dev, bool is_open)
{
struct pcnet32_private *lp = netdev_priv(dev);
volatile struct pcnet32_init_block *ib = lp->init_block;
volatile __le16 *mcast_table = (__le16 *)ib->filter;
struct netdev_hw_addr *ha;
+ char *ha_addr;
+ bool allmulti;
unsigned long ioaddr = dev->base_addr;
- int i;
+ int i, ni;
u32 crc;
+ if (is_open)
+ allmulti = dev->flags & IFF_ALLMULTI;
+ else
+ allmulti = netif_get_rx_mode_cfg(dev,
+ NETIF_RX_MODE_CFG_ALLMULTI);
+
/* set all multicast bits */
- if (dev->flags & IFF_ALLMULTI) {
+ if (allmulti) {
ib->filter[0] = cpu_to_le32(~0U);
ib->filter[1] = cpu_to_le32(~0U);
lp->a->write_csr(ioaddr, PCNET32_MC_FILTER, 0xffff);
@@ -2701,20 +2711,41 @@ static void pcnet32_load_multicast(struct net_device *dev)
ib->filter[1] = 0;
/* Add addresses */
- netdev_for_each_mc_addr(ha, dev) {
- crc = ether_crc_le(6, ha->addr);
- crc = crc >> 26;
- mcast_table[crc >> 4] |= cpu_to_le16(1 << (crc & 0xf));
+ if (is_open) {
+ netdev_for_each_mc_addr(ha, dev) {
+ crc = ether_crc_le(6, ha->addr);
+ crc = crc >> 26;
+ mcast_table[crc >> 4] |= cpu_to_le16(1 << (crc & 0xf));
+ }
+ } else {
+ netif_rx_mode_for_each_mc_addr(ha_addr, dev, ni) {
+ crc = ether_crc_le(6, ha_addr);
+ crc = crc >> 26;
+ mcast_table[crc >> 4] |= cpu_to_le16(1 << (crc & 0xf));
+ }
}
+
for (i = 0; i < 4; i++)
lp->a->write_csr(ioaddr, PCNET32_MC_FILTER + i,
le16_to_cpu(mcast_table[i]));
}
+static void pcnet32_set_multicast_list(struct net_device *dev)
+{
+ bool allmulti = !!(dev->flags & IFF_ALLMULTI);
+ bool promisc = !!(dev->flags & IFF_PROMISC);
+
+ netif_set_rx_mode_flag(dev, NETIF_RX_MODE_UC_SKIP, true);
+ netif_set_rx_mode_flag(dev, NETIF_RX_MODE_MC_SKIP, promisc | allmulti);
+
+ netif_set_rx_mode_cfg(dev, NETIF_RX_MODE_CFG_ALLMULTI, allmulti);
+ netif_set_rx_mode_cfg(dev, NETIF_RX_MODE_CFG_PROMISC, promisc);
+}
+
/*
* Set or clear the multicast filter for this adaptor.
*/
-static void pcnet32_set_multicast_list(struct net_device *dev)
+static void pcnet32_set_multicast_list_async(struct net_device *dev)
{
unsigned long ioaddr = dev->base_addr, flags;
struct pcnet32_private *lp = netdev_priv(dev);
@@ -2723,7 +2754,7 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
spin_lock_irqsave(&lp->lock, flags);
suspended = pcnet32_suspend(dev, &flags, 0);
csr15 = lp->a->read_csr(ioaddr, CSR15);
- if (dev->flags & IFF_PROMISC) {
+ if (netif_get_rx_mode_cfg(dev, NETIF_RX_MODE_CFG_PROMISC)) {
/* Log any net taps. */
netif_info(lp, hw, dev, "Promiscuous mode enabled\n");
lp->init_block->mode =
@@ -2734,7 +2765,7 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
lp->init_block->mode =
cpu_to_le16((lp->options & PCNET32_PORT_PORTSEL) << 7);
lp->a->write_csr(ioaddr, CSR15, csr15 & 0x7fff);
- pcnet32_load_multicast(dev);
+ pcnet32_load_multicast(dev, false);
}
if (suspended) {
@@ -2922,6 +2953,7 @@ static int __maybe_unused pcnet32_pm_suspend(struct device *device_d)
pcnet32_close(dev);
}
+ netif_disable_async_ops(dev);
return 0;
}
@@ -2929,6 +2961,7 @@ static int __maybe_unused pcnet32_pm_resume(struct device *device_d)
{
struct net_device *dev = dev_get_drvdata(device_d);
+ netif_enable_async_ops(dev);
if (netif_running(dev)) {
pcnet32_open(dev);
netif_device_attach(dev);
@@ -2937,6 +2970,13 @@ static int __maybe_unused pcnet32_pm_resume(struct device *device_d)
return 0;
}
+static void pcnet32_shutdown(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+
+ netif_disable_async_ops(dev);
+}
+
static void pcnet32_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
@@ -2964,6 +3004,7 @@ static struct pci_driver pcnet32_driver = {
.driver = {
.pm = &pcnet32_pm_ops,
},
+ .shutdown = pcnet32_shutdown,
};
/* An additional parameter that may be passed in... */
--
2.47.3
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v9 0/7] Introduce async callback ndo_set_rx_mode_async
2026-03-14 20:06 ` [PATCH net-next v9 0/7] Introduce async callback ndo_set_rx_mode_async Jakub Kicinski
@ 2026-03-14 19:59 ` I Viswanath
2026-03-17 16:15 ` Jakub Kicinski
0 siblings, 1 reply; 18+ messages in thread
From: I Viswanath @ 2026-03-14 19:59 UTC (permalink / raw)
To: Jakub Kicinski
Cc: stfomichev, horms, edumazet, pabeni, andrew+netdev, davem,
eperezma, xuanzhuo, jasowang, mst, przemyslaw.kitszel,
anthony.l.nguyen, jacob.e.keller, ronak.doshi, pcnet32,
bcm-kernel-feedback-list, netdev, virtualization, intel-wired-lan,
linux-kernel
On Sun, 15 Mar 2026 at 01:36, Jakub Kicinski <kuba@kernel.org> wrote:
>
> Stan is actively working on this:
> https://lore.kernel.org/20260313145113.1424442-1-sdf@fomichev.me
> I feel like I spent enough time reviewing your attempts and Stan
> will not need as much maintainer attention to bring this to
> a closure so let him cook. Sorry.
Honestly, I should be thanking you for not throwing it out sooner. I
don't think I was skilled/experienced to actually make it work and
someone more qualified should handle this. On the bright side, That
means I am now much better at solving regular boring bugs and I think
that's what matters. Cheers
Thanks
I Viswanath
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v9 0/7] Introduce async callback ndo_set_rx_mode_async
2026-03-14 18:28 [PATCH net-next v9 0/7] Introduce async callback ndo_set_rx_mode_async I Viswanath
` (6 preceding siblings ...)
2026-03-14 18:28 ` [PATCH net-next v9 7/7] pcnet32: " I Viswanath
@ 2026-03-14 20:06 ` Jakub Kicinski
2026-03-14 19:59 ` I Viswanath
7 siblings, 1 reply; 18+ messages in thread
From: Jakub Kicinski @ 2026-03-14 20:06 UTC (permalink / raw)
To: I Viswanath
Cc: stfomichev, horms, edumazet, pabeni, andrew+netdev, davem,
eperezma, xuanzhuo, jasowang, mst, przemyslaw.kitszel,
anthony.l.nguyen, jacob.e.keller, ronak.doshi, pcnet32,
bcm-kernel-feedback-list, netdev, virtualization, intel-wired-lan,
linux-kernel
On Sat, 14 Mar 2026 23:58:02 +0530 I Viswanath wrote:
> This is an implementation of the idea provided by Jakub here
>
> https://lore.kernel.org/netdev/20250923163727.5e97abdb@kernel.org/
>
> The set_rx_mode callback is invoked under the addr_lock spinlock which
> makes it illegal to sleep. This means set_rx_mode is prone to
> sleep-in-atomic bugs as drivers have a tendency to do the I/O directly
> in the callback.
Stan is actively working on this:
https://lore.kernel.org/20260313145113.1424442-1-sdf@fomichev.me
I feel like I spent enough time reviewing your attempts and Stan
will not need as much maintainer attention to bring this to
a closure so let him cook. Sorry.
^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [Intel-wired-lan] [PATCH net-next v9 1/7] net: core: Add state tracking for async netdev ops
2026-03-14 18:28 ` [PATCH net-next v9 1/7] net: core: Add state tracking for async netdev ops I Viswanath
@ 2026-03-16 7:25 ` Loktionov, Aleksandr
0 siblings, 0 replies; 18+ messages in thread
From: Loktionov, Aleksandr @ 2026-03-16 7:25 UTC (permalink / raw)
To: I Viswanath, stfomichev@gmail.com, horms@kernel.org,
edumazet@google.com, pabeni@redhat.com, andrew+netdev@lunn.ch,
kuba@kernel.org, davem@davemloft.net, eperezma@redhat.com,
xuanzhuo@linux.alibaba.com, jasowang@redhat.com, mst@redhat.com,
Kitszel, Przemyslaw, Nguyen, Anthony L, Keller, Jacob E,
ronak.doshi@broadcom.com, pcnet32@frontier.com
Cc: bcm-kernel-feedback-list@broadcom.com, netdev@vger.kernel.org,
virtualization@lists.linux.dev, intel-wired-lan@lists.osuosl.org,
linux-kernel@vger.kernel.org
> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf
> Of I Viswanath
> Sent: Saturday, March 14, 2026 7:28 PM
> To: stfomichev@gmail.com; horms@kernel.org; edumazet@google.com;
> pabeni@redhat.com; andrew+netdev@lunn.ch; kuba@kernel.org;
> davem@davemloft.net; eperezma@redhat.com; xuanzhuo@linux.alibaba.com;
> jasowang@redhat.com; mst@redhat.com; Kitszel, Przemyslaw
> <przemyslaw.kitszel@intel.com>; Nguyen, Anthony L
> <anthony.l.nguyen@intel.com>; Keller, Jacob E
> <jacob.e.keller@intel.com>; ronak.doshi@broadcom.com;
> pcnet32@frontier.com
> Cc: bcm-kernel-feedback-list@broadcom.com; netdev@vger.kernel.org;
> virtualization@lists.linux.dev; intel-wired-lan@lists.osuosl.org;
> linux-kernel@vger.kernel.org; I Viswanath
> <viswanathiyyappan@gmail.com>
> Subject: [Intel-wired-lan] [PATCH net-next v9 1/7] net: core: Add
> state tracking for async netdev ops
>
> Async netdev ops are tricky because of the following problems:
>
> 1) Freeing the context associated with async netdev ops might require
> waiting for completion of the associated work which might require
> the
> rtnl lock or the instance lock. However this will deadlock in
> __dev_close_many as the cleanup is done with those locks already
> held.
>
> 2) We need a way to enable/disable async netdev ops depending on the
> PM
> state to allow/prevent hardware access as appropriate.
>
> We solve these problems by introducing a state variable to track the
> current state of netdev. This can take the following values:
> - ACTIVE (up and normal operation)
> - DOWN (down)
> - INACTIVE (in suspend/shutdown)
>
> To solve 1, we set the state to down in __dev_close_many. In the
> associated op handler, we check for the current state and return if
> the netdev is down.
>
> To solve 2, the commit introduces the following functions:
> - netif_enable_async_ops -> sets state to ACTIVE
> - netif_disable_async_ops -> sets state to INACTIVE and cancels any
> pending work as required.
>
> The op implementation can use the state information to do the required
> processing.
>
> Signed-off-by: I Viswanath <viswanathiyyappan@gmail.com>
> ---
> include/linux/netdevice.h | 29 ++++++++++++++
> net/core/dev.c | 84
> ++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 111 insertions(+), 2 deletions(-)
>
...
> --
> 2.47.3
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [Intel-wired-lan] [PATCH net-next v9 2/7] net: core: Introduce callback ndo_set_rx_mode_async
2026-03-14 18:28 ` [PATCH net-next v9 2/7] net: core: Introduce callback ndo_set_rx_mode_async I Viswanath
@ 2026-03-16 7:29 ` Loktionov, Aleksandr
0 siblings, 0 replies; 18+ messages in thread
From: Loktionov, Aleksandr @ 2026-03-16 7:29 UTC (permalink / raw)
To: I Viswanath, stfomichev@gmail.com, horms@kernel.org,
edumazet@google.com, pabeni@redhat.com, andrew+netdev@lunn.ch,
kuba@kernel.org, davem@davemloft.net, eperezma@redhat.com,
xuanzhuo@linux.alibaba.com, jasowang@redhat.com, mst@redhat.com,
Kitszel, Przemyslaw, Nguyen, Anthony L, Keller, Jacob E,
ronak.doshi@broadcom.com, pcnet32@frontier.com
Cc: bcm-kernel-feedback-list@broadcom.com, netdev@vger.kernel.org,
virtualization@lists.linux.dev, intel-wired-lan@lists.osuosl.org,
linux-kernel@vger.kernel.org
> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf
> Of I Viswanath
> Sent: Saturday, March 14, 2026 7:28 PM
> To: stfomichev@gmail.com; horms@kernel.org; edumazet@google.com;
> pabeni@redhat.com; andrew+netdev@lunn.ch; kuba@kernel.org;
> davem@davemloft.net; eperezma@redhat.com; xuanzhuo@linux.alibaba.com;
> jasowang@redhat.com; mst@redhat.com; Kitszel, Przemyslaw
> <przemyslaw.kitszel@intel.com>; Nguyen, Anthony L
> <anthony.l.nguyen@intel.com>; Keller, Jacob E
> <jacob.e.keller@intel.com>; ronak.doshi@broadcom.com;
> pcnet32@frontier.com
> Cc: bcm-kernel-feedback-list@broadcom.com; netdev@vger.kernel.org;
> virtualization@lists.linux.dev; intel-wired-lan@lists.osuosl.org;
> linux-kernel@vger.kernel.org; I Viswanath
> <viswanathiyyappan@gmail.com>
> Subject: [Intel-wired-lan] [PATCH net-next v9 2/7] net: core:
> Introduce callback ndo_set_rx_mode_async
>
> The set_rx_mode callback is invoked under the addr_lock spinlock which
> makes it illegal to sleep. This means set_rx_mode is prone to sleep-
> in-atomic bugs as drivers have a tendency to do the I/O directly in
> the callback.
>
> This problem can be avoided if set_rx_mode were done in 2 stages:
> snapshot and commit. A handful of drivers implement this idea by
> implementing the rx_mode update as work and scheduling it in the
> set_rx_mode callback.
>
> Implement this idea in net/core as this is not driver specific. To
> facilitate this transition, a new async callback set_rx_mode_async is
> introduced.
>
> When this callback is provided, the set_rx_mode callback customizes
> the snapshot creation and the work behaviour as required while the
> set_rx_mode_async callback is run async as work and commits the
> prepared snapshot.
>
> Apart from this, the drivers need to be updated to have all the RX
> mode updates pass through the netif_set_rx_mode helper to ensure
> correctness.
>
> Suggested-by: Jakub Kicinski <kuba@kernel.org>
> Signed-off-by: I Viswanath <viswanathiyyappan@gmail.com>
> ---
> include/linux/netdevice.h | 94 +++++++++++++-
> include/net/netdev_lock.h | 8 ++
> net/core/dev.c | 251
> +++++++++++++++++++++++++++++++++++++-
> 3 files changed, 347 insertions(+), 6 deletions(-)
>
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index 6d426dc66af9..a69377068f4a 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -1068,7 +1068,36 @@ enum netif_async_state {
> NETIF_ASYNC_INACTIVE
> };
...
> --
> 2.47.3
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [Intel-wired-lan] [PATCH net-next v9 3/7] virtio-net: Implement ndo_set_rx_mode_async callback
2026-03-14 18:28 ` [PATCH net-next v9 3/7] virtio-net: Implement ndo_set_rx_mode_async callback I Viswanath
@ 2026-03-16 7:30 ` Loktionov, Aleksandr
0 siblings, 0 replies; 18+ messages in thread
From: Loktionov, Aleksandr @ 2026-03-16 7:30 UTC (permalink / raw)
To: I Viswanath, stfomichev@gmail.com, horms@kernel.org,
edumazet@google.com, pabeni@redhat.com, andrew+netdev@lunn.ch,
kuba@kernel.org, davem@davemloft.net, eperezma@redhat.com,
xuanzhuo@linux.alibaba.com, jasowang@redhat.com, mst@redhat.com,
Kitszel, Przemyslaw, Nguyen, Anthony L, Keller, Jacob E,
ronak.doshi@broadcom.com, pcnet32@frontier.com
Cc: bcm-kernel-feedback-list@broadcom.com, netdev@vger.kernel.org,
virtualization@lists.linux.dev, intel-wired-lan@lists.osuosl.org,
linux-kernel@vger.kernel.org
> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf
> Of I Viswanath
> Sent: Saturday, March 14, 2026 7:28 PM
> To: stfomichev@gmail.com; horms@kernel.org; edumazet@google.com;
> pabeni@redhat.com; andrew+netdev@lunn.ch; kuba@kernel.org;
> davem@davemloft.net; eperezma@redhat.com; xuanzhuo@linux.alibaba.com;
> jasowang@redhat.com; mst@redhat.com; Kitszel, Przemyslaw
> <przemyslaw.kitszel@intel.com>; Nguyen, Anthony L
> <anthony.l.nguyen@intel.com>; Keller, Jacob E
> <jacob.e.keller@intel.com>; ronak.doshi@broadcom.com;
> pcnet32@frontier.com
> Cc: bcm-kernel-feedback-list@broadcom.com; netdev@vger.kernel.org;
> virtualization@lists.linux.dev; intel-wired-lan@lists.osuosl.org;
> linux-kernel@vger.kernel.org; I Viswanath
> <viswanathiyyappan@gmail.com>
> Subject: [Intel-wired-lan] [PATCH net-next v9 3/7] virtio-net:
> Implement ndo_set_rx_mode_async callback
>
> Implement the ndo_set_rx_mode_async callback and update the driver to
> use the snapshot/commit model for RX mode update.
>
> Signed-off-by: I Viswanath <viswanathiyyappan@gmail.com>
> ---
>
> There are no calls to netif_set_rx_mode in virtio-net
>
> drivers/net/virtio_net.c | 85 ++++++++++++---------------------------
> -
> 1 file changed, 25 insertions(+), 60 deletions(-)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index
> 811b90da15a9..70255d09401c 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -448,12 +448,6 @@ struct virtnet_info {
> /* Work struct for config space updates */
> struct work_struct config_work;
>
...
> }
>
> --
> 2.47.3
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [Intel-wired-lan] [PATCH net-next v9 4/7] e1000: Implement ndo_set_rx_mode_async callback
2026-03-14 18:28 ` [PATCH net-next v9 4/7] e1000: " I Viswanath
@ 2026-03-16 7:30 ` Loktionov, Aleksandr
0 siblings, 0 replies; 18+ messages in thread
From: Loktionov, Aleksandr @ 2026-03-16 7:30 UTC (permalink / raw)
To: I Viswanath, stfomichev@gmail.com, horms@kernel.org,
edumazet@google.com, pabeni@redhat.com, andrew+netdev@lunn.ch,
kuba@kernel.org, davem@davemloft.net, eperezma@redhat.com,
xuanzhuo@linux.alibaba.com, jasowang@redhat.com, mst@redhat.com,
Kitszel, Przemyslaw, Nguyen, Anthony L, Keller, Jacob E,
ronak.doshi@broadcom.com, pcnet32@frontier.com
Cc: bcm-kernel-feedback-list@broadcom.com, netdev@vger.kernel.org,
virtualization@lists.linux.dev, intel-wired-lan@lists.osuosl.org,
linux-kernel@vger.kernel.org
> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf
> Of I Viswanath
> Sent: Saturday, March 14, 2026 7:28 PM
> To: stfomichev@gmail.com; horms@kernel.org; edumazet@google.com;
> pabeni@redhat.com; andrew+netdev@lunn.ch; kuba@kernel.org;
> davem@davemloft.net; eperezma@redhat.com; xuanzhuo@linux.alibaba.com;
> jasowang@redhat.com; mst@redhat.com; Kitszel, Przemyslaw
> <przemyslaw.kitszel@intel.com>; Nguyen, Anthony L
> <anthony.l.nguyen@intel.com>; Keller, Jacob E
> <jacob.e.keller@intel.com>; ronak.doshi@broadcom.com;
> pcnet32@frontier.com
> Cc: bcm-kernel-feedback-list@broadcom.com; netdev@vger.kernel.org;
> virtualization@lists.linux.dev; intel-wired-lan@lists.osuosl.org;
> linux-kernel@vger.kernel.org; I Viswanath
> <viswanathiyyappan@gmail.com>
> Subject: [Intel-wired-lan] [PATCH net-next v9 4/7] e1000: Implement
> ndo_set_rx_mode_async callback
>
> Implement the ndo_set_rx_mode_async callback and update the driver to
> use the snapshot/commit model for RX mode update.
>
> Signed-off-by: I Viswanath <viswanathiyyappan@gmail.com>
> ---
>
> Call paths involving netif_set_rx_mode in e1000
>
> netif_set_rx_mode
> |-- __e1000_shutdown (lock added)
> |
> `-- e1000_configure
> |-- e1000_open (ndo_open, takes lock)
> |
> `-- e1000_up
> |-- e1000_reinit_locked
> | |-- e1000_set_features (ndo_set_features, takes lock)
> | |-- e1000_reset_task (ethtool callback, takes lock)
> | |-- e1000_mii_ioctl
> | | `-- e1000_ioctl (ndo_do_ioctl, takes lock)
> | `-- e1000_nway_reset (ethtool callback, takes lock)
> |
> |-- e1000_change_mtu (ndo_change_mtu, takes lock)
> |-- e1000_resume (lock added)
> |-- e1000_io_resume (lock added)
> |
> |-- e1000_set_link_ksettings (ethtool callback, takes lock)
> |-- e1000_set_pauseparam (ethtool callback, takes lock)
> `-- e1000_set_ringparam (ethtool callback, takes lock)
>
> drivers/net/ethernet/intel/e1000/e1000_main.c | 77 ++++++++++++++----
> -
> 1 file changed, 59 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c
> b/drivers/net/ethernet/intel/e1000/e1000_main.c
> index 9b09eb144b81..ec25b41c63b7 100644
> --- a/drivers/net/ethernet/intel/e1000/e1000_main.c
> +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
> @@ -99,6 +99,7 @@ static void e1000_clean_tx_ring(struct e1000_adapter
> *adapter, static void e1000_clean_rx_ring(struct e1000_adapter
> *adapter,
> struct e1000_rx_ring *rx_ring);
> static void e1000_set_rx_mode(struct net_device *netdev);
> +static void e1000_set_rx_mode_async(struct net_device *netdev);
> static void e1000_update_phy_info_task(struct work_struct *work);
> static void e1000_watchdog(struct work_struct *work); static void
> e1000_82547_tx_fifo_stall_task(struct work_struct *work); @@ -359,7
> +360,7 @@ static void e1000_configure(struct e1000_adapter *adapter)
> struct net_device *netdev = adapter->netdev;
> int i;
>
...
> }
> --
> 2.47.3
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [Intel-wired-lan] [PATCH net-next v9 5/7] 8139cp: Implement ndo_set_rx_mode_async callback
2026-03-14 18:28 ` [PATCH net-next v9 5/7] 8139cp: " I Viswanath
@ 2026-03-16 7:34 ` Loktionov, Aleksandr
0 siblings, 0 replies; 18+ messages in thread
From: Loktionov, Aleksandr @ 2026-03-16 7:34 UTC (permalink / raw)
To: I Viswanath, stfomichev@gmail.com, horms@kernel.org,
edumazet@google.com, pabeni@redhat.com, andrew+netdev@lunn.ch,
kuba@kernel.org, davem@davemloft.net, eperezma@redhat.com,
xuanzhuo@linux.alibaba.com, jasowang@redhat.com, mst@redhat.com,
Kitszel, Przemyslaw, Nguyen, Anthony L, Keller, Jacob E,
ronak.doshi@broadcom.com, pcnet32@frontier.com
Cc: bcm-kernel-feedback-list@broadcom.com, netdev@vger.kernel.org,
virtualization@lists.linux.dev, intel-wired-lan@lists.osuosl.org,
linux-kernel@vger.kernel.org
> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf
> Of I Viswanath
> Sent: Saturday, March 14, 2026 7:28 PM
> To: stfomichev@gmail.com; horms@kernel.org; edumazet@google.com;
> pabeni@redhat.com; andrew+netdev@lunn.ch; kuba@kernel.org;
> davem@davemloft.net; eperezma@redhat.com; xuanzhuo@linux.alibaba.com;
> jasowang@redhat.com; mst@redhat.com; Kitszel, Przemyslaw
> <przemyslaw.kitszel@intel.com>; Nguyen, Anthony L
> <anthony.l.nguyen@intel.com>; Keller, Jacob E
> <jacob.e.keller@intel.com>; ronak.doshi@broadcom.com;
> pcnet32@frontier.com
> Cc: bcm-kernel-feedback-list@broadcom.com; netdev@vger.kernel.org;
> virtualization@lists.linux.dev; intel-wired-lan@lists.osuosl.org;
> linux-kernel@vger.kernel.org; I Viswanath
> <viswanathiyyappan@gmail.com>
> Subject: [Intel-wired-lan] [PATCH net-next v9 5/7] 8139cp: Implement
> ndo_set_rx_mode_async callback
>
> Implement the ndo_set_rx_mode_async callback and update the driver to
> use the snapshot/commit model for RX mode update.
>
> Signed-off-by: I Viswanath <viswanathiyyappan@gmail.com>
> ---
>
> Call paths involving netif_set_rx_mode in 8139cp
>
> netif_set_rx_mode
> |-- cp_init_hw
> | |-- cp_open (ndo_open, takes lock)
> | | `-- cp_change_mtu (ndo_change_mtu, takes lock)
> | |
> | `-- cp_resume (lock added)
> |
> `-- cp_tx_timeout (ndo_tx_timeout, takes lock)
>
> drivers/net/ethernet/realtek/8139cp.c | 49 ++++++++++++++++++--------
> -
> 1 file changed, 33 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/net/ethernet/realtek/8139cp.c
> b/drivers/net/ethernet/realtek/8139cp.c
> index 5652da8a178c..9651a0d9d8f0 100644
> --- a/drivers/net/ethernet/realtek/8139cp.c
> +++ b/drivers/net/ethernet/realtek/8139cp.c
> @@ -372,7 +372,6 @@ struct cp_private {
> } while (0)
...
> static void __cp_get_stats(struct cp_private *cp) @@ -1040,7 +1042,7
> @@ static void cp_init_hw (struct cp_private *cp)
> cp_start_hw(cp);
> cpw8(TxThresh, 0x06); /* XXX convert magic num to a constant */
>
> - __cp_set_rx_mode(dev);
> + netif_set_rx_mode(dev);
> cpw32_f (TxConfig, IFG | (TX_DMA_BURST << TxDMAShift));
>
> cpw8(Config1, cpr8(Config1) | DriverLoaded | PMEnable); @@ -
> 1262,7 +1264,7 @@ static void cp_tx_timeout(struct net_device *dev,
> unsigned int txqueue)
> cp_clean_rings(cp);
> cp_init_rings(cp);
> cp_start_hw(cp);
> - __cp_set_rx_mode(dev);
> + netif_set_rx_mode(dev);
I'm afraid netif_set_rx_mode() in async mode expects netdev ops lock context.
Driver lock != netdev ops lock by definition.
If this path does not hold the required ops lock, lockdep/WARN can trigger.
> cpw16_f(IntrMask, cp_norx_intr_mask);
>
> netif_wake_queue(dev);
> @@ -1870,6 +1872,7 @@ static const struct net_device_ops cp_netdev_ops
> = {
> .ndo_validate_addr = eth_validate_addr,
> .ndo_set_mac_address = cp_set_mac_address,
> .ndo_set_rx_mode = cp_set_rx_mode,
> + .ndo_set_rx_mode_async = cp_set_rx_mode_async,
> .ndo_get_stats = cp_get_stats,
> .ndo_eth_ioctl = cp_ioctl,
> .ndo_start_xmit = cp_start_xmit,
> @@ -2071,7 +2074,7 @@ static int __maybe_unused cp_suspend(struct
...
^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [Intel-wired-lan] [PATCH net-next v9 6/7] vmxnet3: Implement ndo_set_rx_mode_async callback
2026-03-14 18:28 ` [PATCH net-next v9 6/7] vmxnet3: " I Viswanath
@ 2026-03-16 7:35 ` Loktionov, Aleksandr
0 siblings, 0 replies; 18+ messages in thread
From: Loktionov, Aleksandr @ 2026-03-16 7:35 UTC (permalink / raw)
To: I Viswanath, stfomichev@gmail.com, horms@kernel.org,
edumazet@google.com, pabeni@redhat.com, andrew+netdev@lunn.ch,
kuba@kernel.org, davem@davemloft.net, eperezma@redhat.com,
xuanzhuo@linux.alibaba.com, jasowang@redhat.com, mst@redhat.com,
Kitszel, Przemyslaw, Nguyen, Anthony L, Keller, Jacob E,
ronak.doshi@broadcom.com, pcnet32@frontier.com
Cc: bcm-kernel-feedback-list@broadcom.com, netdev@vger.kernel.org,
virtualization@lists.linux.dev, intel-wired-lan@lists.osuosl.org,
linux-kernel@vger.kernel.org
> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf
> Of I Viswanath
> Sent: Saturday, March 14, 2026 7:28 PM
> To: stfomichev@gmail.com; horms@kernel.org; edumazet@google.com;
> pabeni@redhat.com; andrew+netdev@lunn.ch; kuba@kernel.org;
> davem@davemloft.net; eperezma@redhat.com; xuanzhuo@linux.alibaba.com;
> jasowang@redhat.com; mst@redhat.com; Kitszel, Przemyslaw
> <przemyslaw.kitszel@intel.com>; Nguyen, Anthony L
> <anthony.l.nguyen@intel.com>; Keller, Jacob E
> <jacob.e.keller@intel.com>; ronak.doshi@broadcom.com;
> pcnet32@frontier.com
> Cc: bcm-kernel-feedback-list@broadcom.com; netdev@vger.kernel.org;
> virtualization@lists.linux.dev; intel-wired-lan@lists.osuosl.org;
> linux-kernel@vger.kernel.org; I Viswanath
> <viswanathiyyappan@gmail.com>
> Subject: [Intel-wired-lan] [PATCH net-next v9 6/7] vmxnet3: Implement
> ndo_set_rx_mode_async callback
>
> Implement the ndo_set_rx_mode_async callback and update the driver to
> use the snapshot/commit model for RX mode update.
>
> Signed-off-by: I Viswanath <viswanathiyyappan@gmail.com>
> ---
>
> Call paths involving netif_set_rx_mode in vmxnet3
>
> netif_set_rx_mode
> `-- vmxnet3_activate_dev
> |-- vmxnet3_open (ndo_open, takes lock)
> |-- vmxnet3_change_mtu (ndo_change_mtu, takes lock)
> |-- vmxnet3_reset_work (takes lock)
> |-- vmxnet3_resume (lock added)
> |-- vmxnet3_set_ringparam (ethtool callback, takes lock)
> `-- vmxnet3_xdp_set
> `-- vmxnet3_xdp (ndo_bpf, takes lock)
>
> drivers/net/vmxnet3/vmxnet3_drv.c | 46 +++++++++++++++++++++++-------
> -
> 1 file changed, 35 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c
> b/drivers/net/vmxnet3/vmxnet3_drv.c
> index 40522afc0532..350e44286c00 100644
> --- a/drivers/net/vmxnet3/vmxnet3_drv.c
> +++ b/drivers/net/vmxnet3/vmxnet3_drv.c
> @@ -2775,18 +2775,18 @@ static u8 *
> vmxnet3_copy_mc(struct net_device *netdev) {
> u8 *buf = NULL;
...
> err);
> --
> 2.47.3
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [Intel-wired-lan] [PATCH net-next v9 7/7] pcnet32: Implement ndo_set_rx_mode_async callback
2026-03-14 18:28 ` [PATCH net-next v9 7/7] pcnet32: " I Viswanath
@ 2026-03-16 7:35 ` Loktionov, Aleksandr
0 siblings, 0 replies; 18+ messages in thread
From: Loktionov, Aleksandr @ 2026-03-16 7:35 UTC (permalink / raw)
To: I Viswanath, stfomichev@gmail.com, horms@kernel.org,
edumazet@google.com, pabeni@redhat.com, andrew+netdev@lunn.ch,
kuba@kernel.org, davem@davemloft.net, eperezma@redhat.com,
xuanzhuo@linux.alibaba.com, jasowang@redhat.com, mst@redhat.com,
Kitszel, Przemyslaw, Nguyen, Anthony L, Keller, Jacob E,
ronak.doshi@broadcom.com, pcnet32@frontier.com
Cc: bcm-kernel-feedback-list@broadcom.com, netdev@vger.kernel.org,
virtualization@lists.linux.dev, intel-wired-lan@lists.osuosl.org,
linux-kernel@vger.kernel.org
> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf
> Of I Viswanath
> Sent: Saturday, March 14, 2026 7:28 PM
> To: stfomichev@gmail.com; horms@kernel.org; edumazet@google.com;
> pabeni@redhat.com; andrew+netdev@lunn.ch; kuba@kernel.org;
> davem@davemloft.net; eperezma@redhat.com; xuanzhuo@linux.alibaba.com;
> jasowang@redhat.com; mst@redhat.com; Kitszel, Przemyslaw
> <przemyslaw.kitszel@intel.com>; Nguyen, Anthony L
> <anthony.l.nguyen@intel.com>; Keller, Jacob E
> <jacob.e.keller@intel.com>; ronak.doshi@broadcom.com;
> pcnet32@frontier.com
> Cc: bcm-kernel-feedback-list@broadcom.com; netdev@vger.kernel.org;
> virtualization@lists.linux.dev; intel-wired-lan@lists.osuosl.org;
> linux-kernel@vger.kernel.org; I Viswanath
> <viswanathiyyappan@gmail.com>
> Subject: [Intel-wired-lan] [PATCH net-next v9 7/7] pcnet32: Implement
> ndo_set_rx_mode_async callback
>
> Implement the ndo_set_rx_mode_async callback and update the driver to
> use the snapshot/commit model for RX mode update.
>
> Signed-off-by: I Viswanath <viswanathiyyappan@gmail.com>
> ---
>
> There are no calls to netif_set_rx_mode in pcnet32
>
> drivers/net/ethernet/amd/pcnet32.c | 65 ++++++++++++++++++++++++-----
> -
> 1 file changed, 53 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/net/ethernet/amd/pcnet32.c
> b/drivers/net/ethernet/amd/pcnet32.c
> index 911808ab13a7..d5ad96985d68 100644
> --- a/drivers/net/ethernet/amd/pcnet32.c
> +++ b/drivers/net/ethernet/amd/pcnet32.c
> @@ -314,8 +314,9 @@ static void pcnet32_tx_timeout(struct net_device
> *dev, unsigned int txqueue); static irqreturn_t
> pcnet32_interrupt(int, void *); static int pcnet32_close(struct
> net_device *); static struct net_device_stats
> *pcnet32_get_stats(struct net_device *); -static void
> pcnet32_load_multicast(struct net_device *dev);
...
> --
> 2.47.3
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v9 0/7] Introduce async callback ndo_set_rx_mode_async
2026-03-14 19:59 ` I Viswanath
@ 2026-03-17 16:15 ` Jakub Kicinski
0 siblings, 0 replies; 18+ messages in thread
From: Jakub Kicinski @ 2026-03-17 16:15 UTC (permalink / raw)
To: I Viswanath
Cc: stfomichev, horms, edumazet, pabeni, andrew+netdev, davem,
eperezma, xuanzhuo, jasowang, mst, przemyslaw.kitszel,
anthony.l.nguyen, jacob.e.keller, ronak.doshi, pcnet32,
bcm-kernel-feedback-list, netdev, virtualization, intel-wired-lan,
linux-kernel
On Sun, 15 Mar 2026 01:29:14 +0530 I Viswanath wrote:
> On Sun, 15 Mar 2026 at 01:36, Jakub Kicinski <kuba@kernel.org> wrote:
> > Stan is actively working on this:
> > https://lore.kernel.org/20260313145113.1424442-1-sdf@fomichev.me
> > I feel like I spent enough time reviewing your attempts and Stan
> > will not need as much maintainer attention to bring this to
> > a closure so let him cook. Sorry.
>
> Honestly, I should be thanking you for not throwing it out sooner. I
> don't think I was skilled/experienced to actually make it work and
> someone more qualified should handle this. On the bright side, That
> means I am now much better at solving regular boring bugs and I think
> that's what matters. Cheers
Thank you for the understanding!
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2026-03-17 16:15 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-14 18:28 [PATCH net-next v9 0/7] Introduce async callback ndo_set_rx_mode_async I Viswanath
2026-03-14 18:28 ` [PATCH net-next v9 1/7] net: core: Add state tracking for async netdev ops I Viswanath
2026-03-16 7:25 ` [Intel-wired-lan] " Loktionov, Aleksandr
2026-03-14 18:28 ` [PATCH net-next v9 2/7] net: core: Introduce callback ndo_set_rx_mode_async I Viswanath
2026-03-16 7:29 ` [Intel-wired-lan] " Loktionov, Aleksandr
2026-03-14 18:28 ` [PATCH net-next v9 3/7] virtio-net: Implement ndo_set_rx_mode_async callback I Viswanath
2026-03-16 7:30 ` [Intel-wired-lan] " Loktionov, Aleksandr
2026-03-14 18:28 ` [PATCH net-next v9 4/7] e1000: " I Viswanath
2026-03-16 7:30 ` [Intel-wired-lan] " Loktionov, Aleksandr
2026-03-14 18:28 ` [PATCH net-next v9 5/7] 8139cp: " I Viswanath
2026-03-16 7:34 ` [Intel-wired-lan] " Loktionov, Aleksandr
2026-03-14 18:28 ` [PATCH net-next v9 6/7] vmxnet3: " I Viswanath
2026-03-16 7:35 ` [Intel-wired-lan] " Loktionov, Aleksandr
2026-03-14 18:28 ` [PATCH net-next v9 7/7] pcnet32: " I Viswanath
2026-03-16 7:35 ` [Intel-wired-lan] " Loktionov, Aleksandr
2026-03-14 20:06 ` [PATCH net-next v9 0/7] Introduce async callback ndo_set_rx_mode_async Jakub Kicinski
2026-03-14 19:59 ` I Viswanath
2026-03-17 16:15 ` Jakub Kicinski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox