blob: 32fbf38054261602e0c0cb863e7fc13baf54660a [file] [log] [blame]
Simon Glass42a8db52019-12-29 21:19:22 -07001/* SPDX-License-Identifier: GPL-2.0+ */
2/*
3 * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
4 *
5 * Based on the original work in Linux by
6 * Copyright (c) 2006 SUSE Linux Products GmbH
7 * Copyright (c) 2006 Tejun Heo <teheo@suse.de>
8 * Copyright 2019 Google LLC
9 */
10
11#ifndef _DM_DEVRES_H
12#define _DM_DEVRES_H
13
14/* device resource management */
15typedef void (*dr_release_t)(struct udevice *dev, void *res);
16typedef int (*dr_match_t)(struct udevice *dev, void *res, void *match_data);
17
18#ifdef CONFIG_DEVRES
19
20#ifdef CONFIG_DEBUG_DEVRES
21void *__devres_alloc(dr_release_t release, size_t size, gfp_t gfp,
22 const char *name);
23#define _devres_alloc(release, size, gfp) \
24 __devres_alloc(release, size, gfp, #release)
25#else
26void *_devres_alloc(dr_release_t release, size_t size, gfp_t gfp);
27#endif
28
29/**
30 * devres_alloc() - Allocate device resource data
31 * @release: Release function devres will be associated with
32 * @size: Allocation size
33 * @gfp: Allocation flags
34 *
35 * Allocate devres of @size bytes. The allocated area is associated
36 * with @release. The returned pointer can be passed to
37 * other devres_*() functions.
38 *
39 * RETURNS:
40 * Pointer to allocated devres on success, NULL on failure.
41 */
42#define devres_alloc(release, size, gfp) \
43 _devres_alloc(release, size, (gfp) | __GFP_ZERO)
44
45/**
46 * devres_free() - Free device resource data
47 * @res: Pointer to devres data to free
48 *
49 * Free devres created with devres_alloc().
50 */
51void devres_free(void *res);
52
53/**
54 * devres_add() - Register device resource
55 * @dev: Device to add resource to
56 * @res: Resource to register
57 *
58 * Register devres @res to @dev. @res should have been allocated
59 * using devres_alloc(). On driver detach, the associated release
60 * function will be invoked and devres will be freed automatically.
61 */
62void devres_add(struct udevice *dev, void *res);
63
64/**
65 * devres_find() - Find device resource
66 * @dev: Device to lookup resource from
67 * @release: Look for resources associated with this release function
68 * @match: Match function (optional)
69 * @match_data: Data for the match function
70 *
71 * Find the latest devres of @dev which is associated with @release
72 * and for which @match returns 1. If @match is NULL, it's considered
73 * to match all.
74 *
75 * @return pointer to found devres, NULL if not found.
76 */
77void *devres_find(struct udevice *dev, dr_release_t release,
78 dr_match_t match, void *match_data);
79
80/**
81 * devres_get() - Find devres, if non-existent, add one atomically
82 * @dev: Device to lookup or add devres for
83 * @new_res: Pointer to new initialized devres to add if not found
84 * @match: Match function (optional)
85 * @match_data: Data for the match function
86 *
87 * Find the latest devres of @dev which has the same release function
88 * as @new_res and for which @match return 1. If found, @new_res is
89 * freed; otherwise, @new_res is added atomically.
90 *
91 * @return ointer to found or added devres.
92 */
93void *devres_get(struct udevice *dev, void *new_res,
94 dr_match_t match, void *match_data);
95
96/**
97 * devres_remove() - Find a device resource and remove it
98 * @dev: Device to find resource from
99 * @release: Look for resources associated with this release function
100 * @match: Match function (optional)
101 * @match_data: Data for the match function
102 *
103 * Find the latest devres of @dev associated with @release and for
104 * which @match returns 1. If @match is NULL, it's considered to
105 * match all. If found, the resource is removed atomically and
106 * returned.
107 *
108 * @return ointer to removed devres on success, NULL if not found.
109 */
110void *devres_remove(struct udevice *dev, dr_release_t release,
111 dr_match_t match, void *match_data);
112
113/**
114 * devres_destroy() - Find a device resource and destroy it
115 * @dev: Device to find resource from
116 * @release: Look for resources associated with this release function
117 * @match: Match function (optional)
118 * @match_data: Data for the match function
119 *
120 * Find the latest devres of @dev associated with @release and for
121 * which @match returns 1. If @match is NULL, it's considered to
122 * match all. If found, the resource is removed atomically and freed.
123 *
124 * Note that the release function for the resource will not be called,
125 * only the devres-allocated data will be freed. The caller becomes
126 * responsible for freeing any other data.
127 *
128 * @return 0 if devres is found and freed, -ENOENT if not found.
129 */
130int devres_destroy(struct udevice *dev, dr_release_t release,
131 dr_match_t match, void *match_data);
132
133/**
134 * devres_release() - Find a device resource and destroy it, calling release
135 * @dev: Device to find resource from
136 * @release: Look for resources associated with this release function
137 * @match: Match function (optional)
138 * @match_data: Data for the match function
139 *
140 * Find the latest devres of @dev associated with @release and for
141 * which @match returns 1. If @match is NULL, it's considered to
142 * match all. If found, the resource is removed atomically, the
143 * release function called and the resource freed.
144 *
145 * @return 0 if devres is found and freed, -ENOENT if not found.
146 */
147int devres_release(struct udevice *dev, dr_release_t release,
148 dr_match_t match, void *match_data);
149
150/* managed devm_k.alloc/kfree for device drivers */
151/**
152 * devm_kmalloc() - Resource-managed kmalloc
153 * @dev: Device to allocate memory for
154 * @size: Allocation size
155 * @gfp: Allocation gfp flags
156 *
157 * Managed kmalloc. Memory allocated with this function is
158 * automatically freed on driver detach. Like all other devres
159 * resources, guaranteed alignment is unsigned long long.
160 *
161 * @return pointer to allocated memory on success, NULL on failure.
162 */
163void *devm_kmalloc(struct udevice *dev, size_t size, gfp_t gfp);
164static inline void *devm_kzalloc(struct udevice *dev, size_t size, gfp_t gfp)
165{
166 return devm_kmalloc(dev, size, gfp | __GFP_ZERO);
167}
168
169static inline void *devm_kmalloc_array(struct udevice *dev,
170 size_t n, size_t size, gfp_t flags)
171{
172 if (size != 0 && n > SIZE_MAX / size)
173 return NULL;
174 return devm_kmalloc(dev, n * size, flags);
175}
176
177static inline void *devm_kcalloc(struct udevice *dev,
178 size_t n, size_t size, gfp_t flags)
179{
180 return devm_kmalloc_array(dev, n, size, flags | __GFP_ZERO);
181}
182
183/**
184 * devm_kfree() - Resource-managed kfree
185 * @dev: Device this memory belongs to
186 * @ptr: Memory to free
187 *
188 * Free memory allocated with devm_kmalloc().
189 */
190void devm_kfree(struct udevice *dev, void *ptr);
191
192#else /* ! CONFIG_DEVRES */
193
194static inline void *devres_alloc(dr_release_t release, size_t size, gfp_t gfp)
195{
196 return kzalloc(size, gfp);
197}
198
199static inline void devres_free(void *res)
200{
201 kfree(res);
202}
203
204static inline void devres_add(struct udevice *dev, void *res)
205{
206}
207
208static inline void *devres_find(struct udevice *dev, dr_release_t release,
209 dr_match_t match, void *match_data)
210{
211 return NULL;
212}
213
214static inline void *devres_get(struct udevice *dev, void *new_res,
215 dr_match_t match, void *match_data)
216{
217 return NULL;
218}
219
220static inline void *devres_remove(struct udevice *dev, dr_release_t release,
221 dr_match_t match, void *match_data)
222{
223 return NULL;
224}
225
226static inline int devres_destroy(struct udevice *dev, dr_release_t release,
227 dr_match_t match, void *match_data)
228{
229 return 0;
230}
231
232static inline int devres_release(struct udevice *dev, dr_release_t release,
233 dr_match_t match, void *match_data)
234{
235 return 0;
236}
237
238static inline void *devm_kmalloc(struct udevice *dev, size_t size, gfp_t gfp)
239{
240 return kmalloc(size, gfp);
241}
242
243static inline void *devm_kzalloc(struct udevice *dev, size_t size, gfp_t gfp)
244{
245 return kzalloc(size, gfp);
246}
247
248static inline void *devm_kmalloc_array(struct udevice *dev,
249 size_t n, size_t size, gfp_t flags)
250{
251 /* TODO: add kmalloc_array() to linux/compat.h */
252 if (size != 0 && n > SIZE_MAX / size)
253 return NULL;
254 return kmalloc(n * size, flags);
255}
256
257static inline void *devm_kcalloc(struct udevice *dev,
258 size_t n, size_t size, gfp_t flags)
259{
260 /* TODO: add kcalloc() to linux/compat.h */
261 return kmalloc(n * size, flags | __GFP_ZERO);
262}
263
264static inline void devm_kfree(struct udevice *dev, void *ptr)
265{
266 kfree(ptr);
267}
268#endif /* DEVRES */
269#endif /* _DM_DEVRES_H */