13ac435d3SSimon Glass /* 23ac435d3SSimon Glass * Device manager 33ac435d3SSimon Glass * 43ac435d3SSimon Glass * Copyright (c) 2014 Google, Inc 53ac435d3SSimon Glass * 63ac435d3SSimon Glass * (C) Copyright 2012 73ac435d3SSimon Glass * Pavel Herrmann <morpheus.ibis@gmail.com> 83ac435d3SSimon Glass * 93ac435d3SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 103ac435d3SSimon Glass */ 113ac435d3SSimon Glass 123ac435d3SSimon Glass #include <common.h> 133ac435d3SSimon Glass #include <errno.h> 143ac435d3SSimon Glass #include <malloc.h> 153ac435d3SSimon Glass #include <dm/device.h> 163ac435d3SSimon Glass #include <dm/device-internal.h> 173ac435d3SSimon Glass #include <dm/uclass.h> 183ac435d3SSimon Glass #include <dm/uclass-internal.h> 193ac435d3SSimon Glass #include <dm/util.h> 203ac435d3SSimon Glass 2179725ca4SSimon Glass /** 2279725ca4SSimon Glass * device_chld_unbind() - Unbind all device's children from the device 2379725ca4SSimon Glass * 2479725ca4SSimon Glass * On error, the function continues to unbind all children, and reports the 2579725ca4SSimon Glass * first error. 2679725ca4SSimon Glass * 2779725ca4SSimon Glass * @dev: The device that is to be stripped of its children 2879725ca4SSimon Glass * @return 0 on success, -ve on error 2979725ca4SSimon Glass */ 3079725ca4SSimon Glass static int device_chld_unbind(struct udevice *dev) 313ac435d3SSimon Glass { 323ac435d3SSimon Glass struct udevice *pos, *n; 333ac435d3SSimon Glass int ret, saved_ret = 0; 343ac435d3SSimon Glass 353ac435d3SSimon Glass assert(dev); 363ac435d3SSimon Glass 373ac435d3SSimon Glass list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) { 383ac435d3SSimon Glass ret = device_unbind(pos); 393ac435d3SSimon Glass if (ret && !saved_ret) 403ac435d3SSimon Glass saved_ret = ret; 413ac435d3SSimon Glass } 423ac435d3SSimon Glass 433ac435d3SSimon Glass return saved_ret; 443ac435d3SSimon Glass } 453ac435d3SSimon Glass 4679725ca4SSimon Glass /** 4779725ca4SSimon Glass * device_chld_remove() - Stop all device's children 4879725ca4SSimon Glass * @dev: The device whose children are to be removed 4979725ca4SSimon Glass * @return 0 on success, -ve on error 5079725ca4SSimon Glass */ 5179725ca4SSimon Glass static int device_chld_remove(struct udevice *dev) 523ac435d3SSimon Glass { 533ac435d3SSimon Glass struct udevice *pos, *n; 543ac435d3SSimon Glass int ret; 553ac435d3SSimon Glass 563ac435d3SSimon Glass assert(dev); 573ac435d3SSimon Glass 583ac435d3SSimon Glass list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) { 593ac435d3SSimon Glass ret = device_remove(pos); 603ac435d3SSimon Glass if (ret) 613ac435d3SSimon Glass return ret; 623ac435d3SSimon Glass } 633ac435d3SSimon Glass 643ac435d3SSimon Glass return 0; 653ac435d3SSimon Glass } 663ac435d3SSimon Glass 673ac435d3SSimon Glass int device_unbind(struct udevice *dev) 683ac435d3SSimon Glass { 693479253dSSimon Glass const struct driver *drv; 703ac435d3SSimon Glass int ret; 713ac435d3SSimon Glass 723ac435d3SSimon Glass if (!dev) 733ac435d3SSimon Glass return -EINVAL; 743ac435d3SSimon Glass 753ac435d3SSimon Glass if (dev->flags & DM_FLAG_ACTIVATED) 763ac435d3SSimon Glass return -EINVAL; 773ac435d3SSimon Glass 78aed1a4ddSMasahiro Yamada if (!(dev->flags & DM_FLAG_BOUND)) 79aed1a4ddSMasahiro Yamada return -EINVAL; 80aed1a4ddSMasahiro Yamada 813ac435d3SSimon Glass drv = dev->driver; 823ac435d3SSimon Glass assert(drv); 833ac435d3SSimon Glass 843ac435d3SSimon Glass if (drv->unbind) { 853ac435d3SSimon Glass ret = drv->unbind(dev); 863ac435d3SSimon Glass if (ret) 873ac435d3SSimon Glass return ret; 883ac435d3SSimon Glass } 893ac435d3SSimon Glass 9079725ca4SSimon Glass ret = device_chld_unbind(dev); 913ac435d3SSimon Glass if (ret) 923ac435d3SSimon Glass return ret; 933ac435d3SSimon Glass 94f8a85449SSimon Glass if (dev->flags & DM_FLAG_ALLOC_PDATA) { 95f8a85449SSimon Glass free(dev->platdata); 96f8a85449SSimon Glass dev->platdata = NULL; 97f8a85449SSimon Glass } 985eaed880SPrzemyslaw Marczak if (dev->flags & DM_FLAG_ALLOC_UCLASS_PDATA) { 995eaed880SPrzemyslaw Marczak free(dev->uclass_platdata); 1005eaed880SPrzemyslaw Marczak dev->uclass_platdata = NULL; 1015eaed880SPrzemyslaw Marczak } 102cdc133bdSSimon Glass if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) { 103cdc133bdSSimon Glass free(dev->parent_platdata); 104cdc133bdSSimon Glass dev->parent_platdata = NULL; 105cdc133bdSSimon Glass } 1063ac435d3SSimon Glass ret = uclass_unbind_device(dev); 1073ac435d3SSimon Glass if (ret) 1083ac435d3SSimon Glass return ret; 1093ac435d3SSimon Glass 1103ac435d3SSimon Glass if (dev->parent) 1113ac435d3SSimon Glass list_del(&dev->sibling_node); 112608f26c5SMasahiro Yamada 113608f26c5SMasahiro Yamada devres_release_all(dev); 114608f26c5SMasahiro Yamada 115*fd1c2d9bSSimon Glass if (dev->flags & DM_FLAG_NAME_ALLOCED) 116a2040facSSimon Glass free((char *)dev->name); 1173ac435d3SSimon Glass free(dev); 1183ac435d3SSimon Glass 1193ac435d3SSimon Glass return 0; 1203ac435d3SSimon Glass } 1213ac435d3SSimon Glass 1223ac435d3SSimon Glass /** 1233ac435d3SSimon Glass * device_free() - Free memory buffers allocated by a device 1243ac435d3SSimon Glass * @dev: Device that is to be started 1253ac435d3SSimon Glass */ 1263ac435d3SSimon Glass void device_free(struct udevice *dev) 1273ac435d3SSimon Glass { 1283ac435d3SSimon Glass int size; 1293ac435d3SSimon Glass 1303ac435d3SSimon Glass if (dev->driver->priv_auto_alloc_size) { 1313ac435d3SSimon Glass free(dev->priv); 1323ac435d3SSimon Glass dev->priv = NULL; 1333ac435d3SSimon Glass } 1343ac435d3SSimon Glass size = dev->uclass->uc_drv->per_device_auto_alloc_size; 1353ac435d3SSimon Glass if (size) { 1363ac435d3SSimon Glass free(dev->uclass_priv); 1373ac435d3SSimon Glass dev->uclass_priv = NULL; 1383ac435d3SSimon Glass } 1393ac435d3SSimon Glass if (dev->parent) { 1403ac435d3SSimon Glass size = dev->parent->driver->per_child_auto_alloc_size; 141dac8db2cSSimon Glass if (!size) { 142dac8db2cSSimon Glass size = dev->parent->uclass->uc_drv-> 143dac8db2cSSimon Glass per_child_auto_alloc_size; 144dac8db2cSSimon Glass } 1453ac435d3SSimon Glass if (size) { 1463ac435d3SSimon Glass free(dev->parent_priv); 1473ac435d3SSimon Glass dev->parent_priv = NULL; 1483ac435d3SSimon Glass } 1493ac435d3SSimon Glass } 150608f26c5SMasahiro Yamada 151608f26c5SMasahiro Yamada devres_release_probe(dev); 1523ac435d3SSimon Glass } 1533ac435d3SSimon Glass 1543ac435d3SSimon Glass int device_remove(struct udevice *dev) 1553ac435d3SSimon Glass { 1563479253dSSimon Glass const struct driver *drv; 1573ac435d3SSimon Glass int ret; 1583ac435d3SSimon Glass 1593ac435d3SSimon Glass if (!dev) 1603ac435d3SSimon Glass return -EINVAL; 1613ac435d3SSimon Glass 1623ac435d3SSimon Glass if (!(dev->flags & DM_FLAG_ACTIVATED)) 1633ac435d3SSimon Glass return 0; 1643ac435d3SSimon Glass 1653ac435d3SSimon Glass drv = dev->driver; 1663ac435d3SSimon Glass assert(drv); 1673ac435d3SSimon Glass 1683ac435d3SSimon Glass ret = uclass_pre_remove_device(dev); 1693ac435d3SSimon Glass if (ret) 1703ac435d3SSimon Glass return ret; 1713ac435d3SSimon Glass 17279725ca4SSimon Glass ret = device_chld_remove(dev); 1733ac435d3SSimon Glass if (ret) 1743ac435d3SSimon Glass goto err; 1753ac435d3SSimon Glass 1763ac435d3SSimon Glass if (drv->remove) { 1773ac435d3SSimon Glass ret = drv->remove(dev); 1783ac435d3SSimon Glass if (ret) 1793ac435d3SSimon Glass goto err_remove; 1803ac435d3SSimon Glass } 1813ac435d3SSimon Glass 1823ac435d3SSimon Glass if (dev->parent && dev->parent->driver->child_post_remove) { 1833ac435d3SSimon Glass ret = dev->parent->driver->child_post_remove(dev); 1843ac435d3SSimon Glass if (ret) { 1853ac435d3SSimon Glass dm_warn("%s: Device '%s' failed child_post_remove()", 1863ac435d3SSimon Glass __func__, dev->name); 1873ac435d3SSimon Glass } 1883ac435d3SSimon Glass } 1893ac435d3SSimon Glass 1903ac435d3SSimon Glass device_free(dev); 1913ac435d3SSimon Glass 1923ac435d3SSimon Glass dev->seq = -1; 1933ac435d3SSimon Glass dev->flags &= ~DM_FLAG_ACTIVATED; 1943ac435d3SSimon Glass 1953ac435d3SSimon Glass return ret; 1963ac435d3SSimon Glass 1973ac435d3SSimon Glass err_remove: 1983ac435d3SSimon Glass /* We can't put the children back */ 1993ac435d3SSimon Glass dm_warn("%s: Device '%s' failed to remove, but children are gone\n", 2003ac435d3SSimon Glass __func__, dev->name); 2013ac435d3SSimon Glass err: 2023ac435d3SSimon Glass ret = uclass_post_probe_device(dev); 2033ac435d3SSimon Glass if (ret) { 2043ac435d3SSimon Glass dm_warn("%s: Device '%s' failed to post_probe on error path\n", 2053ac435d3SSimon Glass __func__, dev->name); 2063ac435d3SSimon Glass } 2073ac435d3SSimon Glass 2083ac435d3SSimon Glass return ret; 2093ac435d3SSimon Glass } 210