Skip to content

Commit 05ef983

Browse files
Saravana Kannangregkh
authored andcommitted
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 <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 8f677bc commit 05ef983

File tree

2 files changed

+43
-9
lines changed

2 files changed

+43
-9
lines changed

drivers/base/core.c

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ static int device_is_dependent(struct device *dev, void *target)
131131
return ret;
132132

133133
list_for_each_entry(link, &dev->links.consumers, s_node) {
134+
if (link->flags == (DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED))
135+
continue;
136+
134137
if (link->consumer == target)
135138
return 1;
136139

@@ -200,8 +203,11 @@ static int device_reorder_to_tail(struct device *dev, void *not_used)
200203
device_pm_move_last(dev);
201204

202205
device_for_each_child(dev, NULL, device_reorder_to_tail);
203-
list_for_each_entry(link, &dev->links.consumers, s_node)
206+
list_for_each_entry(link, &dev->links.consumers, s_node) {
207+
if (link->flags == (DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED))
208+
continue;
204209
device_reorder_to_tail(link->consumer, NULL);
210+
}
205211

206212
return 0;
207213
}
@@ -228,7 +234,8 @@ void device_pm_move_to_tail(struct device *dev)
228234

229235
#define DL_MANAGED_LINK_FLAGS (DL_FLAG_AUTOREMOVE_CONSUMER | \
230236
DL_FLAG_AUTOREMOVE_SUPPLIER | \
231-
DL_FLAG_AUTOPROBE_CONSUMER)
237+
DL_FLAG_AUTOPROBE_CONSUMER | \
238+
DL_FLAG_SYNC_STATE_ONLY)
232239

233240
#define DL_ADD_VALID_FLAGS (DL_MANAGED_LINK_FLAGS | DL_FLAG_STATELESS | \
234241
DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE)
@@ -296,6 +303,8 @@ struct device_link *device_link_add(struct device *consumer,
296303

297304
if (!consumer || !supplier || flags & ~DL_ADD_VALID_FLAGS ||
298305
(flags & DL_FLAG_STATELESS && flags & DL_MANAGED_LINK_FLAGS) ||
306+
(flags & DL_FLAG_SYNC_STATE_ONLY &&
307+
flags != DL_FLAG_SYNC_STATE_ONLY) ||
299308
(flags & DL_FLAG_AUTOPROBE_CONSUMER &&
300309
flags & (DL_FLAG_AUTOREMOVE_CONSUMER |
301310
DL_FLAG_AUTOREMOVE_SUPPLIER)))
@@ -316,11 +325,14 @@ struct device_link *device_link_add(struct device *consumer,
316325

317326
/*
318327
* If the supplier has not been fully registered yet or there is a
319-
* reverse dependency between the consumer and the supplier already in
320-
* the graph, return NULL.
328+
* reverse (non-SYNC_STATE_ONLY) dependency between the consumer and
329+
* the supplier already in the graph, return NULL. If the link is a
330+
* SYNC_STATE_ONLY link, we don't check for reverse dependencies
331+
* because it only affects sync_state() callbacks.
321332
*/
322333
if (!device_pm_initialized(supplier)
323-
|| device_is_dependent(consumer, supplier)) {
334+
|| (!(flags & DL_FLAG_SYNC_STATE_ONLY) &&
335+
device_is_dependent(consumer, supplier))) {
324336
link = NULL;
325337
goto out;
326338
}
@@ -347,9 +359,14 @@ struct device_link *device_link_add(struct device *consumer,
347359
}
348360

349361
if (flags & DL_FLAG_STATELESS) {
350-
link->flags |= DL_FLAG_STATELESS;
351362
kref_get(&link->kref);
352-
goto out;
363+
if (link->flags & DL_FLAG_SYNC_STATE_ONLY &&
364+
!(link->flags & DL_FLAG_STATELESS)) {
365+
link->flags |= DL_FLAG_STATELESS;
366+
goto reorder;
367+
} else {
368+
goto out;
369+
}
353370
}
354371

355372
/*
@@ -371,6 +388,12 @@ struct device_link *device_link_add(struct device *consumer,
371388
link->flags |= DL_FLAG_MANAGED;
372389
device_link_init_status(link, consumer, supplier);
373390
}
391+
if (link->flags & DL_FLAG_SYNC_STATE_ONLY &&
392+
!(flags & DL_FLAG_SYNC_STATE_ONLY)) {
393+
link->flags &= ~DL_FLAG_SYNC_STATE_ONLY;
394+
goto reorder;
395+
}
396+
374397
goto out;
375398
}
376399

@@ -410,6 +433,13 @@ struct device_link *device_link_add(struct device *consumer,
410433
flags & DL_FLAG_PM_RUNTIME)
411434
pm_runtime_resume(supplier);
412435

436+
if (flags & DL_FLAG_SYNC_STATE_ONLY) {
437+
dev_dbg(consumer,
438+
"Linked as a sync state only consumer to %s\n",
439+
dev_name(supplier));
440+
goto out;
441+
}
442+
reorder:
413443
/*
414444
* Move the consumer and all of the devices depending on it to the end
415445
* of dpm_list and the devices_kset list.
@@ -635,7 +665,8 @@ int device_links_check_suppliers(struct device *dev)
635665
device_links_write_lock();
636666

637667
list_for_each_entry(link, &dev->links.suppliers, c_node) {
638-
if (!(link->flags & DL_FLAG_MANAGED))
668+
if (!(link->flags & DL_FLAG_MANAGED) ||
669+
link->flags & DL_FLAG_SYNC_STATE_ONLY)
639670
continue;
640671

641672
if (link->status != DL_STATE_AVAILABLE) {
@@ -949,7 +980,8 @@ void device_links_unbind_consumers(struct device *dev)
949980
list_for_each_entry(link, &dev->links.consumers, s_node) {
950981
enum device_link_state status;
951982

952-
if (!(link->flags & DL_FLAG_MANAGED))
983+
if (!(link->flags & DL_FLAG_MANAGED) ||
984+
link->flags & DL_FLAG_SYNC_STATE_ONLY)
953985
continue;
954986

955987
status = link->status;

include/linux/device.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,6 +1096,7 @@ enum device_link_state {
10961096
* AUTOREMOVE_SUPPLIER: Remove the link automatically on supplier driver unbind.
10971097
* AUTOPROBE_CONSUMER: Probe consumer driver automatically after supplier binds.
10981098
* MANAGED: The core tracks presence of supplier/consumer drivers (internal).
1099+
* SYNC_STATE_ONLY: Link only affects sync_state() behavior.
10991100
*/
11001101
#define DL_FLAG_STATELESS BIT(0)
11011102
#define DL_FLAG_AUTOREMOVE_CONSUMER BIT(1)
@@ -1104,6 +1105,7 @@ enum device_link_state {
11041105
#define DL_FLAG_AUTOREMOVE_SUPPLIER BIT(4)
11051106
#define DL_FLAG_AUTOPROBE_CONSUMER BIT(5)
11061107
#define DL_FLAG_MANAGED BIT(6)
1108+
#define DL_FLAG_SYNC_STATE_ONLY BIT(7)
11071109

11081110
/**
11091111
* struct device_link - Device link representation.

0 commit comments

Comments
 (0)