xref: /linux-6.15/drivers/base/devres.c (revision 96d01ef3)
1989d42e8SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
29ac7849eSTejun Heo /*
39ac7849eSTejun Heo  * drivers/base/devres.c - device resource management
49ac7849eSTejun Heo  *
59ac7849eSTejun Heo  * Copyright (c) 2006  SUSE Linux Products GmbH
69ac7849eSTejun Heo  * Copyright (c) 2006  Tejun Heo <[email protected]>
79ac7849eSTejun Heo  */
89ac7849eSTejun Heo 
99ac7849eSTejun Heo #include <linux/device.h>
109ac7849eSTejun Heo #include <linux/module.h>
115a0e3ad6STejun Heo #include <linux/slab.h>
12ff86aae3SMadalin Bucur #include <linux/percpu.h>
139ac7849eSTejun Heo 
1409d1ea1cSBartosz Golaszewski #include <asm/sections.h>
1509d1ea1cSBartosz Golaszewski 
162a013455SAdrian Bunk #include "base.h"
1709705dcbSAndy Shevchenko #include "trace.h"
182a013455SAdrian Bunk 
199ac7849eSTejun Heo struct devres_node {
209ac7849eSTejun Heo 	struct list_head		entry;
219ac7849eSTejun Heo 	dr_release_t			release;
229ac7849eSTejun Heo 	const char			*name;
239ac7849eSTejun Heo 	size_t				size;
249ac7849eSTejun Heo };
259ac7849eSTejun Heo 
269ac7849eSTejun Heo struct devres {
279ac7849eSTejun Heo 	struct devres_node		node;
28a66d9724SAlexey Brodkin 	/*
29a66d9724SAlexey Brodkin 	 * Some archs want to perform DMA into kmalloc caches
30a66d9724SAlexey Brodkin 	 * and need a guaranteed alignment larger than
31a66d9724SAlexey Brodkin 	 * the alignment of a 64-bit integer.
32be6a5b5eSCatalin Marinas 	 * Thus we use ARCH_DMA_MINALIGN for data[] which will force the same
33be6a5b5eSCatalin Marinas 	 * alignment for struct devres when allocated by kmalloc().
34a66d9724SAlexey Brodkin 	 */
35be6a5b5eSCatalin Marinas 	u8 __aligned(ARCH_DMA_MINALIGN) data[];
369ac7849eSTejun Heo };
379ac7849eSTejun Heo 
389ac7849eSTejun Heo struct devres_group {
399ac7849eSTejun Heo 	struct devres_node		node[2];
409ac7849eSTejun Heo 	void				*id;
419ac7849eSTejun Heo 	int				color;
429ac7849eSTejun Heo 	/* -- 8 pointers */
439ac7849eSTejun Heo };
449ac7849eSTejun Heo 
set_node_dbginfo(struct devres_node * node,const char * name,size_t size)459ac7849eSTejun Heo static void set_node_dbginfo(struct devres_node *node, const char *name,
469ac7849eSTejun Heo 			     size_t size)
479ac7849eSTejun Heo {
489ac7849eSTejun Heo 	node->name = name;
499ac7849eSTejun Heo 	node->size = size;
509ac7849eSTejun Heo }
519ac7849eSTejun Heo 
5209705dcbSAndy Shevchenko #ifdef CONFIG_DEBUG_DEVRES
5309705dcbSAndy Shevchenko static int log_devres = 0;
5409705dcbSAndy Shevchenko module_param_named(log, log_devres, int, S_IRUGO | S_IWUSR);
5509705dcbSAndy Shevchenko 
devres_dbg(struct device * dev,struct devres_node * node,const char * op)5609705dcbSAndy Shevchenko static void devres_dbg(struct device *dev, struct devres_node *node,
579ac7849eSTejun Heo 		       const char *op)
589ac7849eSTejun Heo {
599ac7849eSTejun Heo 	if (unlikely(log_devres))
60318c3e00SAndy Shevchenko 		dev_err(dev, "DEVRES %3s %p %s (%zu bytes)\n",
61318c3e00SAndy Shevchenko 			op, node, node->name, node->size);
629ac7849eSTejun Heo }
639ac7849eSTejun Heo #else /* CONFIG_DEBUG_DEVRES */
6409705dcbSAndy Shevchenko #define devres_dbg(dev, node, op)	do {} while (0)
659ac7849eSTejun Heo #endif /* CONFIG_DEBUG_DEVRES */
669ac7849eSTejun Heo 
devres_log(struct device * dev,struct devres_node * node,const char * op)6709705dcbSAndy Shevchenko static void devres_log(struct device *dev, struct devres_node *node,
6809705dcbSAndy Shevchenko 		       const char *op)
6909705dcbSAndy Shevchenko {
7009705dcbSAndy Shevchenko 	trace_devres_log(dev, op, node, node->name, node->size);
7109705dcbSAndy Shevchenko 	devres_dbg(dev, node, op);
7209705dcbSAndy Shevchenko }
7309705dcbSAndy Shevchenko 
749ac7849eSTejun Heo /*
759ac7849eSTejun Heo  * Release functions for devres group.  These callbacks are used only
769ac7849eSTejun Heo  * for identification.
779ac7849eSTejun Heo  */
group_open_release(struct device * dev,void * res)789ac7849eSTejun Heo static void group_open_release(struct device *dev, void *res)
799ac7849eSTejun Heo {
809ac7849eSTejun Heo 	/* noop */
819ac7849eSTejun Heo }
829ac7849eSTejun Heo 
group_close_release(struct device * dev,void * res)839ac7849eSTejun Heo static void group_close_release(struct device *dev, void *res)
849ac7849eSTejun Heo {
859ac7849eSTejun Heo 	/* noop */
869ac7849eSTejun Heo }
879ac7849eSTejun Heo 
node_to_group(struct devres_node * node)889ac7849eSTejun Heo static struct devres_group *node_to_group(struct devres_node *node)
899ac7849eSTejun Heo {
909ac7849eSTejun Heo 	if (node->release == &group_open_release)
919ac7849eSTejun Heo 		return container_of(node, struct devres_group, node[0]);
929ac7849eSTejun Heo 	if (node->release == &group_close_release)
939ac7849eSTejun Heo 		return container_of(node, struct devres_group, node[1]);
949ac7849eSTejun Heo 	return NULL;
959ac7849eSTejun Heo }
969ac7849eSTejun Heo 
check_dr_size(size_t size,size_t * tot_size)97dc2a633cSBartosz Golaszewski static bool check_dr_size(size_t size, size_t *tot_size)
98dc2a633cSBartosz Golaszewski {
99dc2a633cSBartosz Golaszewski 	/* We must catch any near-SIZE_MAX cases that could overflow. */
100dc2a633cSBartosz Golaszewski 	if (unlikely(check_add_overflow(sizeof(struct devres),
101dc2a633cSBartosz Golaszewski 					size, tot_size)))
102dc2a633cSBartosz Golaszewski 		return false;
103dc2a633cSBartosz Golaszewski 
1046fcd7e70SKees Cook 	/* Actually allocate the full kmalloc bucket size. */
1056fcd7e70SKees Cook 	*tot_size = kmalloc_size_roundup(*tot_size);
1066fcd7e70SKees Cook 
107dc2a633cSBartosz Golaszewski 	return true;
108dc2a633cSBartosz Golaszewski }
109dc2a633cSBartosz Golaszewski 
alloc_dr(dr_release_t release,size_t size,gfp_t gfp,int nid)1109ac7849eSTejun Heo static __always_inline struct devres *alloc_dr(dr_release_t release,
1117c683941SDan Williams 					       size_t size, gfp_t gfp, int nid)
1129ac7849eSTejun Heo {
1132509b561SKees Cook 	size_t tot_size;
1149ac7849eSTejun Heo 	struct devres *dr;
1159ac7849eSTejun Heo 
116dc2a633cSBartosz Golaszewski 	if (!check_dr_size(size, &tot_size))
1172509b561SKees Cook 		return NULL;
1182509b561SKees Cook 
1197c683941SDan Williams 	dr = kmalloc_node_track_caller(tot_size, gfp, nid);
1209ac7849eSTejun Heo 	if (unlikely(!dr))
1219ac7849eSTejun Heo 		return NULL;
1229ac7849eSTejun Heo 
12361742a7cSChristophe JAILLET 	/* No need to clear memory twice */
12461742a7cSChristophe JAILLET 	if (!(gfp & __GFP_ZERO))
12564c862a8SJoe Perches 		memset(dr, 0, offsetof(struct devres, data));
12664c862a8SJoe Perches 
1279ac7849eSTejun Heo 	INIT_LIST_HEAD(&dr->node.entry);
1289ac7849eSTejun Heo 	dr->node.release = release;
1299ac7849eSTejun Heo 	return dr;
1309ac7849eSTejun Heo }
1319ac7849eSTejun Heo 
add_dr(struct device * dev,struct devres_node * node)1329ac7849eSTejun Heo static void add_dr(struct device *dev, struct devres_node *node)
1339ac7849eSTejun Heo {
1349ac7849eSTejun Heo 	devres_log(dev, node, "ADD");
1359ac7849eSTejun Heo 	BUG_ON(!list_empty(&node->entry));
1369ac7849eSTejun Heo 	list_add_tail(&node->entry, &dev->devres_head);
1379ac7849eSTejun Heo }
1389ac7849eSTejun Heo 
replace_dr(struct device * dev,struct devres_node * old,struct devres_node * new)139f8248572SBartosz Golaszewski static void replace_dr(struct device *dev,
140f8248572SBartosz Golaszewski 		       struct devres_node *old, struct devres_node *new)
141f8248572SBartosz Golaszewski {
142f8248572SBartosz Golaszewski 	devres_log(dev, old, "REPLACE");
143f8248572SBartosz Golaszewski 	BUG_ON(!list_empty(&new->entry));
144f8248572SBartosz Golaszewski 	list_replace(&old->entry, &new->entry);
145f8248572SBartosz Golaszewski }
146f8248572SBartosz Golaszewski 
14709705dcbSAndy Shevchenko /**
14809705dcbSAndy Shevchenko  * __devres_alloc_node - Allocate device resource data
14909705dcbSAndy Shevchenko  * @release: Release function devres will be associated with
15009705dcbSAndy Shevchenko  * @size: Allocation size
15109705dcbSAndy Shevchenko  * @gfp: Allocation flags
15209705dcbSAndy Shevchenko  * @nid: NUMA node
15309705dcbSAndy Shevchenko  * @name: Name of the resource
15409705dcbSAndy Shevchenko  *
15509705dcbSAndy Shevchenko  * Allocate devres of @size bytes.  The allocated area is zeroed, then
15609705dcbSAndy Shevchenko  * associated with @release.  The returned pointer can be passed to
15709705dcbSAndy Shevchenko  * other devres_*() functions.
15809705dcbSAndy Shevchenko  *
15909705dcbSAndy Shevchenko  * RETURNS:
16009705dcbSAndy Shevchenko  * Pointer to allocated devres on success, NULL on failure.
16109705dcbSAndy Shevchenko  */
__devres_alloc_node(dr_release_t release,size_t size,gfp_t gfp,int nid,const char * name)1627c683941SDan Williams void *__devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, int nid,
1639ac7849eSTejun Heo 			  const char *name)
1649ac7849eSTejun Heo {
1659ac7849eSTejun Heo 	struct devres *dr;
1669ac7849eSTejun Heo 
1677c683941SDan Williams 	dr = alloc_dr(release, size, gfp | __GFP_ZERO, nid);
1689ac7849eSTejun Heo 	if (unlikely(!dr))
1699ac7849eSTejun Heo 		return NULL;
1709ac7849eSTejun Heo 	set_node_dbginfo(&dr->node, name, size);
1719ac7849eSTejun Heo 	return dr->data;
1729ac7849eSTejun Heo }
1737c683941SDan Williams EXPORT_SYMBOL_GPL(__devres_alloc_node);
1749ac7849eSTejun Heo 
1759ac7849eSTejun Heo /**
176bddb1b90SMing Lei  * devres_for_each_res - Resource iterator
177bddb1b90SMing Lei  * @dev: Device to iterate resource from
178bddb1b90SMing Lei  * @release: Look for resources associated with this release function
179bddb1b90SMing Lei  * @match: Match function (optional)
180bddb1b90SMing Lei  * @match_data: Data for the match function
181bddb1b90SMing Lei  * @fn: Function to be called for each matched resource.
182bddb1b90SMing Lei  * @data: Data for @fn, the 3rd parameter of @fn
183bddb1b90SMing Lei  *
184bddb1b90SMing Lei  * Call @fn for each devres of @dev which is associated with @release
185bddb1b90SMing Lei  * and for which @match returns 1.
186bddb1b90SMing Lei  *
187bddb1b90SMing Lei  * RETURNS:
188bddb1b90SMing Lei  * 	void
189bddb1b90SMing Lei  */
devres_for_each_res(struct device * dev,dr_release_t release,dr_match_t match,void * match_data,void (* fn)(struct device *,void *,void *),void * data)190bddb1b90SMing Lei void devres_for_each_res(struct device *dev, dr_release_t release,
191bddb1b90SMing Lei 			dr_match_t match, void *match_data,
192bddb1b90SMing Lei 			void (*fn)(struct device *, void *, void *),
193bddb1b90SMing Lei 			void *data)
194bddb1b90SMing Lei {
195bddb1b90SMing Lei 	struct devres_node *node;
196bddb1b90SMing Lei 	struct devres_node *tmp;
197bddb1b90SMing Lei 	unsigned long flags;
198bddb1b90SMing Lei 
199bddb1b90SMing Lei 	if (!fn)
200bddb1b90SMing Lei 		return;
201bddb1b90SMing Lei 
202bddb1b90SMing Lei 	spin_lock_irqsave(&dev->devres_lock, flags);
203bddb1b90SMing Lei 	list_for_each_entry_safe_reverse(node, tmp,
204bddb1b90SMing Lei 			&dev->devres_head, entry) {
205bddb1b90SMing Lei 		struct devres *dr = container_of(node, struct devres, node);
206bddb1b90SMing Lei 
207bddb1b90SMing Lei 		if (node->release != release)
208bddb1b90SMing Lei 			continue;
209bddb1b90SMing Lei 		if (match && !match(dev, dr->data, match_data))
210bddb1b90SMing Lei 			continue;
211bddb1b90SMing Lei 		fn(dev, dr->data, data);
212bddb1b90SMing Lei 	}
213bddb1b90SMing Lei 	spin_unlock_irqrestore(&dev->devres_lock, flags);
214bddb1b90SMing Lei }
215bddb1b90SMing Lei EXPORT_SYMBOL_GPL(devres_for_each_res);
216bddb1b90SMing Lei 
217bddb1b90SMing Lei /**
2189ac7849eSTejun Heo  * devres_free - Free device resource data
2199ac7849eSTejun Heo  * @res: Pointer to devres data to free
2209ac7849eSTejun Heo  *
2219ac7849eSTejun Heo  * Free devres created with devres_alloc().
2229ac7849eSTejun Heo  */
devres_free(void * res)2239ac7849eSTejun Heo void devres_free(void *res)
2249ac7849eSTejun Heo {
2259ac7849eSTejun Heo 	if (res) {
2269ac7849eSTejun Heo 		struct devres *dr = container_of(res, struct devres, data);
2279ac7849eSTejun Heo 
2289ac7849eSTejun Heo 		BUG_ON(!list_empty(&dr->node.entry));
2299ac7849eSTejun Heo 		kfree(dr);
2309ac7849eSTejun Heo 	}
2319ac7849eSTejun Heo }
2329ac7849eSTejun Heo EXPORT_SYMBOL_GPL(devres_free);
2339ac7849eSTejun Heo 
2349ac7849eSTejun Heo /**
2359ac7849eSTejun Heo  * devres_add - Register device resource
2369ac7849eSTejun Heo  * @dev: Device to add resource to
2379ac7849eSTejun Heo  * @res: Resource to register
2389ac7849eSTejun Heo  *
2399ac7849eSTejun Heo  * Register devres @res to @dev.  @res should have been allocated
2409ac7849eSTejun Heo  * using devres_alloc().  On driver detach, the associated release
2419ac7849eSTejun Heo  * function will be invoked and devres will be freed automatically.
2429ac7849eSTejun Heo  */
devres_add(struct device * dev,void * res)2439ac7849eSTejun Heo void devres_add(struct device *dev, void *res)
2449ac7849eSTejun Heo {
2459ac7849eSTejun Heo 	struct devres *dr = container_of(res, struct devres, data);
2469ac7849eSTejun Heo 	unsigned long flags;
2479ac7849eSTejun Heo 
2489ac7849eSTejun Heo 	spin_lock_irqsave(&dev->devres_lock, flags);
2499ac7849eSTejun Heo 	add_dr(dev, &dr->node);
2509ac7849eSTejun Heo 	spin_unlock_irqrestore(&dev->devres_lock, flags);
2519ac7849eSTejun Heo }
2529ac7849eSTejun Heo EXPORT_SYMBOL_GPL(devres_add);
2539ac7849eSTejun Heo 
find_dr(struct device * dev,dr_release_t release,dr_match_t match,void * match_data)2549ac7849eSTejun Heo static struct devres *find_dr(struct device *dev, dr_release_t release,
2559ac7849eSTejun Heo 			      dr_match_t match, void *match_data)
2569ac7849eSTejun Heo {
2579ac7849eSTejun Heo 	struct devres_node *node;
2589ac7849eSTejun Heo 
2599ac7849eSTejun Heo 	list_for_each_entry_reverse(node, &dev->devres_head, entry) {
2609ac7849eSTejun Heo 		struct devres *dr = container_of(node, struct devres, node);
2619ac7849eSTejun Heo 
2629ac7849eSTejun Heo 		if (node->release != release)
2639ac7849eSTejun Heo 			continue;
2649ac7849eSTejun Heo 		if (match && !match(dev, dr->data, match_data))
2659ac7849eSTejun Heo 			continue;
2669ac7849eSTejun Heo 		return dr;
2679ac7849eSTejun Heo 	}
2689ac7849eSTejun Heo 
2699ac7849eSTejun Heo 	return NULL;
2709ac7849eSTejun Heo }
2719ac7849eSTejun Heo 
2729ac7849eSTejun Heo /**
2739ac7849eSTejun Heo  * devres_find - Find device resource
2749ac7849eSTejun Heo  * @dev: Device to lookup resource from
2759ac7849eSTejun Heo  * @release: Look for resources associated with this release function
2769ac7849eSTejun Heo  * @match: Match function (optional)
2779ac7849eSTejun Heo  * @match_data: Data for the match function
2789ac7849eSTejun Heo  *
2799ac7849eSTejun Heo  * Find the latest devres of @dev which is associated with @release
2809ac7849eSTejun Heo  * and for which @match returns 1.  If @match is NULL, it's considered
2819ac7849eSTejun Heo  * to match all.
2829ac7849eSTejun Heo  *
2839ac7849eSTejun Heo  * RETURNS:
2849ac7849eSTejun Heo  * Pointer to found devres, NULL if not found.
2859ac7849eSTejun Heo  */
devres_find(struct device * dev,dr_release_t release,dr_match_t match,void * match_data)2869ac7849eSTejun Heo void *devres_find(struct device *dev, dr_release_t release,
2879ac7849eSTejun Heo 		  dr_match_t match, void *match_data)
2889ac7849eSTejun Heo {
2899ac7849eSTejun Heo 	struct devres *dr;
2909ac7849eSTejun Heo 	unsigned long flags;
2919ac7849eSTejun Heo 
2929ac7849eSTejun Heo 	spin_lock_irqsave(&dev->devres_lock, flags);
2939ac7849eSTejun Heo 	dr = find_dr(dev, release, match, match_data);
2949ac7849eSTejun Heo 	spin_unlock_irqrestore(&dev->devres_lock, flags);
2959ac7849eSTejun Heo 
2969ac7849eSTejun Heo 	if (dr)
2979ac7849eSTejun Heo 		return dr->data;
2989ac7849eSTejun Heo 	return NULL;
2999ac7849eSTejun Heo }
3009ac7849eSTejun Heo EXPORT_SYMBOL_GPL(devres_find);
3019ac7849eSTejun Heo 
3029ac7849eSTejun Heo /**
3039ac7849eSTejun Heo  * devres_get - Find devres, if non-existent, add one atomically
3049ac7849eSTejun Heo  * @dev: Device to lookup or add devres for
3059ac7849eSTejun Heo  * @new_res: Pointer to new initialized devres to add if not found
3069ac7849eSTejun Heo  * @match: Match function (optional)
3079ac7849eSTejun Heo  * @match_data: Data for the match function
3089ac7849eSTejun Heo  *
3099ac7849eSTejun Heo  * Find the latest devres of @dev which has the same release function
3109ac7849eSTejun Heo  * as @new_res and for which @match return 1.  If found, @new_res is
3119ac7849eSTejun Heo  * freed; otherwise, @new_res is added atomically.
3129ac7849eSTejun Heo  *
3139ac7849eSTejun Heo  * RETURNS:
3149ac7849eSTejun Heo  * Pointer to found or added devres.
3159ac7849eSTejun Heo  */
devres_get(struct device * dev,void * new_res,dr_match_t match,void * match_data)3169ac7849eSTejun Heo void *devres_get(struct device *dev, void *new_res,
3179ac7849eSTejun Heo 		 dr_match_t match, void *match_data)
3189ac7849eSTejun Heo {
3199ac7849eSTejun Heo 	struct devres *new_dr = container_of(new_res, struct devres, data);
3209ac7849eSTejun Heo 	struct devres *dr;
3219ac7849eSTejun Heo 	unsigned long flags;
3229ac7849eSTejun Heo 
3239ac7849eSTejun Heo 	spin_lock_irqsave(&dev->devres_lock, flags);
3249ac7849eSTejun Heo 	dr = find_dr(dev, new_dr->node.release, match, match_data);
3259ac7849eSTejun Heo 	if (!dr) {
3269ac7849eSTejun Heo 		add_dr(dev, &new_dr->node);
3279ac7849eSTejun Heo 		dr = new_dr;
32864526370SMasahiro Yamada 		new_res = NULL;
3299ac7849eSTejun Heo 	}
3309ac7849eSTejun Heo 	spin_unlock_irqrestore(&dev->devres_lock, flags);
33164526370SMasahiro Yamada 	devres_free(new_res);
3329ac7849eSTejun Heo 
3339ac7849eSTejun Heo 	return dr->data;
3349ac7849eSTejun Heo }
3359ac7849eSTejun Heo EXPORT_SYMBOL_GPL(devres_get);
3369ac7849eSTejun Heo 
3379ac7849eSTejun Heo /**
3389ac7849eSTejun Heo  * devres_remove - Find a device resource and remove it
3399ac7849eSTejun Heo  * @dev: Device to find resource from
3409ac7849eSTejun Heo  * @release: Look for resources associated with this release function
3419ac7849eSTejun Heo  * @match: Match function (optional)
3429ac7849eSTejun Heo  * @match_data: Data for the match function
3439ac7849eSTejun Heo  *
3449ac7849eSTejun Heo  * Find the latest devres of @dev associated with @release and for
3459ac7849eSTejun Heo  * which @match returns 1.  If @match is NULL, it's considered to
3469ac7849eSTejun Heo  * match all.  If found, the resource is removed atomically and
3479ac7849eSTejun Heo  * returned.
3489ac7849eSTejun Heo  *
3499ac7849eSTejun Heo  * RETURNS:
3509ac7849eSTejun Heo  * Pointer to removed devres on success, NULL if not found.
3519ac7849eSTejun Heo  */
devres_remove(struct device * dev,dr_release_t release,dr_match_t match,void * match_data)3529ac7849eSTejun Heo void *devres_remove(struct device *dev, dr_release_t release,
3539ac7849eSTejun Heo 		    dr_match_t match, void *match_data)
3549ac7849eSTejun Heo {
3559ac7849eSTejun Heo 	struct devres *dr;
3569ac7849eSTejun Heo 	unsigned long flags;
3579ac7849eSTejun Heo 
3589ac7849eSTejun Heo 	spin_lock_irqsave(&dev->devres_lock, flags);
3599ac7849eSTejun Heo 	dr = find_dr(dev, release, match, match_data);
3609ac7849eSTejun Heo 	if (dr) {
3619ac7849eSTejun Heo 		list_del_init(&dr->node.entry);
3629ac7849eSTejun Heo 		devres_log(dev, &dr->node, "REM");
3639ac7849eSTejun Heo 	}
3649ac7849eSTejun Heo 	spin_unlock_irqrestore(&dev->devres_lock, flags);
3659ac7849eSTejun Heo 
3669ac7849eSTejun Heo 	if (dr)
3679ac7849eSTejun Heo 		return dr->data;
3689ac7849eSTejun Heo 	return NULL;
3699ac7849eSTejun Heo }
3709ac7849eSTejun Heo EXPORT_SYMBOL_GPL(devres_remove);
3719ac7849eSTejun Heo 
3729ac7849eSTejun Heo /**
3739ac7849eSTejun Heo  * devres_destroy - Find a device resource and destroy it
3749ac7849eSTejun Heo  * @dev: Device to find resource from
3759ac7849eSTejun Heo  * @release: Look for resources associated with this release function
3769ac7849eSTejun Heo  * @match: Match function (optional)
3779ac7849eSTejun Heo  * @match_data: Data for the match function
3789ac7849eSTejun Heo  *
3799ac7849eSTejun Heo  * Find the latest devres of @dev associated with @release and for
3809ac7849eSTejun Heo  * which @match returns 1.  If @match is NULL, it's considered to
3819ac7849eSTejun Heo  * match all.  If found, the resource is removed atomically and freed.
3829ac7849eSTejun Heo  *
383698cd2ddSMark Brown  * Note that the release function for the resource will not be called,
384698cd2ddSMark Brown  * only the devres-allocated data will be freed.  The caller becomes
385698cd2ddSMark Brown  * responsible for freeing any other data.
386698cd2ddSMark Brown  *
3879ac7849eSTejun Heo  * RETURNS:
3889ac7849eSTejun Heo  * 0 if devres is found and freed, -ENOENT if not found.
3899ac7849eSTejun Heo  */
devres_destroy(struct device * dev,dr_release_t release,dr_match_t match,void * match_data)3909ac7849eSTejun Heo int devres_destroy(struct device *dev, dr_release_t release,
3919ac7849eSTejun Heo 		   dr_match_t match, void *match_data)
3929ac7849eSTejun Heo {
3939ac7849eSTejun Heo 	void *res;
3949ac7849eSTejun Heo 
3959ac7849eSTejun Heo 	res = devres_remove(dev, release, match, match_data);
3969ac7849eSTejun Heo 	if (unlikely(!res))
3979ac7849eSTejun Heo 		return -ENOENT;
3989ac7849eSTejun Heo 
3999ac7849eSTejun Heo 	devres_free(res);
4009ac7849eSTejun Heo 	return 0;
4019ac7849eSTejun Heo }
4029ac7849eSTejun Heo EXPORT_SYMBOL_GPL(devres_destroy);
4039ac7849eSTejun Heo 
404d926d0e4SMark Brown 
405d926d0e4SMark Brown /**
406d926d0e4SMark Brown  * devres_release - Find a device resource and destroy it, calling release
407d926d0e4SMark Brown  * @dev: Device to find resource from
408d926d0e4SMark Brown  * @release: Look for resources associated with this release function
409d926d0e4SMark Brown  * @match: Match function (optional)
410d926d0e4SMark Brown  * @match_data: Data for the match function
411d926d0e4SMark Brown  *
412d926d0e4SMark Brown  * Find the latest devres of @dev associated with @release and for
413d926d0e4SMark Brown  * which @match returns 1.  If @match is NULL, it's considered to
414d926d0e4SMark Brown  * match all.  If found, the resource is removed atomically, the
415d926d0e4SMark Brown  * release function called and the resource freed.
416d926d0e4SMark Brown  *
417d926d0e4SMark Brown  * RETURNS:
418d926d0e4SMark Brown  * 0 if devres is found and freed, -ENOENT if not found.
419d926d0e4SMark Brown  */
devres_release(struct device * dev,dr_release_t release,dr_match_t match,void * match_data)420d926d0e4SMark Brown int devres_release(struct device *dev, dr_release_t release,
421d926d0e4SMark Brown 		   dr_match_t match, void *match_data)
422d926d0e4SMark Brown {
423d926d0e4SMark Brown 	void *res;
424d926d0e4SMark Brown 
425d926d0e4SMark Brown 	res = devres_remove(dev, release, match, match_data);
426d926d0e4SMark Brown 	if (unlikely(!res))
427d926d0e4SMark Brown 		return -ENOENT;
428d926d0e4SMark Brown 
429d926d0e4SMark Brown 	(*release)(dev, res);
430d926d0e4SMark Brown 	devres_free(res);
431d926d0e4SMark Brown 	return 0;
432d926d0e4SMark Brown }
433d926d0e4SMark Brown EXPORT_SYMBOL_GPL(devres_release);
434d926d0e4SMark Brown 
remove_nodes(struct device * dev,struct list_head * first,struct list_head * end,struct list_head * todo)4359ac7849eSTejun Heo static int remove_nodes(struct device *dev,
4369ac7849eSTejun Heo 			struct list_head *first, struct list_head *end,
4379ac7849eSTejun Heo 			struct list_head *todo)
4389ac7849eSTejun Heo {
439c3cd0ff7SAndy Shevchenko 	struct devres_node *node, *n;
4409ac7849eSTejun Heo 	int cnt = 0, nr_groups = 0;
4419ac7849eSTejun Heo 
4429ac7849eSTejun Heo 	/* First pass - move normal devres entries to @todo and clear
4439ac7849eSTejun Heo 	 * devres_group colors.
4449ac7849eSTejun Heo 	 */
445c3cd0ff7SAndy Shevchenko 	node = list_entry(first, struct devres_node, entry);
446c3cd0ff7SAndy Shevchenko 	list_for_each_entry_safe_from(node, n, end, entry) {
4479ac7849eSTejun Heo 		struct devres_group *grp;
4489ac7849eSTejun Heo 
4499ac7849eSTejun Heo 		grp = node_to_group(node);
4509ac7849eSTejun Heo 		if (grp) {
4519ac7849eSTejun Heo 			/* clear color of group markers in the first pass */
4529ac7849eSTejun Heo 			grp->color = 0;
4539ac7849eSTejun Heo 			nr_groups++;
4549ac7849eSTejun Heo 		} else {
4559ac7849eSTejun Heo 			/* regular devres entry */
4569ac7849eSTejun Heo 			if (&node->entry == first)
4579ac7849eSTejun Heo 				first = first->next;
4589ac7849eSTejun Heo 			list_move_tail(&node->entry, todo);
4599ac7849eSTejun Heo 			cnt++;
4609ac7849eSTejun Heo 		}
4619ac7849eSTejun Heo 	}
4629ac7849eSTejun Heo 
4639ac7849eSTejun Heo 	if (!nr_groups)
4649ac7849eSTejun Heo 		return cnt;
4659ac7849eSTejun Heo 
4669ac7849eSTejun Heo 	/* Second pass - Scan groups and color them.  A group gets
4679ac7849eSTejun Heo 	 * color value of two iff the group is wholly contained in
468c3cd0ff7SAndy Shevchenko 	 * [current node, end). That is, for a closed group, both opening
469c3cd0ff7SAndy Shevchenko 	 * and closing markers should be in the range, while just the
4709ac7849eSTejun Heo 	 * opening marker is enough for an open group.
4719ac7849eSTejun Heo 	 */
472c3cd0ff7SAndy Shevchenko 	node = list_entry(first, struct devres_node, entry);
473c3cd0ff7SAndy Shevchenko 	list_for_each_entry_safe_from(node, n, end, entry) {
4749ac7849eSTejun Heo 		struct devres_group *grp;
4759ac7849eSTejun Heo 
4769ac7849eSTejun Heo 		grp = node_to_group(node);
4779ac7849eSTejun Heo 		BUG_ON(!grp || list_empty(&grp->node[0].entry));
4789ac7849eSTejun Heo 
4799ac7849eSTejun Heo 		grp->color++;
4809ac7849eSTejun Heo 		if (list_empty(&grp->node[1].entry))
4819ac7849eSTejun Heo 			grp->color++;
4829ac7849eSTejun Heo 
4839ac7849eSTejun Heo 		BUG_ON(grp->color <= 0 || grp->color > 2);
4849ac7849eSTejun Heo 		if (grp->color == 2) {
485c3cd0ff7SAndy Shevchenko 			/* No need to update current node or end. The removed
4869ac7849eSTejun Heo 			 * nodes are always before both.
4879ac7849eSTejun Heo 			 */
4889ac7849eSTejun Heo 			list_move_tail(&grp->node[0].entry, todo);
4899ac7849eSTejun Heo 			list_del_init(&grp->node[1].entry);
4909ac7849eSTejun Heo 		}
4919ac7849eSTejun Heo 	}
4929ac7849eSTejun Heo 
4939ac7849eSTejun Heo 	return cnt;
4949ac7849eSTejun Heo }
4959ac7849eSTejun Heo 
release_nodes(struct device * dev,struct list_head * todo)496bbc8f3e7SAndy Shevchenko static void release_nodes(struct device *dev, struct list_head *todo)
4979ac7849eSTejun Heo {
4989ac7849eSTejun Heo 	struct devres *dr, *tmp;
4999ac7849eSTejun Heo 
5009ac7849eSTejun Heo 	/* Release.  Note that both devres and devres_group are
5019ac7849eSTejun Heo 	 * handled as devres in the following loop.  This is safe.
5029ac7849eSTejun Heo 	 */
503bbc8f3e7SAndy Shevchenko 	list_for_each_entry_safe_reverse(dr, tmp, todo, node.entry) {
5049ac7849eSTejun Heo 		devres_log(dev, &dr->node, "REL");
5059ac7849eSTejun Heo 		dr->node.release(dev, dr->data);
5069ac7849eSTejun Heo 		kfree(dr);
5079ac7849eSTejun Heo 	}
5089ac7849eSTejun Heo }
5099ac7849eSTejun Heo 
5109ac7849eSTejun Heo /**
511d3e6975eSRandy Dunlap  * devres_release_all - Release all managed resources
5129ac7849eSTejun Heo  * @dev: Device to release resources for
5139ac7849eSTejun Heo  *
5149ac7849eSTejun Heo  * Release all resources associated with @dev.  This function is
5159ac7849eSTejun Heo  * called on driver detach.
5169ac7849eSTejun Heo  */
devres_release_all(struct device * dev)5179ac7849eSTejun Heo int devres_release_all(struct device *dev)
5189ac7849eSTejun Heo {
5199ac7849eSTejun Heo 	unsigned long flags;
520bbc8f3e7SAndy Shevchenko 	LIST_HEAD(todo);
521bbc8f3e7SAndy Shevchenko 	int cnt;
5229ac7849eSTejun Heo 
523eb8d3c60SBenjamin Herrenschmidt 	/* Looks like an uninitialized device structure */
524eb8d3c60SBenjamin Herrenschmidt 	if (WARN_ON(dev->devres_head.next == NULL))
525eb8d3c60SBenjamin Herrenschmidt 		return -ENODEV;
526bbc8f3e7SAndy Shevchenko 
527a7f1d03bSAndy Shevchenko 	/* Nothing to release if list is empty */
528a7f1d03bSAndy Shevchenko 	if (list_empty(&dev->devres_head))
529a7f1d03bSAndy Shevchenko 		return 0;
530a7f1d03bSAndy Shevchenko 
5319ac7849eSTejun Heo 	spin_lock_irqsave(&dev->devres_lock, flags);
532bbc8f3e7SAndy Shevchenko 	cnt = remove_nodes(dev, dev->devres_head.next, &dev->devres_head, &todo);
533bbc8f3e7SAndy Shevchenko 	spin_unlock_irqrestore(&dev->devres_lock, flags);
534bbc8f3e7SAndy Shevchenko 
535bbc8f3e7SAndy Shevchenko 	release_nodes(dev, &todo);
536bbc8f3e7SAndy Shevchenko 	return cnt;
5379ac7849eSTejun Heo }
5389ac7849eSTejun Heo 
5399ac7849eSTejun Heo /**
5409ac7849eSTejun Heo  * devres_open_group - Open a new devres group
5419ac7849eSTejun Heo  * @dev: Device to open devres group for
5429ac7849eSTejun Heo  * @id: Separator ID
5439ac7849eSTejun Heo  * @gfp: Allocation flags
5449ac7849eSTejun Heo  *
5459ac7849eSTejun Heo  * Open a new devres group for @dev with @id.  For @id, using a
5469ac7849eSTejun Heo  * pointer to an object which won't be used for another group is
5479ac7849eSTejun Heo  * recommended.  If @id is NULL, address-wise unique ID is created.
5489ac7849eSTejun Heo  *
5499ac7849eSTejun Heo  * RETURNS:
5509ac7849eSTejun Heo  * ID of the new group, NULL on failure.
5519ac7849eSTejun Heo  */
devres_open_group(struct device * dev,void * id,gfp_t gfp)5529ac7849eSTejun Heo void *devres_open_group(struct device *dev, void *id, gfp_t gfp)
5539ac7849eSTejun Heo {
5549ac7849eSTejun Heo 	struct devres_group *grp;
5559ac7849eSTejun Heo 	unsigned long flags;
5569ac7849eSTejun Heo 
5579ac7849eSTejun Heo 	grp = kmalloc(sizeof(*grp), gfp);
5589ac7849eSTejun Heo 	if (unlikely(!grp))
5599ac7849eSTejun Heo 		return NULL;
5609ac7849eSTejun Heo 
5619ac7849eSTejun Heo 	grp->node[0].release = &group_open_release;
5629ac7849eSTejun Heo 	grp->node[1].release = &group_close_release;
5639ac7849eSTejun Heo 	INIT_LIST_HEAD(&grp->node[0].entry);
5649ac7849eSTejun Heo 	INIT_LIST_HEAD(&grp->node[1].entry);
5659ac7849eSTejun Heo 	set_node_dbginfo(&grp->node[0], "grp<", 0);
5669ac7849eSTejun Heo 	set_node_dbginfo(&grp->node[1], "grp>", 0);
5679ac7849eSTejun Heo 	grp->id = grp;
5689ac7849eSTejun Heo 	if (id)
5699ac7849eSTejun Heo 		grp->id = id;
57056a20ad3SZijun Hu 	grp->color = 0;
5719ac7849eSTejun Heo 
5729ac7849eSTejun Heo 	spin_lock_irqsave(&dev->devres_lock, flags);
5739ac7849eSTejun Heo 	add_dr(dev, &grp->node[0]);
5749ac7849eSTejun Heo 	spin_unlock_irqrestore(&dev->devres_lock, flags);
5759ac7849eSTejun Heo 	return grp->id;
5769ac7849eSTejun Heo }
5779ac7849eSTejun Heo EXPORT_SYMBOL_GPL(devres_open_group);
5789ac7849eSTejun Heo 
579*96d01ef3SLucas De Marchi /*
580*96d01ef3SLucas De Marchi  * Find devres group with ID @id.  If @id is NULL, look for the latest open
581*96d01ef3SLucas De Marchi  * group.
582*96d01ef3SLucas De Marchi  */
find_group(struct device * dev,void * id)5839ac7849eSTejun Heo static struct devres_group *find_group(struct device *dev, void *id)
5849ac7849eSTejun Heo {
5859ac7849eSTejun Heo 	struct devres_node *node;
5869ac7849eSTejun Heo 
5879ac7849eSTejun Heo 	list_for_each_entry_reverse(node, &dev->devres_head, entry) {
5889ac7849eSTejun Heo 		struct devres_group *grp;
5899ac7849eSTejun Heo 
5909ac7849eSTejun Heo 		if (node->release != &group_open_release)
5919ac7849eSTejun Heo 			continue;
5929ac7849eSTejun Heo 
5939ac7849eSTejun Heo 		grp = container_of(node, struct devres_group, node[0]);
5949ac7849eSTejun Heo 
5959ac7849eSTejun Heo 		if (id) {
5969ac7849eSTejun Heo 			if (grp->id == id)
5979ac7849eSTejun Heo 				return grp;
5989ac7849eSTejun Heo 		} else if (list_empty(&grp->node[1].entry))
5999ac7849eSTejun Heo 			return grp;
6009ac7849eSTejun Heo 	}
6019ac7849eSTejun Heo 
6029ac7849eSTejun Heo 	return NULL;
6039ac7849eSTejun Heo }
6049ac7849eSTejun Heo 
6059ac7849eSTejun Heo /**
6069ac7849eSTejun Heo  * devres_close_group - Close a devres group
6079ac7849eSTejun Heo  * @dev: Device to close devres group for
6089ac7849eSTejun Heo  * @id: ID of target group, can be NULL
6099ac7849eSTejun Heo  *
6109ac7849eSTejun Heo  * Close the group identified by @id.  If @id is NULL, the latest open
6119ac7849eSTejun Heo  * group is selected.
6129ac7849eSTejun Heo  */
devres_close_group(struct device * dev,void * id)6139ac7849eSTejun Heo void devres_close_group(struct device *dev, void *id)
6149ac7849eSTejun Heo {
6159ac7849eSTejun Heo 	struct devres_group *grp;
6169ac7849eSTejun Heo 	unsigned long flags;
6179ac7849eSTejun Heo 
6189ac7849eSTejun Heo 	spin_lock_irqsave(&dev->devres_lock, flags);
6199ac7849eSTejun Heo 
6209ac7849eSTejun Heo 	grp = find_group(dev, id);
6219ac7849eSTejun Heo 	if (grp)
6229ac7849eSTejun Heo 		add_dr(dev, &grp->node[1]);
6239ac7849eSTejun Heo 	else
6249ac7849eSTejun Heo 		WARN_ON(1);
6259ac7849eSTejun Heo 
6269ac7849eSTejun Heo 	spin_unlock_irqrestore(&dev->devres_lock, flags);
6279ac7849eSTejun Heo }
6289ac7849eSTejun Heo EXPORT_SYMBOL_GPL(devres_close_group);
6299ac7849eSTejun Heo 
6309ac7849eSTejun Heo /**
6319ac7849eSTejun Heo  * devres_remove_group - Remove a devres group
6329ac7849eSTejun Heo  * @dev: Device to remove group for
6339ac7849eSTejun Heo  * @id: ID of target group, can be NULL
6349ac7849eSTejun Heo  *
6359ac7849eSTejun Heo  * Remove the group identified by @id.  If @id is NULL, the latest
6369ac7849eSTejun Heo  * open group is selected.  Note that removing a group doesn't affect
6379ac7849eSTejun Heo  * any other resources.
6389ac7849eSTejun Heo  */
devres_remove_group(struct device * dev,void * id)6399ac7849eSTejun Heo void devres_remove_group(struct device *dev, void *id)
6409ac7849eSTejun Heo {
6419ac7849eSTejun Heo 	struct devres_group *grp;
6429ac7849eSTejun Heo 	unsigned long flags;
6439ac7849eSTejun Heo 
6449ac7849eSTejun Heo 	spin_lock_irqsave(&dev->devres_lock, flags);
6459ac7849eSTejun Heo 
6469ac7849eSTejun Heo 	grp = find_group(dev, id);
6479ac7849eSTejun Heo 	if (grp) {
6489ac7849eSTejun Heo 		list_del_init(&grp->node[0].entry);
6499ac7849eSTejun Heo 		list_del_init(&grp->node[1].entry);
6509ac7849eSTejun Heo 		devres_log(dev, &grp->node[0], "REM");
6519ac7849eSTejun Heo 	} else
6529ac7849eSTejun Heo 		WARN_ON(1);
6539ac7849eSTejun Heo 
6549ac7849eSTejun Heo 	spin_unlock_irqrestore(&dev->devres_lock, flags);
6559ac7849eSTejun Heo 
6569ac7849eSTejun Heo 	kfree(grp);
6579ac7849eSTejun Heo }
6589ac7849eSTejun Heo EXPORT_SYMBOL_GPL(devres_remove_group);
6599ac7849eSTejun Heo 
6609ac7849eSTejun Heo /**
6619ac7849eSTejun Heo  * devres_release_group - Release resources in a devres group
6629ac7849eSTejun Heo  * @dev: Device to release group for
6639ac7849eSTejun Heo  * @id: ID of target group, can be NULL
6649ac7849eSTejun Heo  *
6659ac7849eSTejun Heo  * Release all resources in the group identified by @id.  If @id is
6669ac7849eSTejun Heo  * NULL, the latest open group is selected.  The selected group and
6679ac7849eSTejun Heo  * groups properly nested inside the selected group are removed.
6689ac7849eSTejun Heo  *
6699ac7849eSTejun Heo  * RETURNS:
6709ac7849eSTejun Heo  * The number of released non-group resources.
6719ac7849eSTejun Heo  */
devres_release_group(struct device * dev,void * id)6729ac7849eSTejun Heo int devres_release_group(struct device *dev, void *id)
6739ac7849eSTejun Heo {
6749ac7849eSTejun Heo 	struct devres_group *grp;
6759ac7849eSTejun Heo 	unsigned long flags;
676bbc8f3e7SAndy Shevchenko 	LIST_HEAD(todo);
6779ac7849eSTejun Heo 	int cnt = 0;
6789ac7849eSTejun Heo 
6799ac7849eSTejun Heo 	spin_lock_irqsave(&dev->devres_lock, flags);
6809ac7849eSTejun Heo 
6819ac7849eSTejun Heo 	grp = find_group(dev, id);
6829ac7849eSTejun Heo 	if (grp) {
6839ac7849eSTejun Heo 		struct list_head *first = &grp->node[0].entry;
6849ac7849eSTejun Heo 		struct list_head *end = &dev->devres_head;
6859ac7849eSTejun Heo 
6869ac7849eSTejun Heo 		if (!list_empty(&grp->node[1].entry))
6879ac7849eSTejun Heo 			end = grp->node[1].entry.next;
6889ac7849eSTejun Heo 
689bbc8f3e7SAndy Shevchenko 		cnt = remove_nodes(dev, first, end, &todo);
690bbc8f3e7SAndy Shevchenko 		spin_unlock_irqrestore(&dev->devres_lock, flags);
691bbc8f3e7SAndy Shevchenko 
692bbc8f3e7SAndy Shevchenko 		release_nodes(dev, &todo);
6938e1ddfadSLucas De Marchi 	} else if (list_empty(&dev->devres_head)) {
6948e1ddfadSLucas De Marchi 		/*
6958e1ddfadSLucas De Marchi 		 * dev is probably dying via devres_release_all(): groups
6968e1ddfadSLucas De Marchi 		 * have already been removed and are on the process of
6978e1ddfadSLucas De Marchi 		 * being released - don't touch and don't warn.
6988e1ddfadSLucas De Marchi 		 */
6998e1ddfadSLucas De Marchi 		spin_unlock_irqrestore(&dev->devres_lock, flags);
7009ac7849eSTejun Heo 	} else {
7019ac7849eSTejun Heo 		WARN_ON(1);
7029ac7849eSTejun Heo 		spin_unlock_irqrestore(&dev->devres_lock, flags);
7039ac7849eSTejun Heo 	}
7049ac7849eSTejun Heo 
7059ac7849eSTejun Heo 	return cnt;
7069ac7849eSTejun Heo }
7079ac7849eSTejun Heo EXPORT_SYMBOL_GPL(devres_release_group);
7089ac7849eSTejun Heo 
7099ac7849eSTejun Heo /*
710d6b0c580SDmitry Torokhov  * Custom devres actions allow inserting a simple function call
711451fd6eeSJulia Lawall  * into the teardown sequence.
712d6b0c580SDmitry Torokhov  */
713d6b0c580SDmitry Torokhov 
714d6b0c580SDmitry Torokhov struct action_devres {
715d6b0c580SDmitry Torokhov 	void *data;
716d6b0c580SDmitry Torokhov 	void (*action)(void *);
717d6b0c580SDmitry Torokhov };
718d6b0c580SDmitry Torokhov 
devm_action_match(struct device * dev,void * res,void * p)719d6b0c580SDmitry Torokhov static int devm_action_match(struct device *dev, void *res, void *p)
720d6b0c580SDmitry Torokhov {
721d6b0c580SDmitry Torokhov 	struct action_devres *devres = res;
722d6b0c580SDmitry Torokhov 	struct action_devres *target = p;
723d6b0c580SDmitry Torokhov 
724d6b0c580SDmitry Torokhov 	return devres->action == target->action &&
725d6b0c580SDmitry Torokhov 	       devres->data == target->data;
726d6b0c580SDmitry Torokhov }
727d6b0c580SDmitry Torokhov 
devm_action_release(struct device * dev,void * res)728d6b0c580SDmitry Torokhov static void devm_action_release(struct device *dev, void *res)
729d6b0c580SDmitry Torokhov {
730d6b0c580SDmitry Torokhov 	struct action_devres *devres = res;
731d6b0c580SDmitry Torokhov 
732d6b0c580SDmitry Torokhov 	devres->action(devres->data);
733d6b0c580SDmitry Torokhov }
734d6b0c580SDmitry Torokhov 
735d6b0c580SDmitry Torokhov /**
7360433686cSAndy Shevchenko  * __devm_add_action() - add a custom action to list of managed resources
737d6b0c580SDmitry Torokhov  * @dev: Device that owns the action
738d6b0c580SDmitry Torokhov  * @action: Function that should be called
739d6b0c580SDmitry Torokhov  * @data: Pointer to data passed to @action implementation
7400433686cSAndy Shevchenko  * @name: Name of the resource (for debugging purposes)
741d6b0c580SDmitry Torokhov  *
742d6b0c580SDmitry Torokhov  * This adds a custom action to the list of managed resources so that
743d6b0c580SDmitry Torokhov  * it gets executed as part of standard resource unwinding.
744d6b0c580SDmitry Torokhov  */
__devm_add_action(struct device * dev,void (* action)(void *),void * data,const char * name)7450433686cSAndy Shevchenko int __devm_add_action(struct device *dev, void (*action)(void *), void *data, const char *name)
746d6b0c580SDmitry Torokhov {
747d6b0c580SDmitry Torokhov 	struct action_devres *devres;
748d6b0c580SDmitry Torokhov 
7490433686cSAndy Shevchenko 	devres = __devres_alloc_node(devm_action_release, sizeof(struct action_devres),
7500433686cSAndy Shevchenko 				     GFP_KERNEL, NUMA_NO_NODE, name);
751d6b0c580SDmitry Torokhov 	if (!devres)
752d6b0c580SDmitry Torokhov 		return -ENOMEM;
753d6b0c580SDmitry Torokhov 
754d6b0c580SDmitry Torokhov 	devres->data = data;
755d6b0c580SDmitry Torokhov 	devres->action = action;
756d6b0c580SDmitry Torokhov 
757d6b0c580SDmitry Torokhov 	devres_add(dev, devres);
758d6b0c580SDmitry Torokhov 	return 0;
759d6b0c580SDmitry Torokhov }
7600433686cSAndy Shevchenko EXPORT_SYMBOL_GPL(__devm_add_action);
761d6b0c580SDmitry Torokhov 
762d6b0c580SDmitry Torokhov /**
763d6b0c580SDmitry Torokhov  * devm_remove_action_nowarn() - removes previously added custom action
764d6b0c580SDmitry Torokhov  * @dev: Device that owns the action
765d6b0c580SDmitry Torokhov  * @action: Function implementing the action
766d6b0c580SDmitry Torokhov  * @data: Pointer to data passed to @action implementation
767d6b0c580SDmitry Torokhov  *
768d6b0c580SDmitry Torokhov  * Removes instance of @action previously added by devm_add_action().
769d6b0c580SDmitry Torokhov  * Both action and data should match one of the existing entries.
770d6b0c580SDmitry Torokhov  *
771d6b0c580SDmitry Torokhov  * In contrast to devm_remove_action(), this function does not WARN() if no
772d6b0c580SDmitry Torokhov  * entry could have been found.
773d6b0c580SDmitry Torokhov  *
774d6b0c580SDmitry Torokhov  * This should only be used if the action is contained in an object with
775d6b0c580SDmitry Torokhov  * independent lifetime management, e.g. the Devres rust abstraction.
776d6b0c580SDmitry Torokhov  *
777d6b0c580SDmitry Torokhov  * Causing the warning from regular driver code most likely indicates an abuse
778d6b0c580SDmitry Torokhov  * of the devres API.
779d6b0c580SDmitry Torokhov  *
780d6b0c580SDmitry Torokhov  * Returns: 0 on success, -ENOENT if no entry could have been found.
781d6b0c580SDmitry Torokhov  */
devm_remove_action_nowarn(struct device * dev,void (* action)(void *),void * data)782d6b0c580SDmitry Torokhov int devm_remove_action_nowarn(struct device *dev,
7832374b682SDan Williams 			      void (*action)(void *),
7842374b682SDan Williams 			      void *data)
7852374b682SDan Williams {
7862374b682SDan Williams 	struct action_devres devres = {
7872374b682SDan Williams 		.data = data,
7882374b682SDan Williams 		.action = action,
7892374b682SDan Williams 	};
7902374b682SDan Williams 
7912374b682SDan Williams 	return devres_destroy(dev, devm_action_release, devm_action_match,
7922374b682SDan Williams 			      &devres);
7932374b682SDan Williams }
7942374b682SDan Williams EXPORT_SYMBOL_GPL(devm_remove_action_nowarn);
7952374b682SDan Williams 
7962374b682SDan Williams /**
7972374b682SDan Williams  * devm_release_action() - release previously added custom action
7982374b682SDan Williams  * @dev: Device that owns the action
7992374b682SDan Williams  * @action: Function implementing the action
8002374b682SDan Williams  * @data: Pointer to data passed to @action implementation
8012374b682SDan Williams  *
8022374b682SDan Williams  * Releases and removes instance of @action previously added by
8032374b682SDan Williams  * devm_add_action().  Both action and data should match one of the
8042374b682SDan Williams  * existing entries.
8052374b682SDan Williams  */
devm_release_action(struct device * dev,void (* action)(void *),void * data)806d6b0c580SDmitry Torokhov void devm_release_action(struct device *dev, void (*action)(void *), void *data)
80764c862a8SJoe Perches {
8089ac7849eSTejun Heo 	struct action_devres devres = {
80964c862a8SJoe Perches 		.data = data,
8109ac7849eSTejun Heo 		.action = action,
8119ac7849eSTejun Heo 	};
8129ac7849eSTejun Heo 
8139ac7849eSTejun Heo 	WARN_ON(devres_release(dev, devm_action_release, devm_action_match,
81464c862a8SJoe Perches 			       &devres));
8159ac7849eSTejun Heo 
8169ac7849eSTejun Heo }
8179ac7849eSTejun Heo EXPORT_SYMBOL_GPL(devm_release_action);
8189ac7849eSTejun Heo 
8199ac7849eSTejun Heo /*
82064c862a8SJoe Perches  * Managed kmalloc/kfree
8219ac7849eSTejun Heo  */
devm_kmalloc_release(struct device * dev,void * res)8229ac7849eSTejun Heo static void devm_kmalloc_release(struct device *dev, void *res)
8239ac7849eSTejun Heo {
8249ac7849eSTejun Heo 	/* noop */
82564c862a8SJoe Perches }
8269ac7849eSTejun Heo 
devm_kmalloc_match(struct device * dev,void * res,void * data)8279ac7849eSTejun Heo static int devm_kmalloc_match(struct device *dev, void *res, void *data)
8289ac7849eSTejun Heo {
8299ac7849eSTejun Heo 	return res == data;
8309ac7849eSTejun Heo }
8319ac7849eSTejun Heo 
83264c862a8SJoe Perches /**
8339ac7849eSTejun Heo  * devm_kmalloc - Resource-managed kmalloc
8349ac7849eSTejun Heo  * @dev: Device to allocate memory for
8359ac7849eSTejun Heo  * @size: Allocation size
836cad064f1SBartosz Golaszewski  * @gfp: Allocation gfp flags
837cad064f1SBartosz Golaszewski  *
838cad064f1SBartosz Golaszewski  * Managed kmalloc.  Memory allocated with this function is
8399ac7849eSTejun Heo  * automatically freed on driver detach.  Like all other devres
8407c683941SDan Williams  * resources, guaranteed alignment is unsigned long long.
8419ac7849eSTejun Heo  *
8429ac7849eSTejun Heo  * RETURNS:
8439ac7849eSTejun Heo  * Pointer to allocated memory on success, NULL on failure.
84464c862a8SJoe Perches  */
devm_kmalloc(struct device * dev,size_t size,gfp_t gfp)84564c862a8SJoe Perches void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp)
84664c862a8SJoe Perches {
84764c862a8SJoe Perches 	struct devres *dr;
8489ac7849eSTejun Heo 
8499ac7849eSTejun Heo 	if (unlikely(!size))
8509ac7849eSTejun Heo 		return ZERO_SIZE_PTR;
8519ac7849eSTejun Heo 
85264c862a8SJoe Perches 	/* use raw alloc_dr for kmalloc caller tracing */
8539ac7849eSTejun Heo 	dr = alloc_dr(devm_kmalloc_release, size, gfp, dev_to_node(dev));
8549ac7849eSTejun Heo 	if (unlikely(!dr))
855f8248572SBartosz Golaszewski 		return NULL;
856f8248572SBartosz Golaszewski 
857f8248572SBartosz Golaszewski 	/*
858f8248572SBartosz Golaszewski 	 * This is named devm_kzalloc_release for historical reasons
859f8248572SBartosz Golaszewski 	 * The initial implementation did not support kmalloc, only kzalloc
860f8248572SBartosz Golaszewski 	 */
861f8248572SBartosz Golaszewski 	set_node_dbginfo(&dr->node, "devm_kzalloc_release", size);
862f8248572SBartosz Golaszewski 	devres_add(dev, dr->data);
863f8248572SBartosz Golaszewski 	return dr->data;
864f8248572SBartosz Golaszewski }
865f8248572SBartosz Golaszewski EXPORT_SYMBOL_GPL(devm_kmalloc);
866f8248572SBartosz Golaszewski 
867f8248572SBartosz Golaszewski /**
868f8248572SBartosz Golaszewski  * devm_krealloc - Resource-managed krealloc()
869f8248572SBartosz Golaszewski  * @dev: Device to re-allocate memory for
870f8248572SBartosz Golaszewski  * @ptr: Pointer to the memory chunk to re-allocate
871f8248572SBartosz Golaszewski  * @new_size: New allocation size
872f8248572SBartosz Golaszewski  * @gfp: Allocation gfp flags
873f8248572SBartosz Golaszewski  *
874f8248572SBartosz Golaszewski  * Managed krealloc(). Resizes the memory chunk allocated with devm_kmalloc().
875f8248572SBartosz Golaszewski  * Behaves similarly to regular krealloc(): if @ptr is NULL or ZERO_SIZE_PTR,
876f8248572SBartosz Golaszewski  * it's the equivalent of devm_kmalloc(). If new_size is zero, it frees the
877f8248572SBartosz Golaszewski  * previously allocated memory and returns ZERO_SIZE_PTR. This function doesn't
878f8248572SBartosz Golaszewski  * change the order in which the release callback for the re-alloc'ed devres
879f8248572SBartosz Golaszewski  * will be called (except when falling back to devm_kmalloc() or when freeing
880f8248572SBartosz Golaszewski  * resources when new_size is zero). The contents of the memory are preserved
881f8248572SBartosz Golaszewski  * up to the lesser of new and old sizes.
882f8248572SBartosz Golaszewski  */
devm_krealloc(struct device * dev,void * ptr,size_t new_size,gfp_t gfp)883f8248572SBartosz Golaszewski void *devm_krealloc(struct device *dev, void *ptr, size_t new_size, gfp_t gfp)
884f8248572SBartosz Golaszewski {
885f8248572SBartosz Golaszewski 	size_t total_new_size, total_old_size;
886f8248572SBartosz Golaszewski 	struct devres *old_dr, *new_dr;
887f8248572SBartosz Golaszewski 	unsigned long flags;
888f8248572SBartosz Golaszewski 
889f8248572SBartosz Golaszewski 	if (unlikely(!new_size)) {
890f8248572SBartosz Golaszewski 		devm_kfree(dev, ptr);
891f8248572SBartosz Golaszewski 		return ZERO_SIZE_PTR;
892f8248572SBartosz Golaszewski 	}
893f8248572SBartosz Golaszewski 
894f8248572SBartosz Golaszewski 	if (unlikely(ZERO_OR_NULL_PTR(ptr)))
895f8248572SBartosz Golaszewski 		return devm_kmalloc(dev, new_size, gfp);
896f8248572SBartosz Golaszewski 
897f8248572SBartosz Golaszewski 	if (WARN_ON(is_kernel_rodata((unsigned long)ptr)))
898f8248572SBartosz Golaszewski 		/*
899f8248572SBartosz Golaszewski 		 * We cannot reliably realloc a const string returned by
900f8248572SBartosz Golaszewski 		 * devm_kstrdup_const().
901f8248572SBartosz Golaszewski 		 */
902f8248572SBartosz Golaszewski 		return NULL;
903f8248572SBartosz Golaszewski 
904f8248572SBartosz Golaszewski 	if (!check_dr_size(new_size, &total_new_size))
905f8248572SBartosz Golaszewski 		return NULL;
906f8248572SBartosz Golaszewski 
907f8248572SBartosz Golaszewski 	total_old_size = ksize(container_of(ptr, struct devres, data));
908f8248572SBartosz Golaszewski 	if (total_old_size == 0) {
909f8248572SBartosz Golaszewski 		WARN(1, "Pointer doesn't point to dynamically allocated memory.");
910c884e324SZijun Hu 		return NULL;
911c884e324SZijun Hu 	}
912c884e324SZijun Hu 
913f8248572SBartosz Golaszewski 	/*
914f8248572SBartosz Golaszewski 	 * If new size is smaller or equal to the actual number of bytes
915c884e324SZijun Hu 	 * allocated previously - just return the same pointer.
916f8248572SBartosz Golaszewski 	 */
917f8248572SBartosz Golaszewski 	if (total_new_size <= total_old_size)
918f8248572SBartosz Golaszewski 		return ptr;
919f8248572SBartosz Golaszewski 
920f8248572SBartosz Golaszewski 	/*
921f8248572SBartosz Golaszewski 	 * Otherwise: allocate new, larger chunk. We need to allocate before
922f8248572SBartosz Golaszewski 	 * taking the lock as most probably the caller uses GFP_KERNEL.
923f8248572SBartosz Golaszewski 	 * alloc_dr() will call check_dr_size() to reserve extra memory
924f8248572SBartosz Golaszewski 	 * for struct devres automatically, so size @new_size user request
925f8248572SBartosz Golaszewski 	 * is delivered to it directly as devm_kmalloc() does.
926f8248572SBartosz Golaszewski 	 */
927f8248572SBartosz Golaszewski 	new_dr = alloc_dr(devm_kmalloc_release,
928f8248572SBartosz Golaszewski 			  new_size, gfp, dev_to_node(dev));
929f8248572SBartosz Golaszewski 	if (!new_dr)
930f8248572SBartosz Golaszewski 		return NULL;
931f8248572SBartosz Golaszewski 
932f8248572SBartosz Golaszewski 	/*
933f8248572SBartosz Golaszewski 	 * The spinlock protects the linked list against concurrent
934f8248572SBartosz Golaszewski 	 * modifications but not the resource itself.
935f8248572SBartosz Golaszewski 	 */
936f8248572SBartosz Golaszewski 	spin_lock_irqsave(&dev->devres_lock, flags);
937f8248572SBartosz Golaszewski 
938f8248572SBartosz Golaszewski 	old_dr = find_dr(dev, devm_kmalloc_release, devm_kmalloc_match, ptr);
939451fd6eeSJulia Lawall 	if (!old_dr) {
940f8248572SBartosz Golaszewski 		spin_unlock_irqrestore(&dev->devres_lock, flags);
941f8248572SBartosz Golaszewski 		kfree(new_dr);
942f8248572SBartosz Golaszewski 		WARN(1, "Memory chunk not managed or managed by a different device.");
943f8248572SBartosz Golaszewski 		return NULL;
944f8248572SBartosz Golaszewski 	}
945f8248572SBartosz Golaszewski 
946f8248572SBartosz Golaszewski 	replace_dr(dev, &old_dr->node, &new_dr->node);
947f8248572SBartosz Golaszewski 
948f8248572SBartosz Golaszewski 	spin_unlock_irqrestore(&dev->devres_lock, flags);
949f8248572SBartosz Golaszewski 
950f8248572SBartosz Golaszewski 	/*
951f8248572SBartosz Golaszewski 	 * We can copy the memory contents after releasing the lock as we're
952f8248572SBartosz Golaszewski 	 * no longer modifying the list links.
953f8248572SBartosz Golaszewski 	 */
954f8248572SBartosz Golaszewski 	memcpy(new_dr->data, old_dr->data,
955e31108caSManish Badarkhe 	       total_old_size - offsetof(struct devres, data));
956e31108caSManish Badarkhe 	/*
957e31108caSManish Badarkhe 	 * Same for releasing the old devres - it's now been removed from the
958e31108caSManish Badarkhe 	 * list. This is also the reason why we must not use devm_kfree() - the
959e31108caSManish Badarkhe 	 * links are no longer valid.
960e31108caSManish Badarkhe 	 */
961e31108caSManish Badarkhe 	kfree(old_dr);
962e31108caSManish Badarkhe 
963e31108caSManish Badarkhe 	return new_dr->data;
964e31108caSManish Badarkhe }
965e31108caSManish Badarkhe EXPORT_SYMBOL_GPL(devm_krealloc);
966e31108caSManish Badarkhe 
967e31108caSManish Badarkhe /**
968e31108caSManish Badarkhe  * devm_kstrdup - Allocate resource managed space and
969e31108caSManish Badarkhe  *                copy an existing string into that.
970e31108caSManish Badarkhe  * @dev: Device to allocate memory for
971e31108caSManish Badarkhe  * @s: the string to duplicate
972e31108caSManish Badarkhe  * @gfp: the GFP mask used in the devm_kmalloc() call when
973e31108caSManish Badarkhe  *       allocating memory
974e31108caSManish Badarkhe  * RETURNS:
975e31108caSManish Badarkhe  * Pointer to allocated string on success, NULL on failure.
976e31108caSManish Badarkhe  */
devm_kstrdup(struct device * dev,const char * s,gfp_t gfp)977e31108caSManish Badarkhe char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp)
978e31108caSManish Badarkhe {
979e31108caSManish Badarkhe 	size_t size;
980e31108caSManish Badarkhe 	char *buf;
98109d1ea1cSBartosz Golaszewski 
98209d1ea1cSBartosz Golaszewski 	if (!s)
98309d1ea1cSBartosz Golaszewski 		return NULL;
98409d1ea1cSBartosz Golaszewski 
98509d1ea1cSBartosz Golaszewski 	size = strlen(s) + 1;
98609d1ea1cSBartosz Golaszewski 	buf = devm_kmalloc(dev, size, gfp);
98709d1ea1cSBartosz Golaszewski 	if (buf)
98809d1ea1cSBartosz Golaszewski 		memcpy(buf, s, size);
98909d1ea1cSBartosz Golaszewski 	return buf;
99009d1ea1cSBartosz Golaszewski }
99109d1ea1cSBartosz Golaszewski EXPORT_SYMBOL_GPL(devm_kstrdup);
99209d1ea1cSBartosz Golaszewski 
99309d1ea1cSBartosz Golaszewski /**
99409d1ea1cSBartosz Golaszewski  * devm_kstrdup_const - resource managed conditional string duplication
99509d1ea1cSBartosz Golaszewski  * @dev: device for which to duplicate the string
99609d1ea1cSBartosz Golaszewski  * @s: the string to duplicate
99709d1ea1cSBartosz Golaszewski  * @gfp: the GFP mask used in the kmalloc() call when allocating memory
99809d1ea1cSBartosz Golaszewski  *
99909d1ea1cSBartosz Golaszewski  * Strings allocated by devm_kstrdup_const will be automatically freed when
100009d1ea1cSBartosz Golaszewski  * the associated device is detached.
100109d1ea1cSBartosz Golaszewski  *
100209d1ea1cSBartosz Golaszewski  * RETURNS:
1003bef59c50SGeert Uytterhoeven  * Source string if it is in .rodata section otherwise it falls back to
1004bef59c50SGeert Uytterhoeven  * devm_kstrdup.
100575f2a4eaSHimangi Saraogi  */
devm_kstrdup_const(struct device * dev,const char * s,gfp_t gfp)100675f2a4eaSHimangi Saraogi const char *devm_kstrdup_const(struct device *dev, const char *s, gfp_t gfp)
100775f2a4eaSHimangi Saraogi {
1008bef59c50SGeert Uytterhoeven 	if (is_kernel_rodata((unsigned long)s))
1009bef59c50SGeert Uytterhoeven 		return s;
101075f2a4eaSHimangi Saraogi 
101175f2a4eaSHimangi Saraogi 	return devm_kstrdup(dev, s, gfp);
101275f2a4eaSHimangi Saraogi }
101375f2a4eaSHimangi Saraogi EXPORT_SYMBOL_GPL(devm_kstrdup_const);
101475f2a4eaSHimangi Saraogi 
101575f2a4eaSHimangi Saraogi /**
101675f2a4eaSHimangi Saraogi  * devm_kvasprintf - Allocate resource managed space and format a string
101775f2a4eaSHimangi Saraogi  *		     into that.
101875f2a4eaSHimangi Saraogi  * @dev: Device to allocate memory for
101975f2a4eaSHimangi Saraogi  * @gfp: the GFP mask used in the devm_kmalloc() call when
102075f2a4eaSHimangi Saraogi  *       allocating memory
102175f2a4eaSHimangi Saraogi  * @fmt: The printf()-style format string
102275f2a4eaSHimangi Saraogi  * @ap: Arguments for the format string
102375f2a4eaSHimangi Saraogi  * RETURNS:
102475f2a4eaSHimangi Saraogi  * Pointer to allocated string on success, NULL on failure.
102575f2a4eaSHimangi Saraogi  */
devm_kvasprintf(struct device * dev,gfp_t gfp,const char * fmt,va_list ap)102675f2a4eaSHimangi Saraogi char *devm_kvasprintf(struct device *dev, gfp_t gfp, const char *fmt,
102775f2a4eaSHimangi Saraogi 		      va_list ap)
102875f2a4eaSHimangi Saraogi {
102975f2a4eaSHimangi Saraogi 	unsigned int len;
103075f2a4eaSHimangi Saraogi 	char *p;
103175f2a4eaSHimangi Saraogi 	va_list aq;
103275f2a4eaSHimangi Saraogi 
103375f2a4eaSHimangi Saraogi 	va_copy(aq, ap);
103475f2a4eaSHimangi Saraogi 	len = vsnprintf(NULL, 0, fmt, aq);
1035bef59c50SGeert Uytterhoeven 	va_end(aq);
1036bef59c50SGeert Uytterhoeven 
103775f2a4eaSHimangi Saraogi 	p = devm_kmalloc(dev, len+1, gfp);
103875f2a4eaSHimangi Saraogi 	if (!p)
103975f2a4eaSHimangi Saraogi 		return NULL;
1040bef59c50SGeert Uytterhoeven 
1041bef59c50SGeert Uytterhoeven 	vsnprintf(p, len+1, fmt, ap);
104275f2a4eaSHimangi Saraogi 
104375f2a4eaSHimangi Saraogi 	return p;
104475f2a4eaSHimangi Saraogi }
104575f2a4eaSHimangi Saraogi EXPORT_SYMBOL(devm_kvasprintf);
104675f2a4eaSHimangi Saraogi 
104775f2a4eaSHimangi Saraogi /**
104875f2a4eaSHimangi Saraogi  * devm_kasprintf - Allocate resource managed space and format a string
104975f2a4eaSHimangi Saraogi  *		    into that.
105075f2a4eaSHimangi Saraogi  * @dev: Device to allocate memory for
105175f2a4eaSHimangi Saraogi  * @gfp: the GFP mask used in the devm_kmalloc() call when
105275f2a4eaSHimangi Saraogi  *       allocating memory
105375f2a4eaSHimangi Saraogi  * @fmt: The printf()-style format string
105475f2a4eaSHimangi Saraogi  * @...: Arguments for the format string
105575f2a4eaSHimangi Saraogi  * RETURNS:
105675f2a4eaSHimangi Saraogi  * Pointer to allocated string on success, NULL on failure.
105775f2a4eaSHimangi Saraogi  */
devm_kasprintf(struct device * dev,gfp_t gfp,const char * fmt,...)105875f2a4eaSHimangi Saraogi char *devm_kasprintf(struct device *dev, gfp_t gfp, const char *fmt, ...)
1059d3e6975eSRandy Dunlap {
10609ac7849eSTejun Heo 	va_list ap;
10619ac7849eSTejun Heo 	char *p;
10629ac7849eSTejun Heo 
106364c862a8SJoe Perches 	va_start(ap, fmt);
10649ac7849eSTejun Heo 	p = devm_kvasprintf(dev, gfp, fmt, ap);
10650571967dSBartosz Golaszewski 	va_end(ap);
10669ac7849eSTejun Heo 
10679ac7849eSTejun Heo 	return p;
10689ac7849eSTejun Heo }
106909d1ea1cSBartosz Golaszewski EXPORT_SYMBOL_GPL(devm_kasprintf);
1070cad064f1SBartosz Golaszewski 
1071cad064f1SBartosz Golaszewski /**
107209d1ea1cSBartosz Golaszewski  * devm_kfree - Resource-managed kfree
1073cad064f1SBartosz Golaszewski  * @dev: Device this memory belongs to
107409d1ea1cSBartosz Golaszewski  * @p: Memory to free
107509d1ea1cSBartosz Golaszewski  *
10760571967dSBartosz Golaszewski  * Free memory allocated with devm_kmalloc().
10770571967dSBartosz Golaszewski  */
devm_kfree(struct device * dev,const void * p)10789ac7849eSTejun Heo void devm_kfree(struct device *dev, const void *p)
10799ac7849eSTejun Heo {
10809ac7849eSTejun Heo 	int rc;
10813046365bSSrinivas Pandruvada 
10823046365bSSrinivas Pandruvada 	/*
10833046365bSSrinivas Pandruvada 	 * Special cases: pointer to a string in .rodata returned by
10843046365bSSrinivas Pandruvada 	 * devm_kstrdup_const() or NULL/ZERO ptr.
10853046365bSSrinivas Pandruvada 	 */
10863046365bSSrinivas Pandruvada 	if (unlikely(is_kernel_rodata((unsigned long)p) || ZERO_OR_NULL_PTR(p)))
10873046365bSSrinivas Pandruvada 		return;
10883046365bSSrinivas Pandruvada 
10893046365bSSrinivas Pandruvada 	rc = devres_destroy(dev, devm_kmalloc_release,
10903046365bSSrinivas Pandruvada 			    devm_kmalloc_match, (void *)p);
10913046365bSSrinivas Pandruvada 	WARN_ON(rc);
10923046365bSSrinivas Pandruvada }
10933046365bSSrinivas Pandruvada EXPORT_SYMBOL_GPL(devm_kfree);
10943046365bSSrinivas Pandruvada 
10953046365bSSrinivas Pandruvada /**
10963046365bSSrinivas Pandruvada  * devm_kmemdup - Resource-managed kmemdup
10973046365bSSrinivas Pandruvada  * @dev: Device this memory belongs to
10983046365bSSrinivas Pandruvada  * @src: Memory region to duplicate
10993046365bSSrinivas Pandruvada  * @len: Memory region length
11003046365bSSrinivas Pandruvada  * @gfp: GFP mask to use
11013046365bSSrinivas Pandruvada  *
110243339bedSEli Billauer  * Duplicate region of a memory using resource managed kmalloc
110343339bedSEli Billauer  */
devm_kmemdup(struct device * dev,const void * src,size_t len,gfp_t gfp)110443339bedSEli Billauer void *devm_kmemdup(struct device *dev, const void *src, size_t len, gfp_t gfp)
110543339bedSEli Billauer {
110643339bedSEli Billauer 	void *p;
110743339bedSEli Billauer 
110843339bedSEli Billauer 	p = devm_kmalloc(dev, len, gfp);
110943339bedSEli Billauer 	if (p)
111043339bedSEli Billauer 		memcpy(p, src, len);
111143339bedSEli Billauer 
111243339bedSEli Billauer 	return p;
111343339bedSEli Billauer }
111443339bedSEli Billauer EXPORT_SYMBOL_GPL(devm_kmemdup);
111543339bedSEli Billauer 
111643339bedSEli Billauer struct pages_devres {
111743339bedSEli Billauer 	unsigned long addr;
111843339bedSEli Billauer 	unsigned int order;
111943339bedSEli Billauer };
112043339bedSEli Billauer 
devm_pages_match(struct device * dev,void * res,void * p)112143339bedSEli Billauer static int devm_pages_match(struct device *dev, void *res, void *p)
112243339bedSEli Billauer {
112343339bedSEli Billauer 	struct pages_devres *devres = res;
112443339bedSEli Billauer 	struct pages_devres *target = p;
112543339bedSEli Billauer 
112643339bedSEli Billauer 	return devres->addr == target->addr;
112743339bedSEli Billauer }
112843339bedSEli Billauer 
devm_pages_release(struct device * dev,void * res)112943339bedSEli Billauer static void devm_pages_release(struct device *dev, void *res)
113043339bedSEli Billauer {
113143339bedSEli Billauer 	struct pages_devres *devres = res;
113243339bedSEli Billauer 
113343339bedSEli Billauer 	free_pages(devres->addr, devres->order);
113443339bedSEli Billauer }
113543339bedSEli Billauer 
113643339bedSEli Billauer /**
113743339bedSEli Billauer  * devm_get_free_pages - Resource-managed __get_free_pages
113843339bedSEli Billauer  * @dev: Device to allocate memory for
113943339bedSEli Billauer  * @gfp_mask: Allocation gfp flags
114043339bedSEli Billauer  * @order: Allocation size is (1 << order) pages
114143339bedSEli Billauer  *
114243339bedSEli Billauer  * Managed get_free_pages.  Memory allocated with this function is
114343339bedSEli Billauer  * automatically freed on driver detach.
114443339bedSEli Billauer  *
114543339bedSEli Billauer  * RETURNS:
114643339bedSEli Billauer  * Address of allocated memory on success, 0 on failure.
114743339bedSEli Billauer  */
114843339bedSEli Billauer 
devm_get_free_pages(struct device * dev,gfp_t gfp_mask,unsigned int order)114943339bedSEli Billauer unsigned long devm_get_free_pages(struct device *dev,
115043339bedSEli Billauer 				  gfp_t gfp_mask, unsigned int order)
115143339bedSEli Billauer {
115243339bedSEli Billauer 	struct pages_devres *devres;
115343339bedSEli Billauer 	unsigned long addr;
115443339bedSEli Billauer 
115543339bedSEli Billauer 	addr = __get_free_pages(gfp_mask, order);
115643339bedSEli Billauer 
115743339bedSEli Billauer 	if (unlikely(!addr))
115843339bedSEli Billauer 		return 0;
115943339bedSEli Billauer 
116043339bedSEli Billauer 	devres = devres_alloc(devm_pages_release,
116143339bedSEli Billauer 			      sizeof(struct pages_devres), GFP_KERNEL);
116243339bedSEli Billauer 	if (unlikely(!devres)) {
116343339bedSEli Billauer 		free_pages(addr, order);
116443339bedSEli Billauer 		return 0;
116543339bedSEli Billauer 	}
116643339bedSEli Billauer 
116743339bedSEli Billauer 	devres->addr = addr;
116843339bedSEli Billauer 	devres->order = order;
116943339bedSEli Billauer 
117043339bedSEli Billauer 	devres_add(dev, devres);
117143339bedSEli Billauer 	return addr;
117243339bedSEli Billauer }
117343339bedSEli Billauer EXPORT_SYMBOL_GPL(devm_get_free_pages);
117443339bedSEli Billauer 
117543339bedSEli Billauer /**
117643339bedSEli Billauer  * devm_free_pages - Resource-managed free_pages
117743339bedSEli Billauer  * @dev: Device this memory belongs to
1178ff86aae3SMadalin Bucur  * @addr: Memory to free
1179ff86aae3SMadalin Bucur  *
1180ff86aae3SMadalin Bucur  * Free memory allocated with devm_get_free_pages(). Unlike free_pages,
1181ff86aae3SMadalin Bucur  * there is no need to supply the @order.
1182ff86aae3SMadalin Bucur  */
devm_free_pages(struct device * dev,unsigned long addr)1183ff86aae3SMadalin Bucur void devm_free_pages(struct device *dev, unsigned long addr)
1184ff86aae3SMadalin Bucur {
1185ff86aae3SMadalin Bucur 	struct pages_devres devres = { .addr = addr };
1186ff86aae3SMadalin Bucur 
1187ff86aae3SMadalin Bucur 	WARN_ON(devres_release(dev, devm_pages_release, devm_pages_match,
1188ff86aae3SMadalin Bucur 			       &devres));
1189ff86aae3SMadalin Bucur }
1190ff86aae3SMadalin Bucur EXPORT_SYMBOL_GPL(devm_free_pages);
1191ff86aae3SMadalin Bucur 
devm_percpu_release(struct device * dev,void * pdata)1192ff86aae3SMadalin Bucur static void devm_percpu_release(struct device *dev, void *pdata)
1193ff86aae3SMadalin Bucur {
1194ff86aae3SMadalin Bucur 	void __percpu *p;
1195ff86aae3SMadalin Bucur 
1196ff86aae3SMadalin Bucur 	p = *(void __percpu **)pdata;
1197ff86aae3SMadalin Bucur 	free_percpu(p);
1198ff86aae3SMadalin Bucur }
1199ff86aae3SMadalin Bucur 
devm_percpu_match(struct device * dev,void * data,void * p)1200ff86aae3SMadalin Bucur static int devm_percpu_match(struct device *dev, void *data, void *p)
1201ff86aae3SMadalin Bucur {
1202ff86aae3SMadalin Bucur 	struct devres *devr = container_of(data, struct devres, data);
1203ff86aae3SMadalin Bucur 
1204ff86aae3SMadalin Bucur 	return *(void **)devr->data == p;
1205ff86aae3SMadalin Bucur }
1206ff86aae3SMadalin Bucur 
1207ff86aae3SMadalin Bucur /**
1208ff86aae3SMadalin Bucur  * __devm_alloc_percpu - Resource-managed alloc_percpu
1209ff86aae3SMadalin Bucur  * @dev: Device to allocate per-cpu memory for
1210ff86aae3SMadalin Bucur  * @size: Size of per-cpu memory to allocate
1211ff86aae3SMadalin Bucur  * @align: Alignment of per-cpu memory to allocate
1212ff86aae3SMadalin Bucur  *
1213ff86aae3SMadalin Bucur  * Managed alloc_percpu. Per-cpu memory allocated with this function is
1214ff86aae3SMadalin Bucur  * automatically freed on driver detach.
1215ff86aae3SMadalin Bucur  *
1216ff86aae3SMadalin Bucur  * RETURNS:
1217ff86aae3SMadalin Bucur  * Pointer to allocated memory on success, NULL on failure.
1218ff86aae3SMadalin Bucur  */
__devm_alloc_percpu(struct device * dev,size_t size,size_t align)1219ff86aae3SMadalin Bucur void __percpu *__devm_alloc_percpu(struct device *dev, size_t size,
1220ff86aae3SMadalin Bucur 		size_t align)
1221ff86aae3SMadalin Bucur {
1222ff86aae3SMadalin Bucur 	void *p;
1223ff86aae3SMadalin Bucur 	void __percpu *pcpu;
1224ff86aae3SMadalin Bucur 
1225ff86aae3SMadalin Bucur 	pcpu = __alloc_percpu(size, align);
1226ff86aae3SMadalin Bucur 	if (!pcpu)
1227ff86aae3SMadalin Bucur 		return NULL;
1228ff86aae3SMadalin Bucur 
1229ff86aae3SMadalin Bucur 	p = devres_alloc(devm_percpu_release, sizeof(void *), GFP_KERNEL);
1230ff86aae3SMadalin Bucur 	if (!p) {
1231ff86aae3SMadalin Bucur 		free_percpu(pcpu);
1232ff86aae3SMadalin Bucur 		return NULL;
1233ff86aae3SMadalin Bucur 	}
1234ff86aae3SMadalin Bucur 
1235ff86aae3SMadalin Bucur 	*(void __percpu **)p = pcpu;
1236ff86aae3SMadalin Bucur 
1237ff86aae3SMadalin Bucur 	devres_add(dev, p);
1238ff86aae3SMadalin Bucur 
1239bd50a974SZijun Hu 	return pcpu;
1240bd50a974SZijun Hu }
1241bd50a974SZijun Hu EXPORT_SYMBOL_GPL(__devm_alloc_percpu);
1242bd50a974SZijun Hu 
1243bd50a974SZijun Hu /**
1244fea64fa0SUros Bizjak  * devm_free_percpu - Resource-managed free_percpu
1245ff86aae3SMadalin Bucur  * @dev: Device this memory belongs to
1246ff86aae3SMadalin Bucur  * @pdata: Per-cpu memory to free
1247  *
1248  * Free memory allocated with devm_alloc_percpu().
1249  */
devm_free_percpu(struct device * dev,void __percpu * pdata)1250 void devm_free_percpu(struct device *dev, void __percpu *pdata)
1251 {
1252 	/*
1253 	 * Use devres_release() to prevent memory leakage as
1254 	 * devm_free_pages() does.
1255 	 */
1256 	WARN_ON(devres_release(dev, devm_percpu_release, devm_percpu_match,
1257 			       (void *)(__force unsigned long)pdata));
1258 }
1259 EXPORT_SYMBOL_GPL(devm_free_percpu);
1260