Branch data Line data Source code
1 : : /*
2 : : * drivers/base/devres.c - device resource management
3 : : *
4 : : * Copyright (c) 2006 SUSE Linux Products GmbH
5 : : * Copyright (c) 2006 Tejun Heo <teheo@suse.de>
6 : : *
7 : : * This file is released under the GPLv2.
8 : : */
9 : :
10 : : #include <linux/device.h>
11 : : #include <linux/module.h>
12 : : #include <linux/slab.h>
13 : :
14 : : #include "base.h"
15 : :
16 : : struct devres_node {
17 : : struct list_head entry;
18 : : dr_release_t release;
19 : : #ifdef CONFIG_DEBUG_DEVRES
20 : : const char *name;
21 : : size_t size;
22 : : #endif
23 : : };
24 : :
25 : : struct devres {
26 : : struct devres_node node;
27 : : /* -- 3 pointers */
28 : : unsigned long long data[]; /* guarantee ull alignment */
29 : : };
30 : :
31 : : struct devres_group {
32 : : struct devres_node node[2];
33 : : void *id;
34 : : int color;
35 : : /* -- 8 pointers */
36 : : };
37 : :
38 : : #ifdef CONFIG_DEBUG_DEVRES
39 : : static int log_devres = 0;
40 : : module_param_named(log, log_devres, int, S_IRUGO | S_IWUSR);
41 : :
42 : : static void set_node_dbginfo(struct devres_node *node, const char *name,
43 : : size_t size)
44 : : {
45 : : node->name = name;
46 : : node->size = size;
47 : : }
48 : :
49 : : static void devres_log(struct device *dev, struct devres_node *node,
50 : : const char *op)
51 : : {
52 : : if (unlikely(log_devres))
53 : : dev_err(dev, "DEVRES %3s %p %s (%lu bytes)\n",
54 : : op, node, node->name, (unsigned long)node->size);
55 : : }
56 : : #else /* CONFIG_DEBUG_DEVRES */
57 : : #define set_node_dbginfo(node, n, s) do {} while (0)
58 : : #define devres_log(dev, node, op) do {} while (0)
59 : : #endif /* CONFIG_DEBUG_DEVRES */
60 : :
61 : : /*
62 : : * Release functions for devres group. These callbacks are used only
63 : : * for identification.
64 : : */
65 : 0 : static void group_open_release(struct device *dev, void *res)
66 : : {
67 : : /* noop */
68 : 0 : }
69 : :
70 : 0 : static void group_close_release(struct device *dev, void *res)
71 : : {
72 : : /* noop */
73 : 0 : }
74 : :
75 : : static struct devres_group * node_to_group(struct devres_node *node)
76 : : {
77 [ # # ][ # # ]: 0 : if (node->release == &group_open_release)
78 : : return container_of(node, struct devres_group, node[0]);
79 [ # # ][ # # ]: 0 : if (node->release == &group_close_release)
80 : 0 : return container_of(node, struct devres_group, node[1]);
81 : : return NULL;
82 : : }
83 : :
84 : : static __always_inline struct devres * alloc_dr(dr_release_t release,
85 : : size_t size, gfp_t gfp)
86 : : {
87 : 0 : size_t tot_size = sizeof(struct devres) + size;
88 : : struct devres *dr;
89 : :
90 : 0 : dr = kmalloc_track_caller(tot_size, gfp);
91 [ # # # # ]: 0 : if (unlikely(!dr))
92 : : return NULL;
93 : :
94 : 0 : memset(dr, 0, offsetof(struct devres, data));
95 : :
96 : 0 : INIT_LIST_HEAD(&dr->node.entry);
97 : 0 : dr->node.release = release;
98 : : return dr;
99 : : }
100 : :
101 : 0 : static void add_dr(struct device *dev, struct devres_node *node)
102 : : {
103 : : devres_log(dev, node, "ADD");
104 [ # # ]: 0 : BUG_ON(!list_empty(&node->entry));
105 : 0 : list_add_tail(&node->entry, &dev->devres_head);
106 : 0 : }
107 : :
108 : : #ifdef CONFIG_DEBUG_DEVRES
109 : : void * __devres_alloc(dr_release_t release, size_t size, gfp_t gfp,
110 : : const char *name)
111 : : {
112 : : struct devres *dr;
113 : :
114 : : dr = alloc_dr(release, size, gfp | __GFP_ZERO);
115 : : if (unlikely(!dr))
116 : : return NULL;
117 : : set_node_dbginfo(&dr->node, name, size);
118 : : return dr->data;
119 : : }
120 : : EXPORT_SYMBOL_GPL(__devres_alloc);
121 : : #else
122 : : /**
123 : : * devres_alloc - Allocate device resource data
124 : : * @release: Release function devres will be associated with
125 : : * @size: Allocation size
126 : : * @gfp: Allocation flags
127 : : *
128 : : * Allocate devres of @size bytes. The allocated area is zeroed, then
129 : : * associated with @release. The returned pointer can be passed to
130 : : * other devres_*() functions.
131 : : *
132 : : * RETURNS:
133 : : * Pointer to allocated devres on success, NULL on failure.
134 : : */
135 : 0 : void * devres_alloc(dr_release_t release, size_t size, gfp_t gfp)
136 : : {
137 : : struct devres *dr;
138 : :
139 : 0 : dr = alloc_dr(release, size, gfp | __GFP_ZERO);
140 [ # # ]: 0 : if (unlikely(!dr))
141 : : return NULL;
142 : 0 : return dr->data;
143 : : }
144 : : EXPORT_SYMBOL_GPL(devres_alloc);
145 : : #endif
146 : :
147 : : /**
148 : : * devres_for_each_res - Resource iterator
149 : : * @dev: Device to iterate resource from
150 : : * @release: Look for resources associated with this release function
151 : : * @match: Match function (optional)
152 : : * @match_data: Data for the match function
153 : : * @fn: Function to be called for each matched resource.
154 : : * @data: Data for @fn, the 3rd parameter of @fn
155 : : *
156 : : * Call @fn for each devres of @dev which is associated with @release
157 : : * and for which @match returns 1.
158 : : *
159 : : * RETURNS:
160 : : * void
161 : : */
162 : 0 : void devres_for_each_res(struct device *dev, dr_release_t release,
163 : : dr_match_t match, void *match_data,
164 : : void (*fn)(struct device *, void *, void *),
165 : : void *data)
166 : : {
167 : : struct devres_node *node;
168 : : struct devres_node *tmp;
169 : : unsigned long flags;
170 : :
171 [ # # ]: 0 : if (!fn)
172 : 0 : return;
173 : :
174 : 0 : spin_lock_irqsave(&dev->devres_lock, flags);
175 [ # # ]: 0 : list_for_each_entry_safe_reverse(node, tmp,
176 : : &dev->devres_head, entry) {
177 : : struct devres *dr = container_of(node, struct devres, node);
178 : :
179 [ # # ]: 0 : if (node->release != release)
180 : 0 : continue;
181 [ # # ][ # # ]: 0 : if (match && !match(dev, dr->data, match_data))
182 : 0 : continue;
183 : 0 : fn(dev, dr->data, data);
184 : : }
185 : : spin_unlock_irqrestore(&dev->devres_lock, flags);
186 : : }
187 : : EXPORT_SYMBOL_GPL(devres_for_each_res);
188 : :
189 : : /**
190 : : * devres_free - Free device resource data
191 : : * @res: Pointer to devres data to free
192 : : *
193 : : * Free devres created with devres_alloc().
194 : : */
195 : 0 : void devres_free(void *res)
196 : : {
197 [ # # ]: 0 : if (res) {
198 : 0 : struct devres *dr = container_of(res, struct devres, data);
199 : :
200 [ # # ]: 0 : BUG_ON(!list_empty(&dr->node.entry));
201 : 0 : kfree(dr);
202 : : }
203 : 0 : }
204 : : EXPORT_SYMBOL_GPL(devres_free);
205 : :
206 : : /**
207 : : * devres_add - Register device resource
208 : : * @dev: Device to add resource to
209 : : * @res: Resource to register
210 : : *
211 : : * Register devres @res to @dev. @res should have been allocated
212 : : * using devres_alloc(). On driver detach, the associated release
213 : : * function will be invoked and devres will be freed automatically.
214 : : */
215 : 0 : void devres_add(struct device *dev, void *res)
216 : : {
217 : : struct devres *dr = container_of(res, struct devres, data);
218 : : unsigned long flags;
219 : :
220 : 0 : spin_lock_irqsave(&dev->devres_lock, flags);
221 : 0 : add_dr(dev, &dr->node);
222 : : spin_unlock_irqrestore(&dev->devres_lock, flags);
223 : 0 : }
224 : : EXPORT_SYMBOL_GPL(devres_add);
225 : :
226 : 0 : static struct devres *find_dr(struct device *dev, dr_release_t release,
227 : : dr_match_t match, void *match_data)
228 : : {
229 : : struct devres_node *node;
230 : :
231 [ # # ]: 0 : list_for_each_entry_reverse(node, &dev->devres_head, entry) {
232 : : struct devres *dr = container_of(node, struct devres, node);
233 : :
234 [ # # ]: 0 : if (node->release != release)
235 : 0 : continue;
236 [ # # ][ # # ]: 0 : if (match && !match(dev, dr->data, match_data))
237 : 0 : continue;
238 : 0 : return dr;
239 : : }
240 : :
241 : : return NULL;
242 : : }
243 : :
244 : : /**
245 : : * devres_find - Find device resource
246 : : * @dev: Device to lookup resource from
247 : : * @release: Look for resources associated with this release function
248 : : * @match: Match function (optional)
249 : : * @match_data: Data for the match function
250 : : *
251 : : * Find the latest devres of @dev which is associated with @release
252 : : * and for which @match returns 1. If @match is NULL, it's considered
253 : : * to match all.
254 : : *
255 : : * RETURNS:
256 : : * Pointer to found devres, NULL if not found.
257 : : */
258 : 0 : void * devres_find(struct device *dev, dr_release_t release,
259 : : dr_match_t match, void *match_data)
260 : : {
261 : : struct devres *dr;
262 : : unsigned long flags;
263 : :
264 : 0 : spin_lock_irqsave(&dev->devres_lock, flags);
265 : 0 : dr = find_dr(dev, release, match, match_data);
266 : : spin_unlock_irqrestore(&dev->devres_lock, flags);
267 : :
268 [ # # ]: 0 : if (dr)
269 : 0 : return dr->data;
270 : : return NULL;
271 : : }
272 : : EXPORT_SYMBOL_GPL(devres_find);
273 : :
274 : : /**
275 : : * devres_get - Find devres, if non-existent, add one atomically
276 : : * @dev: Device to lookup or add devres for
277 : : * @new_res: Pointer to new initialized devres to add if not found
278 : : * @match: Match function (optional)
279 : : * @match_data: Data for the match function
280 : : *
281 : : * Find the latest devres of @dev which has the same release function
282 : : * as @new_res and for which @match return 1. If found, @new_res is
283 : : * freed; otherwise, @new_res is added atomically.
284 : : *
285 : : * RETURNS:
286 : : * Pointer to found or added devres.
287 : : */
288 : 0 : void * devres_get(struct device *dev, void *new_res,
289 : : dr_match_t match, void *match_data)
290 : : {
291 : 0 : struct devres *new_dr = container_of(new_res, struct devres, data);
292 : : struct devres *dr;
293 : : unsigned long flags;
294 : :
295 : 0 : spin_lock_irqsave(&dev->devres_lock, flags);
296 : 0 : dr = find_dr(dev, new_dr->node.release, match, match_data);
297 [ # # ]: 0 : if (!dr) {
298 : 0 : add_dr(dev, &new_dr->node);
299 : : dr = new_dr;
300 : : new_dr = NULL;
301 : : }
302 : : spin_unlock_irqrestore(&dev->devres_lock, flags);
303 : 0 : devres_free(new_dr);
304 : :
305 : 0 : return dr->data;
306 : : }
307 : : EXPORT_SYMBOL_GPL(devres_get);
308 : :
309 : : /**
310 : : * devres_remove - Find a device resource and remove it
311 : : * @dev: Device to find resource from
312 : : * @release: Look for resources associated with this release function
313 : : * @match: Match function (optional)
314 : : * @match_data: Data for the match function
315 : : *
316 : : * Find the latest devres of @dev associated with @release and for
317 : : * which @match returns 1. If @match is NULL, it's considered to
318 : : * match all. If found, the resource is removed atomically and
319 : : * returned.
320 : : *
321 : : * RETURNS:
322 : : * Pointer to removed devres on success, NULL if not found.
323 : : */
324 : 0 : void * devres_remove(struct device *dev, dr_release_t release,
325 : : dr_match_t match, void *match_data)
326 : : {
327 : : struct devres *dr;
328 : : unsigned long flags;
329 : :
330 : 0 : spin_lock_irqsave(&dev->devres_lock, flags);
331 : 0 : dr = find_dr(dev, release, match, match_data);
332 [ # # ]: 0 : if (dr) {
333 : 0 : list_del_init(&dr->node.entry);
334 : : devres_log(dev, &dr->node, "REM");
335 : : }
336 : : spin_unlock_irqrestore(&dev->devres_lock, flags);
337 : :
338 [ # # ]: 0 : if (dr)
339 : 0 : return dr->data;
340 : : return NULL;
341 : : }
342 : : EXPORT_SYMBOL_GPL(devres_remove);
343 : :
344 : : /**
345 : : * devres_destroy - Find a device resource and destroy it
346 : : * @dev: Device to find resource from
347 : : * @release: Look for resources associated with this release function
348 : : * @match: Match function (optional)
349 : : * @match_data: Data for the match function
350 : : *
351 : : * Find the latest devres of @dev associated with @release and for
352 : : * which @match returns 1. If @match is NULL, it's considered to
353 : : * match all. If found, the resource is removed atomically and freed.
354 : : *
355 : : * Note that the release function for the resource will not be called,
356 : : * only the devres-allocated data will be freed. The caller becomes
357 : : * responsible for freeing any other data.
358 : : *
359 : : * RETURNS:
360 : : * 0 if devres is found and freed, -ENOENT if not found.
361 : : */
362 : 0 : int devres_destroy(struct device *dev, dr_release_t release,
363 : : dr_match_t match, void *match_data)
364 : : {
365 : : void *res;
366 : :
367 : 0 : res = devres_remove(dev, release, match, match_data);
368 [ # # ]: 0 : if (unlikely(!res))
369 : : return -ENOENT;
370 : :
371 : 0 : devres_free(res);
372 : 0 : return 0;
373 : : }
374 : : EXPORT_SYMBOL_GPL(devres_destroy);
375 : :
376 : :
377 : : /**
378 : : * devres_release - Find a device resource and destroy it, calling release
379 : : * @dev: Device to find resource from
380 : : * @release: Look for resources associated with this release function
381 : : * @match: Match function (optional)
382 : : * @match_data: Data for the match function
383 : : *
384 : : * Find the latest devres of @dev associated with @release and for
385 : : * which @match returns 1. If @match is NULL, it's considered to
386 : : * match all. If found, the resource is removed atomically, the
387 : : * release function called and the resource freed.
388 : : *
389 : : * RETURNS:
390 : : * 0 if devres is found and freed, -ENOENT if not found.
391 : : */
392 : 0 : int devres_release(struct device *dev, dr_release_t release,
393 : : dr_match_t match, void *match_data)
394 : : {
395 : : void *res;
396 : :
397 : 0 : res = devres_remove(dev, release, match, match_data);
398 [ # # ]: 0 : if (unlikely(!res))
399 : : return -ENOENT;
400 : :
401 : 0 : (*release)(dev, res);
402 : 0 : devres_free(res);
403 : 0 : return 0;
404 : : }
405 : : EXPORT_SYMBOL_GPL(devres_release);
406 : :
407 : 0 : static int remove_nodes(struct device *dev,
408 : : struct list_head *first, struct list_head *end,
409 : : struct list_head *todo)
410 : : {
411 : : int cnt = 0, nr_groups = 0;
412 : : struct list_head *cur;
413 : :
414 : : /* First pass - move normal devres entries to @todo and clear
415 : : * devres_group colors.
416 : : */
417 : : cur = first;
418 [ # # ]: 0 : while (cur != end) {
419 : : struct devres_node *node;
420 : : struct devres_group *grp;
421 : :
422 : : node = list_entry(cur, struct devres_node, entry);
423 : 0 : cur = cur->next;
424 : :
425 : : grp = node_to_group(node);
426 [ # # ]: 0 : if (grp) {
427 : : /* clear color of group markers in the first pass */
428 : 0 : grp->color = 0;
429 : 0 : nr_groups++;
430 : : } else {
431 : : /* regular devres entry */
432 [ # # ]: 0 : if (&node->entry == first)
433 : 0 : first = first->next;
434 : : list_move_tail(&node->entry, todo);
435 : 0 : cnt++;
436 : : }
437 : : }
438 : :
439 [ # # ]: 0 : if (!nr_groups)
440 : : return cnt;
441 : :
442 : : /* Second pass - Scan groups and color them. A group gets
443 : : * color value of two iff the group is wholly contained in
444 : : * [cur, end). That is, for a closed group, both opening and
445 : : * closing markers should be in the range, while just the
446 : : * opening marker is enough for an open group.
447 : : */
448 : : cur = first;
449 [ # # ]: 0 : while (cur != end) {
450 : : struct devres_node *node;
451 : : struct devres_group *grp;
452 : :
453 : : node = list_entry(cur, struct devres_node, entry);
454 : 0 : cur = cur->next;
455 : :
456 : : grp = node_to_group(node);
457 [ # # ][ # # ]: 0 : BUG_ON(!grp || list_empty(&grp->node[0].entry));
458 : :
459 : 0 : grp->color++;
460 [ # # ]: 0 : if (list_empty(&grp->node[1].entry))
461 : 0 : grp->color++;
462 : :
463 [ # # ]: 0 : BUG_ON(grp->color <= 0 || grp->color > 2);
464 [ # # ]: 0 : if (grp->color == 2) {
465 : : /* No need to update cur or end. The removed
466 : : * nodes are always before both.
467 : : */
468 : : list_move_tail(&grp->node[0].entry, todo);
469 : : list_del_init(&grp->node[1].entry);
470 : : }
471 : : }
472 : :
473 : : return cnt;
474 : : }
475 : :
476 : 0 : static int release_nodes(struct device *dev, struct list_head *first,
477 : : struct list_head *end, unsigned long flags)
478 : : __releases(&dev->devres_lock)
479 : : {
480 : 0 : LIST_HEAD(todo);
481 : : int cnt;
482 : : struct devres *dr, *tmp;
483 : :
484 : 0 : cnt = remove_nodes(dev, first, end, &todo);
485 : :
486 : : spin_unlock_irqrestore(&dev->devres_lock, flags);
487 : :
488 : : /* Release. Note that both devres and devres_group are
489 : : * handled as devres in the following loop. This is safe.
490 : : */
491 [ # # ]: 0 : list_for_each_entry_safe_reverse(dr, tmp, &todo, node.entry) {
492 : : devres_log(dev, &dr->node, "REL");
493 : 0 : dr->node.release(dev, dr->data);
494 : 0 : kfree(dr);
495 : : }
496 : :
497 : 0 : return cnt;
498 : : }
499 : :
500 : : /**
501 : : * devres_release_all - Release all managed resources
502 : : * @dev: Device to release resources for
503 : : *
504 : : * Release all resources associated with @dev. This function is
505 : : * called on driver detach.
506 : : */
507 : 0 : int devres_release_all(struct device *dev)
508 : : {
509 : : unsigned long flags;
510 : :
511 : : /* Looks like an uninitialized device structure */
512 [ # # ][ # # ]: 0 : if (WARN_ON(dev->devres_head.next == NULL))
513 : : return -ENODEV;
514 : 0 : spin_lock_irqsave(&dev->devres_lock, flags);
515 : 0 : return release_nodes(dev, dev->devres_head.next, &dev->devres_head,
516 : : flags);
517 : : }
518 : :
519 : : /**
520 : : * devres_open_group - Open a new devres group
521 : : * @dev: Device to open devres group for
522 : : * @id: Separator ID
523 : : * @gfp: Allocation flags
524 : : *
525 : : * Open a new devres group for @dev with @id. For @id, using a
526 : : * pointer to an object which won't be used for another group is
527 : : * recommended. If @id is NULL, address-wise unique ID is created.
528 : : *
529 : : * RETURNS:
530 : : * ID of the new group, NULL on failure.
531 : : */
532 : 0 : void * devres_open_group(struct device *dev, void *id, gfp_t gfp)
533 : : {
534 : : struct devres_group *grp;
535 : : unsigned long flags;
536 : :
537 : : grp = kmalloc(sizeof(*grp), gfp);
538 [ # # ]: 0 : if (unlikely(!grp))
539 : : return NULL;
540 : :
541 : 0 : grp->node[0].release = &group_open_release;
542 : 0 : grp->node[1].release = &group_close_release;
543 : 0 : INIT_LIST_HEAD(&grp->node[0].entry);
544 : 0 : INIT_LIST_HEAD(&grp->node[1].entry);
545 : : set_node_dbginfo(&grp->node[0], "grp<", 0);
546 : : set_node_dbginfo(&grp->node[1], "grp>", 0);
547 : 0 : grp->id = grp;
548 [ # # ]: 0 : if (id)
549 : 0 : grp->id = id;
550 : :
551 : 0 : spin_lock_irqsave(&dev->devres_lock, flags);
552 : 0 : add_dr(dev, &grp->node[0]);
553 : : spin_unlock_irqrestore(&dev->devres_lock, flags);
554 : 0 : return grp->id;
555 : : }
556 : : EXPORT_SYMBOL_GPL(devres_open_group);
557 : :
558 : : /* Find devres group with ID @id. If @id is NULL, look for the latest. */
559 : : static struct devres_group * find_group(struct device *dev, void *id)
560 : : {
561 : : struct devres_node *node;
562 : :
563 [ # # ][ # # ]: 0 : list_for_each_entry_reverse(node, &dev->devres_head, entry) {
[ # # ]
564 : : struct devres_group *grp;
565 : :
566 [ # # ][ # # ]: 0 : if (node->release != &group_open_release)
[ # # ]
567 : 0 : continue;
568 : :
569 : : grp = container_of(node, struct devres_group, node[0]);
570 : :
571 [ # # ][ # # ]: 0 : if (id) {
[ # # ]
572 [ # # ][ # # ]: 0 : if (grp->id == id)
[ # # ]
573 : : return grp;
574 [ # # ][ # # ]: 0 : } else if (list_empty(&grp->node[1].entry))
[ # # ]
575 : : return grp;
576 : : }
577 : :
578 : : return NULL;
579 : : }
580 : :
581 : : /**
582 : : * devres_close_group - Close a devres group
583 : : * @dev: Device to close devres group for
584 : : * @id: ID of target group, can be NULL
585 : : *
586 : : * Close the group identified by @id. If @id is NULL, the latest open
587 : : * group is selected.
588 : : */
589 : 0 : void devres_close_group(struct device *dev, void *id)
590 : : {
591 : : struct devres_group *grp;
592 : : unsigned long flags;
593 : :
594 : 0 : spin_lock_irqsave(&dev->devres_lock, flags);
595 : :
596 : : grp = find_group(dev, id);
597 [ # # ]: 0 : if (grp)
598 : 0 : add_dr(dev, &grp->node[1]);
599 : : else
600 : 0 : WARN_ON(1);
601 : :
602 : : spin_unlock_irqrestore(&dev->devres_lock, flags);
603 : 0 : }
604 : : EXPORT_SYMBOL_GPL(devres_close_group);
605 : :
606 : : /**
607 : : * devres_remove_group - Remove a devres group
608 : : * @dev: Device to remove group for
609 : : * @id: ID of target group, can be NULL
610 : : *
611 : : * Remove the group identified by @id. If @id is NULL, the latest
612 : : * open group is selected. Note that removing a group doesn't affect
613 : : * any other resources.
614 : : */
615 : 0 : void devres_remove_group(struct device *dev, void *id)
616 : : {
617 : : struct devres_group *grp;
618 : : unsigned long flags;
619 : :
620 : 0 : spin_lock_irqsave(&dev->devres_lock, flags);
621 : :
622 : : grp = find_group(dev, id);
623 [ # # ]: 0 : if (grp) {
624 : 0 : list_del_init(&grp->node[0].entry);
625 : 0 : list_del_init(&grp->node[1].entry);
626 : : devres_log(dev, &grp->node[0], "REM");
627 : : } else
628 : 0 : WARN_ON(1);
629 : :
630 : : spin_unlock_irqrestore(&dev->devres_lock, flags);
631 : :
632 : 0 : kfree(grp);
633 : 0 : }
634 : : EXPORT_SYMBOL_GPL(devres_remove_group);
635 : :
636 : : /**
637 : : * devres_release_group - Release resources in a devres group
638 : : * @dev: Device to release group for
639 : : * @id: ID of target group, can be NULL
640 : : *
641 : : * Release all resources in the group identified by @id. If @id is
642 : : * NULL, the latest open group is selected. The selected group and
643 : : * groups properly nested inside the selected group are removed.
644 : : *
645 : : * RETURNS:
646 : : * The number of released non-group resources.
647 : : */
648 : 0 : int devres_release_group(struct device *dev, void *id)
649 : : {
650 : : struct devres_group *grp;
651 : : unsigned long flags;
652 : : int cnt = 0;
653 : :
654 : 0 : spin_lock_irqsave(&dev->devres_lock, flags);
655 : :
656 : : grp = find_group(dev, id);
657 [ # # ]: 0 : if (grp) {
658 : 0 : struct list_head *first = &grp->node[0].entry;
659 : : struct list_head *end = &dev->devres_head;
660 : :
661 [ # # ]: 0 : if (!list_empty(&grp->node[1].entry))
662 : : end = grp->node[1].entry.next;
663 : :
664 : 0 : cnt = release_nodes(dev, first, end, flags);
665 : : } else {
666 : 0 : WARN_ON(1);
667 : : spin_unlock_irqrestore(&dev->devres_lock, flags);
668 : : }
669 : :
670 : 0 : return cnt;
671 : : }
672 : : EXPORT_SYMBOL_GPL(devres_release_group);
673 : :
674 : : /*
675 : : * Custom devres actions allow inserting a simple function call
676 : : * into the teadown sequence.
677 : : */
678 : :
679 : : struct action_devres {
680 : : void *data;
681 : : void (*action)(void *);
682 : : };
683 : :
684 : 0 : static int devm_action_match(struct device *dev, void *res, void *p)
685 : : {
686 : : struct action_devres *devres = res;
687 : : struct action_devres *target = p;
688 : :
689 [ # # ][ # # ]: 0 : return devres->action == target->action &&
690 : 0 : devres->data == target->data;
691 : : }
692 : :
693 : 0 : static void devm_action_release(struct device *dev, void *res)
694 : : {
695 : : struct action_devres *devres = res;
696 : :
697 : 0 : devres->action(devres->data);
698 : 0 : }
699 : :
700 : : /**
701 : : * devm_add_action() - add a custom action to list of managed resources
702 : : * @dev: Device that owns the action
703 : : * @action: Function that should be called
704 : : * @data: Pointer to data passed to @action implementation
705 : : *
706 : : * This adds a custom action to the list of managed resources so that
707 : : * it gets executed as part of standard resource unwinding.
708 : : */
709 : 0 : int devm_add_action(struct device *dev, void (*action)(void *), void *data)
710 : : {
711 : : struct action_devres *devres;
712 : :
713 : 0 : devres = devres_alloc(devm_action_release,
714 : : sizeof(struct action_devres), GFP_KERNEL);
715 [ # # ]: 0 : if (!devres)
716 : : return -ENOMEM;
717 : :
718 : 0 : devres->data = data;
719 : 0 : devres->action = action;
720 : :
721 : 0 : devres_add(dev, devres);
722 : 0 : return 0;
723 : : }
724 : : EXPORT_SYMBOL_GPL(devm_add_action);
725 : :
726 : : /**
727 : : * devm_remove_action() - removes previously added custom action
728 : : * @dev: Device that owns the action
729 : : * @action: Function implementing the action
730 : : * @data: Pointer to data passed to @action implementation
731 : : *
732 : : * Removes instance of @action previously added by devm_add_action().
733 : : * Both action and data should match one of the existing entries.
734 : : */
735 : 0 : void devm_remove_action(struct device *dev, void (*action)(void *), void *data)
736 : : {
737 : 0 : struct action_devres devres = {
738 : : .data = data,
739 : : .action = action,
740 : : };
741 : :
742 [ # # ]: 0 : WARN_ON(devres_destroy(dev, devm_action_release, devm_action_match,
743 : : &devres));
744 : :
745 : 0 : }
746 : : EXPORT_SYMBOL_GPL(devm_remove_action);
747 : :
748 : : /*
749 : : * Managed kmalloc/kfree
750 : : */
751 : 0 : static void devm_kmalloc_release(struct device *dev, void *res)
752 : : {
753 : : /* noop */
754 : 0 : }
755 : :
756 : 0 : static int devm_kmalloc_match(struct device *dev, void *res, void *data)
757 : : {
758 : 0 : return res == data;
759 : : }
760 : :
761 : : /**
762 : : * devm_kmalloc - Resource-managed kmalloc
763 : : * @dev: Device to allocate memory for
764 : : * @size: Allocation size
765 : : * @gfp: Allocation gfp flags
766 : : *
767 : : * Managed kmalloc. Memory allocated with this function is
768 : : * automatically freed on driver detach. Like all other devres
769 : : * resources, guaranteed alignment is unsigned long long.
770 : : *
771 : : * RETURNS:
772 : : * Pointer to allocated memory on success, NULL on failure.
773 : : */
774 : 0 : void * devm_kmalloc(struct device *dev, size_t size, gfp_t gfp)
775 : : {
776 : : struct devres *dr;
777 : :
778 : : /* use raw alloc_dr for kmalloc caller tracing */
779 : : dr = alloc_dr(devm_kmalloc_release, size, gfp);
780 [ # # ]: 0 : if (unlikely(!dr))
781 : : return NULL;
782 : :
783 : : /*
784 : : * This is named devm_kzalloc_release for historical reasons
785 : : * The initial implementation did not support kmalloc, only kzalloc
786 : : */
787 : : set_node_dbginfo(&dr->node, "devm_kzalloc_release", size);
788 : 0 : devres_add(dev, dr->data);
789 : 0 : return dr->data;
790 : : }
791 : : EXPORT_SYMBOL_GPL(devm_kmalloc);
792 : :
793 : : /**
794 : : * devm_kfree - Resource-managed kfree
795 : : * @dev: Device this memory belongs to
796 : : * @p: Memory to free
797 : : *
798 : : * Free memory allocated with devm_kmalloc().
799 : : */
800 : 0 : void devm_kfree(struct device *dev, void *p)
801 : : {
802 : : int rc;
803 : :
804 : 0 : rc = devres_destroy(dev, devm_kmalloc_release, devm_kmalloc_match, p);
805 [ # # ]: 0 : WARN_ON(rc);
806 : 0 : }
807 : : EXPORT_SYMBOL_GPL(devm_kfree);
|