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