diff mbox series

[1/3,RFC] dm: core: Add late driver remove option

Message ID 20200426105157.24791-1-marek.vasut+renesas@gmail.com
State New
Headers show
Series [1/3,RFC] dm: core: Add late driver remove option | expand

Commit Message

Marek Vasut April 26, 2020, 10:51 a.m. UTC
Add another flag to the DM core which could be assigned to drivers and
which makes those drivers call their remove callbacks last, just before
booting OS and after all the other drivers finished with their remove
callbacks. This is necessary for things like clock drivers, where the
other drivers might depend on the clock driver in their remove callbacks.
Prime example is the mmc subsystem, which can reconfigure a card from HS
mode to slower modes in the remove callback and for that it needs to
reconfigure the controller clock.

Signed-off-by: Marek Vasut <marek.vasut+renesas at gmail.com>
Cc: Simon Glass <sjg at chromium.org>
Cc: Tom Rini <trini at konsulko.com>
---
 arch/arm/lib/bootm.c         |  1 +
 drivers/core/device-remove.c | 11 ++++++++---
 drivers/core/root.c          |  2 ++
 include/dm/device.h          |  4 ++++
 4 files changed, 15 insertions(+), 3 deletions(-)

Comments

Simon Glass April 27, 2020, 10:25 p.m. UTC | #1
Hi Marek,

On Sun, 26 Apr 2020 at 04:52, Marek Vasut <marek.vasut at gmail.com> wrote:
>
> Add another flag to the DM core which could be assigned to drivers and
> which makes those drivers call their remove callbacks last, just before
> booting OS and after all the other drivers finished with their remove
> callbacks. This is necessary for things like clock drivers, where the
> other drivers might depend on the clock driver in their remove callbacks.
> Prime example is the mmc subsystem, which can reconfigure a card from HS
> mode to slower modes in the remove callback and for that it needs to
> reconfigure the controller clock.
>
> Signed-off-by: Marek Vasut <marek.vasut+renesas at gmail.com>
> Cc: Simon Glass <sjg at chromium.org>
> Cc: Tom Rini <trini at konsulko.com>
> ---
>  arch/arm/lib/bootm.c         |  1 +
>  drivers/core/device-remove.c | 11 ++++++++---
>  drivers/core/root.c          |  2 ++
>  include/dm/device.h          |  4 ++++
>  4 files changed, 15 insertions(+), 3 deletions(-)

I think this solution is simpler than trying to track device
dependencies, something that driver model currently makes no attempt
to do.

It does need a test though.

Regards,
Simon
diff mbox series

Patch

diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c
index f4b5ca6de0..1d247128b7 100644
--- a/arch/arm/lib/bootm.c
+++ b/arch/arm/lib/bootm.c
@@ -116,6 +116,7 @@  static void announce_and_cleanup(int fake)
 	 * of DMA operation or releasing device internal buffers.
 	 */
 	dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
+	dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL | DM_REMOVE_LATE);
 
 	cleanup_before_linux();
 }
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index efdb0f2905..07b241b6bb 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -172,14 +172,19 @@  int device_remove(struct udevice *dev, uint flags)
 	drv = dev->driver;
 	assert(drv);
 
-	ret = uclass_pre_remove_device(dev);
-	if (ret)
-		return ret;
+	if (!(flags & DM_REMOVE_LATE)) {
+		ret = uclass_pre_remove_device(dev);
+		if (ret)
+			return ret;
+	}
 
 	ret = device_chld_remove(dev, NULL, flags);
 	if (ret)
 		goto err;
 
+	if (!(flags & DM_REMOVE_LATE) && (drv->flags & DM_FLAG_REMOVE_LATE))
+		return 0;
+
 	/*
 	 * Remove the device if called with the "normal" remove flag set,
 	 * or if the remove flag matches any of the drivers remove flags
diff --git a/drivers/core/root.c b/drivers/core/root.c
index 14df16c280..fcb1dfddf5 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -166,6 +166,7 @@  int dm_init(bool of_live)
 int dm_uninit(void)
 {
 	device_remove(dm_root(), DM_REMOVE_NORMAL);
+	device_remove(dm_root(), DM_REMOVE_LATE);
 	device_unbind(dm_root());
 	gd->dm_root = NULL;
 
@@ -376,6 +377,7 @@  int dm_init_and_scan(bool pre_reloc_only)
 U_BOOT_DRIVER(root_driver) = {
 	.name	= "root_driver",
 	.id	= UCLASS_ROOT,
+	.flags	= DM_FLAG_REMOVE_LATE,
 };
 
 /* This is the root uclass */
diff --git a/include/dm/device.h b/include/dm/device.h
index 975eec5d0e..e7c1c343fe 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -73,6 +73,8 @@  struct driver_info;
  */
 #define DM_FLAG_REMOVE_WITH_PD_ON	(1 << 13)
 
+#define DM_FLAG_REMOVE_LATE		(1 << 14)
+
 /*
  * One or multiple of these flags are passed to device_remove() so that
  * a selective device removal as specified by the remove-stage and the
@@ -95,6 +97,8 @@  enum {
 
 	/* Don't power down any attached power domains */
 	DM_REMOVE_NO_PD		= 1 << 1,
+
+	DM_REMOVE_LATE		= 1 << 2,
 };
 
 /**