* [PATCH net-next v5 1/6] ibmvnic: Change system_long_wq with system_dfl_long_wq
2026-11-02 10:56 [PATCH net-next v5 0/6] net: Move system_long_wq to system_dfl_long_wq Marco Crivellari
@ 2026-11-02 10:56 ` Marco Crivellari
2026-11-02 10:56 ` [PATCH net-next v5 2/6] net: ti: icssg-stats: Move long delayed work on system_dfl_long_wq Marco Crivellari
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Marco Crivellari @ 2026-11-02 10:56 UTC (permalink / raw)
To: linux-kernel, netdev
Cc: Tejun Heo, Lai Jiangshan, Frederic Weisbecker,
Sebastian Andrzej Siewior, Marco Crivellari, Michal Hocko,
Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Haren Myneni, Rick Lindsley, Nick Child,
Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy (CS GROUP),
linuxppc-dev, Mingming Cao
Currently the code enqueues the reset work items on system_long_wq: the
ibmvnic_delayed_reset delayed work using queue_delayed_work(), and the
ibmvnic_reset work using queue_work(). This workqueue should be used when
long works are expected and it is a per-cpu workqueue.
queue_delayed_work() ends up calling __queue_delayed_work(), which, since
IBMVNIC_RESET_DELAY is non-zero, sets a global timer that could fire
anywhere, enqueuing the work where the timer fired. queue_work(), instead,
enqueues the work on the local CPU, i.e. the CPU that requested the reset.
Unbound works could benefit from scheduler task placement, to optimize
performance and power consumption. Long work shouldn't stick to a single
CPU.
Recently, a new unbound workqueue specific for long running work has
been added:
c116737e972e ("workqueue: Add system_dfl_long_wq for long unbound works")
Since the reset work doesn't rely on per-cpu variables, there is no
obvious reason that justify the use of a per-cpu workqueue. So change
system_long_wq with system_dfl_long_wq so that the work may benefit from
scheduler task placement.
Both work items run the same handler, __ibmvnic_reset(), and every reset
request is scheduled through the queue_work() call in ibmvnic_reset().
So convert this call site too, so that all the reset work runs on an
unbound workqueue instead of the CPU that submitted the request.
Cc: Haren Myneni <haren@linux.ibm.com>
Cc: Rick Lindsley <ricklind@linux.ibm.com>
Cc: Nick Child <nnac123@linux.ibm.com>
Cc: Madhavan Srinivasan <maddy@linux.ibm.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
Cc: linuxppc-dev@lists.ozlabs.org
Signed-off-by: Marco Crivellari <marco.crivellari@suse.com>
Acked-by: Mingming Cao <mmc@linux.ibm.com>
---
drivers/net/ethernet/ibm/ibmvnic.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
index 5a510eed335e..d4c284c8ef43 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -3229,7 +3229,7 @@ static void __ibmvnic_reset(struct work_struct *work)
if (adapter->state == VNIC_PROBING &&
!wait_for_completion_timeout(&adapter->probe_done, timeout)) {
dev_err(dev, "Reset thread timed out on probe");
- queue_delayed_work(system_long_wq,
+ queue_delayed_work(system_dfl_long_wq,
&adapter->ibmvnic_delayed_reset,
IBMVNIC_RESET_DELAY);
return;
@@ -3267,7 +3267,7 @@ static void __ibmvnic_reset(struct work_struct *work)
spin_lock(&adapter->rwi_lock);
if (!list_empty(&adapter->rwi_list)) {
if (test_and_set_bit_lock(0, &adapter->resetting)) {
- queue_delayed_work(system_long_wq,
+ queue_delayed_work(system_dfl_long_wq,
&adapter->ibmvnic_delayed_reset,
IBMVNIC_RESET_DELAY);
} else {
@@ -3454,7 +3454,7 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
list_add_tail(&rwi->list, &adapter->rwi_list);
netdev_dbg(adapter->netdev, "Scheduling reset (reason %s)\n",
reset_reason_to_string(reason));
- queue_work(system_long_wq, &adapter->ibmvnic_reset);
+ queue_work(system_dfl_long_wq, &adapter->ibmvnic_reset);
ret = 0;
err:
--
2.56.0
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH net-next v5 2/6] net: ti: icssg-stats: Move long delayed work on system_dfl_long_wq
2026-11-02 10:56 [PATCH net-next v5 0/6] net: Move system_long_wq to system_dfl_long_wq Marco Crivellari
2026-11-02 10:56 ` [PATCH net-next v5 1/6] ibmvnic: Change system_long_wq with system_dfl_long_wq Marco Crivellari
@ 2026-11-02 10:56 ` Marco Crivellari
2026-11-02 10:56 ` [PATCH net-next v5 3/6] net: ti: icssg-prueth: " Marco Crivellari
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Marco Crivellari @ 2026-11-02 10:56 UTC (permalink / raw)
To: linux-kernel, netdev
Cc: Tejun Heo, Lai Jiangshan, Frederic Weisbecker,
Sebastian Andrzej Siewior, Marco Crivellari, Michal Hocko,
Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, MD Danish Anwar, Roger Quadros, linux-arm-kernel,
Richard Cheng
Currently the code enqueue work items using {queue|mod}_delayed_work(),
using system_long_wq. This workqueue should be used when long works are
expected and it is a per-cpu workqueue.
The function(s) end up calling __queue_delayed_work(), which set a global
timer that could fire anywhere, enqueuing the work where the timer fired.
Unbound works could benefit from scheduler task placement, to optimize
performance and power consumption. Long work shouldn't stick to a single
CPU.
Recently, a new unbound workqueue specific for long running work has
been added:
c116737e972e ("workqueue: Add system_dfl_long_wq for long unbound works")
Since the workqueue work doesn't rely on per-cpu variables, there is no
obvious reason that justify the use of a per-cpu workqueue. So change
system_long_wq with system_dfl_long_wq so that the work may benefit from
scheduler task placement.
Cc: MD Danish Anwar <danishanwar@ti.com>
Cc: Roger Quadros <rogerq@kernel.org>
Cc: linux-arm-kernel@lists.infradead.org
Signed-off-by: Marco Crivellari <marco.crivellari@suse.com>
Reviewed-by: Richard Cheng <icheng@nvidia.com>
---
drivers/net/ethernet/ti/icssg/icssg_stats.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.c b/drivers/net/ethernet/ti/icssg/icssg_stats.c
index 7159baa0155c..7d6d6692d819 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_stats.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_stats.c
@@ -69,7 +69,7 @@ void icssg_stats_work_handler(struct work_struct *work)
stats_work.work);
emac_update_hardware_stats(emac);
- queue_delayed_work(system_long_wq, &emac->stats_work,
+ queue_delayed_work(system_dfl_long_wq, &emac->stats_work,
msecs_to_jiffies((STATS_TIME_LIMIT_1G_MS * 1000) / emac->speed));
}
EXPORT_SYMBOL_GPL(icssg_stats_work_handler);
--
2.56.0
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH net-next v5 3/6] net: ti: icssg-prueth: Move long delayed work on system_dfl_long_wq
2026-11-02 10:56 [PATCH net-next v5 0/6] net: Move system_long_wq to system_dfl_long_wq Marco Crivellari
2026-11-02 10:56 ` [PATCH net-next v5 1/6] ibmvnic: Change system_long_wq with system_dfl_long_wq Marco Crivellari
2026-11-02 10:56 ` [PATCH net-next v5 2/6] net: ti: icssg-stats: Move long delayed work on system_dfl_long_wq Marco Crivellari
@ 2026-11-02 10:56 ` Marco Crivellari
2026-11-02 10:56 ` [PATCH net-next v5 4/6] net: thunderbolt: " Marco Crivellari
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Marco Crivellari @ 2026-11-02 10:56 UTC (permalink / raw)
To: linux-kernel, netdev
Cc: Tejun Heo, Lai Jiangshan, Frederic Weisbecker,
Sebastian Andrzej Siewior, Marco Crivellari, Michal Hocko,
Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, MD Danish Anwar, Roger Quadros
Currently emac_ndo_open() starts the stats work for the first time with
queue_work(), using system_long_wq. This workqueue should be used when
long works are expected and it is a per-cpu workqueue.
queue_work() on a per-cpu workqueue enqueues the work on the local CPU,
so the first execution of the work is bound to the CPU that opened the
interface.
Unbound works could benefit from scheduler task placement, to optimize
performance and power consumption. Long work shouldn't stick to a single
CPU.
Recently, a new unbound workqueue specific for long running work has
been added:
c116737e972e ("workqueue: Add system_dfl_long_wq for long unbound works")
The stats work handler, icssg_stats_work_handler(), already re-queues
itself on system_dfl_long_wq. Since the work doesn't rely on per-cpu
variables, there is no obvious reason that justify the use of a per-cpu
workqueue for the initial queueing either. So change system_long_wq with
system_dfl_long_wq in emac_ndo_open(), in both icssg_prueth.c and
icssg_prueth_sr1.c, so that the work may benefit from scheduler task
placement.
Cc: MD Danish Anwar <danishanwar@ti.com>
Cc: Roger Quadros <rogerq@kernel.org>
Signed-off-by: Marco Crivellari <marco.crivellari@suse.com>
---
drivers/net/ethernet/ti/icssg/icssg_prueth.c | 2 +-
drivers/net/ethernet/ti/icssg/icssg_prueth_sr1.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
index 591be5c8056b..0fba22c1046e 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
@@ -1100,7 +1100,7 @@ static int emac_ndo_open(struct net_device *ndev)
prueth->emacs_initialized++;
- queue_work(system_long_wq, &emac->stats_work.work);
+ queue_work(system_dfl_long_wq, &emac->stats_work.work);
return 0;
diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth_sr1.c b/drivers/net/ethernet/ti/icssg/icssg_prueth_sr1.c
index b8115ca47082..fb7140330671 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth_sr1.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth_sr1.c
@@ -602,7 +602,7 @@ static int emac_ndo_open(struct net_device *ndev)
prueth->emacs_initialized++;
- queue_work(system_long_wq, &emac->stats_work.work);
+ queue_work(system_dfl_long_wq, &emac->stats_work.work);
return 0;
--
2.56.0
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH net-next v5 4/6] net: thunderbolt: Move long delayed work on system_dfl_long_wq
2026-11-02 10:56 [PATCH net-next v5 0/6] net: Move system_long_wq to system_dfl_long_wq Marco Crivellari
` (2 preceding siblings ...)
2026-11-02 10:56 ` [PATCH net-next v5 3/6] net: ti: icssg-prueth: " Marco Crivellari
@ 2026-11-02 10:56 ` Marco Crivellari
2026-11-02 10:56 ` [PATCH net-next v5 5/6] net: usb: pegasus: " Marco Crivellari
2026-11-02 10:56 ` [PATCH net-next v5 6/6] net: usb: r8152: " Marco Crivellari
5 siblings, 0 replies; 7+ messages in thread
From: Marco Crivellari @ 2026-11-02 10:56 UTC (permalink / raw)
To: linux-kernel, netdev
Cc: Tejun Heo, Lai Jiangshan, Frederic Weisbecker,
Sebastian Andrzej Siewior, Marco Crivellari, Michal Hocko,
Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Mika Westerberg, Yehezkel Bernat
Currently the code enqueues the login_work delayed work using
queue_delayed_work(), on system_long_wq. This workqueue should be used
when long works are expected and it is a per-cpu workqueue.
queue_delayed_work() ends up calling __queue_delayed_work(), which, for
a non-zero delay, sets a global timer that could fire anywhere, enqueuing
the work where the timer fired. With a zero delay, as in
tbnet_handle_packet(), no timer is armed and the work is enqueued
directly on the local CPU, i.e. the CPU that handled the TBIP_LOGIN
packet.
Unbound works could benefit from scheduler task placement, to optimize
performance and power consumption. Long work shouldn't stick to a single
CPU.
Recently, a new unbound workqueue specific for long running work has
been added:
c116737e972e ("workqueue: Add system_dfl_long_wq for long unbound works")
Since login_work doesn't rely on per-cpu variables, there is no obvious
reason that justify the use of a per-cpu workqueue. So change
system_long_wq with system_dfl_long_wq for login_work, so that the work
may benefit from scheduler task placement.
Cc: Mika Westerberg <westeri@kernel.org>
Cc: Yehezkel Bernat <YehezkelShB@gmail.com>
Signed-off-by: Marco Crivellari <marco.crivellari@suse.com>
Acked-by: Mika Westerberg <westeri@kernel.org>
---
drivers/net/thunderbolt/main.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/net/thunderbolt/main.c b/drivers/net/thunderbolt/main.c
index cf51b9c39f4e..e36a4e1da05d 100644
--- a/drivers/net/thunderbolt/main.c
+++ b/drivers/net/thunderbolt/main.c
@@ -316,7 +316,7 @@ static void start_login(struct tbnet *net)
net->login_received = false;
mutex_unlock(&net->connection_lock);
- queue_delayed_work(system_long_wq, &net->login_work,
+ queue_delayed_work(system_dfl_long_wq, &net->login_work,
msecs_to_jiffies(1000));
}
@@ -470,7 +470,7 @@ static int tbnet_handle_packet(const void *buf, size_t size, void *data)
if (net->login_retries >= TBNET_LOGIN_RETRIES ||
!net->login_sent) {
net->login_retries = 0;
- queue_delayed_work(system_long_wq,
+ queue_delayed_work(system_dfl_long_wq,
&net->login_work, 0);
}
mutex_unlock(&net->connection_lock);
@@ -723,7 +723,8 @@ static void tbnet_login_work(struct work_struct *work)
netdev_dbg(net->dev, "sending login request failed, ret=%d\n",
ret);
if (net->login_retries++ < TBNET_LOGIN_RETRIES) {
- queue_delayed_work(system_long_wq, &net->login_work,
+ queue_delayed_work(system_dfl_long_wq,
+ &net->login_work,
delay);
} else {
netdev_info(net->dev, "ThunderboltIP login timed out\n");
--
2.56.0
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH net-next v5 5/6] net: usb: pegasus: Move long delayed work on system_dfl_long_wq
2026-11-02 10:56 [PATCH net-next v5 0/6] net: Move system_long_wq to system_dfl_long_wq Marco Crivellari
` (3 preceding siblings ...)
2026-11-02 10:56 ` [PATCH net-next v5 4/6] net: thunderbolt: " Marco Crivellari
@ 2026-11-02 10:56 ` Marco Crivellari
2026-11-02 10:56 ` [PATCH net-next v5 6/6] net: usb: r8152: " Marco Crivellari
5 siblings, 0 replies; 7+ messages in thread
From: Marco Crivellari @ 2026-11-02 10:56 UTC (permalink / raw)
To: linux-kernel, netdev
Cc: Tejun Heo, Lai Jiangshan, Frederic Weisbecker,
Sebastian Andrzej Siewior, Marco Crivellari, Michal Hocko,
Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Petko Manolov, linux-usb
Currently the code enqueues the carrier_check delayed work using
queue_delayed_work(), on system_long_wq. This workqueue should be used
when long works are expected and it is a per-cpu workqueue.
queue_delayed_work() ends up calling __queue_delayed_work(), which, since
the work is always queued with CARRIER_CHECK_DELAY, sets a global timer
that could fire anywhere, enqueuing the work where the timer fired.
Unbound works could benefit from scheduler task placement, to optimize
performance and power consumption. Long work shouldn't stick to a single
CPU.
Recently, a new unbound workqueue specific for long running work has
been added:
c116737e972e ("workqueue: Add system_dfl_long_wq for long unbound works")
Since carrier_check doesn't rely on per-cpu variables, there is no
obvious reason that justify the use of a per-cpu workqueue. So change
system_long_wq with system_dfl_long_wq so that the work may benefit from
scheduler task placement.
Cc: Petko Manolov <petkan@nucleusys.com>
Cc: linux-usb@vger.kernel.org
Signed-off-by: Marco Crivellari <marco.crivellari@suse.com>
Reviewed-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
drivers/net/usb/pegasus.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index 68e4b6658dd2..a4ecfec290b6 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -1126,8 +1126,9 @@ static void check_carrier(struct work_struct *work)
pegasus_t *pegasus = container_of(work, pegasus_t, carrier_check.work);
set_carrier(pegasus->net);
if (!(pegasus->flags & PEGASUS_UNPLUG)) {
- queue_delayed_work(system_long_wq, &pegasus->carrier_check,
- CARRIER_CHECK_DELAY);
+ queue_delayed_work(system_dfl_long_wq,
+ &pegasus->carrier_check,
+ CARRIER_CHECK_DELAY);
}
}
@@ -1231,7 +1232,7 @@ static int pegasus_probe(struct usb_interface *intf,
res = register_netdev(net);
if (res)
goto out3;
- queue_delayed_work(system_long_wq, &pegasus->carrier_check,
+ queue_delayed_work(system_dfl_long_wq, &pegasus->carrier_check,
CARRIER_CHECK_DELAY);
dev_info(&intf->dev, "%s, %s, %pM\n", net->name,
info ? info->name : "(unknown)", net->dev_addr);
@@ -1296,7 +1297,7 @@ static int pegasus_resume(struct usb_interface *intf)
pegasus->intr_urb->actual_length = 0;
intr_callback(pegasus->intr_urb);
}
- queue_delayed_work(system_long_wq, &pegasus->carrier_check,
+ queue_delayed_work(system_dfl_long_wq, &pegasus->carrier_check,
CARRIER_CHECK_DELAY);
return 0;
}
--
2.56.0
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH net-next v5 6/6] net: usb: r8152: Move long delayed work on system_dfl_long_wq
2026-11-02 10:56 [PATCH net-next v5 0/6] net: Move system_long_wq to system_dfl_long_wq Marco Crivellari
` (4 preceding siblings ...)
2026-11-02 10:56 ` [PATCH net-next v5 5/6] net: usb: pegasus: " Marco Crivellari
@ 2026-11-02 10:56 ` Marco Crivellari
5 siblings, 0 replies; 7+ messages in thread
From: Marco Crivellari @ 2026-11-02 10:56 UTC (permalink / raw)
To: linux-kernel, netdev
Cc: Tejun Heo, Lai Jiangshan, Frederic Weisbecker,
Sebastian Andrzej Siewior, Marco Crivellari, Michal Hocko,
Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Ethan Nelson-Moore, linux-usb
Currently the code enqueue work items using {queue|mod}_delayed_work(),
using system_long_wq. This workqueue should be used when long works are
expected and it is a per-cpu workqueue.
The function(s) end up calling __queue_delayed_work(), which set a global
timer that could fire anywhere, enqueuing the work where the timer fired.
Unbound works could benefit from scheduler task placement, to optimize
performance and power consumption. Long work shouldn't stick to a single
CPU.
Recently, a new unbound workqueue specific for long running work has
been added:
c116737e972e ("workqueue: Add system_dfl_long_wq for long unbound works")
Since the workqueue work doesn't rely on per-cpu variables, there is no
obvious reason that justify the use of a per-cpu workqueue. So change
system_long_wq with system_dfl_long_wq so that the work may benefit from
scheduler task placement.
Cc: Ethan Nelson-Moore <enelsonmoore@gmail.com>
Cc: linux-usb@vger.kernel.org
Signed-off-by: Marco Crivellari <marco.crivellari@suse.com>
---
drivers/net/usb/r8152.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index d3bb7ee9c9bf..4815235e8e73 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -7053,7 +7053,8 @@ static void rtl_hw_phy_work_func_t(struct work_struct *work)
/* Delay execution in case request_firmware() is not ready yet.
*/
- queue_delayed_work(system_long_wq, &tp->hw_phy_work, HZ * 10);
+ queue_delayed_work(system_dfl_long_wq, &tp->hw_phy_work,
+ HZ * 10);
goto ignore_once;
}
@@ -8821,7 +8822,7 @@ static int rtl8152_reset_resume(struct usb_interface *intf)
clear_bit(SELECTIVE_SUSPEND, &tp->flags);
rtl_reset_ocp_base(tp);
tp->rtl_ops.init(tp);
- queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0);
+ queue_delayed_work(system_dfl_long_wq, &tp->hw_phy_work, 0);
set_ethernet_addr(tp, true);
return rtl8152_resume(intf);
}
@@ -10276,7 +10277,7 @@ static int rtl8152_probe_once(struct usb_interface *intf,
/* Retry in case request_firmware() is not ready yet. */
tp->rtl_fw.retry = true;
#endif
- queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0);
+ queue_delayed_work(system_dfl_long_wq, &tp->hw_phy_work, 0);
set_ethernet_addr(tp, false);
usb_set_intfdata(intf, tp);
--
2.56.0
^ permalink raw reply [flat|nested] 7+ messages in thread