summaryrefslogtreecommitdiff
path: root/drivers/base
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/power/main.c16
-rw-r--r--drivers/base/property.c27
2 files changed, 39 insertions, 4 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 19fd55b8ac77..77c7a99f0870 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -638,6 +638,13 @@ static int dpm_async_with_cleanup(struct device *dev, void *fn)
static void dpm_async_resume_children(struct device *dev, async_func_t func)
{
/*
+ * Prevent racing with dpm_clear_async_state() during initial list
+ * walks in dpm_noirq_resume_devices(), dpm_resume_early(), and
+ * dpm_resume().
+ */
+ guard(mutex)(&dpm_list_mtx);
+
+ /*
* Start processing "async" children of the device unless it's been
* started already for them.
*
@@ -985,6 +992,8 @@ static void device_resume(struct device *dev, pm_message_t state, bool async)
if (!dev->power.is_suspended)
goto Complete;
+ dev->power.is_suspended = false;
+
if (dev->power.direct_complete) {
/*
* Allow new children to be added under the device after this
@@ -1047,7 +1056,6 @@ static void device_resume(struct device *dev, pm_message_t state, bool async)
End:
error = dpm_run_callback(callback, dev, state, info);
- dev->power.is_suspended = false;
device_unlock(dev);
dpm_watchdog_clear(&wd);
@@ -1451,7 +1459,7 @@ static int dpm_noirq_suspend_devices(pm_message_t state)
* Move all devices to the target list to resume them
* properly.
*/
- list_splice(&dpm_late_early_list, &dpm_noirq_list);
+ list_splice_init(&dpm_late_early_list, &dpm_noirq_list);
break;
}
}
@@ -1653,7 +1661,7 @@ int dpm_suspend_late(pm_message_t state)
* Move all devices to the target list to resume them
* properly.
*/
- list_splice(&dpm_suspended_list, &dpm_late_early_list);
+ list_splice_init(&dpm_suspended_list, &dpm_late_early_list);
break;
}
}
@@ -1946,7 +1954,7 @@ int dpm_suspend(pm_message_t state)
* Move all devices to the target list to resume them
* properly.
*/
- list_splice(&dpm_prepared_list, &dpm_suspended_list);
+ list_splice_init(&dpm_prepared_list, &dpm_suspended_list);
break;
}
}
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 805f75b35115..f626d5bbe806 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -945,6 +945,33 @@ unsigned int fwnode_get_child_node_count(const struct fwnode_handle *fwnode)
}
EXPORT_SYMBOL_GPL(fwnode_get_child_node_count);
+/**
+ * fwnode_get_named_child_node_count - number of child nodes with given name
+ * @fwnode: Node which child nodes are counted.
+ * @name: String to match child node name against.
+ *
+ * Scan child nodes and count all the nodes with a specific name. Potential
+ * 'number' -ending after the 'at sign' for scanned names is ignored.
+ * E.g.::
+ * fwnode_get_named_child_node_count(fwnode, "channel");
+ * would match all the nodes::
+ * channel { }, channel@0 {}, channel@0xabba {}...
+ *
+ * Return: the number of child nodes with a matching name for a given device.
+ */
+unsigned int fwnode_get_named_child_node_count(const struct fwnode_handle *fwnode,
+ const char *name)
+{
+ struct fwnode_handle *child;
+ unsigned int count = 0;
+
+ fwnode_for_each_named_child_node(fwnode, child, name)
+ count++;
+
+ return count;
+}
+EXPORT_SYMBOL_GPL(fwnode_get_named_child_node_count);
+
bool device_dma_supported(const struct device *dev)
{
return fwnode_call_bool_op(dev_fwnode(dev), device_dma_supported);