forked from Minki/linux
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> Link: https://lore.kernel.org/r/20191028220027.251605-2-saravanak@google.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
8f677bc819
commit
05ef983e0d
@ -131,6 +131,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 | DL_FLAG_MANAGED))
|
||||
continue;
|
||||
|
||||
if (link->consumer == target)
|
||||
return 1;
|
||||
|
||||
@ -200,8 +203,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 | DL_FLAG_MANAGED))
|
||||
continue;
|
||||
device_reorder_to_tail(link->consumer, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -228,7 +234,8 @@ void device_pm_move_to_tail(struct device *dev)
|
||||
|
||||
#define DL_MANAGED_LINK_FLAGS (DL_FLAG_AUTOREMOVE_CONSUMER | \
|
||||
DL_FLAG_AUTOREMOVE_SUPPLIER | \
|
||||
DL_FLAG_AUTOPROBE_CONSUMER)
|
||||
DL_FLAG_AUTOPROBE_CONSUMER | \
|
||||
DL_FLAG_SYNC_STATE_ONLY)
|
||||
|
||||
#define DL_ADD_VALID_FLAGS (DL_MANAGED_LINK_FLAGS | DL_FLAG_STATELESS | \
|
||||
DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE)
|
||||
@ -296,6 +303,8 @@ struct device_link *device_link_add(struct device *consumer,
|
||||
|
||||
if (!consumer || !supplier || flags & ~DL_ADD_VALID_FLAGS ||
|
||||
(flags & DL_FLAG_STATELESS && flags & DL_MANAGED_LINK_FLAGS) ||
|
||||
(flags & DL_FLAG_SYNC_STATE_ONLY &&
|
||||
flags != DL_FLAG_SYNC_STATE_ONLY) ||
|
||||
(flags & DL_FLAG_AUTOPROBE_CONSUMER &&
|
||||
flags & (DL_FLAG_AUTOREMOVE_CONSUMER |
|
||||
DL_FLAG_AUTOREMOVE_SUPPLIER)))
|
||||
@ -316,11 +325,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;
|
||||
}
|
||||
@ -347,9 +359,14 @@ struct device_link *device_link_add(struct device *consumer,
|
||||
}
|
||||
|
||||
if (flags & DL_FLAG_STATELESS) {
|
||||
link->flags |= DL_FLAG_STATELESS;
|
||||
kref_get(&link->kref);
|
||||
goto out;
|
||||
if (link->flags & DL_FLAG_SYNC_STATE_ONLY &&
|
||||
!(link->flags & DL_FLAG_STATELESS)) {
|
||||
link->flags |= DL_FLAG_STATELESS;
|
||||
goto reorder;
|
||||
} else {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -371,6 +388,12 @@ struct device_link *device_link_add(struct device *consumer,
|
||||
link->flags |= DL_FLAG_MANAGED;
|
||||
device_link_init_status(link, consumer, supplier);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@ -410,6 +433,13 @@ struct device_link *device_link_add(struct device *consumer,
|
||||
flags & DL_FLAG_PM_RUNTIME)
|
||||
pm_runtime_resume(supplier);
|
||||
|
||||
if (flags & DL_FLAG_SYNC_STATE_ONLY) {
|
||||
dev_dbg(consumer,
|
||||
"Linked as a sync state only consumer to %s\n",
|
||||
dev_name(supplier));
|
||||
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.
|
||||
@ -635,7 +665,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_MANAGED))
|
||||
if (!(link->flags & DL_FLAG_MANAGED) ||
|
||||
link->flags & DL_FLAG_SYNC_STATE_ONLY)
|
||||
continue;
|
||||
|
||||
if (link->status != DL_STATE_AVAILABLE) {
|
||||
@ -949,7 +980,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_MANAGED))
|
||||
if (!(link->flags & DL_FLAG_MANAGED) ||
|
||||
link->flags & DL_FLAG_SYNC_STATE_ONLY)
|
||||
continue;
|
||||
|
||||
status = link->status;
|
||||
|
@ -1096,6 +1096,7 @@ enum device_link_state {
|
||||
* AUTOREMOVE_SUPPLIER: Remove the link automatically on supplier driver unbind.
|
||||
* AUTOPROBE_CONSUMER: Probe consumer driver automatically after supplier binds.
|
||||
* MANAGED: The core tracks presence of supplier/consumer drivers (internal).
|
||||
* SYNC_STATE_ONLY: Link only affects sync_state() behavior.
|
||||
*/
|
||||
#define DL_FLAG_STATELESS BIT(0)
|
||||
#define DL_FLAG_AUTOREMOVE_CONSUMER BIT(1)
|
||||
@ -1104,6 +1105,7 @@ enum device_link_state {
|
||||
#define DL_FLAG_AUTOREMOVE_SUPPLIER BIT(4)
|
||||
#define DL_FLAG_AUTOPROBE_CONSUMER BIT(5)
|
||||
#define DL_FLAG_MANAGED BIT(6)
|
||||
#define DL_FLAG_SYNC_STATE_ONLY BIT(7)
|
||||
|
||||
/**
|
||||
* struct device_link - Device link representation.
|
||||
|
Loading…
Reference in New Issue
Block a user