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