All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 0/2] Fix deferred_probe_timeout and fw_devlink=on
@ 2021-04-02  4:03 Saravana Kannan
  2021-04-02  4:03 ` [PATCH v1 1/2] driver core: Fix locking bug in deferred_probe_timeout_work_func() Saravana Kannan
  2021-04-02  4:03 ` [PATCH v1 2/2] driver core: Improve fw_devlink & deferred_probe_timeout interaction Saravana Kannan
  0 siblings, 2 replies; 3+ messages in thread
From: Saravana Kannan @ 2021-04-02  4:03 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Rafael J. Wysocki, Rob Herring
  Cc: Saravana Kannan, kernel-team, linux-kernel

This series fixes existing bugs in deferred_probe_timeout and fixes some
interaction with fw_devlink=on.

Saravana Kannan (2):
  driver core: Fix locking bug in deferred_probe_timeout_work_func()
  driver core: Improve fw_devlink & deferred_probe_timeout interaction

 drivers/base/base.h |  1 +
 drivers/base/core.c | 64 ++++++++++++++++++++++++++++++++++++++++-----
 drivers/base/dd.c   | 13 ++++++---
 3 files changed, 68 insertions(+), 10 deletions(-)

-- 
2.31.0.208.g409f899ff0-goog


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH v1 1/2] driver core: Fix locking bug in deferred_probe_timeout_work_func()
  2021-04-02  4:03 [PATCH v1 0/2] Fix deferred_probe_timeout and fw_devlink=on Saravana Kannan
@ 2021-04-02  4:03 ` Saravana Kannan
  2021-04-02  4:03 ` [PATCH v1 2/2] driver core: Improve fw_devlink & deferred_probe_timeout interaction Saravana Kannan
  1 sibling, 0 replies; 3+ messages in thread
From: Saravana Kannan @ 2021-04-02  4:03 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Rafael J. Wysocki, Rob Herring
  Cc: Saravana Kannan, kernel-team, linux-kernel, stable

list_for_each_entry_safe() is only useful if we are deleting nodes in a
linked list within the loop. It doesn't protect against other threads
adding/deleting nodes to the list in parallel. We need to grab
deferred_probe_mutex when traversing the deferred_probe_pending_list.

Cc: stable@vger.kernel.org
Fixes: 25b4e70dcce9 ("driver core: allow stopping deferred probe after init")
Signed-off-by: Saravana Kannan <saravanak@google.com>
---
 drivers/base/dd.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 20b69b5e0e91..28ad8afd87bc 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -291,14 +291,16 @@ int driver_deferred_probe_check_state(struct device *dev)
 
 static void deferred_probe_timeout_work_func(struct work_struct *work)
 {
-	struct device_private *private, *p;
+	struct device_private *p;
 
 	driver_deferred_probe_timeout = 0;
 	driver_deferred_probe_trigger();
 	flush_work(&deferred_probe_work);
 
-	list_for_each_entry_safe(private, p, &deferred_probe_pending_list, deferred_probe)
-		dev_info(private->device, "deferred probe pending\n");
+	mutex_lock(&deferred_probe_mutex);
+	list_for_each_entry(p, &deferred_probe_pending_list, deferred_probe)
+		dev_info(p->device, "deferred probe pending\n");
+	mutex_unlock(&deferred_probe_mutex);
 	wake_up_all(&probe_timeout_waitqueue);
 }
 static DECLARE_DELAYED_WORK(deferred_probe_timeout_work, deferred_probe_timeout_work_func);
-- 
2.31.0.208.g409f899ff0-goog


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH v1 2/2] driver core: Improve fw_devlink & deferred_probe_timeout interaction
  2021-04-02  4:03 [PATCH v1 0/2] Fix deferred_probe_timeout and fw_devlink=on Saravana Kannan
  2021-04-02  4:03 ` [PATCH v1 1/2] driver core: Fix locking bug in deferred_probe_timeout_work_func() Saravana Kannan
@ 2021-04-02  4:03 ` Saravana Kannan
  1 sibling, 0 replies; 3+ messages in thread
From: Saravana Kannan @ 2021-04-02  4:03 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Rafael J. Wysocki, Rob Herring
  Cc: Saravana Kannan, kernel-team, linux-kernel

deferred_probe_timeout kernel commandline parameter allows probing of
consumer devices if the supplier devices don't have any drivers.

fw_devlink=on will indefintely block probe() calls on a device if all
its suppliers haven't probed successfully. This completely skips calls
to driver_deferred_probe_check_state() since that's only called when a
.probe() function calls framework APIs. So fw_devlink=on breaks
deferred_probe_timeout.

deferred_probe_timeout in its current state also ignores a lot of
information that's now available to the kernel. It assumes all suppliers
that haven't probed when the timer expires (or when initcalls are done
on a static kernel) will never probe and fails any calls to acquire
resources from these unprobed suppliers.

However, this assumption by deferred_probe_timeout isn't true under many
conditions. For example:
- If the consumer happens to be before the supplier in the deferred
  probe list.
- If the supplier itself is waiting on its supplier to probe.

This patch fixes both these issues by relaxing device links between
devices only if the supplier doesn't have any driver that could match
with (NOT bound to) the supplier device. This way, we only fail attempts
to acquire resources from suppliers that truly don't have any driver vs
suppliers that just happen to not have probed yet.

Signed-off-by: Saravana Kannan <saravanak@google.com>
---
 drivers/base/base.h |  1 +
 drivers/base/core.c | 64 ++++++++++++++++++++++++++++++++++++++++-----
 drivers/base/dd.c   |  5 ++++
 3 files changed, 63 insertions(+), 7 deletions(-)

diff --git a/drivers/base/base.h b/drivers/base/base.h
index 1b44ed588f66..e5f9b7e656c3 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -191,6 +191,7 @@ extern void device_links_driver_cleanup(struct device *dev);
 extern void device_links_no_driver(struct device *dev);
 extern bool device_links_busy(struct device *dev);
 extern void device_links_unbind_consumers(struct device *dev);
+extern void fw_devlink_drivers_done(void);
 
 /* device pm support */
 void device_pm_move_to_tail(struct device *dev);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index de518178ac36..c05dae75b696 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -51,6 +51,7 @@ static LIST_HEAD(deferred_sync);
 static unsigned int defer_sync_state_count = 1;
 static DEFINE_MUTEX(fwnode_link_lock);
 static bool fw_devlink_is_permissive(void);
+static bool fw_devlink_drv_reg_done;
 
 /**
  * fwnode_link_add - Create a link between two fwnode_handles.
@@ -1598,6 +1599,52 @@ static void fw_devlink_parse_fwtree(struct fwnode_handle *fwnode)
 		fw_devlink_parse_fwtree(child);
 }
 
+static void fw_devlink_relax_link(struct device_link *link)
+{
+	if (!(link->flags & DL_FLAG_INFERRED))
+		return;
+
+	if (link->flags == (DL_FLAG_MANAGED | FW_DEVLINK_FLAGS_PERMISSIVE))
+		return;
+
+	pm_runtime_drop_link(link);
+	link->flags = DL_FLAG_MANAGED | FW_DEVLINK_FLAGS_PERMISSIVE;
+	dev_dbg(link->consumer, "Relaxing link with %s\n",
+		dev_name(link->supplier));
+}
+
+static int fw_devlink_no_driver(struct device *dev, void *data)
+{
+	struct device_link *link = to_devlink(dev);
+
+	if (!link->supplier->can_match)
+		fw_devlink_relax_link(link);
+
+	return 0;
+}
+
+void fw_devlink_drivers_done(void)
+{
+	fw_devlink_drv_reg_done = true;
+	device_links_write_lock();
+	class_for_each_device(&devlink_class, NULL, NULL,
+			      fw_devlink_no_driver);
+	device_links_write_unlock();
+}
+
+static void fw_devlink_unblock_consumers(struct device *dev)
+{
+	struct device_link *link;
+
+	if (!fw_devlink_flags || fw_devlink_is_permissive())
+		return;
+
+	device_links_write_lock();
+	list_for_each_entry(link, &dev->links.consumers, s_node)
+		fw_devlink_relax_link(link);
+	device_links_write_unlock();
+}
+
 /**
  * fw_devlink_relax_cycle - Convert cyclic links to SYNC_STATE_ONLY links
  * @con: Device to check dependencies for.
@@ -1634,13 +1681,7 @@ static int fw_devlink_relax_cycle(struct device *con, void *sup)
 
 		ret = 1;
 
-		if (!(link->flags & DL_FLAG_INFERRED))
-			continue;
-
-		pm_runtime_drop_link(link);
-		link->flags = DL_FLAG_MANAGED | FW_DEVLINK_FLAGS_PERMISSIVE;
-		dev_dbg(link->consumer, "Relaxing link with %s\n",
-			dev_name(link->supplier));
+		fw_devlink_relax_link(link);
 	}
 	return ret;
 }
@@ -3275,6 +3316,15 @@ int device_add(struct device *dev)
 	}
 
 	bus_probe_device(dev);
+
+	/*
+	 * If all driver registration is done and a newly added device doesn't
+	 * match with any driver, don't block its consumers from probing in
+	 * case the consumer device is able to operate without this supplier.
+	 */
+	if (dev->fwnode && fw_devlink_drv_reg_done && !dev->can_match)
+		fw_devlink_unblock_consumers(dev);
+
 	if (parent)
 		klist_add_tail(&dev->p->knode_parent,
 			       &parent->p->klist_children);
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 28ad8afd87bc..ef988e04a287 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -293,6 +293,8 @@ static void deferred_probe_timeout_work_func(struct work_struct *work)
 {
 	struct device_private *p;
 
+	fw_devlink_drivers_done();
+
 	driver_deferred_probe_timeout = 0;
 	driver_deferred_probe_trigger();
 	flush_work(&deferred_probe_work);
@@ -323,6 +325,9 @@ static int deferred_probe_initcall(void)
 	flush_work(&deferred_probe_work);
 	initcalls_done = true;
 
+	if (!IS_ENABLED(CONFIG_MODULES))
+		fw_devlink_drivers_done();
+
 	/*
 	 * Trigger deferred probe again, this time we won't defer anything
 	 * that is optional
-- 
2.31.0.208.g409f899ff0-goog


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2021-04-02  4:04 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-02  4:03 [PATCH v1 0/2] Fix deferred_probe_timeout and fw_devlink=on Saravana Kannan
2021-04-02  4:03 ` [PATCH v1 1/2] driver core: Fix locking bug in deferred_probe_timeout_work_func() Saravana Kannan
2021-04-02  4:03 ` [PATCH v1 2/2] driver core: Improve fw_devlink & deferred_probe_timeout interaction Saravana Kannan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.