dm: core: Add flags parameter to device_remove()
authorStefan Roese <sr@denx.de>
Mon, 20 Mar 2017 11:51:48 +0000 (12:51 +0100)
committerSimon Glass <sjg@chromium.org>
Wed, 5 Apr 2017 02:15:10 +0000 (20:15 -0600)
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>
21 files changed:
arch/x86/cpu/queensbay/tnc.c
cmd/cros_ec.c
cmd/sf.c
drivers/block/blk-uclass.c
drivers/block/sandbox.c
drivers/core/device-remove.c
drivers/core/device.c
drivers/core/root.c
drivers/core/uclass.c
drivers/mmc/mmc-uclass.c
drivers/mtd/spi/sandbox.c
drivers/mtd/spi/sf-uclass.c
drivers/spi/spi-uclass.c
drivers/usb/emul/sandbox_hub.c
drivers/usb/host/usb-uclass.c
include/dm/device-internal.h
include/dm/device.h
test/dm/bus.c
test/dm/core.c
test/dm/eth.c
test/dm/spi.c

index f307c622c8891472b0cef6371600a4fd50ad01b5..94668a4fda12a91dbdcb444a162635c7dedf73fc 100644 (file)
@@ -76,13 +76,13 @@ static int __maybe_unused disable_igd(void)
         *
         * 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);
index 9d42f870dc9a4e3ea61a7d267591a73a38b3135b..af0b4eee78388155e16be590a23ab8af5c10a83a 100644 (file)
@@ -110,7 +110,7 @@ static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
                /* 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);
index 65b117feee22c631cd7ef0f4d42570b52c15dea5..f971eec781cc88978f181a9a24ec9d37dff6b11d 100644 (file)
--- a/cmd/sf.c
+++ b/cmd/sf.c
@@ -124,7 +124,7 @@ static int do_spi_flash_probe(int argc, char * const argv[])
        /* 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);
index 38cb9388da6f19a0117d025fdef51de962a794e0..af3c35f6d0b5de9d1c8990c4bed9a326d4a241fc 100644 (file)
@@ -530,7 +530,7 @@ int blk_unbind_all(int if_type)
                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);
index 36c2ff30075e6432c363d79d6c7d83a8e868d2a6..34d1c638bc7788755f10b76154e513ae1ec3c806 100644 (file)
@@ -98,7 +98,7 @@ int host_dev_bind(int devnum, char *filename)
        /* 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);
index a7f77b4a21dc33efbdc62b2983de5fb970cd8979..b80bf52320e2ded743fe202939b06b11d209486f 100644 (file)
@@ -46,9 +46,10 @@ static int device_chld_unbind(struct udevice *dev)
 /**
  * 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 @@ static int device_chld_remove(struct udevice *dev)
        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 @@ void device_free(struct udevice *dev)
        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 @@ int device_remove(struct udevice *dev)
        if (ret)
                return ret;
 
-       ret = device_chld_remove(dev);
+       ret = device_chld_remove(dev, flags);
        if (ret)
                goto err;
 
index 70fcfc23e0cbceb78e3440e759f225f10932f474..e1b0ebffc559c9ddf52c86c68b4404eafe966dae 100644 (file)
@@ -378,7 +378,7 @@ int device_probe(struct udevice *dev)
 
        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);
        }
index 33cfde6a5c39332c7f0df70d16893bc78cf16ffb..d8c51fb496f10d2c6f7a2412093160b286da86d1 100644 (file)
@@ -178,7 +178,7 @@ int dm_init(void)
 
 int dm_uninit(void)
 {
-       device_remove(dm_root());
+       device_remove(dm_root(), DM_REMOVE_NORMAL);
        device_unbind(dm_root());
 
        return 0;
index 7de370644d72c6ff9232b9f1f6337495ae318aae..d94d43a98d2f8619d6a803029ee2e162fa1d1b24 100644 (file)
@@ -116,7 +116,7 @@ int uclass_destroy(struct uclass *uc)
        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);
index 5bb446bcc2a8ff91d42b73071828bdd43ce810ce..9c07871d3a2c7751a17b834dc9da8692b9a23c0f 100644 (file)
@@ -232,7 +232,7 @@ int mmc_unbind(struct udevice *dev)
 
        device_find_first_child(dev, &bdev);
        if (bdev) {
-               device_remove(bdev);
+               device_remove(bdev, DM_REMOVE_NORMAL);
                device_unbind(bdev);
        }
 
index 36a50fe3a15d9ebd393765cdaa5c7462c68681c7..a53f4ebc68d8588fc2013126bec5f0a71b75db41 100644 (file)
@@ -595,7 +595,7 @@ void sandbox_sf_unbind_emul(struct sandbox_state *state, int busnum, int cs)
        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;
 }
index 19de964e6121c53642d07a8c28b8afde8f9d137c..83876485fedec73fc717c343392113ae1dce171f 100644 (file)
@@ -46,7 +46,7 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
 
 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,
index ac17da0777d53a07769da1100e908960fe77405a..c061c05443d442e5a12759d5272b719c559133bb 100644 (file)
@@ -343,7 +343,7 @@ err:
        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 @@ struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs,
 
 void spi_free_slave(struct spi_slave *slave)
 {
-       device_remove(slave->dev);
+       device_remove(slave->dev, DM_REMOVE_NORMAL);
        slave->dev = NULL;
 }
 
index c3a8e73389d4afc3e38f7a561b5263568f6125de..f0939b19f484b2bbfac8e0db01bd5f8ce12e48e9 100644 (file)
@@ -156,7 +156,7 @@ static int clrset_post_state(struct udevice *hub, int port, int clear, int set)
                        } 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;
                        }
                }
index 5cf1e9a36cbc1deffddf40b41658317821744288..6eded4abad029ac11fea795628771ea9e7e40517 100644 (file)
@@ -154,7 +154,7 @@ int usb_stop(void)
        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 @@ int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp)
        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;
 
index 0bf8707493a9d3f6c3d0ce368e5a7b075c64edd9..2cabc87338fb97f6f8ff1ea993a902e39757405e 100644 (file)
@@ -96,12 +96,13 @@ int device_probe(struct udevice *dev);
  * 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
 
 /**
index 4e95fb7773d961cc1f9d20e1fe3b157d0209e431..079ec5700302657b16b9eb094e0ec609a95b6801 100644 (file)
@@ -46,6 +46,32 @@ struct driver_info;
 
 #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
  *
index d94dcf7a60d87988d9c50dae5f959c056a3777be..6a2773565ebcf846c92d02d8335bf6e83fa56150 100644 (file)
@@ -222,7 +222,7 @@ static int test_bus_parent_data(struct unit_test_state *uts)
        /* 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 @@ static int dm_test_bus_parent_ops(struct unit_test_state *uts)
                        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 @@ static int test_bus_parent_platdata(struct unit_test_state *uts)
                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 @@ static int test_bus_parent_platdata(struct unit_test_state *uts)
        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)) {
index 70bf4d0605a0fb4e8ddf73dbfe16837b884b8e49..07b2419ea4a3fe31c3cde2349ac57deec12a934e 100644 (file)
@@ -319,7 +319,7 @@ static int dm_test_lifecycle(struct unit_test_state *uts)
 
        /* 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 @@ static int dm_test_ordering(struct unit_test_state *uts)
        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 @@ static int dm_test_ordering(struct unit_test_state *uts)
        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 @@ static int dm_test_ordering(struct unit_test_state *uts)
        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 @@ static int dm_test_remove(struct unit_test_state *uts)
                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 @@ static int dm_test_children(struct unit_test_state *uts)
        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]);
 
index 6288ae24abb4467580bb5e1cbd1515c59a6f69b5..564ad36916016f241909fc90971e1cae91e4fe54 100644 (file)
@@ -116,7 +116,7 @@ static int dm_test_eth_act(struct unit_test_state *uts)
        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]));
index f52cb733c775f7f1f9661b6f245f1e5182c0c8a7..24fa2a48ae9c37b34bdfacb0fb2c8becbb13a46c 100644 (file)
@@ -36,7 +36,7 @@ static int dm_test_spi_find(struct unit_test_state *uts)
        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);
 
        /*