[RFC PATCH v4 12/38] NTB: core: Add driver_override support for NTB devices

Koichiro Den <[email protected]>
Newsgroups dev.linux.lists.ntb,dev.linux.lists.iommu,org.kernel.vger.dmaengine,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-doc,org.kernel.vger.linux-kernel,org.kernel.vger.linux-kselftest,org.kernel.vger.linux-pci,org.kernel.vger.linux-renesas-soc,org.kernel.vger.netdev
Message-ID <[email protected]>
When multiple NTB client drivers are available, selecting which driver
should bind to a given NTB device becomes necessary. The NTB bus match
logic currently has no way to force a specific driver.

Add a standard driver_override sysfs attribute to NTB devices and honor
it in the bus match callback. Also export ntb_bus_reprobe() so newly
loaded drivers can trigger probing of currently unbound NTB devices.

Signed-off-by: Koichiro Den <[email protected]>
---
 drivers/ntb/core.c  | 68 +++++++++++++++++++++++++++++++++++++++++++++
 include/linux/ntb.h |  4 +++
 2 files changed, 72 insertions(+)

diff --git a/drivers/ntb/core.c b/drivers/ntb/core.c
index ed6f4adc6130..404fa1433fab 100644
--- a/drivers/ntb/core.c
+++ b/drivers/ntb/core.c
@@ -56,6 +56,7 @@
 #include <linux/device.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/sysfs.h>
 
 #include <linux/ntb.h>
 #include <linux/pci.h>
@@ -298,10 +299,77 @@ static void ntb_dev_release(struct device *dev)
 	complete(&ntb->released);
 }
 
+static int ntb_bus_reprobe_one(struct device *dev, void *data)
+{
+	if (!dev->driver)
+		return device_attach(dev);
+	return 0;
+}
+
+void ntb_bus_reprobe(void)
+{
+	bus_for_each_dev(&ntb_bus, NULL, NULL, ntb_bus_reprobe_one);
+}
+EXPORT_SYMBOL_GPL(ntb_bus_reprobe);
+
+static ssize_t driver_override_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct ntb_dev *ntb = dev_ntb(dev);
+	ssize_t len;
+
+	device_lock(dev);
+	len = sysfs_emit(buf, "%s\n", ntb->driver_override);
+	device_unlock(dev);
+
+	return len;
+}
+
+static ssize_t driver_override_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct ntb_dev *ntb = dev_ntb(dev);
+	int ret;
+
+	ret = driver_set_override(dev, &ntb->driver_override, buf, count);
+	if (ret)
+		return ret;
+
+	return count;
+}
+static DEVICE_ATTR_RW(driver_override);
+
+static struct attribute *ntb_attrs[] = {
+	&dev_attr_driver_override.attr,
+	NULL,
+};
+
+static const struct attribute_group ntb_group = {
+	.attrs = ntb_attrs,
+};
+__ATTRIBUTE_GROUPS(ntb);
+
+static int ntb_match(struct device *dev, const struct device_driver *drv)
+{
+	struct ntb_dev *ntb = dev_ntb(dev);
+
+	/*
+	 * If driver_override is set, only allow binding to the named driver.
+	 * Otherwise keep the historical behavior (match all clients).
+	 */
+	if (ntb->driver_override)
+		return sysfs_streq(ntb->driver_override, drv->name);
+
+	return 1;
+}
+
 static const struct bus_type ntb_bus = {
 	.name = "ntb",
+	.match = ntb_match,
 	.probe = ntb_probe,
 	.remove = ntb_remove,
+	.dev_groups = ntb_groups,
 };
 
 static int __init ntb_driver_init(void)
diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index 7ac8cb13e90d..d0115b0bb14b 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -431,6 +431,7 @@ struct ntb_client {
  * @ops:		See &ntb_dev_ops.
  * @ctx:		See &ntb_ctx_ops.
  * @ctx_ops:		See &ntb_ctx_ops.
+ * @driver_override:	Driver name to force a match.
  */
 struct ntb_dev {
 	struct device			dev;
@@ -439,6 +440,7 @@ struct ntb_dev {
 	const struct ntb_dev_ops	*ops;
 	void				*ctx;
 	const struct ntb_ctx_ops	*ctx_ops;
+	const char			*driver_override;
 
 	/* private: */
 
@@ -1770,4 +1772,6 @@ static inline int ntbm_msi_request_irq(struct ntb_dev *ntb,
 					     dev_id, msi_desc);
 }
 
+void ntb_bus_reprobe(void);
+
 #endif
-- 
2.51.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.