blob: 9c6919605454bf12839be16f93697f493c35dade [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
Simon Glass8d6320c2019-12-29 21:19:26 -070018/**
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 */
24struct devres_stats {
25 int allocs;
26 int total_size;
27};
28
Simon Glass42a8db52019-12-29 21:19:22 -070029#ifdef CONFIG_DEVRES
30
31#ifdef CONFIG_DEBUG_DEVRES
32void *__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
37void *_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 */
62void 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 */
73void 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 */
88void *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 */
104void *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 */
121void *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 */
141int 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 */
158int 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 */
174void *devm_kmalloc(struct udevice *dev, size_t size, gfp_t gfp);
175static 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
180static 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
188static 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 */
201void devm_kfree(struct udevice *dev, void *ptr);
202
Simon Glass8d6320c2019-12-29 21:19:26 -0700203/* Get basic stats on allocations */
204void devres_get_stats(const struct udevice *dev, struct devres_stats *stats);
205
Simon Glass42a8db52019-12-29 21:19:22 -0700206#else /* ! CONFIG_DEVRES */
207
208static inline void *devres_alloc(dr_release_t release, size_t size, gfp_t gfp)
209{
210 return kzalloc(size, gfp);
211}
212
213static inline void devres_free(void *res)
214{
215 kfree(res);
216}
217
218static inline void devres_add(struct udevice *dev, void *res)
219{
220}
221
222static 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
228static inline void *devres_get(struct udevice *dev, void *new_res,
229 dr_match_t match, void *match_data)
230{
231 return NULL;
232}
233
234static 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
240static 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
246static 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
252static inline void *devm_kmalloc(struct udevice *dev, size_t size, gfp_t gfp)
253{
254 return kmalloc(size, gfp);
255}
256
257static inline void *devm_kzalloc(struct udevice *dev, size_t size, gfp_t gfp)
258{
259 return kzalloc(size, gfp);
260}
261
262static 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
271static 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
278static inline void devm_kfree(struct udevice *dev, void *ptr)
279{
280 kfree(ptr);
281}
Simon Glass8d6320c2019-12-29 21:19:26 -0700282
283static inline void devres_get_stats(const struct udevice *dev,
284 struct devres_stats *stats)
285{
286}
287
Simon Glass42a8db52019-12-29 21:19:22 -0700288#endif /* DEVRES */
289#endif /* _DM_DEVRES_H */