X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=drivers%2Fcore%2Fdevice-remove.c;h=0924a575f537d51bfe04959cf88b4d39b0d088c1;hb=5a1a8a63be8f7262a300eddafb18020926b12fb6;hp=45d6543067bcabfd7877bc200dcf6208c2871404;hpb=aed1a4dd88e94001b811b297c1ff734c3f8d22d9;p=platform%2Fkernel%2Fu-boot.git diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c index 45d6543..0924a57 100644 --- a/drivers/core/device-remove.c +++ b/drivers/core/device-remove.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Device manager * @@ -5,20 +6,20 @@ * * (C) Copyright 2012 * Pavel Herrmann - * - * SPDX-License-Identifier: GPL-2.0+ */ #include #include +#include #include #include #include #include #include #include +#include -int device_unbind_children(struct udevice *dev) +int device_chld_unbind(struct udevice *dev, struct driver *drv) { struct udevice *pos, *n; int ret, saved_ret = 0; @@ -26,15 +27,22 @@ int device_unbind_children(struct udevice *dev) assert(dev); list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) { + if (drv && (pos->driver != drv)) + continue; + ret = device_unbind(pos); - if (ret && !saved_ret) + if (ret && !saved_ret) { + log_warning("device '%s' failed to unbind\n", + pos->name); saved_ret = ret; + } } - return saved_ret; + return log_ret(saved_ret); } -int device_remove_children(struct udevice *dev) +int device_chld_remove(struct udevice *dev, struct driver *drv, + uint flags) { struct udevice *pos, *n; int ret; @@ -42,7 +50,10 @@ int device_remove_children(struct udevice *dev) assert(dev); list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) { - ret = device_remove(pos); + if (drv && (pos->driver != drv)) + continue; + + ret = device_remove(pos, flags); if (ret) return ret; } @@ -56,13 +67,13 @@ int device_unbind(struct udevice *dev) int ret; if (!dev) - return -EINVAL; + return log_msg_ret("dev", -EINVAL); if (dev->flags & DM_FLAG_ACTIVATED) - return -EINVAL; + return log_msg_ret("active", -EINVAL); if (!(dev->flags & DM_FLAG_BOUND)) - return -EINVAL; + return log_msg_ret("not-bound", -EINVAL); drv = dev->driver; assert(drv); @@ -70,12 +81,12 @@ int device_unbind(struct udevice *dev) if (drv->unbind) { ret = drv->unbind(dev); if (ret) - return ret; + return log_msg_ret("unbind", ret); } - ret = device_unbind_children(dev); + ret = device_chld_unbind(dev, NULL); if (ret) - return ret; + return log_msg_ret("child unbind", ret); if (dev->flags & DM_FLAG_ALLOC_PDATA) { free(dev->platdata); @@ -91,10 +102,15 @@ int device_unbind(struct udevice *dev) } ret = uclass_unbind_device(dev); if (ret) - return ret; + return log_msg_ret("uc", ret); if (dev->parent) list_del(&dev->sibling_node); + + devres_release_all(dev); + + if (dev->flags & DM_FLAG_NAME_ALLOCED) + free((char *)dev->name); free(dev); return 0; @@ -128,9 +144,21 @@ void device_free(struct udevice *dev) dev->parent_priv = NULL; } } + dev->flags &= ~DM_FLAG_PLATDATA_VALID; + + devres_release_probe(dev); } -int device_remove(struct udevice *dev) +static bool flags_remove(uint flags, uint drv_flags) +{ + if ((flags & DM_REMOVE_NORMAL) || + (flags && (drv_flags & (DM_FLAG_ACTIVE_DMA | DM_FLAG_OS_PREPARE)))) + return true; + + return false; +} + +int device_remove(struct udevice *dev, uint flags) { const struct driver *drv; int ret; @@ -148,11 +176,15 @@ int device_remove(struct udevice *dev) if (ret) return ret; - ret = device_remove_children(dev); + ret = device_chld_remove(dev, NULL, flags); if (ret) goto err; - if (drv->remove) { + /* + * Remove the device if called with the "normal" remove flag set, + * or if the remove flag matches any of the drivers remove flags + */ + if (drv->remove && flags_remove(flags, drv->flags)) { ret = drv->remove(dev); if (ret) goto err_remove; @@ -166,10 +198,18 @@ int device_remove(struct udevice *dev) } } - device_free(dev); + if (!(flags & DM_REMOVE_NO_PD) && + !(drv->flags & + (DM_FLAG_DEFAULT_PD_CTRL_OFF | DM_FLAG_REMOVE_WITH_PD_ON)) && + dev != gd->cur_serial_dev) + dev_power_domain_off(dev); - dev->seq = -1; - dev->flags &= ~DM_FLAG_ACTIVATED; + if (flags_remove(flags, drv->flags)) { + device_free(dev); + + dev->seq = -1; + dev->flags &= ~DM_FLAG_ACTIVATED; + } return ret;