From 78f5d0d5a23dd81106cbe999d9dcd522964a8f1a Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Fri, 7 Nov 2025 15:25:26 +0100 Subject: [PATCH 1/3] PCI: Add WQ_PERCPU to alloc_workqueue() users Currently work items enqueued by schedule_delayed_work() use "system_wq" (a per-CPU wq), while queue_delayed_work() uses WORK_CPU_UNBOUND (used when a CPU is not specified). The same applies to schedule_work() that is using system_wq and queue_work(), that makes use again of WORK_CPU_UNBOUND. This lack of consistency cannot be addressed without refactoring the API. alloc_workqueue() treats all queues as per-CPU by default, while unbound workqueues must opt-in via WQ_UNBOUND. This default is suboptimal: most workloads benefit from unbound queues, allowing the scheduler to place worker threads where they're needed and reducing noise when CPUs are isolated. This continues the effort to refactor workqueue APIs, which began with the introduction of new workqueues and a new alloc_workqueue() flag in: 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq") 930c2ea566af ("workqueue: Add new WQ_PERCPU flag") Add WQ_PERCPU to explicitly request alloc_workqueue() to be per-CPU when WQ_UNBOUND has not been specified. With the introduction of the WQ_PERCPU flag (equivalent to !WQ_UNBOUND), any alloc_workqueue() caller that doesn't explicitly specify WQ_UNBOUND must now use WQ_PERCPU. Once migration is complete, WQ_UNBOUND can be removed and unbound will become the implicit default. Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari [bhelgaas: squash similar commits] Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20251107142526.234685-1-marco.crivellari@suse.com Link: https://patch.msgid.link/20251107142835.237636-1-marco.crivellari@suse.com Link: https://patch.msgid.link/20251107143108.240025-1-marco.crivellari@suse.com Link: https://patch.msgid.link/20251107143335.242342-1-marco.crivellari@suse.com Link: https://patch.msgid.link/20251107143624.244978-1-marco.crivellari@suse.com --- drivers/pci/endpoint/functions/pci-epf-mhi.c | 2 +- drivers/pci/endpoint/functions/pci-epf-ntb.c | 4 ++-- drivers/pci/endpoint/functions/pci-epf-test.c | 2 +- drivers/pci/endpoint/functions/pci-epf-vntb.c | 4 ++-- drivers/pci/hotplug/pnv_php.c | 2 +- drivers/pci/hotplug/shpchp_core.c | 3 ++- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/pci/endpoint/functions/pci-epf-mhi.c b/drivers/pci/endpoint/functions/pci-epf-mhi.c index 6643a88c7a0c..27de533f0571 100644 --- a/drivers/pci/endpoint/functions/pci-epf-mhi.c +++ b/drivers/pci/endpoint/functions/pci-epf-mhi.c @@ -686,7 +686,7 @@ static int pci_epf_mhi_dma_init(struct pci_epf_mhi *epf_mhi) goto err_release_tx; } - epf_mhi->dma_wq = alloc_workqueue("pci_epf_mhi_dma_wq", 0, 0); + epf_mhi->dma_wq = alloc_workqueue("pci_epf_mhi_dma_wq", WQ_PERCPU, 0); if (!epf_mhi->dma_wq) { ret = -ENOMEM; goto err_release_rx; diff --git a/drivers/pci/endpoint/functions/pci-epf-ntb.c b/drivers/pci/endpoint/functions/pci-epf-ntb.c index e01a98e74d21..9ea8b57d69d7 100644 --- a/drivers/pci/endpoint/functions/pci-epf-ntb.c +++ b/drivers/pci/endpoint/functions/pci-epf-ntb.c @@ -2124,8 +2124,8 @@ static int __init epf_ntb_init(void) { int ret; - kpcintb_workqueue = alloc_workqueue("kpcintb", WQ_MEM_RECLAIM | - WQ_HIGHPRI, 0); + kpcintb_workqueue = alloc_workqueue("kpcintb", + WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_PERCPU, 0); ret = pci_epf_register_driver(&epf_ntb_driver); if (ret) { destroy_workqueue(kpcintb_workqueue); diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c index debd235253c5..62804120cd79 100644 --- a/drivers/pci/endpoint/functions/pci-epf-test.c +++ b/drivers/pci/endpoint/functions/pci-epf-test.c @@ -1188,7 +1188,7 @@ static int __init pci_epf_test_init(void) int ret; kpcitest_workqueue = alloc_workqueue("kpcitest", - WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); + WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_PERCPU, 0); if (!kpcitest_workqueue) { pr_err("Failed to allocate the kpcitest work queue\n"); return -ENOMEM; diff --git a/drivers/pci/endpoint/functions/pci-epf-vntb.c b/drivers/pci/endpoint/functions/pci-epf-vntb.c index 3ecc5059f92b..a098727f784b 100644 --- a/drivers/pci/endpoint/functions/pci-epf-vntb.c +++ b/drivers/pci/endpoint/functions/pci-epf-vntb.c @@ -1651,8 +1651,8 @@ static int __init epf_ntb_init(void) { int ret; - kpcintb_workqueue = alloc_workqueue("kpcintb", WQ_MEM_RECLAIM | - WQ_HIGHPRI, 0); + kpcintb_workqueue = alloc_workqueue("kpcintb", + WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_PERCPU, 0); ret = pci_epf_register_driver(&epf_ntb_driver); if (ret) { destroy_workqueue(kpcintb_workqueue); diff --git a/drivers/pci/hotplug/pnv_php.c b/drivers/pci/hotplug/pnv_php.c index c5345bff9a55..35f1758126c6 100644 --- a/drivers/pci/hotplug/pnv_php.c +++ b/drivers/pci/hotplug/pnv_php.c @@ -802,7 +802,7 @@ static struct pnv_php_slot *pnv_php_alloc_slot(struct device_node *dn) } /* Allocate workqueue for this slot's interrupt handling */ - php_slot->wq = alloc_workqueue("pciehp-%s", 0, 0, php_slot->name); + php_slot->wq = alloc_workqueue("pciehp-%s", WQ_PERCPU, 0, php_slot->name); if (!php_slot->wq) { SLOT_WARN(php_slot, "Cannot alloc workqueue\n"); kfree(php_slot->name); diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 0c341453afc6..56308515ecba 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -80,7 +80,8 @@ static int init_slots(struct controller *ctrl) slot->device = ctrl->slot_device_offset + i; slot->number = ctrl->first_slot + (ctrl->slot_num_inc * i); - slot->wq = alloc_workqueue("shpchp-%d", 0, 0, slot->number); + slot->wq = alloc_workqueue("shpchp-%d", WQ_PERCPU, 0, + slot->number); if (!slot->wq) { retval = -ENOMEM; goto error_slot; From 0d325cbdc5ce97e6bd391d6a742607814025e69d Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Wed, 5 Nov 2025 16:16:49 +0100 Subject: [PATCH 2/3] PCI: endpoint: Replace use of system_wq with system_percpu_wq Currently work items enqueued by schedule_delayed_work() use "system_wq" (a per-CPU wq) while queue_delayed_work() uses WORK_CPU_UNBOUND (used when a CPU is not specified). The same applies to schedule_work() that is using system_wq and queue_work(), that makes use again of WORK_CPU_UNBOUND. This lack of consistency cannot be addressed without refactoring the API. This continues the effort to refactor workqueue APIs, which began with the introduction of new workqueues and a new alloc_workqueue() flag in: 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq") 930c2ea566af ("workqueue: Add new WQ_PERCPU flag") Replace system_wq with system_percpu_wq, keeping the same behavior. The old wq (system_wq) will be kept for a few release cycles. Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20251105151649.256274-1-marco.crivellari@suse.com --- drivers/pci/endpoint/pci-ep-cfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/endpoint/pci-ep-cfs.c b/drivers/pci/endpoint/pci-ep-cfs.c index ef50c82e647f..c787ce59d9de 100644 --- a/drivers/pci/endpoint/pci-ep-cfs.c +++ b/drivers/pci/endpoint/pci-ep-cfs.c @@ -638,7 +638,7 @@ static struct config_group *pci_epf_make(struct config_group *group, kfree(epf_name); INIT_DELAYED_WORK(&epf_group->cfs_work, pci_epf_cfs_work); - queue_delayed_work(system_wq, &epf_group->cfs_work, + queue_delayed_work(system_percpu_wq, &epf_group->cfs_work, msecs_to_jiffies(1)); return &epf_group->group; From 03f336a869b3a3f119d3ae52ac9723739c7fb7b6 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Mon, 10 Nov 2025 12:04:46 +0800 Subject: [PATCH 3/3] PCI: endpoint: Add missing NULL check for alloc_workqueue() alloc_workqueue() can return NULL on memory allocation failure. Without proper error checking, this may lead to a NULL pointer dereference when queue_work() is later called with the NULL workqueue pointer in epf_ntb_epc_init(). Add a NULL check immediately after alloc_workqueue() and return -ENOMEM on failure to prevent the driver from loading with an invalid workqueue pointer. Fixes: e35f56bb0330 ("PCI: endpoint: Support NTB transfer between RC and EP") Fixes: 8b821cf76150 ("PCI: endpoint: Add EP function driver to provide NTB functionality") Signed-off-by: Haotian Zhang Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20251110040446.2065-1-vulab@iscas.ac.cn --- drivers/pci/endpoint/functions/pci-epf-ntb.c | 5 +++++ drivers/pci/endpoint/functions/pci-epf-vntb.c | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/drivers/pci/endpoint/functions/pci-epf-ntb.c b/drivers/pci/endpoint/functions/pci-epf-ntb.c index 9ea8b57d69d7..a3a588e522e7 100644 --- a/drivers/pci/endpoint/functions/pci-epf-ntb.c +++ b/drivers/pci/endpoint/functions/pci-epf-ntb.c @@ -2126,6 +2126,11 @@ static int __init epf_ntb_init(void) kpcintb_workqueue = alloc_workqueue("kpcintb", WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_PERCPU, 0); + if (!kpcintb_workqueue) { + pr_err("Failed to allocate kpcintb workqueue\n"); + return -ENOMEM; + } + ret = pci_epf_register_driver(&epf_ntb_driver); if (ret) { destroy_workqueue(kpcintb_workqueue); diff --git a/drivers/pci/endpoint/functions/pci-epf-vntb.c b/drivers/pci/endpoint/functions/pci-epf-vntb.c index a098727f784b..20a400e83439 100644 --- a/drivers/pci/endpoint/functions/pci-epf-vntb.c +++ b/drivers/pci/endpoint/functions/pci-epf-vntb.c @@ -1653,6 +1653,11 @@ static int __init epf_ntb_init(void) kpcintb_workqueue = alloc_workqueue("kpcintb", WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_PERCPU, 0); + if (!kpcintb_workqueue) { + pr_err("Failed to allocate kpcintb workqueue\n"); + return -ENOMEM; + } + ret = pci_epf_register_driver(&epf_ntb_driver); if (ret) { destroy_workqueue(kpcintb_workqueue);