aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/component.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-08-04 21:34:04 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-08-04 21:34:04 -0400
commit29b88e23a9212136d39b0161a39afe587d0170a5 (patch)
tree48d9f857b137222e35f853004973e12a515314f5 /drivers/base/component.c
parent2521129a6d2fd8a81f99cf95055eddea3df914ff (diff)
parent4e3a25b0274b8474f5ad46215a270785dd18265e (diff)
Merge tag 'driver-core-3.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core
Pull driver core updates from Greg KH: "Here's the big driver-core pull request for 3.17-rc1. Largest thing in here is the dma-buf rework and fence code, that touched many different subsystems so it was agreed it should go through this tree to handle merge issues. There's also some firmware loading updates, as well as tests added, and a few other tiny changes, the changelog has the details. All have been in linux-next for a long time" * tag 'driver-core-3.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (32 commits) ARM: imx: Remove references to platform_bus in mxc code firmware loader: Fix _request_firmware_load() return val for fw load abort platform: Remove most references to platform_bus device test: add firmware_class loader test doc: fix minor typos in firmware_class README staging: android: Cleanup style issues Documentation: devres: Sort managed interfaces Documentation: devres: Add devm_kmalloc() et al fs: debugfs: remove trailing whitespace kernfs: kernel-doc warning fix debugfs: Fix corrupted loop in debugfs_remove_recursive stable_kernel_rules: Add pointer to netdev-FAQ for network patches driver core: platform: add device binding path 'driver_override' driver core/platform: remove unused implicit padding in platform_object firmware loader: inform direct failure when udev loader is disabled firmware: replace ALIGN(PAGE_SIZE) by PAGE_ALIGN firmware: read firmware size using i_size_read() firmware loader: allow disabling of udev as firmware loader reservation: add suppport for read-only access using rcu reservation: update api and add some helpers ... Conflicts: drivers/base/platform.c
Diffstat (limited to 'drivers/base/component.c')
-rw-r--r--drivers/base/component.c192
1 files changed, 157 insertions, 35 deletions
diff --git a/drivers/base/component.c b/drivers/base/component.c
index c4778995cd72..f748430bb654 100644
--- a/drivers/base/component.c
+++ b/drivers/base/component.c
@@ -18,6 +18,15 @@
18#include <linux/mutex.h> 18#include <linux/mutex.h>
19#include <linux/slab.h> 19#include <linux/slab.h>
20 20
21struct component_match {
22 size_t alloc;
23 size_t num;
24 struct {
25 void *data;
26 int (*fn)(struct device *, void *);
27 } compare[0];
28};
29
21struct master { 30struct master {
22 struct list_head node; 31 struct list_head node;
23 struct list_head components; 32 struct list_head components;
@@ -25,6 +34,7 @@ struct master {
25 34
26 const struct component_master_ops *ops; 35 const struct component_master_ops *ops;
27 struct device *dev; 36 struct device *dev;
37 struct component_match *match;
28}; 38};
29 39
30struct component { 40struct component {
@@ -69,6 +79,11 @@ static void component_detach_master(struct master *master, struct component *c)
69 c->master = NULL; 79 c->master = NULL;
70} 80}
71 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 */
72int component_master_add_child(struct master *master, 87int component_master_add_child(struct master *master,
73 int (*compare)(struct device *, void *), void *compare_data) 88 int (*compare)(struct device *, void *), void *compare_data)
74{ 89{
@@ -76,11 +91,12 @@ int component_master_add_child(struct master *master,
76 int ret = -ENXIO; 91 int ret = -ENXIO;
77 92
78 list_for_each_entry(c, &component_list, node) { 93 list_for_each_entry(c, &component_list, node) {
79 if (c->master) 94 if (c->master && c->master != master)
80 continue; 95 continue;
81 96
82 if (compare(c->dev, compare_data)) { 97 if (compare(c->dev, compare_data)) {
83 component_attach_master(master, c); 98 if (!c->master)
99 component_attach_master(master, c);
84 ret = 0; 100 ret = 0;
85 break; 101 break;
86 } 102 }
@@ -90,6 +106,34 @@ int component_master_add_child(struct master *master,
90} 106}
91EXPORT_SYMBOL_GPL(component_master_add_child); 107EXPORT_SYMBOL_GPL(component_master_add_child);
92 108
109static int find_components(struct master *master)
110{
111 struct component_match *match = master->match;
112 size_t i;
113 int ret = 0;
114
115 if (!match) {
116 /*
117 * Search the list of components, looking for components that
118 * belong to this master, and attach them to the master.
119 */
120 return master->ops->add_components(master->dev, master);
121 }
122
123 /*
124 * Scan the array of match functions and attach
125 * any components which are found to this master.
126 */
127 for (i = 0; i < match->num; i++) {
128 ret = component_master_add_child(master,
129 match->compare[i].fn,
130 match->compare[i].data);
131 if (ret)
132 break;
133 }
134 return ret;
135}
136
93/* Detach all attached components from this master */ 137/* Detach all attached components from this master */
94static void master_remove_components(struct master *master) 138static void master_remove_components(struct master *master)
95{ 139{
@@ -113,44 +157,44 @@ static void master_remove_components(struct master *master)
113static int try_to_bring_up_master(struct master *master, 157static int try_to_bring_up_master(struct master *master,
114 struct component *component) 158 struct component *component)
115{ 159{
116 int ret = 0; 160 int ret;
117 161
118 if (!master->bound) { 162 if (master->bound)
119 /* 163 return 0;
120 * Search the list of components, looking for components that
121 * belong to this master, and attach them to the master.
122 */
123 if (master->ops->add_components(master->dev, master)) {
124 /* Failed to find all components */
125 master_remove_components(master);
126 ret = 0;
127 goto out;
128 }
129 164
130 if (component && component->master != master) { 165 /*
131 master_remove_components(master); 166 * Search the list of components, looking for components that
132 ret = 0; 167 * belong to this master, and attach them to the master.
133 goto out; 168 */
134 } 169 if (find_components(master)) {
170 /* Failed to find all components */
171 ret = 0;
172 goto out;
173 }
135 174
136 if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) { 175 if (component && component->master != master) {
137 ret = -ENOMEM; 176 ret = 0;
138 goto out; 177 goto out;
139 } 178 }
140 179
141 /* Found all components */ 180 if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) {
142 ret = master->ops->bind(master->dev); 181 ret = -ENOMEM;
143 if (ret < 0) { 182 goto out;
144 devres_release_group(master->dev, NULL); 183 }
145 dev_info(master->dev, "master bind failed: %d\n", ret);
146 master_remove_components(master);
147 goto out;
148 }
149 184
150 master->bound = true; 185 /* Found all components */
151 ret = 1; 186 ret = master->ops->bind(master->dev);
187 if (ret < 0) {
188 devres_release_group(master->dev, NULL);
189 dev_info(master->dev, "master bind failed: %d\n", ret);
190 goto out;
152 } 191 }
192
193 master->bound = true;
194 return 1;
195
153out: 196out:
197 master_remove_components(master);
154 198
155 return ret; 199 return ret;
156} 200}
@@ -180,18 +224,89 @@ static void take_down_master(struct master *master)
180 master_remove_components(master); 224 master_remove_components(master);
181} 225}
182 226
183int component_master_add(struct device *dev, 227static size_t component_match_size(size_t num)
184 const struct component_master_ops *ops) 228{
229 return offsetof(struct component_match, compare[num]);
230}
231
232static struct component_match *component_match_realloc(struct device *dev,
233 struct component_match *match, size_t num)
234{
235 struct component_match *new;
236
237 if (match && match->alloc == num)
238 return match;
239
240 new = devm_kmalloc(dev, component_match_size(num), GFP_KERNEL);
241 if (!new)
242 return ERR_PTR(-ENOMEM);
243
244 if (match) {
245 memcpy(new, match, component_match_size(min(match->num, num)));
246 devm_kfree(dev, match);
247 } else {
248 new->num = 0;
249 }
250
251 new->alloc = num;
252
253 return new;
254}
255
256/*
257 * Add a component to be matched.
258 *
259 * The match array is first created or extended if necessary.
260 */
261void component_match_add(struct device *dev, struct component_match **matchptr,
262 int (*compare)(struct device *, void *), void *compare_data)
263{
264 struct component_match *match = *matchptr;
265
266 if (IS_ERR(match))
267 return;
268
269 if (!match || match->num == match->alloc) {
270 size_t new_size = match ? match->alloc + 16 : 15;
271
272 match = component_match_realloc(dev, match, new_size);
273
274 *matchptr = match;
275
276 if (IS_ERR(match))
277 return;
278 }
279
280 match->compare[match->num].fn = compare;
281 match->compare[match->num].data = compare_data;
282 match->num++;
283}
284EXPORT_SYMBOL(component_match_add);
285
286int component_master_add_with_match(struct device *dev,
287 const struct component_master_ops *ops,
288 struct component_match *match)
185{ 289{
186 struct master *master; 290 struct master *master;
187 int ret; 291 int ret;
188 292
293 if (ops->add_components && match)
294 return -EINVAL;
295
296 if (match) {
297 /* Reallocate the match array for its true size */
298 match = component_match_realloc(dev, match, match->num);
299 if (IS_ERR(match))
300 return PTR_ERR(match);
301 }
302
189 master = kzalloc(sizeof(*master), GFP_KERNEL); 303 master = kzalloc(sizeof(*master), GFP_KERNEL);
190 if (!master) 304 if (!master)
191 return -ENOMEM; 305 return -ENOMEM;
192 306
193 master->dev = dev; 307 master->dev = dev;
194 master->ops = ops; 308 master->ops = ops;
309 master->match = match;
195 INIT_LIST_HEAD(&master->components); 310 INIT_LIST_HEAD(&master->components);
196 311
197 /* Add to the list of available masters. */ 312 /* Add to the list of available masters. */
@@ -209,6 +324,13 @@ int component_master_add(struct device *dev,
209 324
210 return ret < 0 ? ret : 0; 325 return ret < 0 ? ret : 0;
211} 326}
327EXPORT_SYMBOL_GPL(component_master_add_with_match);
328
329int component_master_add(struct device *dev,
330 const struct component_master_ops *ops)
331{
332 return component_master_add_with_match(dev, ops, NULL);
333}
212EXPORT_SYMBOL_GPL(component_master_add); 334EXPORT_SYMBOL_GPL(component_master_add);
213 335
214void component_master_del(struct device *dev, 336void component_master_del(struct device *dev,