xref: /rk3399_rockchip-uboot/drivers/core/device-remove.c (revision 3ac435d33a8f6a4e28df6bc068cb0569bc8061ad)
1*3ac435d3SSimon Glass /*
2*3ac435d3SSimon Glass  * Device manager
3*3ac435d3SSimon Glass  *
4*3ac435d3SSimon Glass  * Copyright (c) 2014 Google, Inc
5*3ac435d3SSimon Glass  *
6*3ac435d3SSimon Glass  * (C) Copyright 2012
7*3ac435d3SSimon Glass  * Pavel Herrmann <morpheus.ibis@gmail.com>
8*3ac435d3SSimon Glass  *
9*3ac435d3SSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
10*3ac435d3SSimon Glass  */
11*3ac435d3SSimon Glass 
12*3ac435d3SSimon Glass #include <common.h>
13*3ac435d3SSimon Glass #include <errno.h>
14*3ac435d3SSimon Glass #include <malloc.h>
15*3ac435d3SSimon Glass #include <dm/device.h>
16*3ac435d3SSimon Glass #include <dm/device-internal.h>
17*3ac435d3SSimon Glass #include <dm/uclass.h>
18*3ac435d3SSimon Glass #include <dm/uclass-internal.h>
19*3ac435d3SSimon Glass #include <dm/util.h>
20*3ac435d3SSimon Glass 
21*3ac435d3SSimon Glass /**
22*3ac435d3SSimon Glass  * device_chld_unbind() - Unbind all device's children from the device
23*3ac435d3SSimon Glass  *
24*3ac435d3SSimon Glass  * On error, the function continues to unbind all children, and reports the
25*3ac435d3SSimon Glass  * first error.
26*3ac435d3SSimon Glass  *
27*3ac435d3SSimon Glass  * @dev:	The device that is to be stripped of its children
28*3ac435d3SSimon Glass  * @return 0 on success, -ve on error
29*3ac435d3SSimon Glass  */
30*3ac435d3SSimon Glass static int device_chld_unbind(struct udevice *dev)
31*3ac435d3SSimon Glass {
32*3ac435d3SSimon Glass 	struct udevice *pos, *n;
33*3ac435d3SSimon Glass 	int ret, saved_ret = 0;
34*3ac435d3SSimon Glass 
35*3ac435d3SSimon Glass 	assert(dev);
36*3ac435d3SSimon Glass 
37*3ac435d3SSimon Glass 	list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
38*3ac435d3SSimon Glass 		ret = device_unbind(pos);
39*3ac435d3SSimon Glass 		if (ret && !saved_ret)
40*3ac435d3SSimon Glass 			saved_ret = ret;
41*3ac435d3SSimon Glass 	}
42*3ac435d3SSimon Glass 
43*3ac435d3SSimon Glass 	return saved_ret;
44*3ac435d3SSimon Glass }
45*3ac435d3SSimon Glass 
46*3ac435d3SSimon Glass /**
47*3ac435d3SSimon Glass  * device_chld_remove() - Stop all device's children
48*3ac435d3SSimon Glass  * @dev:	The device whose children are to be removed
49*3ac435d3SSimon Glass  * @return 0 on success, -ve on error
50*3ac435d3SSimon Glass  */
51*3ac435d3SSimon Glass static int device_chld_remove(struct udevice *dev)
52*3ac435d3SSimon Glass {
53*3ac435d3SSimon Glass 	struct udevice *pos, *n;
54*3ac435d3SSimon Glass 	int ret;
55*3ac435d3SSimon Glass 
56*3ac435d3SSimon Glass 	assert(dev);
57*3ac435d3SSimon Glass 
58*3ac435d3SSimon Glass 	list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
59*3ac435d3SSimon Glass 		ret = device_remove(pos);
60*3ac435d3SSimon Glass 		if (ret)
61*3ac435d3SSimon Glass 			return ret;
62*3ac435d3SSimon Glass 	}
63*3ac435d3SSimon Glass 
64*3ac435d3SSimon Glass 	return 0;
65*3ac435d3SSimon Glass }
66*3ac435d3SSimon Glass 
67*3ac435d3SSimon Glass int device_unbind(struct udevice *dev)
68*3ac435d3SSimon Glass {
69*3ac435d3SSimon Glass 	struct driver *drv;
70*3ac435d3SSimon Glass 	int ret;
71*3ac435d3SSimon Glass 
72*3ac435d3SSimon Glass 	if (!dev)
73*3ac435d3SSimon Glass 		return -EINVAL;
74*3ac435d3SSimon Glass 
75*3ac435d3SSimon Glass 	if (dev->flags & DM_FLAG_ACTIVATED)
76*3ac435d3SSimon Glass 		return -EINVAL;
77*3ac435d3SSimon Glass 
78*3ac435d3SSimon Glass 	drv = dev->driver;
79*3ac435d3SSimon Glass 	assert(drv);
80*3ac435d3SSimon Glass 
81*3ac435d3SSimon Glass 	if (drv->unbind) {
82*3ac435d3SSimon Glass 		ret = drv->unbind(dev);
83*3ac435d3SSimon Glass 		if (ret)
84*3ac435d3SSimon Glass 			return ret;
85*3ac435d3SSimon Glass 	}
86*3ac435d3SSimon Glass 
87*3ac435d3SSimon Glass 	ret = device_chld_unbind(dev);
88*3ac435d3SSimon Glass 	if (ret)
89*3ac435d3SSimon Glass 		return ret;
90*3ac435d3SSimon Glass 
91*3ac435d3SSimon Glass 	ret = uclass_unbind_device(dev);
92*3ac435d3SSimon Glass 	if (ret)
93*3ac435d3SSimon Glass 		return ret;
94*3ac435d3SSimon Glass 
95*3ac435d3SSimon Glass 	if (dev->parent)
96*3ac435d3SSimon Glass 		list_del(&dev->sibling_node);
97*3ac435d3SSimon Glass 	free(dev);
98*3ac435d3SSimon Glass 
99*3ac435d3SSimon Glass 	return 0;
100*3ac435d3SSimon Glass }
101*3ac435d3SSimon Glass 
102*3ac435d3SSimon Glass /**
103*3ac435d3SSimon Glass  * device_free() - Free memory buffers allocated by a device
104*3ac435d3SSimon Glass  * @dev:	Device that is to be started
105*3ac435d3SSimon Glass  */
106*3ac435d3SSimon Glass void device_free(struct udevice *dev)
107*3ac435d3SSimon Glass {
108*3ac435d3SSimon Glass 	int size;
109*3ac435d3SSimon Glass 
110*3ac435d3SSimon Glass 	if (dev->driver->priv_auto_alloc_size) {
111*3ac435d3SSimon Glass 		free(dev->priv);
112*3ac435d3SSimon Glass 		dev->priv = NULL;
113*3ac435d3SSimon Glass 	}
114*3ac435d3SSimon Glass 	if (dev->flags & DM_FLAG_ALLOC_PDATA) {
115*3ac435d3SSimon Glass 		free(dev->platdata);
116*3ac435d3SSimon Glass 		dev->platdata = NULL;
117*3ac435d3SSimon Glass 	}
118*3ac435d3SSimon Glass 	size = dev->uclass->uc_drv->per_device_auto_alloc_size;
119*3ac435d3SSimon Glass 	if (size) {
120*3ac435d3SSimon Glass 		free(dev->uclass_priv);
121*3ac435d3SSimon Glass 		dev->uclass_priv = NULL;
122*3ac435d3SSimon Glass 	}
123*3ac435d3SSimon Glass 	if (dev->parent) {
124*3ac435d3SSimon Glass 		size = dev->parent->driver->per_child_auto_alloc_size;
125*3ac435d3SSimon Glass 		if (size) {
126*3ac435d3SSimon Glass 			free(dev->parent_priv);
127*3ac435d3SSimon Glass 			dev->parent_priv = NULL;
128*3ac435d3SSimon Glass 		}
129*3ac435d3SSimon Glass 	}
130*3ac435d3SSimon Glass }
131*3ac435d3SSimon Glass 
132*3ac435d3SSimon Glass int device_remove(struct udevice *dev)
133*3ac435d3SSimon Glass {
134*3ac435d3SSimon Glass 	struct driver *drv;
135*3ac435d3SSimon Glass 	int ret;
136*3ac435d3SSimon Glass 
137*3ac435d3SSimon Glass 	if (!dev)
138*3ac435d3SSimon Glass 		return -EINVAL;
139*3ac435d3SSimon Glass 
140*3ac435d3SSimon Glass 	if (!(dev->flags & DM_FLAG_ACTIVATED))
141*3ac435d3SSimon Glass 		return 0;
142*3ac435d3SSimon Glass 
143*3ac435d3SSimon Glass 	drv = dev->driver;
144*3ac435d3SSimon Glass 	assert(drv);
145*3ac435d3SSimon Glass 
146*3ac435d3SSimon Glass 	ret = uclass_pre_remove_device(dev);
147*3ac435d3SSimon Glass 	if (ret)
148*3ac435d3SSimon Glass 		return ret;
149*3ac435d3SSimon Glass 
150*3ac435d3SSimon Glass 	ret = device_chld_remove(dev);
151*3ac435d3SSimon Glass 	if (ret)
152*3ac435d3SSimon Glass 		goto err;
153*3ac435d3SSimon Glass 
154*3ac435d3SSimon Glass 	if (drv->remove) {
155*3ac435d3SSimon Glass 		ret = drv->remove(dev);
156*3ac435d3SSimon Glass 		if (ret)
157*3ac435d3SSimon Glass 			goto err_remove;
158*3ac435d3SSimon Glass 	}
159*3ac435d3SSimon Glass 
160*3ac435d3SSimon Glass 	if (dev->parent && dev->parent->driver->child_post_remove) {
161*3ac435d3SSimon Glass 		ret = dev->parent->driver->child_post_remove(dev);
162*3ac435d3SSimon Glass 		if (ret) {
163*3ac435d3SSimon Glass 			dm_warn("%s: Device '%s' failed child_post_remove()",
164*3ac435d3SSimon Glass 				__func__, dev->name);
165*3ac435d3SSimon Glass 		}
166*3ac435d3SSimon Glass 	}
167*3ac435d3SSimon Glass 
168*3ac435d3SSimon Glass 	device_free(dev);
169*3ac435d3SSimon Glass 
170*3ac435d3SSimon Glass 	dev->seq = -1;
171*3ac435d3SSimon Glass 	dev->flags &= ~DM_FLAG_ACTIVATED;
172*3ac435d3SSimon Glass 
173*3ac435d3SSimon Glass 	return ret;
174*3ac435d3SSimon Glass 
175*3ac435d3SSimon Glass err_remove:
176*3ac435d3SSimon Glass 	/* We can't put the children back */
177*3ac435d3SSimon Glass 	dm_warn("%s: Device '%s' failed to remove, but children are gone\n",
178*3ac435d3SSimon Glass 		__func__, dev->name);
179*3ac435d3SSimon Glass err:
180*3ac435d3SSimon Glass 	ret = uclass_post_probe_device(dev);
181*3ac435d3SSimon Glass 	if (ret) {
182*3ac435d3SSimon Glass 		dm_warn("%s: Device '%s' failed to post_probe on error path\n",
183*3ac435d3SSimon Glass 			__func__, dev->name);
184*3ac435d3SSimon Glass 	}
185*3ac435d3SSimon Glass 
186*3ac435d3SSimon Glass 	return ret;
187*3ac435d3SSimon Glass }
188