xref: /rk3399_rockchip-uboot/drivers/core/devres.c (revision 608f26c51bebc68db7f2edc7590ee513d2bc5465)
1*608f26c5SMasahiro Yamada /*
2*608f26c5SMasahiro Yamada  * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
3*608f26c5SMasahiro Yamada  *
4*608f26c5SMasahiro Yamada  * Based on the original work in Linux by
5*608f26c5SMasahiro Yamada  * Copyright (c) 2006  SUSE Linux Products GmbH
6*608f26c5SMasahiro Yamada  * Copyright (c) 2006  Tejun Heo <teheo@suse.de>
7*608f26c5SMasahiro Yamada  *
8*608f26c5SMasahiro Yamada  * SPDX-License-Identifier:	GPL-2.0+
9*608f26c5SMasahiro Yamada  */
10*608f26c5SMasahiro Yamada 
11*608f26c5SMasahiro Yamada #include <common.h>
12*608f26c5SMasahiro Yamada #include <linux/compat.h>
13*608f26c5SMasahiro Yamada #include <linux/kernel.h>
14*608f26c5SMasahiro Yamada #include <linux/list.h>
15*608f26c5SMasahiro Yamada #include <dm/device.h>
16*608f26c5SMasahiro Yamada 
17*608f26c5SMasahiro Yamada /**
18*608f26c5SMasahiro Yamada  * struct devres - Bookkeeping info for managed device resource
19*608f26c5SMasahiro Yamada  * @entry: List to associate this structure with a device
20*608f26c5SMasahiro Yamada  * @release: Callback invoked when this resource is released
21*608f26c5SMasahiro Yamada  * @probe: Flag to show when this resource was allocated
22*608f26c5SMasahiro Yamada 	   (true = probe, false = bind)
23*608f26c5SMasahiro Yamada  * @name: Name of release function
24*608f26c5SMasahiro Yamada  * @size: Size of resource data
25*608f26c5SMasahiro Yamada  * @data: Resource data
26*608f26c5SMasahiro Yamada  */
27*608f26c5SMasahiro Yamada struct devres {
28*608f26c5SMasahiro Yamada 	struct list_head		entry;
29*608f26c5SMasahiro Yamada 	dr_release_t			release;
30*608f26c5SMasahiro Yamada 	bool				probe;
31*608f26c5SMasahiro Yamada #ifdef CONFIG_DEBUG_DEVRES
32*608f26c5SMasahiro Yamada 	const char			*name;
33*608f26c5SMasahiro Yamada 	size_t				size;
34*608f26c5SMasahiro Yamada #endif
35*608f26c5SMasahiro Yamada 	unsigned long long		data[];
36*608f26c5SMasahiro Yamada };
37*608f26c5SMasahiro Yamada 
38*608f26c5SMasahiro Yamada #ifdef CONFIG_DEBUG_DEVRES
39*608f26c5SMasahiro Yamada static void set_node_dbginfo(struct devres *dr, const char *name, size_t size)
40*608f26c5SMasahiro Yamada {
41*608f26c5SMasahiro Yamada 	dr->name = name;
42*608f26c5SMasahiro Yamada 	dr->size = size;
43*608f26c5SMasahiro Yamada }
44*608f26c5SMasahiro Yamada 
45*608f26c5SMasahiro Yamada static void devres_log(struct udevice *dev, struct devres *dr,
46*608f26c5SMasahiro Yamada 		       const char *op)
47*608f26c5SMasahiro Yamada {
48*608f26c5SMasahiro Yamada 	printf("%s: DEVRES %3s %p %s (%lu bytes)\n",
49*608f26c5SMasahiro Yamada 	       dev->name, op, dr, dr->name, (unsigned long)dr->size);
50*608f26c5SMasahiro Yamada }
51*608f26c5SMasahiro Yamada #else /* CONFIG_DEBUG_DEVRES */
52*608f26c5SMasahiro Yamada #define set_node_dbginfo(dr, n, s)	do {} while (0)
53*608f26c5SMasahiro Yamada #define devres_log(dev, dr, op)		do {} while (0)
54*608f26c5SMasahiro Yamada #endif
55*608f26c5SMasahiro Yamada 
56*608f26c5SMasahiro Yamada #if CONFIG_DEBUG_DEVRES
57*608f26c5SMasahiro Yamada void *__devres_alloc(dr_release_t release, size_t size, gfp_t gfp,
58*608f26c5SMasahiro Yamada 		     const char *name)
59*608f26c5SMasahiro Yamada #else
60*608f26c5SMasahiro Yamada void *_devres_alloc(dr_release_t release, size_t size, gfp_t gfp)
61*608f26c5SMasahiro Yamada #endif
62*608f26c5SMasahiro Yamada {
63*608f26c5SMasahiro Yamada 	size_t tot_size = sizeof(struct devres) + size;
64*608f26c5SMasahiro Yamada 	struct devres *dr;
65*608f26c5SMasahiro Yamada 
66*608f26c5SMasahiro Yamada 	dr = kmalloc(tot_size, gfp);
67*608f26c5SMasahiro Yamada 	if (unlikely(!dr))
68*608f26c5SMasahiro Yamada 		return NULL;
69*608f26c5SMasahiro Yamada 
70*608f26c5SMasahiro Yamada 	INIT_LIST_HEAD(&dr->entry);
71*608f26c5SMasahiro Yamada 	dr->release = release;
72*608f26c5SMasahiro Yamada 	set_node_dbginfo(dr, name, size);
73*608f26c5SMasahiro Yamada 
74*608f26c5SMasahiro Yamada 	return dr->data;
75*608f26c5SMasahiro Yamada }
76*608f26c5SMasahiro Yamada 
77*608f26c5SMasahiro Yamada void devres_free(void *res)
78*608f26c5SMasahiro Yamada {
79*608f26c5SMasahiro Yamada 	if (res) {
80*608f26c5SMasahiro Yamada 		struct devres *dr = container_of(res, struct devres, data);
81*608f26c5SMasahiro Yamada 
82*608f26c5SMasahiro Yamada 		BUG_ON(!list_empty(&dr->entry));
83*608f26c5SMasahiro Yamada 		kfree(dr);
84*608f26c5SMasahiro Yamada 	}
85*608f26c5SMasahiro Yamada }
86*608f26c5SMasahiro Yamada 
87*608f26c5SMasahiro Yamada void devres_add(struct udevice *dev, void *res)
88*608f26c5SMasahiro Yamada {
89*608f26c5SMasahiro Yamada 	struct devres *dr = container_of(res, struct devres, data);
90*608f26c5SMasahiro Yamada 
91*608f26c5SMasahiro Yamada 	devres_log(dev, dr, "ADD");
92*608f26c5SMasahiro Yamada 	BUG_ON(!list_empty(&dr->entry));
93*608f26c5SMasahiro Yamada 	dr->probe = dev->flags & DM_FLAG_BOUND ? true : false;
94*608f26c5SMasahiro Yamada 	list_add_tail(&dr->entry, &dev->devres_head);
95*608f26c5SMasahiro Yamada }
96*608f26c5SMasahiro Yamada 
97*608f26c5SMasahiro Yamada void *devres_find(struct udevice *dev, dr_release_t release,
98*608f26c5SMasahiro Yamada 		  dr_match_t match, void *match_data)
99*608f26c5SMasahiro Yamada {
100*608f26c5SMasahiro Yamada 	struct devres *dr;
101*608f26c5SMasahiro Yamada 
102*608f26c5SMasahiro Yamada 	list_for_each_entry_reverse(dr, &dev->devres_head, entry) {
103*608f26c5SMasahiro Yamada 		if (dr->release != release)
104*608f26c5SMasahiro Yamada 			continue;
105*608f26c5SMasahiro Yamada 		if (match && !match(dev, dr->data, match_data))
106*608f26c5SMasahiro Yamada 			continue;
107*608f26c5SMasahiro Yamada 		return dr->data;
108*608f26c5SMasahiro Yamada 	}
109*608f26c5SMasahiro Yamada 
110*608f26c5SMasahiro Yamada 	return NULL;
111*608f26c5SMasahiro Yamada }
112*608f26c5SMasahiro Yamada 
113*608f26c5SMasahiro Yamada void *devres_get(struct udevice *dev, void *new_res,
114*608f26c5SMasahiro Yamada 		 dr_match_t match, void *match_data)
115*608f26c5SMasahiro Yamada {
116*608f26c5SMasahiro Yamada 	struct devres *new_dr = container_of(new_res, struct devres, data);
117*608f26c5SMasahiro Yamada 	void *res;
118*608f26c5SMasahiro Yamada 
119*608f26c5SMasahiro Yamada 	res = devres_find(dev, new_dr->release, match, match_data);
120*608f26c5SMasahiro Yamada 	if (!res) {
121*608f26c5SMasahiro Yamada 		devres_add(dev, new_res);
122*608f26c5SMasahiro Yamada 		res = new_res;
123*608f26c5SMasahiro Yamada 		new_res = NULL;
124*608f26c5SMasahiro Yamada 	}
125*608f26c5SMasahiro Yamada 	devres_free(new_res);
126*608f26c5SMasahiro Yamada 
127*608f26c5SMasahiro Yamada 	return res;
128*608f26c5SMasahiro Yamada }
129*608f26c5SMasahiro Yamada 
130*608f26c5SMasahiro Yamada void *devres_remove(struct udevice *dev, dr_release_t release,
131*608f26c5SMasahiro Yamada 		    dr_match_t match, void *match_data)
132*608f26c5SMasahiro Yamada {
133*608f26c5SMasahiro Yamada 	void *res;
134*608f26c5SMasahiro Yamada 
135*608f26c5SMasahiro Yamada 	res = devres_find(dev, release, match, match_data);
136*608f26c5SMasahiro Yamada 	if (res) {
137*608f26c5SMasahiro Yamada 		struct devres *dr = container_of(res, struct devres, data);
138*608f26c5SMasahiro Yamada 
139*608f26c5SMasahiro Yamada 		list_del_init(&dr->entry);
140*608f26c5SMasahiro Yamada 		devres_log(dev, dr, "REM");
141*608f26c5SMasahiro Yamada 	}
142*608f26c5SMasahiro Yamada 
143*608f26c5SMasahiro Yamada 	return res;
144*608f26c5SMasahiro Yamada }
145*608f26c5SMasahiro Yamada 
146*608f26c5SMasahiro Yamada int devres_destroy(struct udevice *dev, dr_release_t release,
147*608f26c5SMasahiro Yamada 		   dr_match_t match, void *match_data)
148*608f26c5SMasahiro Yamada {
149*608f26c5SMasahiro Yamada 	void *res;
150*608f26c5SMasahiro Yamada 
151*608f26c5SMasahiro Yamada 	res = devres_remove(dev, release, match, match_data);
152*608f26c5SMasahiro Yamada 	if (unlikely(!res))
153*608f26c5SMasahiro Yamada 		return -ENOENT;
154*608f26c5SMasahiro Yamada 
155*608f26c5SMasahiro Yamada 	devres_free(res);
156*608f26c5SMasahiro Yamada 	return 0;
157*608f26c5SMasahiro Yamada }
158*608f26c5SMasahiro Yamada 
159*608f26c5SMasahiro Yamada int devres_release(struct udevice *dev, dr_release_t release,
160*608f26c5SMasahiro Yamada 		   dr_match_t match, void *match_data)
161*608f26c5SMasahiro Yamada {
162*608f26c5SMasahiro Yamada 	void *res;
163*608f26c5SMasahiro Yamada 
164*608f26c5SMasahiro Yamada 	res = devres_remove(dev, release, match, match_data);
165*608f26c5SMasahiro Yamada 	if (unlikely(!res))
166*608f26c5SMasahiro Yamada 		return -ENOENT;
167*608f26c5SMasahiro Yamada 
168*608f26c5SMasahiro Yamada 	(*release)(dev, res);
169*608f26c5SMasahiro Yamada 	devres_free(res);
170*608f26c5SMasahiro Yamada 	return 0;
171*608f26c5SMasahiro Yamada }
172*608f26c5SMasahiro Yamada 
173*608f26c5SMasahiro Yamada static void release_nodes(struct udevice *dev, struct list_head *head,
174*608f26c5SMasahiro Yamada 			  bool probe_only)
175*608f26c5SMasahiro Yamada {
176*608f26c5SMasahiro Yamada 	struct devres *dr, *tmp;
177*608f26c5SMasahiro Yamada 
178*608f26c5SMasahiro Yamada 	list_for_each_entry_safe_reverse(dr, tmp, head, entry)  {
179*608f26c5SMasahiro Yamada 		if (probe_only && !dr->probe)
180*608f26c5SMasahiro Yamada 			break;
181*608f26c5SMasahiro Yamada 		devres_log(dev, dr, "REL");
182*608f26c5SMasahiro Yamada 		dr->release(dev, dr->data);
183*608f26c5SMasahiro Yamada 		list_del(&dr->entry);
184*608f26c5SMasahiro Yamada 		kfree(dr);
185*608f26c5SMasahiro Yamada 	}
186*608f26c5SMasahiro Yamada }
187*608f26c5SMasahiro Yamada 
188*608f26c5SMasahiro Yamada void devres_release_probe(struct udevice *dev)
189*608f26c5SMasahiro Yamada {
190*608f26c5SMasahiro Yamada 	release_nodes(dev, &dev->devres_head, true);
191*608f26c5SMasahiro Yamada }
192*608f26c5SMasahiro Yamada 
193*608f26c5SMasahiro Yamada void devres_release_all(struct udevice *dev)
194*608f26c5SMasahiro Yamada {
195*608f26c5SMasahiro Yamada 	release_nodes(dev, &dev->devres_head, false);
196*608f26c5SMasahiro Yamada }
197