[13/21] dm: core: Add a way to iterate through children, probing each
diff mbox series

Message ID 20200127084920.13.I307389a2de896b0eee9728fa4cb109f1b5379693@changeid
State Accepted
Commit 903e83ee84649c1a70bfd8b9ec84dacb8c24e7cb
Delegated to: Simon Glass
Headers show
Series
  • dm: Various enhancements to prepare for ACPI
Related show

Commit Message

Simon Glass Jan. 27, 2020, 3:49 p.m. UTC
It is sometimes useful to process all children, making sure they are
probed first. Add functions to help with this and a macro to make it more
convenient.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/core/device.c | 22 ++++++++++++++++++++++
 include/dm/device.h   | 39 +++++++++++++++++++++++++++++++++++++++
 test/dm/test-fdt.c    | 19 +++++++++++++++++++
 3 files changed, 80 insertions(+)

Comments

Simon Glass Feb. 5, 2020, 5:56 p.m. UTC | #1
It is sometimes useful to process all children, making sure they are
probed first. Add functions to help with this and a macro to make it more
convenient.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/core/device.c | 22 ++++++++++++++++++++++
 include/dm/device.h   | 39 +++++++++++++++++++++++++++++++++++++++
 test/dm/test-fdt.c    | 19 +++++++++++++++++++
 3 files changed, 80 insertions(+)

Applied to u-boot-dm, thanks!

Patch
diff mbox series

diff --git a/drivers/core/device.c b/drivers/core/device.c
index c948d8dbbc..89ea820d48 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -792,6 +792,28 @@  int device_find_child_by_name(const struct udevice *parent, const char *name,
 	return -ENODEV;
 }
 
+int device_first_child_err(struct udevice *parent, struct udevice **devp)
+{
+	struct udevice *dev;
+
+	device_find_first_child(parent, &dev);
+	if (!dev)
+		return -ENODEV;
+
+	return device_get_device_tail(dev, 0, devp);
+}
+
+int device_next_child_err(struct udevice **devp)
+{
+	struct udevice *dev = *devp;
+
+	device_find_next_child(&dev);
+	if (!dev)
+		return -ENODEV;
+
+	return device_get_device_tail(dev, 0, devp);
+}
+
 int device_first_child_ofdata_err(struct udevice *parent, struct udevice **devp)
 {
 	struct udevice *dev;
diff --git a/include/dm/device.h b/include/dm/device.h
index 2618952336..517ae7fc90 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -602,6 +602,28 @@  int device_first_child_ofdata_err(struct udevice *parent,
  */
 int device_next_child_ofdata_err(struct udevice **devp);
 
+/**
+ * device_first_child_err() - Get the first child of a device
+ *
+ * The device returned is probed if necessary, and ready for use
+ *
+ * @parent:	Parent device to search
+ * @devp:	Returns device found, if any
+ * @return 0 if found, -ENODEV if not, -ve error if device failed to probe
+ */
+int device_first_child_err(struct udevice *parent, struct udevice **devp);
+
+/**
+ * device_next_child_err() - Get the next child of a parent device
+ *
+ * The device returned is probed if necessary, and ready for use
+ *
+ * @devp: On entry, pointer to device to lookup. On exit, returns pointer
+ * to the next sibling if no error occurred
+ * @return 0 if found, -ENODEV if not, -ve error if device failed to probe
+ */
+int device_next_child_err(struct udevice **devp);
+
 /**
  * device_has_children() - check if a device has any children
  *
@@ -748,6 +770,23 @@  static inline bool device_is_on_pci_bus(const struct udevice *dev)
 	for (int _ret = device_first_child_ofdata_err(parent, &dev); !_ret; \
 	     _ret = device_next_child_ofdata_err(&dev))
 
+/**
+ * device_foreach_child_probe() - iterate through children, probing them
+ *
+ * This creates a for() loop which works through the available children of
+ * a device in order from start to end. Devices are probed if necessary,
+ * and ready for use.
+ *
+ * This stops when it gets an error, with @pos set to the device that failed to
+ * probe
+ *
+ * @pos: struct udevice * for the current device
+ * @parent: parent device to scan
+ */
+#define device_foreach_child_probe(pos, parent)	\
+	for (int _ret = device_first_child_err(parent, &dev); !_ret; \
+	     _ret = device_next_child_err(&dev))
+
 /**
  * dm_scan_fdt_dev() - Bind child device in a the device tree
  *
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index 8fe4425b21..cd65e42a88 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -891,3 +891,22 @@  static int dm_test_child_ofdata(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_child_ofdata, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test device_first_child_err(), etc. */
+static int dm_test_first_child_probe(struct unit_test_state *uts)
+{
+	struct udevice *bus, *dev;
+	int count;
+
+	ut_assertok(uclass_first_device_err(UCLASS_TEST_BUS, &bus));
+	count = 0;
+	device_foreach_child_probe(dev, bus) {
+		ut_assert(dev->flags & DM_FLAG_PLATDATA_VALID);
+		ut_assert(dev->flags & DM_FLAG_ACTIVATED);
+		count++;
+	}
+	ut_asserteq(3, count);
+
+	return 0;
+}
+DM_TEST(dm_test_first_child_probe, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);