dm: Allow device removal features to be dropped
authorSimon Glass <sjg@chromium.org>
Tue, 11 Nov 2014 00:16:47 +0000 (17:16 -0700)
committerSimon Glass <sjg@chromium.org>
Fri, 21 Nov 2014 07:13:02 +0000 (08:13 +0100)
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 <sjg@chromium.org>
Reviewed-by: Tom Rini <trini@ti.com>
drivers/core/Makefile
drivers/core/device-remove.c [new file with mode: 0644]
drivers/core/device.c
include/config_defaults.h
include/dm/device-internal.h

index 151c2398a4d47fce304d43a6ae775befd379baa2..f14695b2d6eae985d366827d69bcedda1ce1e2ce 100644 (file)
@@ -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 (file)
index 0000000..8fc6b71
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Device manager
+ *
+ * Copyright (c) 2014 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <dm/device.h>
+#include <dm/device-internal.h>
+#include <dm/uclass.h>
+#include <dm/uclass-internal.h>
+#include <dm/util.h>
+
+/**
+ * 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;
+}
index 49faa29dc1a0eecaa84e76371b8301c2eef14d7b..576a4f253b8196072019b203bf6c92de338acbf3 100644 (file)
 
 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) {
index ad08c1d335d3ba29fd75dcab99f948a5c6a7e278..985f055ccefb0651f857a7b3cbf080f25ef990c3 100644 (file)
@@ -20,4 +20,8 @@
 #define CONFIG_ZLIB 1
 #define CONFIG_PARTITIONS 1
 
+#ifndef CONFIG_SPL_BUILD
+#define CONFIG_DM_DEVICE_REMOVE
+#endif
+
 #endif
index 44cb7ef93bfdeea682ea0602d33bf9615260ad9d..f0cc7947505176907677840bd47554b8a22973c6 100644 (file)
@@ -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)