summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2021-10-24 02:26:05 +0300
committerSimon Glass <sjg@chromium.org>2021-11-29 02:51:51 +0300
commit804431830593820575158aa5c4b098aab59efc88 (patch)
tree8baf7751a924db68b550a409276bde47f7a95ce4
parentfb933d070eb00274bb7e041cae98e858208961e2 (diff)
downloadu-boot-804431830593820575158aa5c4b098aab59efc88.tar.xz
dm: core: Fix handling of uclass pre_unbind method
This method is currently called after the platform data has been freed. But the pre_unbind() method may wish to access this, e.g. to free some data structures stored there. Split the unbinding of devices into two pieces, as is done with removal. This corrects the problem. Also tidy a code-style issue in device_remove() while we are here. Signed-off-by: Simon Glass <sjg@chromium.org>
-rw-r--r--drivers/core/device-remove.c9
-rw-r--r--drivers/core/uclass.c8
-rw-r--r--include/dm/uclass-internal.h14
3 files changed, 25 insertions, 6 deletions
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index 11d3959d20..69c50da44a 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -95,6 +95,9 @@ int device_unbind(struct udevice *dev)
if (ret)
return log_msg_ret("child unbind", ret);
+ ret = uclass_pre_unbind_device(dev);
+ if (ret)
+ return log_msg_ret("uc", ret);
if (dev_get_flags(dev) & DM_FLAG_ALLOC_PDATA) {
free(dev_get_plat(dev));
dev_set_plat(dev, NULL);
@@ -142,10 +145,8 @@ void device_free(struct udevice *dev)
}
if (dev->parent) {
size = dev->parent->driver->per_child_auto;
- if (!size) {
- size = dev->parent->uclass->uc_drv->
- per_child_auto;
- }
+ if (!size)
+ size = dev->parent->uclass->uc_drv->per_child_auto;
if (size) {
free(dev_get_parent_priv(dev));
dev_set_parent_priv(dev, NULL);
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index c5a50952fd..2fede896bf 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -682,7 +682,7 @@ err:
}
#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
-int uclass_unbind_device(struct udevice *dev)
+int uclass_pre_unbind_device(struct udevice *dev)
{
struct uclass *uc;
int ret;
@@ -694,7 +694,13 @@ int uclass_unbind_device(struct udevice *dev)
return ret;
}
+ return 0;
+}
+
+int uclass_unbind_device(struct udevice *dev)
+{
list_del(&dev->uclass_node);
+
return 0;
}
#endif
diff --git a/include/dm/uclass-internal.h b/include/dm/uclass-internal.h
index 57c664c6da..49808c5c85 100644
--- a/include/dm/uclass-internal.h
+++ b/include/dm/uclass-internal.h
@@ -243,6 +243,17 @@ int uclass_find_device_by_phandle(enum uclass_id id, struct udevice *parent,
*/
int uclass_bind_device(struct udevice *dev);
+#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
+/**
+ * uclass_pre_unbind_device() - Prepare to deassociate device with a uclass
+ *
+ * Call any handled needed before uclass_unbind_device() is called
+ *
+ * @dev: Pointer to the device
+ * #return 0 on success, -ve on error
+ */
+int uclass_pre_unbind_device(struct udevice *dev);
+
/**
* uclass_unbind_device() - Deassociate device with a uclass
*
@@ -251,9 +262,10 @@ int uclass_bind_device(struct udevice *dev);
* @dev: Pointer to the device
* #return 0 on success, -ve on error
*/
-#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
int uclass_unbind_device(struct udevice *dev);
+
#else
+static inline int uclass_pre_unbind_device(struct udevice *dev) { return 0; }
static inline int uclass_unbind_device(struct udevice *dev) { return 0; }
#endif