ANDROID: driver core: Add device link support for SYNC_STATE_ONLY flag

Parent devices might need to create "proxy" device links from themselves
to supplier devices to make sure the supplier devices don't get a
sync_state() before the child consumer devices get a chance to add
device links to the supplier devices.

However, the parent device has no real dependency on the supplier device
and probing, suspend/resume or runtime PM don't need to be affected by
the supplier device.  To capture these cases, create a SYNC_STATE_ONLY
device link flag that only affects sync_state() behavior and doesn't
affect probing, suspend/resume or runtime PM.

Signed-off-by: Saravana Kannan <saravanak@google.com>
Bug: 142657042
Change-Id: Ie709d3b6cd07ac9e09d1473fc0e0a21a8146a1dc
(cherry-picked from android-mainline)
Conflicts: drivers/base/core.c
	include/linux/device.h
[Fix use of MANAGED flag]
Signed-off-by: Saravana Kannan <saravanak@google.com>
This commit is contained in:
Saravana Kannan
2019-10-14 16:15:42 -07:00
parent 2876c5dcfa
commit 6b3cf9491b
2 changed files with 29 additions and 6 deletions

View File

@@ -117,6 +117,9 @@ static int device_is_dependent(struct device *dev, void *target)
return ret;
list_for_each_entry(link, &dev->links.consumers, s_node) {
if (link->flags == DL_FLAG_SYNC_STATE_ONLY)
continue;
if (link->consumer == target)
return 1;
@@ -142,8 +145,11 @@ static int device_reorder_to_tail(struct device *dev, void *not_used)
device_pm_move_last(dev);
device_for_each_child(dev, NULL, device_reorder_to_tail);
list_for_each_entry(link, &dev->links.consumers, s_node)
list_for_each_entry(link, &dev->links.consumers, s_node) {
if (link->flags == DL_FLAG_SYNC_STATE_ONLY)
continue;
device_reorder_to_tail(link->consumer, NULL);
}
return 0;
}
@@ -202,6 +208,8 @@ struct device_link *device_link_add(struct device *consumer,
struct device_link *link;
if (!consumer || !supplier ||
(flags & DL_FLAG_SYNC_STATE_ONLY &&
flags != DL_FLAG_SYNC_STATE_ONLY) ||
((flags & DL_FLAG_STATELESS) &&
(flags & DL_FLAG_AUTOREMOVE_CONSUMER)))
return NULL;
@@ -211,11 +219,14 @@ struct device_link *device_link_add(struct device *consumer,
/*
* If the supplier has not been fully registered yet or there is a
* reverse dependency between the consumer and the supplier already in
* the graph, return NULL.
* reverse (non-SYNC_STATE_ONLY) dependency between the consumer and
* the supplier already in the graph, return NULL. If the link is a
* SYNC_STATE_ONLY link, we don't check for reverse dependencies
* because it only affects sync_state() callbacks.
*/
if (!device_pm_initialized(supplier)
|| device_is_dependent(consumer, supplier)) {
|| (!(flags & DL_FLAG_SYNC_STATE_ONLY) &&
device_is_dependent(consumer, supplier))) {
link = NULL;
goto out;
}
@@ -223,6 +234,11 @@ struct device_link *device_link_add(struct device *consumer,
list_for_each_entry(link, &supplier->links.consumers, s_node)
if (link->consumer == consumer) {
kref_get(&link->kref);
if (link->flags & DL_FLAG_SYNC_STATE_ONLY &&
!(flags & DL_FLAG_SYNC_STATE_ONLY)) {
link->flags &= ~DL_FLAG_SYNC_STATE_ONLY;
goto reorder;
}
goto out;
}
@@ -293,6 +309,9 @@ struct device_link *device_link_add(struct device *consumer,
}
}
if (flags & DL_FLAG_SYNC_STATE_ONLY)
goto out;
reorder:
/*
* Move the consumer and all of the devices depending on it to the end
* of dpm_list and the devices_kset list.
@@ -503,7 +522,8 @@ int device_links_check_suppliers(struct device *dev)
device_links_write_lock();
list_for_each_entry(link, &dev->links.suppliers, c_node) {
if (link->flags & DL_FLAG_STATELESS)
if (link->flags & DL_FLAG_STATELESS ||
link->flags & DL_FLAG_SYNC_STATE_ONLY)
continue;
if (link->status != DL_STATE_AVAILABLE) {
@@ -766,7 +786,8 @@ void device_links_unbind_consumers(struct device *dev)
list_for_each_entry(link, &dev->links.consumers, s_node) {
enum device_link_state status;
if (link->flags & DL_FLAG_STATELESS)
if (link->flags & DL_FLAG_STATELESS ||
link->flags & DL_FLAG_SYNC_STATE_ONLY)
continue;
status = link->status;

View File

@@ -839,12 +839,14 @@ enum device_link_state {
* PM_RUNTIME: If set, the runtime PM framework will use this link.
* RPM_ACTIVE: Run pm_runtime_get_sync() on the supplier during link creation.
* AUTOREMOVE_SUPPLIER: Remove the link automatically on supplier driver unbind.
* SYNC_STATE_ONLY: Link only affects sync_state() behavior.
*/
#define DL_FLAG_STATELESS BIT(0)
#define DL_FLAG_AUTOREMOVE_CONSUMER BIT(1)
#define DL_FLAG_PM_RUNTIME BIT(2)
#define DL_FLAG_RPM_ACTIVE BIT(3)
#define DL_FLAG_AUTOREMOVE_SUPPLIER BIT(4)
#define DL_FLAG_SYNC_STATE_ONLY BIT(7)
/**
* struct device_link - Device link representation.