dm: core: Add flags parameter to device_remove()
This patch adds the flags parameter to device_remove() and changes all
calls to this function to provide the default value of DM_REMOVE_NORMAL
for "normal" device removal.
This is in preparation for the driver specific pre-OS (e.g. DMA
cancelling) remove support.
Signed-off-by: Stefan Roese <sr@denx.de>
Cc: Simon Glass <sjg@chromium.org>
Acked-by: Simon Glass <sjg@chromium.org>
diff --git a/arch/x86/cpu/queensbay/tnc.c b/arch/x86/cpu/queensbay/tnc.c
index f307c62..94668a4 100644
--- a/arch/x86/cpu/queensbay/tnc.c
+++ b/arch/x86/cpu/queensbay/tnc.c
@@ -76,13 +76,13 @@
*
* So the only option we have is to manually remove these two devices.
*/
- ret = device_remove(igd);
+ ret = device_remove(igd, DM_REMOVE_NORMAL);
if (ret)
return ret;
ret = device_unbind(igd);
if (ret)
return ret;
- ret = device_remove(sdvo);
+ ret = device_remove(sdvo, DM_REMOVE_NORMAL);
if (ret)
return ret;
ret = device_unbind(sdvo);
diff --git a/cmd/cros_ec.c b/cmd/cros_ec.c
index 9d42f87..af0b4ee 100644
--- a/cmd/cros_ec.c
+++ b/cmd/cros_ec.c
@@ -110,7 +110,7 @@
/* Remove any existing device */
ret = uclass_find_device(UCLASS_CROS_EC, 0, &udev);
if (!ret)
- device_remove(udev);
+ device_remove(udev, DM_REMOVE_NORMAL);
ret = uclass_get_device(UCLASS_CROS_EC, 0, &udev);
if (ret) {
printf("Could not init cros_ec device (err %d)\n", ret);
diff --git a/cmd/sf.c b/cmd/sf.c
index 65b117f..f971eec 100644
--- a/cmd/sf.c
+++ b/cmd/sf.c
@@ -124,7 +124,7 @@
/* Remove the old device, otherwise probe will just be a nop */
ret = spi_find_bus_and_cs(bus, cs, &bus_dev, &new);
if (!ret) {
- device_remove(new);
+ device_remove(new, DM_REMOVE_NORMAL);
}
flash = NULL;
ret = spi_flash_probe_bus_cs(bus, cs, speed, mode, &new);
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c
index 38cb938..af3c35f 100644
--- a/drivers/block/blk-uclass.c
+++ b/drivers/block/blk-uclass.c
@@ -530,7 +530,7 @@
struct blk_desc *desc = dev_get_uclass_platdata(dev);
if (desc->if_type == if_type) {
- ret = device_remove(dev);
+ ret = device_remove(dev, DM_REMOVE_NORMAL);
if (ret)
return ret;
ret = device_unbind(dev);
diff --git a/drivers/block/sandbox.c b/drivers/block/sandbox.c
index 36c2ff3..34d1c63 100644
--- a/drivers/block/sandbox.c
+++ b/drivers/block/sandbox.c
@@ -98,7 +98,7 @@
/* Remove and unbind the old device, if any */
ret = blk_get_device(IF_TYPE_HOST, devnum, &dev);
if (ret == 0) {
- ret = device_remove(dev);
+ ret = device_remove(dev, DM_REMOVE_NORMAL);
if (ret)
return ret;
ret = device_unbind(dev);
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index a7f77b4..b80bf52 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -46,9 +46,10 @@
/**
* device_chld_remove() - Stop all device's children
* @dev: The device whose children are to be removed
+ * @pre_os_remove: Flag, if this functions is called in the pre-OS stage
* @return 0 on success, -ve on error
*/
-static int device_chld_remove(struct udevice *dev)
+static int device_chld_remove(struct udevice *dev, uint flags)
{
struct udevice *pos, *n;
int ret;
@@ -56,7 +57,7 @@
assert(dev);
list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
- ret = device_remove(pos);
+ ret = device_remove(pos, flags);
if (ret)
return ret;
}
@@ -151,7 +152,7 @@
devres_release_probe(dev);
}
-int device_remove(struct udevice *dev)
+int device_remove(struct udevice *dev, uint flags)
{
const struct driver *drv;
int ret;
@@ -169,7 +170,7 @@
if (ret)
return ret;
- ret = device_chld_remove(dev);
+ ret = device_chld_remove(dev, flags);
if (ret)
goto err;
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 70fcfc2..e1b0ebf 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -378,7 +378,7 @@
return 0;
fail_uclass:
- if (device_remove(dev)) {
+ if (device_remove(dev, DM_REMOVE_NORMAL)) {
dm_warn("%s: Device '%s' failed to remove on error path\n",
__func__, dev->name);
}
diff --git a/drivers/core/root.c b/drivers/core/root.c
index 33cfde6..d8c51fb 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -178,7 +178,7 @@
int dm_uninit(void)
{
- device_remove(dm_root());
+ device_remove(dm_root(), DM_REMOVE_NORMAL);
device_unbind(dm_root());
return 0;
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 7de3706..d94d43a 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -116,7 +116,7 @@
while (!list_empty(&uc->dev_head)) {
dev = list_first_entry(&uc->dev_head, struct udevice,
uclass_node);
- ret = device_remove(dev);
+ ret = device_remove(dev, DM_REMOVE_NORMAL);
if (ret)
return ret;
ret = device_unbind(dev);
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c
index 5bb446b..9c07871 100644
--- a/drivers/mmc/mmc-uclass.c
+++ b/drivers/mmc/mmc-uclass.c
@@ -232,7 +232,7 @@
device_find_first_child(dev, &bdev);
if (bdev) {
- device_remove(bdev);
+ device_remove(bdev, DM_REMOVE_NORMAL);
device_unbind(bdev);
}
diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c
index 36a50fe..a53f4eb 100644
--- a/drivers/mtd/spi/sandbox.c
+++ b/drivers/mtd/spi/sandbox.c
@@ -595,7 +595,7 @@
struct udevice *dev;
dev = state->spi[busnum][cs].emul;
- device_remove(dev);
+ device_remove(dev, DM_REMOVE_NORMAL);
device_unbind(dev);
state->spi[busnum][cs].emul = NULL;
}
diff --git a/drivers/mtd/spi/sf-uclass.c b/drivers/mtd/spi/sf-uclass.c
index 19de964..8387648 100644
--- a/drivers/mtd/spi/sf-uclass.c
+++ b/drivers/mtd/spi/sf-uclass.c
@@ -46,7 +46,7 @@
void spi_flash_free(struct spi_flash *flash)
{
- device_remove(flash->spi->dev);
+ device_remove(flash->spi->dev, DM_REMOVE_NORMAL);
}
int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs,
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index ac17da0..c061c05 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -343,7 +343,7 @@
debug("%s: Error path, created=%d, device '%s'\n", __func__,
created, dev->name);
if (created) {
- device_remove(dev);
+ device_remove(dev, DM_REMOVE_NORMAL);
device_unbind(dev);
}
@@ -384,7 +384,7 @@
void spi_free_slave(struct spi_slave *slave)
{
- device_remove(slave->dev);
+ device_remove(slave->dev, DM_REMOVE_NORMAL);
slave->dev = NULL;
}
diff --git a/drivers/usb/emul/sandbox_hub.c b/drivers/usb/emul/sandbox_hub.c
index c3a8e73..f0939b1 100644
--- a/drivers/usb/emul/sandbox_hub.c
+++ b/drivers/usb/emul/sandbox_hub.c
@@ -156,7 +156,7 @@
} else if (clear & USB_PORT_STAT_POWER) {
debug("%s: %s: power off, removed, ret=%d\n",
__func__, dev->name, ret);
- ret = device_remove(dev);
+ ret = device_remove(dev, DM_REMOVE_NORMAL);
clear |= USB_PORT_STAT_CONNECTION;
}
}
diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c
index 5cf1e9a..6eded4a 100644
--- a/drivers/usb/host/usb-uclass.c
+++ b/drivers/usb/host/usb-uclass.c
@@ -154,7 +154,7 @@
uc_priv = uc->priv;
uclass_foreach_dev(bus, uc) {
- ret = device_remove(bus);
+ ret = device_remove(bus, DM_REMOVE_NORMAL);
if (ret && !err)
err = ret;
}
@@ -358,7 +358,7 @@
ret = uclass_find_device_by_seq(UCLASS_USB, 0, true, &dev);
if (ret)
return ret;
- ret = device_remove(dev);
+ ret = device_remove(dev, DM_REMOVE_NORMAL);
if (ret)
return ret;
diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h
index 0bf8707..2cabc87 100644
--- a/include/dm/device-internal.h
+++ b/include/dm/device-internal.h
@@ -96,12 +96,13 @@
* children are deactivated first.
*
* @dev: Pointer to device to remove
+ * @flags: Flags for selective device removal
* @return 0 if OK, -ve on error (an error here is normally a very bad thing)
*/
#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
-int device_remove(struct udevice *dev);
+int device_remove(struct udevice *dev, uint flags);
#else
-static inline int device_remove(struct udevice *dev) { return 0; }
+static inline int device_remove(struct udevice *dev, uint flags) { return 0; }
#endif
/**
diff --git a/include/dm/device.h b/include/dm/device.h
index 4e95fb7..079ec57 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -46,6 +46,32 @@
#define DM_FLAG_OF_PLATDATA (1 << 8)
+/*
+ * Call driver remove function to stop currently active DMA transfers or
+ * give DMA buffers back to the HW / controller. This may be needed for
+ * some drivers to do some final stage cleanup before the OS is called
+ * (U-Boot exit)
+ */
+#define DM_FLAG_ACTIVE_DMA (1 << 9)
+
+/*
+ * 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
+ * driver flags can be done.
+ */
+enum {
+ /* Normal remove, remove all devices */
+ DM_REMOVE_NORMAL = 1 << 0,
+
+ /* Remove devices with active DMA */
+ DM_REMOVE_ACTIVE_DMA = DM_FLAG_ACTIVE_DMA,
+
+ /* Add more use cases here */
+
+ /* Remove devices with any active flag */
+ DM_REMOVE_ACTIVE_ALL = DM_REMOVE_ACTIVE_DMA,
+};
+
/**
* struct udevice - An instance of a driver
*
diff --git a/test/dm/bus.c b/test/dm/bus.c
index d94dcf7..6a27735 100644
--- a/test/dm/bus.c
+++ b/test/dm/bus.c
@@ -222,7 +222,7 @@
/* Check that it starts at 0 and goes away when device is removed */
parent_data->sum += 5;
ut_asserteq(5, parent_data->sum);
- device_remove(dev);
+ device_remove(dev, DM_REMOVE_NORMAL);
ut_asserteq_ptr(NULL, dev_get_parent_priv(dev));
/* Check that we can do this twice */
@@ -323,7 +323,7 @@
continue;
parent_data = dev_get_parent_priv(dev);
ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag);
- ut_assertok(device_remove(dev));
+ ut_assertok(device_remove(dev, DM_REMOVE_NORMAL));
ut_asserteq_ptr(NULL, dev_get_parent_priv(dev));
ut_asserteq_ptr(dms->removed, dev);
}
@@ -360,7 +360,7 @@
plat->count++;
ut_asserteq(1, plat->count);
device_probe(dev);
- device_remove(dev);
+ device_remove(dev, DM_REMOVE_NORMAL);
ut_asserteq_ptr(plat, dev_get_parent_platdata(dev));
ut_asserteq(1, plat->count);
@@ -370,7 +370,7 @@
ut_asserteq(3, child_count);
/* Removing the bus should also have no effect (it is still bound) */
- device_remove(bus);
+ device_remove(bus, DM_REMOVE_NORMAL);
for (device_find_first_child(bus, &dev), child_count = 0;
dev;
device_find_next_child(&dev)) {
diff --git a/test/dm/core.c b/test/dm/core.c
index 70bf4d0..07b2419 100644
--- a/test/dm/core.c
+++ b/test/dm/core.c
@@ -319,7 +319,7 @@
/* Now remove device 3 */
ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_PRE_REMOVE]);
- ut_assertok(device_remove(dev));
+ ut_assertok(device_remove(dev, DM_REMOVE_NORMAL));
ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_PRE_REMOVE]);
ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_UNBIND]);
@@ -352,7 +352,7 @@
ut_assert(dev_last);
/* Now remove device 3 */
- ut_assertok(device_remove(dev));
+ ut_assertok(device_remove(dev, DM_REMOVE_NORMAL));
ut_assertok(device_unbind(dev));
/* The device numbering should have shifted down one */
@@ -371,9 +371,9 @@
ut_assert(pingret == 102);
/* Remove 3 and 4 */
- ut_assertok(device_remove(dev_penultimate));
+ ut_assertok(device_remove(dev_penultimate, DM_REMOVE_NORMAL));
ut_assertok(device_unbind(dev_penultimate));
- ut_assertok(device_remove(dev_last));
+ ut_assertok(device_remove(dev_last, DM_REMOVE_NORMAL));
ut_assertok(device_unbind(dev_last));
/* Our device should now be in position 3 */
@@ -381,7 +381,7 @@
ut_assert(dev == test_dev);
/* Now remove device 3 */
- ut_assertok(device_remove(dev));
+ ut_assertok(device_remove(dev, DM_REMOVE_NORMAL));
ut_assertok(device_unbind(dev));
return 0;
@@ -457,7 +457,7 @@
ut_assert(dev);
ut_assertf(dev->flags & DM_FLAG_ACTIVATED,
"Driver %d/%s not activated", i, dev->name);
- ut_assertok(device_remove(dev));
+ ut_assertok(device_remove(dev, DM_REMOVE_NORMAL));
ut_assertf(!(dev->flags & DM_FLAG_ACTIVATED),
"Driver %d/%s should have deactivated", i,
dev->name);
@@ -611,14 +611,14 @@
ut_asserteq(total, dm_testdrv_op_count[DM_TEST_OP_PROBE]);
/* Remove a top-level child and check that the children are removed */
- ut_assertok(device_remove(top[2]));
+ ut_assertok(device_remove(top[2], DM_REMOVE_NORMAL));
ut_asserteq(NODE_COUNT + 1, dm_testdrv_op_count[DM_TEST_OP_REMOVE]);
dm_testdrv_op_count[DM_TEST_OP_REMOVE] = 0;
/* Try one with grandchildren */
ut_assertok(uclass_get_device(UCLASS_TEST, 5, &dev));
ut_asserteq_ptr(dev, top[5]);
- ut_assertok(device_remove(dev));
+ ut_assertok(device_remove(dev, DM_REMOVE_NORMAL));
ut_asserteq(1 + NODE_COUNT * (1 + NODE_COUNT),
dm_testdrv_op_count[DM_TEST_OP_REMOVE]);
diff --git a/test/dm/eth.c b/test/dm/eth.c
index 6288ae2..564ad36 100644
--- a/test/dm/eth.c
+++ b/test/dm/eth.c
@@ -116,7 +116,7 @@
for (i = 0; i < DM_TEST_ETH_NUM; i++) {
ut_assertok(uclass_find_device_by_name(UCLASS_ETH,
ethname[i], &dev[i]));
- ut_assertok(device_remove(dev[i]));
+ ut_assertok(device_remove(dev[i], DM_REMOVE_NORMAL));
/* Invalidate MAC address */
strcpy(ethaddr[i], getenv(addrname[i]));
diff --git a/test/dm/spi.c b/test/dm/spi.c
index f52cb73..24fa2a4 100644
--- a/test/dm/spi.c
+++ b/test/dm/spi.c
@@ -36,7 +36,7 @@
ut_asserteq(0, uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus));
ut_assertok(spi_cs_info(bus, cs, &info));
of_offset = dev_of_offset(info.dev);
- device_remove(info.dev);
+ device_remove(info.dev, DM_REMOVE_NORMAL);
device_unbind(info.dev);
/*