Skip to content

Commit 6a6dfdf

Browse files
Saravana Kannangregkh
authored andcommitted
driver core: fw_devlink: Allow marking a fwnode link as being part of a cycle
To improve detection and handling of dependency cycles, we need to be able to mark fwnode links as being part of cycles. fwnode links marked as being part of a cycle should not block their consumers from probing. 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 67cad5c commit 6a6dfdf

File tree

2 files changed

+50
-11
lines changed

2 files changed

+50
-11
lines changed

drivers/base/core.c

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,15 @@ static bool fw_devlink_best_effort;
7676
* are ignored and there is no reference counting.
7777
*/
7878
static int __fwnode_link_add(struct fwnode_handle *con,
79-
struct fwnode_handle *sup)
79+
struct fwnode_handle *sup, u8 flags)
8080
{
8181
struct fwnode_link *link;
8282

8383
list_for_each_entry(link, &sup->consumers, s_hook)
84-
if (link->consumer == con)
84+
if (link->consumer == con) {
85+
link->flags |= flags;
8586
return 0;
87+
}
8688

8789
link = kzalloc(sizeof(*link), GFP_KERNEL);
8890
if (!link)
@@ -92,6 +94,7 @@ static int __fwnode_link_add(struct fwnode_handle *con,
9294
INIT_LIST_HEAD(&link->s_hook);
9395
link->consumer = con;
9496
INIT_LIST_HEAD(&link->c_hook);
97+
link->flags = flags;
9598

9699
list_add(&link->s_hook, &sup->consumers);
97100
list_add(&link->c_hook, &con->suppliers);
@@ -106,7 +109,7 @@ int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup)
106109
int ret;
107110

108111
mutex_lock(&fwnode_link_lock);
109-
ret = __fwnode_link_add(con, sup);
112+
ret = __fwnode_link_add(con, sup, 0);
110113
mutex_unlock(&fwnode_link_lock);
111114
return ret;
112115
}
@@ -126,6 +129,19 @@ static void __fwnode_link_del(struct fwnode_link *link)
126129
kfree(link);
127130
}
128131

132+
/**
133+
* __fwnode_link_cycle - Mark a fwnode link as being part of a cycle.
134+
* @link: the fwnode_link to be marked
135+
*
136+
* The fwnode_link_lock needs to be held when this function is called.
137+
*/
138+
static void __fwnode_link_cycle(struct fwnode_link *link)
139+
{
140+
pr_debug("%pfwf: Relaxing link with %pfwf\n",
141+
link->consumer, link->supplier);
142+
link->flags |= FWLINK_FLAG_CYCLE;
143+
}
144+
129145
/**
130146
* fwnode_links_purge_suppliers - Delete all supplier links of fwnode_handle.
131147
* @fwnode: fwnode whose supplier links need to be deleted
@@ -199,7 +215,7 @@ static void __fwnode_links_move_consumers(struct fwnode_handle *from,
199215
struct fwnode_link *link, *tmp;
200216

201217
list_for_each_entry_safe(link, tmp, &from->consumers, s_hook) {
202-
__fwnode_link_add(link->consumer, to);
218+
__fwnode_link_add(link->consumer, to, link->flags);
203219
__fwnode_link_del(link);
204220
}
205221
}
@@ -1041,6 +1057,21 @@ static bool dev_is_best_effort(struct device *dev)
10411057
(dev->fwnode && (dev->fwnode->flags & FWNODE_FLAG_BEST_EFFORT));
10421058
}
10431059

1060+
static struct fwnode_handle *fwnode_links_check_suppliers(
1061+
struct fwnode_handle *fwnode)
1062+
{
1063+
struct fwnode_link *link;
1064+
1065+
if (!fwnode || fw_devlink_is_permissive())
1066+
return NULL;
1067+
1068+
list_for_each_entry(link, &fwnode->suppliers, c_hook)
1069+
if (!(link->flags & FWLINK_FLAG_CYCLE))
1070+
return link->supplier;
1071+
1072+
return NULL;
1073+
}
1074+
10441075
/**
10451076
* device_links_check_suppliers - Check presence of supplier drivers.
10461077
* @dev: Consumer device.
@@ -1068,11 +1099,8 @@ int device_links_check_suppliers(struct device *dev)
10681099
* probe.
10691100
*/
10701101
mutex_lock(&fwnode_link_lock);
1071-
if (dev->fwnode && !list_empty(&dev->fwnode->suppliers) &&
1072-
!fw_devlink_is_permissive()) {
1073-
sup_fw = list_first_entry(&dev->fwnode->suppliers,
1074-
struct fwnode_link,
1075-
c_hook)->supplier;
1102+
sup_fw = fwnode_links_check_suppliers(dev->fwnode);
1103+
if (sup_fw) {
10761104
if (!dev_is_best_effort(dev)) {
10771105
fwnode_ret = -EPROBE_DEFER;
10781106
dev_err_probe(dev, -EPROBE_DEFER,
@@ -1261,7 +1289,9 @@ static ssize_t waiting_for_supplier_show(struct device *dev,
12611289
bool val;
12621290

12631291
device_lock(dev);
1264-
val = !list_empty(&dev->fwnode->suppliers);
1292+
mutex_lock(&fwnode_link_lock);
1293+
val = !!fwnode_links_check_suppliers(dev->fwnode);
1294+
mutex_unlock(&fwnode_link_lock);
12651295
device_unlock(dev);
12661296
return sysfs_emit(buf, "%u\n", val);
12671297
}

include/linux/fwnode.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ struct fwnode_operations;
1818
struct device;
1919

2020
/*
21-
* fwnode link flags
21+
* fwnode flags
2222
*
2323
* LINKS_ADDED: The fwnode has already be parsed to add fwnode links.
2424
* NOT_DEVICE: The fwnode will never be populated as a struct device.
@@ -36,6 +36,7 @@ struct device;
3636
#define FWNODE_FLAG_INITIALIZED BIT(2)
3737
#define FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD BIT(3)
3838
#define FWNODE_FLAG_BEST_EFFORT BIT(4)
39+
#define FWNODE_FLAG_VISITED BIT(5)
3940

4041
struct fwnode_handle {
4142
struct fwnode_handle *secondary;
@@ -46,11 +47,19 @@ struct fwnode_handle {
4647
u8 flags;
4748
};
4849

50+
/*
51+
* fwnode link flags
52+
*
53+
* CYCLE: The fwnode link is part of a cycle. Don't defer probe.
54+
*/
55+
#define FWLINK_FLAG_CYCLE BIT(0)
56+
4957
struct fwnode_link {
5058
struct fwnode_handle *supplier;
5159
struct list_head s_hook;
5260
struct fwnode_handle *consumer;
5361
struct list_head c_hook;
62+
u8 flags;
5463
};
5564

5665
/**

0 commit comments

Comments
 (0)