From patchwork Sat Mar 28 20:03:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 244468 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Sat, 28 Mar 2020 14:03:47 -0600 Subject: [PATCH 1/2] dm: core: Add logging on unbind failure Message-ID: <20200328140343.1.I8183b50f3c4223d0d42173b24f93d96789427223@changeid> This failure path is tricky to debug since it continues after failure and there are a lot of error paths. Add logging to help. Signed-off-by: Simon Glass --- drivers/core/device-remove.c | 20 ++++++++++++-------- drivers/core/uclass.c | 4 ++-- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c index ff5b28cb6a7..8736fd9821e 100644 --- a/drivers/core/device-remove.c +++ b/drivers/core/device-remove.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -30,11 +31,14 @@ int device_chld_unbind(struct udevice *dev, struct 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_chld_remove(struct udevice *dev, struct driver *drv, @@ -63,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); @@ -77,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_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); @@ -98,7 +102,7 @@ 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); diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 58b19a42109..b24b677c55d 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -120,10 +120,10 @@ int uclass_destroy(struct uclass *uc) uclass_node); ret = device_remove(dev, DM_REMOVE_NORMAL); if (ret) - return ret; + return log_msg_ret("remove", ret); ret = device_unbind(dev); if (ret) - return ret; + return log_msg_ret("unbind", ret); } uc_drv = uc->uc_drv; From patchwork Sat Mar 28 20:03:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 244469 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Sat, 28 Mar 2020 14:03:48 -0600 Subject: [PATCH 2/2] dm: core: Add a way to skip powering down power domains In-Reply-To: <20200328140343.1.I8183b50f3c4223d0d42173b24f93d96789427223@changeid> References: <20200328140343.1.I8183b50f3c4223d0d42173b24f93d96789427223@changeid> Message-ID: <20200328140343.2.I67ec46b666e0712ab0c80c271698dc97719385e4@changeid> When removing a device the power domains it uses are generally powered off. But when we are trying to unbind all devices (e.g. for running tests) we don't want to probe a device in the 'remove' path. Add a new flag to skip this power-down step. Signed-off-by: Simon Glass --- drivers/core/device-remove.c | 3 ++- drivers/core/uclass.c | 2 +- include/dm/device.h | 11 +++++++---- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c index 8736fd9821e..efdb0f29058 100644 --- a/drivers/core/device-remove.c +++ b/drivers/core/device-remove.c @@ -198,7 +198,8 @@ int device_remove(struct udevice *dev, uint flags) } } - if (!(drv->flags & + 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); diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index b24b677c55d..68493029364 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -118,7 +118,7 @@ int uclass_destroy(struct uclass *uc) while (!list_empty(&uc->dev_head)) { dev = list_first_entry(&uc->dev_head, struct udevice, uclass_node); - ret = device_remove(dev, DM_REMOVE_NORMAL); + ret = device_remove(dev, DM_REMOVE_NORMAL | DM_REMOVE_NO_PD); if (ret) return log_msg_ret("remove", ret); ret = device_unbind(dev); diff --git a/include/dm/device.h b/include/dm/device.h index a56164b19bb..17e57bf829c 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -80,18 +80,21 @@ struct driver_info; */ enum { /* Normal remove, remove all devices */ - DM_REMOVE_NORMAL = 1 << 0, + DM_REMOVE_NORMAL = 1 << 0, /* Remove devices with active DMA */ - DM_REMOVE_ACTIVE_DMA = DM_FLAG_ACTIVE_DMA, + DM_REMOVE_ACTIVE_DMA = DM_FLAG_ACTIVE_DMA, /* Remove devices which need some final OS preparation steps */ - DM_REMOVE_OS_PREPARE = DM_FLAG_OS_PREPARE, + DM_REMOVE_OS_PREPARE = DM_FLAG_OS_PREPARE, /* Add more use cases here */ /* Remove devices with any active flag */ - DM_REMOVE_ACTIVE_ALL = DM_REMOVE_ACTIVE_DMA | DM_REMOVE_OS_PREPARE, + DM_REMOVE_ACTIVE_ALL = DM_REMOVE_ACTIVE_DMA | DM_REMOVE_OS_PREPARE, + + /* Don't power down any attached power domains */ + DM_REMOVE_NO_PD = 1 << 1, }; /**