From patchwork Tue Nov 11 00:16:47 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 409117 X-Patchwork-Delegate: sjg@chromium.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 70B6B14010F for ; Tue, 11 Nov 2014 11:18:42 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id F2B3A4B6DE; Tue, 11 Nov 2014 01:18:24 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id gaMwtuiodyi2; Tue, 11 Nov 2014 01:18:24 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id EC4AB4B6F6; Tue, 11 Nov 2014 01:18:06 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id A3CC74B69A for ; Tue, 11 Nov 2014 01:17:44 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id UyATkzR6do1M for ; Tue, 11 Nov 2014 01:17:44 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-ig0-f201.google.com (mail-ig0-f201.google.com [209.85.213.201]) by theia.denx.de (Postfix) with ESMTPS id EEBEB4B69C for ; Tue, 11 Nov 2014 01:17:39 +0100 (CET) Received: by mail-ig0-f201.google.com with SMTP id h15so14572igd.4 for ; Mon, 10 Nov 2014 16:17:38 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=bdRrUXaFXDWrlV0WUCyGWk6WkmAkVHXTSJO5CK0f58s=; b=MD9EOG5W8vPSviIp98j9/cVKQxeRHe2VnD5WOEqXyaIS8JngBo8kMP6W94t2X5NhiE 6QjNHuhvplv2xex3xg8IMDUUoWzDxCMTMNZYMHdHNp0oZ+T78aLMvN8H3Ks9w6CUYVqE DZ44Y4vcrmTcniap6/hXVRZcWL3ppUpO4Fofb5Oi5bIIZC/+AOrjpDxy/guuh8MMASEz XrYc3cM7YbNLifsaT9hTE57McZhzgXAkHuXpskoSr4V6CJ1zFgH1JL2bXpaeLDutEQwd pd839ogZdWBzVEmfPgR/y7Tb39h/5e6UczNcQ6sD6F+mT8wcH6+x7ZVk9awahO5kEEKx rB8Q== X-Gm-Message-State: ALoCoQlZ6yV9tmtv9qIi0UPnjd1MtZ1Jr+eInB4O9xt8AfqcaQrh0VtmDepM0OOy7BXwjNhJCoG0 X-Received: by 10.50.29.48 with SMTP id g16mr21149390igh.2.1415665058660; Mon, 10 Nov 2014 16:17:38 -0800 (PST) Received: from corpmail-nozzle1-2.hot.corp.google.com ([100.108.1.103]) by gmr-mx.google.com with ESMTPS id r6si710581yhg.1.2014.11.10.16.17.38 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 10 Nov 2014 16:17:38 -0800 (PST) Received: from kaki.bld.corp.google.com ([172.29.216.32]) by corpmail-nozzle1-2.hot.corp.google.com with ESMTP id BeN1Luny.1; Mon, 10 Nov 2014 16:17:38 -0800 Received: by kaki.bld.corp.google.com (Postfix, from userid 121222) id 4A73E221162; Mon, 10 Nov 2014 17:17:37 -0700 (MST) From: Simon Glass To: u-boot@lists.denx.de Date: Mon, 10 Nov 2014 17:16:47 -0700 Message-Id: <1415665015-12651-8-git-send-email-sjg@chromium.org> X-Mailer: git-send-email 2.1.0.rc2.206.gedb03e5 In-Reply-To: <1415665015-12651-1-git-send-email-sjg@chromium.org> References: <1415665015-12651-1-git-send-email-sjg@chromium.org> Cc: Stephen Warren , Tom Warren Subject: [U-Boot] [PATCH v3 07/14] dm: Allow device removal features to be dropped X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.13 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de For SPL we don't expect to need to remove a device. Save some code space by dropping this feature. The board config can define CONFIG_DM_DEVICE_REMOVE if this is in fact needed. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- Changes in v3: None Changes in v2: None drivers/core/Makefile | 3 +- drivers/core/device-remove.c | 187 +++++++++++++++++++++++++++++++++++++++++++ drivers/core/device.c | 168 -------------------------------------- include/config_defaults.h | 4 + include/dm/device-internal.h | 10 +++ 5 files changed, 203 insertions(+), 169 deletions(-) create mode 100644 drivers/core/device-remove.c diff --git a/drivers/core/Makefile b/drivers/core/Makefile index 151c239..f14695b 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -4,5 +4,6 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-y := device.o lists.o root.o uclass.o util.o +obj-$(CONFIG_DM) += device.o lists.o root.o uclass.o util.o obj-$(CONFIG_OF_CONTROL) += simple-bus.o +obj-$(CONFIG_DM_DEVICE_REMOVE) += device-remove.o diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c new file mode 100644 index 0000000..8fc6b71 --- /dev/null +++ b/drivers/core/device-remove.c @@ -0,0 +1,187 @@ +/* + * Device manager + * + * Copyright (c) 2014 Google, Inc + * + * (C) Copyright 2012 + * Pavel Herrmann + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * device_chld_unbind() - Unbind all device's children from the device + * + * On error, the function continues to unbind all children, and reports the + * first error. + * + * @dev: The device that is to be stripped of its children + * @return 0 on success, -ve on error + */ +static int device_chld_unbind(struct udevice *dev) +{ + struct udevice *pos, *n; + int ret, saved_ret = 0; + + assert(dev); + + list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) { + ret = device_unbind(pos); + if (ret && !saved_ret) + saved_ret = ret; + } + + return saved_ret; +} + +/** + * device_chld_remove() - Stop all device's children + * @dev: The device whose children are to be removed + * @return 0 on success, -ve on error + */ +static int device_chld_remove(struct udevice *dev) +{ + struct udevice *pos, *n; + int ret; + + assert(dev); + + list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) { + ret = device_remove(pos); + if (ret) + return ret; + } + + return 0; +} + +int device_unbind(struct udevice *dev) +{ + struct driver *drv; + int ret; + + if (!dev) + return -EINVAL; + + if (dev->flags & DM_FLAG_ACTIVATED) + return -EINVAL; + + drv = dev->driver; + assert(drv); + + if (drv->unbind) { + ret = drv->unbind(dev); + if (ret) + return ret; + } + + ret = device_chld_unbind(dev); + if (ret) + return ret; + + ret = uclass_unbind_device(dev); + if (ret) + return ret; + + if (dev->parent) + list_del(&dev->sibling_node); + free(dev); + + return 0; +} + +/** + * device_free() - Free memory buffers allocated by a device + * @dev: Device that is to be started + */ +void device_free(struct udevice *dev) +{ + int size; + + if (dev->driver->priv_auto_alloc_size) { + free(dev->priv); + dev->priv = NULL; + } + if (dev->flags & DM_FLAG_ALLOC_PDATA) { + free(dev->platdata); + dev->platdata = NULL; + } + size = dev->uclass->uc_drv->per_device_auto_alloc_size; + if (size) { + free(dev->uclass_priv); + dev->uclass_priv = NULL; + } + if (dev->parent) { + size = dev->parent->driver->per_child_auto_alloc_size; + if (size) { + free(dev->parent_priv); + dev->parent_priv = NULL; + } + } +} + +int device_remove(struct udevice *dev) +{ + struct driver *drv; + int ret; + + if (!dev) + return -EINVAL; + + if (!(dev->flags & DM_FLAG_ACTIVATED)) + return 0; + + drv = dev->driver; + assert(drv); + + ret = uclass_pre_remove_device(dev); + if (ret) + return ret; + + ret = device_chld_remove(dev); + if (ret) + goto err; + + if (drv->remove) { + ret = drv->remove(dev); + if (ret) + goto err_remove; + } + + if (dev->parent && dev->parent->driver->child_post_remove) { + ret = dev->parent->driver->child_post_remove(dev); + if (ret) { + dm_warn("%s: Device '%s' failed child_post_remove()", + __func__, dev->name); + } + } + + device_free(dev); + + dev->seq = -1; + dev->flags &= ~DM_FLAG_ACTIVATED; + + return ret; + +err_remove: + /* We can't put the children back */ + dm_warn("%s: Device '%s' failed to remove, but children are gone\n", + __func__, dev->name); +err: + ret = uclass_post_probe_device(dev); + if (ret) { + dm_warn("%s: Device '%s' failed to post_probe on error path\n", + __func__, dev->name); + } + + return ret; +} diff --git a/drivers/core/device.c b/drivers/core/device.c index 49faa29..576a4f2 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -24,52 +24,6 @@ DECLARE_GLOBAL_DATA_PTR; -/** - * device_chld_unbind() - Unbind all device's children from the device - * - * On error, the function continues to unbind all children, and reports the - * first error. - * - * @dev: The device that is to be stripped of its children - * @return 0 on success, -ve on error - */ -static int device_chld_unbind(struct udevice *dev) -{ - struct udevice *pos, *n; - int ret, saved_ret = 0; - - assert(dev); - - list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) { - ret = device_unbind(pos); - if (ret && !saved_ret) - saved_ret = ret; - } - - return saved_ret; -} - -/** - * device_chld_remove() - Stop all device's children - * @dev: The device whose children are to be removed - * @return 0 on success, -ve on error - */ -static int device_chld_remove(struct udevice *dev) -{ - struct udevice *pos, *n; - int ret; - - assert(dev); - - list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) { - ret = device_remove(pos); - if (ret) - return ret; - } - - return 0; -} - int device_bind(struct udevice *parent, struct driver *drv, const char *name, void *platdata, int of_offset, struct udevice **devp) { @@ -167,71 +121,6 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only, -1, devp); } -int device_unbind(struct udevice *dev) -{ - struct driver *drv; - int ret; - - if (!dev) - return -EINVAL; - - if (dev->flags & DM_FLAG_ACTIVATED) - return -EINVAL; - - drv = dev->driver; - assert(drv); - - if (drv->unbind) { - ret = drv->unbind(dev); - if (ret) - return ret; - } - - ret = device_chld_unbind(dev); - if (ret) - return ret; - - ret = uclass_unbind_device(dev); - if (ret) - return ret; - - if (dev->parent) - list_del(&dev->sibling_node); - free(dev); - - return 0; -} - -/** - * device_free() - Free memory buffers allocated by a device - * @dev: Device that is to be started - */ -static void device_free(struct udevice *dev) -{ - int size; - - if (dev->driver->priv_auto_alloc_size) { - free(dev->priv); - dev->priv = NULL; - } - if (dev->flags & DM_FLAG_ALLOC_PDATA) { - free(dev->platdata); - dev->platdata = NULL; - } - size = dev->uclass->uc_drv->per_device_auto_alloc_size; - if (size) { - free(dev->uclass_priv); - dev->uclass_priv = NULL; - } - if (dev->parent) { - size = dev->parent->driver->per_child_auto_alloc_size; - if (size) { - free(dev->parent_priv); - dev->parent_priv = NULL; - } - } -} - int device_probe_child(struct udevice *dev, void *parent_priv) { struct driver *drv; @@ -342,63 +231,6 @@ int device_probe(struct udevice *dev) return device_probe_child(dev, NULL); } -int device_remove(struct udevice *dev) -{ - struct driver *drv; - int ret; - - if (!dev) - return -EINVAL; - - if (!(dev->flags & DM_FLAG_ACTIVATED)) - return 0; - - drv = dev->driver; - assert(drv); - - ret = uclass_pre_remove_device(dev); - if (ret) - return ret; - - ret = device_chld_remove(dev); - if (ret) - goto err; - - if (drv->remove) { - ret = drv->remove(dev); - if (ret) - goto err_remove; - } - - if (dev->parent && dev->parent->driver->child_post_remove) { - ret = dev->parent->driver->child_post_remove(dev); - if (ret) { - dm_warn("%s: Device '%s' failed child_post_remove()", - __func__, dev->name); - } - } - - device_free(dev); - - dev->seq = -1; - dev->flags &= ~DM_FLAG_ACTIVATED; - - return ret; - -err_remove: - /* We can't put the children back */ - dm_warn("%s: Device '%s' failed to remove, but children are gone\n", - __func__, dev->name); -err: - ret = uclass_post_probe_device(dev); - if (ret) { - dm_warn("%s: Device '%s' failed to post_probe on error path\n", - __func__, dev->name); - } - - return ret; -} - void *dev_get_platdata(struct udevice *dev) { if (!dev) { diff --git a/include/config_defaults.h b/include/config_defaults.h index ad08c1d..985f055 100644 --- a/include/config_defaults.h +++ b/include/config_defaults.h @@ -20,4 +20,8 @@ #define CONFIG_ZLIB 1 #define CONFIG_PARTITIONS 1 +#ifndef CONFIG_SPL_BUILD +#define CONFIG_DM_DEVICE_REMOVE +#endif + #endif diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h index 44cb7ef..f0cc794 100644 --- a/include/dm/device-internal.h +++ b/include/dm/device-internal.h @@ -87,7 +87,11 @@ int device_probe_child(struct udevice *dev, void *parent_priv); * @dev: Pointer to device to remove * @return 0 if OK, -ve on error (an error here is normally a very bad thing) */ +#ifdef CONFIG_DM_DEVICE_REMOVE int device_remove(struct udevice *dev); +#else +static inline int device_remove(struct udevice *dev) { return 0; } +#endif /** * device_unbind() - Unbind a device, destroying it @@ -99,6 +103,12 @@ int device_remove(struct udevice *dev); */ int device_unbind(struct udevice *dev); +#ifdef CONFIG_DM_DEVICE_REMOVE +void device_free(struct udevice *dev); +#else +static inline void device_free(struct udevice *dev) {} +#endif + /* Cast away any volatile pointer */ #define DM_ROOT_NON_CONST (((gd_t *)gd)->dm_root) #define DM_UCLASS_ROOT_NON_CONST (((gd_t *)gd)->uclass_root)