From: "Jinhui Guo" <guojinhui.liam@bytedance.com>
To: <dakr@kernel.org>, <alexanderduyck@fb.com>, <bhelgaas@google.com>,
<bvanassche@acm.org>, <dan.j.williams@intel.com>,
<gregkh@linuxfoundation.org>, <helgaas@kernel.org>,
<rafael@kernel.org>, <tj@kernel.org>, <frederic@kernel.org>
Cc: <guojinhui.liam@bytedance.com>, <linux-kernel@vger.kernel.org>,
<linux-pci@vger.kernel.org>
Subject: [PATCH v2 2/3] driver core: Add NUMA-node awareness to the synchronous probe path
Date: Thu, 22 Jan 2026 22:52:07 +0800 [thread overview]
Message-ID: <20260122145208.1013-3-guojinhui.liam@bytedance.com> (raw)
In-Reply-To: <20260122145208.1013-1-guojinhui.liam@bytedance.com>
Introduce NUMA-node-aware synchronous probing: drivers
can initialize and allocate memory on the device’s local
node without scattering kmalloc_node() calls throughout
the code.
NUMA-aware probing was first added to PCI drivers by
commit d42c69972b85 ("[PATCH] PCI: Run PCI driver
initialization on local node") in 2005 and has benefited
PCI drivers ever since.
The asynchronous probe path already supports NUMA-node-aware
probing via async_schedule_dev() in the driver core. Since
NUMA affinity is orthogonal to sync/async probing, this
patch adds NUMA-node-aware support to the synchronous
probe path.
Signed-off-by: Jinhui Guo <guojinhui.liam@bytedance.com>
---
drivers/base/dd.c | 76 +++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 70 insertions(+), 6 deletions(-)
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index b6be95871d3d..a8d560034abe 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -810,10 +810,56 @@ static int __driver_probe_device(const struct device_driver *drv, struct device
return ret;
}
+/* Context for NUMA execution */
+struct numa_work_ctx {
+ struct work_struct work;
+ const struct device_driver *drv;
+ struct device *dev;
+ int result;
+};
+
+/* Worker function running on the target node */
+static void __driver_probe_device_node_helper(struct work_struct *work)
+{
+ struct numa_work_ctx *ctx = container_of(work, struct numa_work_ctx, work);
+
+ ctx->result = __driver_probe_device(ctx->drv, ctx->dev);
+}
+
+/*
+ * __driver_probe_device_node - execute __driver_probe_device on a specific NUMA node synchronously
+ * @drv: driver to bind a device to
+ * @dev: device to try to bind to the driver
+ *
+ * Returns the result of the function execution, or -ENODEV if initialization fails.
+ * If the node is invalid or offline, it falls back to local execution.
+ */
+static int __driver_probe_device_node(const struct device_driver *drv, struct device *dev)
+{
+ struct numa_work_ctx ctx;
+ int node = dev_to_node(dev);
+
+ if (node < 0 || node >= MAX_NUMNODES || !node_online(node))
+ return __driver_probe_device(drv, dev);
+
+ ctx.drv = drv;
+ ctx.dev = dev;
+ ctx.result = -ENODEV;
+ INIT_WORK_ONSTACK(&ctx.work, __driver_probe_device_node_helper);
+
+ /* Use system_dfl_wq to allow execution on the specific node. */
+ queue_work_node(node, system_dfl_wq, &ctx.work);
+ flush_work(&ctx.work);
+ destroy_work_on_stack(&ctx.work);
+
+ return ctx.result;
+}
+
/**
* driver_probe_device - attempt to bind device & driver together
* @drv: driver to bind a device to
* @dev: device to try to bind to the driver
+ * @in_async: true if the caller is running in an asynchronous worker context
*
* This function returns -ENODEV if the device is not registered, -EBUSY if it
* already has a driver, 0 if the device is bound successfully and a positive
@@ -824,13 +870,22 @@ static int __driver_probe_device(const struct device_driver *drv, struct device
*
* If the device has a parent, runtime-resume the parent before driver probing.
*/
-static int driver_probe_device(const struct device_driver *drv, struct device *dev)
+static int driver_probe_device(const struct device_driver *drv, struct device *dev, bool in_async)
{
int trigger_count = atomic_read(&deferred_trigger_count);
int ret;
atomic_inc(&probe_count);
- ret = __driver_probe_device(drv, dev);
+ /*
+ * If we are already in an asynchronous worker, invoke __driver_probe_device()
+ * directly to avoid the overhead of an additional workqueue scheduling.
+ * The async subsystem manages its own concurrency and placement.
+ */
+ if (in_async)
+ ret = __driver_probe_device(drv, dev);
+ else
+ ret = __driver_probe_device_node(drv, dev);
+
if (ret == -EPROBE_DEFER || ret == EPROBE_DEFER) {
driver_deferred_probe_add(dev);
@@ -919,6 +974,13 @@ struct device_attach_data {
* driver, we'll encounter one that requests asynchronous probing.
*/
bool have_async;
+
+ /*
+ * True when running inside an asynchronous worker context scheduled
+ * by async_schedule_dev() with callback function
+ * __device_attach_async_helper().
+ */
+ bool in_async;
};
static int __device_attach_driver(struct device_driver *drv, void *_data)
@@ -958,7 +1020,7 @@ static int __device_attach_driver(struct device_driver *drv, void *_data)
* Ignore errors returned by ->probe so that the next driver can try
* its luck.
*/
- ret = driver_probe_device(drv, dev);
+ ret = driver_probe_device(drv, dev, data->in_async);
if (ret < 0)
return ret;
return ret == 0;
@@ -1009,6 +1071,7 @@ static void __device_attach_async_helper(void *_dev, async_cookie_t cookie)
.dev = dev,
.check_async = true,
.want_async = true,
+ .in_async = true,
};
device_lock(dev);
@@ -1055,6 +1118,7 @@ static int __device_attach(struct device *dev, bool allow_async)
.dev = dev,
.check_async = allow_async,
.want_async = false,
+ .in_async = false,
};
ret = __device_attach_driver_scan(&data, &async);
@@ -1144,7 +1208,7 @@ int device_driver_attach(const struct device_driver *drv, struct device *dev)
int ret;
__device_driver_lock(dev, dev->parent);
- ret = __driver_probe_device(drv, dev);
+ ret = __driver_probe_device_node(drv, dev);
__device_driver_unlock(dev, dev->parent);
/* also return probe errors as normal negative errnos */
@@ -1165,7 +1229,7 @@ static void __driver_attach_async_helper(void *_dev, async_cookie_t cookie)
__device_driver_lock(dev, dev->parent);
drv = dev->p->async_driver;
dev->p->async_driver = NULL;
- ret = driver_probe_device(drv, dev);
+ ret = driver_probe_device(drv, dev, true);
__device_driver_unlock(dev, dev->parent);
dev_dbg(dev, "driver %s async attach completed: %d\n", drv->name, ret);
@@ -1233,7 +1297,7 @@ static int __driver_attach(struct device *dev, void *data)
}
__device_driver_lock(dev, dev->parent);
- driver_probe_device(drv, dev);
+ driver_probe_device(drv, dev, false);
__device_driver_unlock(dev, dev->parent);
return 0;
--
2.20.1
next prev parent reply other threads:[~2026-01-22 14:53 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-22 14:52 [PATCH v2 0/3] Add NUMA-node-aware synchronous probing to driver core Jinhui Guo
2026-01-22 14:52 ` [PATCH v2 1/3] driver core: Introduce helper function __device_attach_driver_scan() Jinhui Guo
2026-01-22 14:52 ` Jinhui Guo [this message]
2026-01-22 14:52 ` [PATCH v2 3/3] PCI: Clean up NUMA-node awareness in pci_bus_type probe Jinhui Guo
2026-01-24 1:04 ` [PATCH v2 0/3] Add NUMA-node-aware synchronous probing to driver core dan.j.williams
2026-01-26 9:17 ` Jinhui Guo
2026-01-27 2:32 ` Jinhui Guo
2026-01-27 3:37 ` dan.j.williams
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260122145208.1013-3-guojinhui.liam@bytedance.com \
--to=guojinhui.liam@bytedance.com \
--cc=alexanderduyck@fb.com \
--cc=bhelgaas@google.com \
--cc=bvanassche@acm.org \
--cc=dakr@kernel.org \
--cc=dan.j.williams@intel.com \
--cc=frederic@kernel.org \
--cc=gregkh@linuxfoundation.org \
--cc=helgaas@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=rafael@kernel.org \
--cc=tj@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®