[PATCH v2 08/19] driver core: Add a compatibility API for manual driver attachment

From: Leon Romanovsky

Date: Mon Nov 09 2026 - 02:39:08 EST


From: Leon Romanovsky <leonro@xxxxxxxxxx>

Existing manual binding paths probe drivers under subsystem locks before
publishing their bindings. Normal attachment would add device locking to
these paths.

Add device_driver_attach_full() to preserve their serialization while
centralizing probe and binding cleanup. This compatibility API must not
be used in any new code: it prevents devices from using the device trust
authorization infrastructure. New code must use device_driver_attach().

Signed-off-by: Leon Romanovsky <leonro@xxxxxxxxxx>
---
drivers/base/dd.c | 74 +++++++++++++++++++++++++++++++++++++++++++++-----
include/linux/device.h | 2 ++
2 files changed, 69 insertions(+), 7 deletions(-)

diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 52123251965de..0f56c3d825731 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -526,6 +526,21 @@ static void driver_sysfs_remove(struct device *dev)
}
}

+static int __device_bind_driver(struct device *dev)
+{
+ int ret;
+
+ ret = driver_sysfs_add(dev);
+ if (ret) {
+ bus_notify(dev, BUS_NOTIFY_DRIVER_NOT_BOUND);
+ return ret;
+ }
+
+ device_links_force_bind(dev);
+ driver_bound(dev);
+ return 0;
+}
+
/**
* device_bind_driver - bind a driver to one device.
* @dev: device.
@@ -542,19 +557,64 @@ static void driver_sysfs_remove(struct device *dev)
* Callers should prefer to use device_driver_attach() instead.
*/
int device_bind_driver(struct device *dev)
+{
+ return __device_bind_driver(dev);
+}
+EXPORT_SYMBOL_GPL(device_bind_driver);
+
+/**
+ * device_driver_attach_full - attach a driver using subsystem serialization
+ * @drv: driver to attach
+ * @dev: device to attach it to
+ *
+ * This compatibility API must not be used in any new code. It prevents
+ * devices from using the device trust authorization infrastructure.
+ * New code must use device_driver_attach().
+ *
+ * Callers must serialize attachment and removal using their subsystem's
+ * existing locks. This function does not acquire the device or parent lock.
+ * It calls the bus or driver probe callback and publishes the binding without
+ * performing the normal driver-core DMA, pinctrl or power-domain setup.
+ *
+ * Return: 0 on success, or a negative error before binding.
+ */
+int device_driver_attach_full(const struct device_driver *drv, struct device *dev)
{
int ret;

- ret = driver_sysfs_add(dev);
- if (!ret) {
- device_links_force_bind(dev);
- driver_bound(dev);
- }
+ if (!device_is_registered(dev) || dev->p->dead)
+ return -ENODEV;
+ if (dev->driver)
+ return -EBUSY;
+
+ device_set_driver(dev, drv);
+ if (dev->bus->probe)
+ ret = dev->bus->probe(dev);
else
- bus_notify(dev, BUS_NOTIFY_DRIVER_NOT_BOUND);
+ ret = drv->probe(dev);
+ if (ret)
+ goto clear_driver;
+
+ ret = __device_bind_driver(dev);
+ if (ret)
+ goto bus_remove;
+
+ return 0;
+
+bus_remove:
+ if (dev->bus->remove)
+ dev->bus->remove(dev);
+ else
+ drv->remove(dev);
+clear_driver:
+ devres_release_all(dev);
+ device_set_driver(dev, NULL);
+ dev_set_drvdata(dev, NULL);
+ if (ret == -EPROBE_DEFER)
+ return -EAGAIN;
return ret;
}
-EXPORT_SYMBOL_GPL(device_bind_driver);
+EXPORT_SYMBOL_GPL(device_driver_attach_full);

static atomic_t probe_count = ATOMIC_INIT(0);
static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);
diff --git a/include/linux/device.h b/include/linux/device.h
index 429e39f647cf9..42e966ebaa2d3 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -1314,6 +1314,8 @@ static inline void *dev_get_platdata(const struct device *dev)
*/
int __must_check device_driver_attach(const struct device_driver *drv,
struct device *dev);
+int __must_check device_driver_attach_full(const struct device_driver *drv,
+ struct device *dev);
int __must_check device_bind_driver(struct device *dev);
void device_release_driver(struct device *dev);
int __must_check device_attach(struct device *dev);

--
2.56.0