From 58ddb937e1699de241e4aa39de90a68a0be71744 Mon Sep 17 00:00:00 2001 From: Michal Suchanek Date: Sun, 25 Sep 2022 13:08:16 +0200 Subject: dm: core: Switch uclass_*_device_err to use uclass_*_device_check Clarify documentation, fix a few more cases that could be broken by the change. Signed-off-by: Michal Suchanek --- include/dm/uclass.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'include/dm') diff --git a/include/dm/uclass.h b/include/dm/uclass.h index 823a16527f7..b1c016ef9f5 100644 --- a/include/dm/uclass.h +++ b/include/dm/uclass.h @@ -350,7 +350,8 @@ int uclass_next_device(struct udevice **devp); /** * uclass_first_device_err() - Get the first device in a uclass * - * The device returned is probed if necessary, and ready for use + * The device returned is probed if necessary, and ready for use if no error is + * returned * * @id: Uclass ID to look up * @devp: Returns pointer to the first device in that uclass, or NULL if none @@ -361,7 +362,8 @@ int uclass_first_device_err(enum uclass_id id, struct udevice **devp); /** * uclass_next_device_err() - Get the next device in a uclass * - * The device returned is probed if necessary, and ready for use + * The device returned is probed if necessary, and ready for use if no error is + * returned * * @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 @@ -373,7 +375,8 @@ int uclass_next_device_err(struct udevice **devp); /** * uclass_first_device_check() - Get the first device in a uclass * - * The device returned is probed if necessary, and ready for use + * The device returned is probed if necessary, and ready for use if no error is + * returned * * This function is useful to start iterating through a list of devices which * are functioning correctly and can be probed. @@ -389,7 +392,8 @@ int uclass_first_device_check(enum uclass_id id, struct udevice **devp); /** * uclass_next_device_check() - Get the next device in a uclass * - * The device returned is probed if necessary, and ready for use + * The device returned is probed if necessary, and ready for use if no error is + * returned * * This function is useful to start iterating through a list of devices which * are functioning correctly and can be probed. -- cgit v1.3.1 From 73f8fbc532c3546dd4bf6f267e530a82f04703fa Mon Sep 17 00:00:00 2001 From: Michal Suchanek Date: Tue, 27 Sep 2022 23:24:36 +0200 Subject: dm: core: Document return value of device bind functions These functions use device_bind_with_driver_data internally, copy the return value description. Signed-off-by: Michal Suchanek --- include/dm/lists.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/dm') diff --git a/include/dm/lists.h b/include/dm/lists.h index fc3b4ae5850..97236f8fa0d 100644 --- a/include/dm/lists.h +++ b/include/dm/lists.h @@ -73,6 +73,7 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp, * @drv_name: Name of driver to attach to this parent * @dev_name: Name of the new device thus created * @devp: If non-NULL, returns the newly bound device + * Return: 0 if OK, -ve on error */ int device_bind_driver(struct udevice *parent, const char *drv_name, const char *dev_name, struct udevice **devp); @@ -88,6 +89,7 @@ int device_bind_driver(struct udevice *parent, const char *drv_name, * @dev_name: Name of the new device thus created * @node: Device tree node * @devp: If non-NULL, returns the newly bound device + * Return: 0 if OK, -ve on error */ int device_bind_driver_to_node(struct udevice *parent, const char *drv_name, const char *dev_name, ofnode node, -- cgit v1.3.1 From aa5511e77b8bd8f943c66b6403896d06083b1d92 Mon Sep 17 00:00:00 2001 From: Michal Suchanek Date: Tue, 27 Sep 2022 23:25:08 +0200 Subject: dm: core: Add note about device_probe idempotence device_probe returns early when the device is already activated. Add a note to the documentation that it can be used on already activated devices. Signed-off-by: Michal Suchanek --- include/dm/device-internal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/dm') diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h index 94844d30d85..f31c4702086 100644 --- a/include/dm/device-internal.h +++ b/include/dm/device-internal.h @@ -184,8 +184,8 @@ int device_of_to_plat(struct udevice *dev); /** * device_probe() - Probe a device, activating it * - * Activate a device so that it is ready for use. All its parents are probed - * first. + * Activate a device (if not yet activated) so that it is ready for use. + * All its parents are probed first. * * @dev: Pointer to device to probe * Return: 0 if OK, -ve on error -- cgit v1.3.1 From f21954750aa8ed445ab83998bb099e366136c428 Mon Sep 17 00:00:00 2001 From: Michal Suchanek Date: Wed, 12 Oct 2022 21:58:09 +0200 Subject: dm: core: Do not stop uclass iteration on error 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 Reviewed-by: Simon Glass --- 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(-) (limited to 'include/dm') diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index b7d11bdd23a..1762a0796db 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 @dev, return pointer to the first device in + * the uclass that probes successfully in @devp. + */ +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 b1c016ef9f5..ee15c920633 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 84eb76ed5fc..7f3f8d183bc 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 1f14513d9f1..8bb868b6787 100644 --- a/test/dm/test-fdt.c +++ b/test/dm/test-fdt.c @@ -403,13 +403,12 @@ static int dm_test_first_next_device_probeall(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_probeall(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); /* Now that broken devices are set up test probe_all */ device_remove(parent, DM_REMOVE_NORMAL); -- cgit v1.3.1