Skip to content

Commit 67cad5c

Browse files
Saravana Kannangregkh
authored andcommitted
driver core: fw_devlink: Add DL_FLAG_CYCLE support to device links
fw_devlink uses DL_FLAG_SYNC_STATE_ONLY device link flag for two purposes: 1. To allow a parent device to proxy its child device's dependency on a supplier so that the supplier doesn't get its sync_state() callback before the child device/consumer can be added and probed. In this usage scenario, we need to ignore cycles for ensure correctness of sync_state() callbacks. 2. When there are dependency cycles in firmware, we don't know which of those dependencies are valid. So, we have to ignore them all wrt probe ordering while still making sure the sync_state() callbacks come correctly. However, when detecting dependency cycles, there can be multiple dependency cycles between two devices that we need to detect. For example: A -> B -> A and A -> C -> B -> A. To detect multiple cycles correct, we need to be able to differentiate DL_FLAG_SYNC_STATE_ONLY device links used for (1) vs (2) above. To allow this differentiation, add a DL_FLAG_CYCLE that can be use to mark use case (2). We can then use the DL_FLAG_CYCLE to decide which DL_FLAG_SYNC_STATE_ONLY device links to follow when looking for dependency cycles. Fixes: 2de9d8e ("driver core: fw_devlink: Improve handling of cyclic dependencies") Signed-off-by: Saravana Kannan <[email protected]> Tested-by: Colin Foster <[email protected]> Tested-by: Sudeep Holla <[email protected]> Tested-by: Douglas Anderson <[email protected]> Tested-by: Geert Uytterhoeven <[email protected]> Tested-by: Luca Weiss <[email protected]> # qcom/sm7225-fairphone-fp4 Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 38dfa56 commit 67cad5c

File tree

2 files changed

+19
-10
lines changed

2 files changed

+19
-10
lines changed

drivers/base/core.c

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,12 @@ static bool device_is_ancestor(struct device *dev, struct device *target)
322322
return false;
323323
}
324324

325+
static inline bool device_link_flag_is_sync_state_only(u32 flags)
326+
{
327+
return (flags & ~(DL_FLAG_INFERRED | DL_FLAG_CYCLE)) ==
328+
(DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED);
329+
}
330+
325331
/**
326332
* device_is_dependent - Check if one device depends on another one
327333
* @dev: Device to check dependencies for.
@@ -348,8 +354,7 @@ int device_is_dependent(struct device *dev, void *target)
348354
return ret;
349355

350356
list_for_each_entry(link, &dev->links.consumers, s_node) {
351-
if ((link->flags & ~DL_FLAG_INFERRED) ==
352-
(DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED))
357+
if (device_link_flag_is_sync_state_only(link->flags))
353358
continue;
354359

355360
if (link->consumer == target)
@@ -422,8 +427,7 @@ static int device_reorder_to_tail(struct device *dev, void *not_used)
422427

423428
device_for_each_child(dev, NULL, device_reorder_to_tail);
424429
list_for_each_entry(link, &dev->links.consumers, s_node) {
425-
if ((link->flags & ~DL_FLAG_INFERRED) ==
426-
(DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED))
430+
if (device_link_flag_is_sync_state_only(link->flags))
427431
continue;
428432
device_reorder_to_tail(link->consumer, NULL);
429433
}
@@ -684,7 +688,8 @@ postcore_initcall(devlink_class_init);
684688
DL_FLAG_AUTOREMOVE_SUPPLIER | \
685689
DL_FLAG_AUTOPROBE_CONSUMER | \
686690
DL_FLAG_SYNC_STATE_ONLY | \
687-
DL_FLAG_INFERRED)
691+
DL_FLAG_INFERRED | \
692+
DL_FLAG_CYCLE)
688693

689694
#define DL_ADD_VALID_FLAGS (DL_MANAGED_LINK_FLAGS | DL_FLAG_STATELESS | \
690695
DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE)
@@ -753,8 +758,6 @@ struct device_link *device_link_add(struct device *consumer,
753758
if (!consumer || !supplier || consumer == supplier ||
754759
flags & ~DL_ADD_VALID_FLAGS ||
755760
(flags & DL_FLAG_STATELESS && flags & DL_MANAGED_LINK_FLAGS) ||
756-
(flags & DL_FLAG_SYNC_STATE_ONLY &&
757-
(flags & ~DL_FLAG_INFERRED) != DL_FLAG_SYNC_STATE_ONLY) ||
758761
(flags & DL_FLAG_AUTOPROBE_CONSUMER &&
759762
flags & (DL_FLAG_AUTOREMOVE_CONSUMER |
760763
DL_FLAG_AUTOREMOVE_SUPPLIER)))
@@ -770,6 +773,10 @@ struct device_link *device_link_add(struct device *consumer,
770773
if (!(flags & DL_FLAG_STATELESS))
771774
flags |= DL_FLAG_MANAGED;
772775

776+
if (flags & DL_FLAG_SYNC_STATE_ONLY &&
777+
!device_link_flag_is_sync_state_only(flags))
778+
return NULL;
779+
773780
device_links_write_lock();
774781
device_pm_lock();
775782

@@ -1729,7 +1736,7 @@ static void fw_devlink_relax_link(struct device_link *link)
17291736
if (!(link->flags & DL_FLAG_INFERRED))
17301737
return;
17311738

1732-
if (link->flags == (DL_FLAG_MANAGED | FW_DEVLINK_FLAGS_PERMISSIVE))
1739+
if (device_link_flag_is_sync_state_only(link->flags))
17331740
return;
17341741

17351742
pm_runtime_drop_link(link);
@@ -1853,8 +1860,8 @@ static int fw_devlink_relax_cycle(struct device *con, void *sup)
18531860
return ret;
18541861

18551862
list_for_each_entry(link, &con->links.consumers, s_node) {
1856-
if ((link->flags & ~DL_FLAG_INFERRED) ==
1857-
(DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED))
1863+
if (!(link->flags & DL_FLAG_CYCLE) &&
1864+
device_link_flag_is_sync_state_only(link->flags))
18581865
continue;
18591866

18601867
if (!fw_devlink_relax_cycle(link->consumer, sup))
@@ -1863,6 +1870,7 @@ static int fw_devlink_relax_cycle(struct device *con, void *sup)
18631870
ret = 1;
18641871

18651872
fw_devlink_relax_link(link);
1873+
link->flags |= DL_FLAG_CYCLE;
18661874
}
18671875
return ret;
18681876
}

include/linux/device.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ enum device_link_state {
328328
#define DL_FLAG_MANAGED BIT(6)
329329
#define DL_FLAG_SYNC_STATE_ONLY BIT(7)
330330
#define DL_FLAG_INFERRED BIT(8)
331+
#define DL_FLAG_CYCLE BIT(9)
331332

332333
/**
333334
* enum dl_dev_state - Device driver presence tracking information.

0 commit comments

Comments
 (0)