diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2014-04-18 18:05:53 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2015-12-06 19:02:05 -0500 |
commit | ffc30b74fd6d01588bd3fdebc3b1acc0857e6fc8 (patch) | |
tree | f013e9daec3d283bbf34d34f1f9312e5531a7d71 /drivers/base/component.c | |
parent | 29f1c7fd61a31e0335ce41d4b2788959ad7c468d (diff) |
component: track components via array rather than list
Since we now have an array which defines each component, maintain the
components to be bound in the array rather than a separate list. We
also need duplicate tracking so we can eliminate multiple bind calls
for the same component: we preserve the list-based component order in
that the first match which adds the component determines its position.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/base/component.c')
-rw-r--r-- | drivers/base/component.c | 154 |
1 files changed, 80 insertions, 74 deletions
diff --git a/drivers/base/component.c b/drivers/base/component.c index cd70b68d9780..d99b06b341fb 100644 --- a/drivers/base/component.c +++ b/drivers/base/component.c | |||
@@ -18,18 +18,21 @@ | |||
18 | #include <linux/mutex.h> | 18 | #include <linux/mutex.h> |
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | 20 | ||
21 | struct component; | ||
22 | |||
21 | struct component_match { | 23 | struct component_match { |
22 | size_t alloc; | 24 | size_t alloc; |
23 | size_t num; | 25 | size_t num; |
24 | struct { | 26 | struct { |
25 | void *data; | 27 | void *data; |
26 | int (*fn)(struct device *, void *); | 28 | int (*fn)(struct device *, void *); |
29 | struct component *component; | ||
30 | bool duplicate; | ||
27 | } compare[0]; | 31 | } compare[0]; |
28 | }; | 32 | }; |
29 | 33 | ||
30 | struct master { | 34 | struct master { |
31 | struct list_head node; | 35 | struct list_head node; |
32 | struct list_head components; | ||
33 | bool bound; | 36 | bool bound; |
34 | 37 | ||
35 | const struct component_master_ops *ops; | 38 | const struct component_master_ops *ops; |
@@ -39,7 +42,6 @@ struct master { | |||
39 | 42 | ||
40 | struct component { | 43 | struct component { |
41 | struct list_head node; | 44 | struct list_head node; |
42 | struct list_head master_node; | ||
43 | struct master *master; | 45 | struct master *master; |
44 | bool bound; | 46 | bool bound; |
45 | 47 | ||
@@ -63,46 +65,20 @@ static struct master *__master_find(struct device *dev, | |||
63 | return NULL; | 65 | return NULL; |
64 | } | 66 | } |
65 | 67 | ||
66 | /* Attach an unattached component to a master. */ | 68 | static struct component *find_component(struct master *master, |
67 | static void component_attach_master(struct master *master, struct component *c) | ||
68 | { | ||
69 | c->master = master; | ||
70 | |||
71 | list_add_tail(&c->master_node, &master->components); | ||
72 | } | ||
73 | |||
74 | /* Detach a component from a master. */ | ||
75 | static void component_detach_master(struct master *master, struct component *c) | ||
76 | { | ||
77 | list_del(&c->master_node); | ||
78 | |||
79 | c->master = NULL; | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * Add a component to a master, finding the component via the compare | ||
84 | * function and compare data. This is safe to call for duplicate matches | ||
85 | * and will not result in the same component being added multiple times. | ||
86 | */ | ||
87 | static int component_master_add_child(struct master *master, | ||
88 | int (*compare)(struct device *, void *), void *compare_data) | 69 | int (*compare)(struct device *, void *), void *compare_data) |
89 | { | 70 | { |
90 | struct component *c; | 71 | struct component *c; |
91 | int ret = -ENXIO; | ||
92 | 72 | ||
93 | list_for_each_entry(c, &component_list, node) { | 73 | list_for_each_entry(c, &component_list, node) { |
94 | if (c->master && c->master != master) | 74 | if (c->master && c->master != master) |
95 | continue; | 75 | continue; |
96 | 76 | ||
97 | if (compare(c->dev, compare_data)) { | 77 | if (compare(c->dev, compare_data)) |
98 | if (!c->master) | 78 | return c; |
99 | component_attach_master(master, c); | ||
100 | ret = 0; | ||
101 | break; | ||
102 | } | ||
103 | } | 79 | } |
104 | 80 | ||
105 | return ret; | 81 | return NULL; |
106 | } | 82 | } |
107 | 83 | ||
108 | static int find_components(struct master *master) | 84 | static int find_components(struct master *master) |
@@ -116,26 +92,39 @@ static int find_components(struct master *master) | |||
116 | * any components which are found to this master. | 92 | * any components which are found to this master. |
117 | */ | 93 | */ |
118 | for (i = 0; i < match->num; i++) { | 94 | for (i = 0; i < match->num; i++) { |
119 | ret = component_master_add_child(master, | 95 | struct component *c; |
120 | match->compare[i].fn, | 96 | |
121 | match->compare[i].data); | 97 | dev_dbg(master->dev, "Looking for component %zu\n", i); |
122 | if (ret) | 98 | |
99 | if (match->compare[i].component) | ||
100 | continue; | ||
101 | |||
102 | c = find_component(master, match->compare[i].fn, | ||
103 | match->compare[i].data); | ||
104 | if (!c) { | ||
105 | ret = -ENXIO; | ||
123 | break; | 106 | break; |
107 | } | ||
108 | |||
109 | dev_dbg(master->dev, "found component %s, duplicate %u\n", dev_name(c->dev), !!c->master); | ||
110 | |||
111 | /* Attach this component to the master */ | ||
112 | match->compare[i].duplicate = !!c->master; | ||
113 | match->compare[i].component = c; | ||
114 | c->master = master; | ||
124 | } | 115 | } |
125 | return ret; | 116 | return ret; |
126 | } | 117 | } |
127 | 118 | ||
128 | /* Detach all attached components from this master */ | 119 | /* Detach component from associated master */ |
129 | static void master_remove_components(struct master *master) | 120 | static void remove_component(struct master *master, struct component *c) |
130 | { | 121 | { |
131 | while (!list_empty(&master->components)) { | 122 | size_t i; |
132 | struct component *c = list_first_entry(&master->components, | ||
133 | struct component, master_node); | ||
134 | |||
135 | WARN_ON(c->master != master); | ||
136 | 123 | ||
137 | component_detach_master(master, c); | 124 | /* Detach the component from this master. */ |
138 | } | 125 | for (i = 0; i < master->match->num; i++) |
126 | if (master->match->compare[i].component == c) | ||
127 | master->match->compare[i].component = NULL; | ||
139 | } | 128 | } |
140 | 129 | ||
141 | /* | 130 | /* |
@@ -150,37 +139,32 @@ static int try_to_bring_up_master(struct master *master, | |||
150 | { | 139 | { |
151 | int ret; | 140 | int ret; |
152 | 141 | ||
142 | dev_dbg(master->dev, "trying to bring up master\n"); | ||
143 | |||
153 | if (find_components(master)) { | 144 | if (find_components(master)) { |
154 | /* Failed to find all components */ | 145 | dev_dbg(master->dev, "master has incomplete components\n"); |
155 | ret = 0; | 146 | return 0; |
156 | goto out; | ||
157 | } | 147 | } |
158 | 148 | ||
159 | if (component && component->master != master) { | 149 | if (component && component->master != master) { |
160 | ret = 0; | 150 | dev_dbg(master->dev, "master is not for this component (%s)\n", |
161 | goto out; | 151 | dev_name(component->dev)); |
152 | return 0; | ||
162 | } | 153 | } |
163 | 154 | ||
164 | if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) { | 155 | if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) |
165 | ret = -ENOMEM; | 156 | return -ENOMEM; |
166 | goto out; | ||
167 | } | ||
168 | 157 | ||
169 | /* Found all components */ | 158 | /* Found all components */ |
170 | ret = master->ops->bind(master->dev); | 159 | ret = master->ops->bind(master->dev); |
171 | if (ret < 0) { | 160 | if (ret < 0) { |
172 | devres_release_group(master->dev, NULL); | 161 | devres_release_group(master->dev, NULL); |
173 | dev_info(master->dev, "master bind failed: %d\n", ret); | 162 | dev_info(master->dev, "master bind failed: %d\n", ret); |
174 | goto out; | 163 | return ret; |
175 | } | 164 | } |
176 | 165 | ||
177 | master->bound = true; | 166 | master->bound = true; |
178 | return 1; | 167 | return 1; |
179 | |||
180 | out: | ||
181 | master_remove_components(master); | ||
182 | |||
183 | return ret; | ||
184 | } | 168 | } |
185 | 169 | ||
186 | static int try_to_bring_up_masters(struct component *component) | 170 | static int try_to_bring_up_masters(struct component *component) |
@@ -206,8 +190,6 @@ static void take_down_master(struct master *master) | |||
206 | devres_release_group(master->dev, NULL); | 190 | devres_release_group(master->dev, NULL); |
207 | master->bound = false; | 191 | master->bound = false; |
208 | } | 192 | } |
209 | |||
210 | master_remove_components(master); | ||
211 | } | 193 | } |
212 | 194 | ||
213 | static size_t component_match_size(size_t num) | 195 | static size_t component_match_size(size_t num) |
@@ -265,6 +247,7 @@ void component_match_add(struct device *dev, struct component_match **matchptr, | |||
265 | 247 | ||
266 | match->compare[match->num].fn = compare; | 248 | match->compare[match->num].fn = compare; |
267 | match->compare[match->num].data = compare_data; | 249 | match->compare[match->num].data = compare_data; |
250 | match->compare[match->num].component = NULL; | ||
268 | match->num++; | 251 | match->num++; |
269 | } | 252 | } |
270 | EXPORT_SYMBOL(component_match_add); | 253 | EXPORT_SYMBOL(component_match_add); |
@@ -288,7 +271,6 @@ int component_master_add_with_match(struct device *dev, | |||
288 | master->dev = dev; | 271 | master->dev = dev; |
289 | master->ops = ops; | 272 | master->ops = ops; |
290 | master->match = match; | 273 | master->match = match; |
291 | INIT_LIST_HEAD(&master->components); | ||
292 | 274 | ||
293 | /* Add to the list of available masters. */ | 275 | /* Add to the list of available masters. */ |
294 | mutex_lock(&component_mutex); | 276 | mutex_lock(&component_mutex); |
@@ -311,13 +293,24 @@ void component_master_del(struct device *dev, | |||
311 | const struct component_master_ops *ops) | 293 | const struct component_master_ops *ops) |
312 | { | 294 | { |
313 | struct master *master; | 295 | struct master *master; |
296 | int i; | ||
314 | 297 | ||
315 | mutex_lock(&component_mutex); | 298 | mutex_lock(&component_mutex); |
316 | master = __master_find(dev, ops); | 299 | master = __master_find(dev, ops); |
317 | if (master) { | 300 | if (master) { |
301 | struct component_match *match = master->match; | ||
302 | |||
318 | take_down_master(master); | 303 | take_down_master(master); |
319 | 304 | ||
320 | list_del(&master->node); | 305 | list_del(&master->node); |
306 | |||
307 | if (match) { | ||
308 | for (i = 0; i < match->num; i++) { | ||
309 | struct component *c = match->compare[i].component; | ||
310 | if (c) | ||
311 | c->master = NULL; | ||
312 | } | ||
313 | } | ||
321 | kfree(master); | 314 | kfree(master); |
322 | } | 315 | } |
323 | mutex_unlock(&component_mutex); | 316 | mutex_unlock(&component_mutex); |
@@ -340,6 +333,7 @@ void component_unbind_all(struct device *master_dev, void *data) | |||
340 | { | 333 | { |
341 | struct master *master; | 334 | struct master *master; |
342 | struct component *c; | 335 | struct component *c; |
336 | size_t i; | ||
343 | 337 | ||
344 | WARN_ON(!mutex_is_locked(&component_mutex)); | 338 | WARN_ON(!mutex_is_locked(&component_mutex)); |
345 | 339 | ||
@@ -347,8 +341,12 @@ void component_unbind_all(struct device *master_dev, void *data) | |||
347 | if (!master) | 341 | if (!master) |
348 | return; | 342 | return; |
349 | 343 | ||
350 | list_for_each_entry_reverse(c, &master->components, master_node) | 344 | /* Unbind components in reverse order */ |
351 | component_unbind(c, master, data); | 345 | for (i = master->match->num; i--; ) |
346 | if (!master->match->compare[i].duplicate) { | ||
347 | c = master->match->compare[i].component; | ||
348 | component_unbind(c, master, data); | ||
349 | } | ||
352 | } | 350 | } |
353 | EXPORT_SYMBOL_GPL(component_unbind_all); | 351 | EXPORT_SYMBOL_GPL(component_unbind_all); |
354 | 352 | ||
@@ -408,6 +406,7 @@ int component_bind_all(struct device *master_dev, void *data) | |||
408 | { | 406 | { |
409 | struct master *master; | 407 | struct master *master; |
410 | struct component *c; | 408 | struct component *c; |
409 | size_t i; | ||
411 | int ret = 0; | 410 | int ret = 0; |
412 | 411 | ||
413 | WARN_ON(!mutex_is_locked(&component_mutex)); | 412 | WARN_ON(!mutex_is_locked(&component_mutex)); |
@@ -416,16 +415,21 @@ int component_bind_all(struct device *master_dev, void *data) | |||
416 | if (!master) | 415 | if (!master) |
417 | return -EINVAL; | 416 | return -EINVAL; |
418 | 417 | ||
419 | list_for_each_entry(c, &master->components, master_node) { | 418 | /* Bind components in match order */ |
420 | ret = component_bind(c, master, data); | 419 | for (i = 0; i < master->match->num; i++) |
421 | if (ret) | 420 | if (!master->match->compare[i].duplicate) { |
422 | break; | 421 | c = master->match->compare[i].component; |
423 | } | 422 | ret = component_bind(c, master, data); |
423 | if (ret) | ||
424 | break; | ||
425 | } | ||
424 | 426 | ||
425 | if (ret != 0) { | 427 | if (ret != 0) { |
426 | list_for_each_entry_continue_reverse(c, &master->components, | 428 | for (; i--; ) |
427 | master_node) | 429 | if (!master->match->compare[i].duplicate) { |
428 | component_unbind(c, master, data); | 430 | c = master->match->compare[i].component; |
431 | component_unbind(c, master, data); | ||
432 | } | ||
429 | } | 433 | } |
430 | 434 | ||
431 | return ret; | 435 | return ret; |
@@ -473,8 +477,10 @@ void component_del(struct device *dev, const struct component_ops *ops) | |||
473 | break; | 477 | break; |
474 | } | 478 | } |
475 | 479 | ||
476 | if (component && component->master) | 480 | if (component && component->master) { |
477 | take_down_master(component->master); | 481 | take_down_master(component->master); |
482 | remove_component(component->master, component); | ||
483 | } | ||
478 | 484 | ||
479 | mutex_unlock(&component_mutex); | 485 | mutex_unlock(&component_mutex); |
480 | 486 | ||