[PATCH v5 15/15] dm: core: Do not stop uclass iteration on error
Simon Glass
sjg at chromium.org
Thu Sep 29 12:00:53 CEST 2022
On Tue, 27 Sept 2022 at 15:38, Michal Suchanek <msuchanek at suse.de> wrote:
>
> When probing a device fails NULL pointer is returned, and following
> devices in uclass list cannot be iterated. Skip to next device on error
> instead.
>
> With that the only condition under which these simple iteration
> functions return error is when the dm is not initialized at uclass_get
> time. This is not all that interesting, change return type to void.
>
> Fixes: 6494d708bf ("dm: Add base driver model support")
> Signed-off-by: Michal Suchanek <msuchanek at suse.de>
> ---
> v2: - Fix up tests
> v3: - Fix up API doc
> - Correctly forward error from uclass_get
> - Do not return an error when last device fails to probe
> - Drop redundant initialization
> - Wrap at 80 columns
> v4: - change return value to void
> - further simplify iteration
> ---
> drivers/core/uclass.c | 30 ++++++++++++++++++------------
> include/dm/uclass.h | 13 ++++++-------
> test/dm/core.c | 10 ++++------
> test/dm/test-fdt.c | 27 ++++++++++++++++++++-------
> 4 files changed, 48 insertions(+), 32 deletions(-)
>
Reviewed-by: Simon Glass <sjg at chromium.org>
> diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
> index b7d11bdd23..6dec6a3973 100644
> --- a/drivers/core/uclass.c
> +++ b/drivers/core/uclass.c
> @@ -574,28 +574,34 @@ int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent,
> }
> #endif
>
> -int uclass_first_device(enum uclass_id id, struct udevice **devp)
> +/*
> + * Starting from the given device return first device in the uclass that
device, return the first
> + * probes successfully.
Please describe the args here.
> + */
> +static void _uclass_next_device(struct udevice *dev, struct udevice **devp)
> +{
> + for (; dev; uclass_find_next_device(&dev)) {
> + if (!device_probe(dev))
> + break;
> + }
> + *devp = dev;
> +}
> +
> +void uclass_first_device(enum uclass_id id, struct udevice **devp)
> {
> struct udevice *dev;
> int ret;
>
> - *devp = NULL;
> ret = uclass_find_first_device(id, &dev);
> - if (!dev)
> - return 0;
> - return uclass_get_device_tail(dev, ret, devp);
> + _uclass_next_device(dev, devp);
> }
>
> -int uclass_next_device(struct udevice **devp)
> +void uclass_next_device(struct udevice **devp)
> {
> struct udevice *dev = *devp;
> - int ret;
>
> - *devp = NULL;
> - ret = uclass_find_next_device(&dev);
> - if (!dev)
> - return 0;
> - return uclass_get_device_tail(dev, ret, devp);
> + uclass_find_next_device(&dev);
> + _uclass_next_device(dev, devp);
> }
>
> int uclass_first_device_err(enum uclass_id id, struct udevice **devp)
> diff --git a/include/dm/uclass.h b/include/dm/uclass.h
> index b1c016ef9f..ee15c92063 100644
> --- a/include/dm/uclass.h
> +++ b/include/dm/uclass.h
> @@ -320,32 +320,31 @@ int uclass_get_device_by_driver(enum uclass_id id, const struct driver *drv,
> * uclass_first_device() - Get the first device in a uclass
> *
> * The device returned is probed if necessary, and ready for use
> + * Devices that fail to probe are skipped
> *
> * This function is useful to start iterating through a list of devices which
> * are functioning correctly and can be probed.
> *
> * @id: Uclass ID to look up
> * @devp: Returns pointer to the first device in that uclass if no error
> - * occurred, or NULL if there is no first device, or an error occurred with
> - * that device.
> - * Return: 0 if OK (found or not found), other -ve on error
> + * occurred, or NULL if there is no usable device
> */
> -int uclass_first_device(enum uclass_id id, struct udevice **devp);
> +void uclass_first_device(enum uclass_id id, struct udevice **devp);
>
> /**
> * uclass_next_device() - Get the next device in a uclass
> *
> * The device returned is probed if necessary, and ready for use
> + * Devices that fail to probe are skipped
> *
> * This function is useful to iterate through a list of devices which
> * are functioning correctly and can be probed.
> *
> * @devp: On entry, pointer to device to lookup. On exit, returns pointer
> * to the next device in the uclass if no error occurred, or NULL if there is
> - * no next device, or an error occurred with that next device.
> - * Return: 0 if OK (found or not found), other -ve on error
> + * no next device
> */
> -int uclass_next_device(struct udevice **devp);
> +void uclass_next_device(struct udevice **devp);
>
> /**
> * uclass_first_device_err() - Get the first device in a uclass
> diff --git a/test/dm/core.c b/test/dm/core.c
> index 84eb76ed5f..7f3f8d183b 100644
> --- a/test/dm/core.c
> +++ b/test/dm/core.c
> @@ -1078,11 +1078,10 @@ static int dm_test_uclass_devices_get(struct unit_test_state *uts)
> struct udevice *dev;
> int ret;
>
> - for (ret = uclass_first_device(UCLASS_TEST, &dev);
> + for (ret = uclass_first_device_check(UCLASS_TEST, &dev);
> dev;
> - ret = uclass_next_device(&dev)) {
> + ret = uclass_next_device_check(&dev)) {
> ut_assert(!ret);
> - ut_assert(dev);
> ut_assert(device_active(dev));
> }
>
> @@ -1112,11 +1111,10 @@ static int dm_test_uclass_devices_get_by_name(struct unit_test_state *uts)
> * this will fail on checking condition: testdev == finddev, since the
> * uclass_get_device_by_name(), returns the first device by given name.
> */
> - for (ret = uclass_first_device(UCLASS_TEST_FDT, &testdev);
> + for (ret = uclass_first_device_check(UCLASS_TEST_FDT, &testdev);
> testdev;
> - ret = uclass_next_device(&testdev)) {
> + ret = uclass_next_device_check(&testdev)) {
> ut_assertok(ret);
> - ut_assert(testdev);
> ut_assert(device_active(testdev));
>
> findret = uclass_get_device_by_name(UCLASS_TEST_FDT,
> diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
> index 6118ad42ca..7cbc595c51 100644
> --- a/test/dm/test-fdt.c
> +++ b/test/dm/test-fdt.c
> @@ -403,13 +403,12 @@ static int dm_test_first_next_device(struct unit_test_state *uts)
> int ret;
>
> /* There should be 4 devices */
> - for (ret = uclass_first_device(UCLASS_TEST_PROBE, &dev), count = 0;
> + for (uclass_first_device(UCLASS_TEST_PROBE, &dev), count = 0;
> dev;
> - ret = uclass_next_device(&dev)) {
> + uclass_next_device(&dev)) {
> count++;
> parent = dev_get_parent(dev);
> }
> - ut_assertok(ret);
> ut_asserteq(4, count);
>
> /* Remove them and try again, with an error on the second one */
> @@ -417,16 +416,30 @@ static int dm_test_first_next_device(struct unit_test_state *uts)
> pdata = dev_get_plat(dev);
> pdata->probe_err = -ENOMEM;
> device_remove(parent, DM_REMOVE_NORMAL);
> - ut_assertok(uclass_first_device(UCLASS_TEST_PROBE, &dev));
> - ut_asserteq(-ENOMEM, uclass_next_device(&dev));
> - ut_asserteq_ptr(dev, NULL);
> + for (ret = uclass_first_device_check(UCLASS_TEST_PROBE, &dev),
> + count = 0;
> + dev;
> + ret = uclass_next_device_check(&dev)) {
> + if (!ret)
> + count++;
> + else
> + ut_asserteq(-ENOMEM, ret);
> + parent = dev_get_parent(dev);
> + }
> + ut_asserteq(3, count);
>
> /* Now an error on the first one */
> ut_assertok(uclass_get_device(UCLASS_TEST_PROBE, 0, &dev));
> pdata = dev_get_plat(dev);
> pdata->probe_err = -ENOENT;
> device_remove(parent, DM_REMOVE_NORMAL);
> - ut_asserteq(-ENOENT, uclass_first_device(UCLASS_TEST_PROBE, &dev));
> + for (uclass_first_device(UCLASS_TEST_PROBE, &dev), count = 0;
> + dev;
> + uclass_next_device(&dev)) {
> + count++;
> + parent = dev_get_parent(dev);
> + }
> + ut_asserteq(2, count);
>
> return 0;
> }
> --
> 2.37.3
>
More information about the U-Boot
mailing list