aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/component.c
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2014-04-18 18:05:53 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2015-12-06 19:02:05 -0500
commitffc30b74fd6d01588bd3fdebc3b1acc0857e6fc8 (patch)
treef013e9daec3d283bbf34d34f1f9312e5531a7d71 /drivers/base/component.c
parent29f1c7fd61a31e0335ce41d4b2788959ad7c468d (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.c154
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
21struct component;
22
21struct component_match { 23struct 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
30struct master { 34struct 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
40struct component { 43struct 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. */ 68static struct component *find_component(struct master *master,
67static 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. */
75static 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 */
87static 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
108static int find_components(struct master *master) 84static 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 */
129static void master_remove_components(struct master *master) 120static 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
180out:
181 master_remove_components(master);
182
183 return ret;
184} 168}
185 169
186static int try_to_bring_up_masters(struct component *component) 170static 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
213static size_t component_match_size(size_t num) 195static 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}
270EXPORT_SYMBOL(component_match_add); 253EXPORT_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}
353EXPORT_SYMBOL_GPL(component_unbind_all); 351EXPORT_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