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