Branch data Line data Source code
1 : : /*
2 : : * Componentized device handling.
3 : : *
4 : : * This program is free software; you can redistribute it and/or modify
5 : : * it under the terms of the GNU General Public License version 2 as
6 : : * published by the Free Software Foundation.
7 : : *
8 : : * This is work in progress. We gather up the component devices into a list,
9 : : * and bind them when instructed. At the moment, we're specific to the DRM
10 : : * subsystem, and only handles one master device, but this doesn't have to be
11 : : * the case.
12 : : */
13 : : #include <linux/component.h>
14 : : #include <linux/device.h>
15 : : #include <linux/kref.h>
16 : : #include <linux/list.h>
17 : : #include <linux/module.h>
18 : : #include <linux/mutex.h>
19 : : #include <linux/slab.h>
20 : :
21 : : struct master {
22 : : struct list_head node;
23 : : struct list_head components;
24 : : bool bound;
25 : :
26 : : const struct component_master_ops *ops;
27 : : struct device *dev;
28 : : };
29 : :
30 : : struct component {
31 : : struct list_head node;
32 : : struct list_head master_node;
33 : : struct master *master;
34 : : bool bound;
35 : :
36 : : const struct component_ops *ops;
37 : : struct device *dev;
38 : : };
39 : :
40 : : static DEFINE_MUTEX(component_mutex);
41 : : static LIST_HEAD(component_list);
42 : : static LIST_HEAD(masters);
43 : :
44 : : static struct master *__master_find(struct device *dev,
45 : : const struct component_master_ops *ops)
46 : : {
47 : : struct master *m;
48 : :
49 [ # # ][ # # ]: 0 : list_for_each_entry(m, &masters, node)
[ # # ]
50 [ # # ][ # # ]: 0 : if (m->dev == dev && (!ops || m->ops == ops))
[ # # ][ # # ]
[ # # ]
51 : : return m;
52 : :
53 : : return NULL;
54 : : }
55 : :
56 : : /* Attach an unattached component to a master. */
57 : : static void component_attach_master(struct master *master, struct component *c)
58 : : {
59 : 0 : c->master = master;
60 : :
61 : 0 : list_add_tail(&c->master_node, &master->components);
62 : : }
63 : :
64 : : /* Detach a component from a master. */
65 : : static void component_detach_master(struct master *master, struct component *c)
66 : : {
67 : : list_del(&c->master_node);
68 : :
69 : 0 : c->master = NULL;
70 : : }
71 : :
72 : 0 : int component_master_add_child(struct master *master,
73 : : int (*compare)(struct device *, void *), void *compare_data)
74 : : {
75 : : struct component *c;
76 : : int ret = -ENXIO;
77 : :
78 [ # # ]: 0 : list_for_each_entry(c, &component_list, node) {
79 [ # # ]: 0 : if (c->master)
80 : 0 : continue;
81 : :
82 [ # # ]: 0 : if (compare(c->dev, compare_data)) {
83 : : component_attach_master(master, c);
84 : : ret = 0;
85 : 0 : break;
86 : : }
87 : : }
88 : :
89 : 0 : return ret;
90 : : }
91 : : EXPORT_SYMBOL_GPL(component_master_add_child);
92 : :
93 : : /* Detach all attached components from this master */
94 : 0 : static void master_remove_components(struct master *master)
95 : : {
96 [ # # ]: 0 : while (!list_empty(&master->components)) {
97 : : struct component *c = list_first_entry(&master->components,
98 : : struct component, master_node);
99 : :
100 [ # # ]: 0 : WARN_ON(c->master != master);
101 : :
102 : : component_detach_master(master, c);
103 : : }
104 : 0 : }
105 : :
106 : : /*
107 : : * Try to bring up a master. If component is NULL, we're interested in
108 : : * this master, otherwise it's a component which must be present to try
109 : : * and bring up the master.
110 : : *
111 : : * Returns 1 for successful bringup, 0 if not ready, or -ve errno.
112 : : */
113 : 0 : static int try_to_bring_up_master(struct master *master,
114 : : struct component *component)
115 : : {
116 : : int ret = 0;
117 : :
118 [ # # ]: 0 : if (!master->bound) {
119 : : /*
120 : : * Search the list of components, looking for components that
121 : : * belong to this master, and attach them to the master.
122 : : */
123 [ # # ]: 0 : if (master->ops->add_components(master->dev, master)) {
124 : : /* Failed to find all components */
125 : 0 : master_remove_components(master);
126 : : ret = 0;
127 : 0 : goto out;
128 : : }
129 : :
130 [ # # ][ # # ]: 0 : if (component && component->master != master) {
131 : 0 : master_remove_components(master);
132 : : ret = 0;
133 : 0 : goto out;
134 : : }
135 : :
136 [ # # ]: 0 : if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) {
137 : : ret = -ENOMEM;
138 : : goto out;
139 : : }
140 : :
141 : : /* Found all components */
142 : 0 : ret = master->ops->bind(master->dev);
143 [ # # ]: 0 : if (ret < 0) {
144 : 0 : devres_release_group(master->dev, NULL);
145 : 0 : dev_info(master->dev, "master bind failed: %d\n", ret);
146 : 0 : master_remove_components(master);
147 : 0 : goto out;
148 : : }
149 : :
150 : 0 : master->bound = true;
151 : : ret = 1;
152 : : }
153 : : out:
154 : :
155 : 0 : return ret;
156 : : }
157 : :
158 : 0 : static int try_to_bring_up_masters(struct component *component)
159 : : {
160 : : struct master *m;
161 : : int ret = 0;
162 : :
163 [ # # ]: 0 : list_for_each_entry(m, &masters, node) {
164 : 0 : ret = try_to_bring_up_master(m, component);
165 [ # # ]: 0 : if (ret != 0)
166 : : break;
167 : : }
168 : :
169 : 0 : return ret;
170 : : }
171 : :
172 : 0 : static void take_down_master(struct master *master)
173 : : {
174 [ # # ]: 0 : if (master->bound) {
175 : 0 : master->ops->unbind(master->dev);
176 : 0 : devres_release_group(master->dev, NULL);
177 : 0 : master->bound = false;
178 : : }
179 : :
180 : 0 : master_remove_components(master);
181 : 0 : }
182 : :
183 : 0 : int component_master_add(struct device *dev,
184 : : const struct component_master_ops *ops)
185 : : {
186 : : struct master *master;
187 : : int ret;
188 : :
189 : : master = kzalloc(sizeof(*master), GFP_KERNEL);
190 [ # # ]: 0 : if (!master)
191 : : return -ENOMEM;
192 : :
193 : 0 : master->dev = dev;
194 : 0 : master->ops = ops;
195 : 0 : INIT_LIST_HEAD(&master->components);
196 : :
197 : : /* Add to the list of available masters. */
198 : 0 : mutex_lock(&component_mutex);
199 : 0 : list_add(&master->node, &masters);
200 : :
201 : 0 : ret = try_to_bring_up_master(master, NULL);
202 : :
203 [ # # ]: 0 : if (ret < 0) {
204 : : /* Delete off the list if we weren't successful */
205 : : list_del(&master->node);
206 : 0 : kfree(master);
207 : : }
208 : 0 : mutex_unlock(&component_mutex);
209 : :
210 : 0 : return ret < 0 ? ret : 0;
211 : : }
212 : : EXPORT_SYMBOL_GPL(component_master_add);
213 : :
214 : 0 : void component_master_del(struct device *dev,
215 : : const struct component_master_ops *ops)
216 : : {
217 : : struct master *master;
218 : :
219 : 0 : mutex_lock(&component_mutex);
220 : : master = __master_find(dev, ops);
221 [ # # ]: 0 : if (master) {
222 : 0 : take_down_master(master);
223 : :
224 : : list_del(&master->node);
225 : 0 : kfree(master);
226 : : }
227 : 0 : mutex_unlock(&component_mutex);
228 : 0 : }
229 : : EXPORT_SYMBOL_GPL(component_master_del);
230 : :
231 : 0 : static void component_unbind(struct component *component,
232 : : struct master *master, void *data)
233 : : {
234 [ # # ]: 0 : WARN_ON(!component->bound);
235 : :
236 : 0 : component->ops->unbind(component->dev, master->dev, data);
237 : 0 : component->bound = false;
238 : :
239 : : /* Release all resources claimed in the binding of this component */
240 : 0 : devres_release_group(component->dev, component);
241 : 0 : }
242 : :
243 : 0 : void component_unbind_all(struct device *master_dev, void *data)
244 : : {
245 : : struct master *master;
246 : : struct component *c;
247 : :
248 [ # # ]: 0 : WARN_ON(!mutex_is_locked(&component_mutex));
249 : :
250 : : master = __master_find(master_dev, NULL);
251 [ # # ]: 0 : if (!master)
252 : 0 : return;
253 : :
254 [ # # ]: 0 : list_for_each_entry_reverse(c, &master->components, master_node)
255 : 0 : component_unbind(c, master, data);
256 : : }
257 : : EXPORT_SYMBOL_GPL(component_unbind_all);
258 : :
259 : 0 : static int component_bind(struct component *component, struct master *master,
260 : : void *data)
261 : : {
262 : : int ret;
263 : :
264 : : /*
265 : : * Each component initialises inside its own devres group.
266 : : * This allows us to roll-back a failed component without
267 : : * affecting anything else.
268 : : */
269 [ # # ]: 0 : if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
270 : : return -ENOMEM;
271 : :
272 : : /*
273 : : * Also open a group for the device itself: this allows us
274 : : * to release the resources claimed against the sub-device
275 : : * at the appropriate moment.
276 : : */
277 [ # # ]: 0 : if (!devres_open_group(component->dev, component, GFP_KERNEL)) {
278 : 0 : devres_release_group(master->dev, NULL);
279 : : return -ENOMEM;
280 : : }
281 : :
282 : : dev_dbg(master->dev, "binding %s (ops %ps)\n",
283 : : dev_name(component->dev), component->ops);
284 : :
285 : 0 : ret = component->ops->bind(component->dev, master->dev, data);
286 [ # # ]: 0 : if (!ret) {
287 : 0 : component->bound = true;
288 : :
289 : : /*
290 : : * Close the component device's group so that resources
291 : : * allocated in the binding are encapsulated for removal
292 : : * at unbind. Remove the group on the DRM device as we
293 : : * can clean those resources up independently.
294 : : */
295 : 0 : devres_close_group(component->dev, NULL);
296 : 0 : devres_remove_group(master->dev, NULL);
297 : :
298 : 0 : dev_info(master->dev, "bound %s (ops %ps)\n",
299 : : dev_name(component->dev), component->ops);
300 : : } else {
301 : 0 : devres_release_group(component->dev, NULL);
302 : 0 : devres_release_group(master->dev, NULL);
303 : :
304 : 0 : dev_err(master->dev, "failed to bind %s (ops %ps): %d\n",
305 : 0 : dev_name(component->dev), component->ops, ret);
306 : : }
307 : :
308 : : return ret;
309 : : }
310 : :
311 : 0 : int component_bind_all(struct device *master_dev, void *data)
312 : : {
313 : : struct master *master;
314 : : struct component *c;
315 : : int ret = 0;
316 : :
317 [ # # ]: 0 : WARN_ON(!mutex_is_locked(&component_mutex));
318 : :
319 : : master = __master_find(master_dev, NULL);
320 [ # # ]: 0 : if (!master)
321 : : return -EINVAL;
322 : :
323 [ # # ]: 0 : list_for_each_entry(c, &master->components, master_node) {
324 : 0 : ret = component_bind(c, master, data);
325 [ # # ]: 0 : if (ret)
326 : : break;
327 : : }
328 : :
329 [ # # ]: 0 : if (ret != 0) {
330 [ # # ]: 0 : list_for_each_entry_continue_reverse(c, &master->components,
331 : : master_node)
332 : 0 : component_unbind(c, master, data);
333 : : }
334 : :
335 : 0 : return ret;
336 : : }
337 : : EXPORT_SYMBOL_GPL(component_bind_all);
338 : :
339 : 0 : int component_add(struct device *dev, const struct component_ops *ops)
340 : : {
341 : : struct component *component;
342 : : int ret;
343 : :
344 : : component = kzalloc(sizeof(*component), GFP_KERNEL);
345 [ # # ]: 0 : if (!component)
346 : : return -ENOMEM;
347 : :
348 : 0 : component->ops = ops;
349 : 0 : component->dev = dev;
350 : :
351 : : dev_dbg(dev, "adding component (ops %ps)\n", ops);
352 : :
353 : 0 : mutex_lock(&component_mutex);
354 : 0 : list_add_tail(&component->node, &component_list);
355 : :
356 : 0 : ret = try_to_bring_up_masters(component);
357 [ # # ]: 0 : if (ret < 0) {
358 : : list_del(&component->node);
359 : :
360 : 0 : kfree(component);
361 : : }
362 : 0 : mutex_unlock(&component_mutex);
363 : :
364 : 0 : return ret < 0 ? ret : 0;
365 : : }
366 : : EXPORT_SYMBOL_GPL(component_add);
367 : :
368 : 0 : void component_del(struct device *dev, const struct component_ops *ops)
369 : : {
370 : : struct component *c, *component = NULL;
371 : :
372 : 0 : mutex_lock(&component_mutex);
373 [ # # ]: 0 : list_for_each_entry(c, &component_list, node)
374 [ # # ][ # # ]: 0 : if (c->dev == dev && c->ops == ops) {
375 : : list_del(&c->node);
376 : : component = c;
377 : 0 : break;
378 : : }
379 : :
380 [ # # ][ # # ]: 0 : if (component && component->master)
381 : 0 : take_down_master(component->master);
382 : :
383 : 0 : mutex_unlock(&component_mutex);
384 : :
385 [ # # ]: 0 : WARN_ON(!component);
386 : 0 : kfree(component);
387 : 0 : }
388 : : EXPORT_SYMBOL_GPL(component_del);
389 : :
390 : : MODULE_LICENSE("GPL v2");
|