dm: core: Allow uclass to set up a device's child before it is probed

Some buses need to set up their devices before they can be used. This setup
may well be common to all buses in a particular uclass. Support a common
pre-probe method for the uclass, called before any bus devices are probed.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Masahiro Yamada <yamada.m@jp.panasonic.com>
master
Simon Glass 10 years ago
parent 1603bf3cc1
commit 83c7e434c9
  1. 4
      drivers/core/device.c
  2. 13
      drivers/core/uclass.c
  3. 3
      include/dm/test.h
  4. 11
      include/dm/uclass-internal.h
  5. 1
      include/dm/uclass.h
  6. 46
      test/dm/bus.c
  7. 7
      test/dm/test-fdt.c

@ -227,6 +227,10 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
} }
dev->seq = seq; dev->seq = seq;
ret = uclass_pre_probe_child(dev);
if (ret)
goto fail;
if (dev->parent && dev->parent->driver->child_pre_probe) { if (dev->parent && dev->parent->driver->child_pre_probe) {
ret = dev->parent->driver->child_pre_probe(dev); ret = dev->parent->driver->child_pre_probe(dev);
if (ret) if (ret)

@ -391,6 +391,19 @@ int uclass_resolve_seq(struct udevice *dev)
return seq; return seq;
} }
int uclass_pre_probe_child(struct udevice *dev)
{
struct uclass_driver *uc_drv;
if (!dev->parent)
return 0;
uc_drv = dev->parent->uclass->uc_drv;
if (uc_drv->child_pre_probe)
return uc_drv->child_pre_probe(dev);
return 0;
}
int uclass_post_probe_device(struct udevice *dev) int uclass_post_probe_device(struct udevice *dev)
{ {
struct uclass_driver *uc_drv = dev->uclass->uc_drv; struct uclass_driver *uc_drv = dev->uclass->uc_drv;

@ -67,6 +67,8 @@ enum {
struct dm_test_priv { struct dm_test_priv {
int ping_total; int ping_total;
int op_count[DM_TEST_OP_COUNT]; int op_count[DM_TEST_OP_COUNT];
int uclass_flag;
int uclass_total;
}; };
/** /**
@ -88,6 +90,7 @@ struct dm_test_uclass_priv {
* *
* @sum: Test value used to check parent data works correctly * @sum: Test value used to check parent data works correctly
* @flag: Used to track calling of parent operations * @flag: Used to track calling of parent operations
* @uclass_flag: Used to track calling of parent operations by uclass
*/ */
struct dm_test_parent_data { struct dm_test_parent_data {
int sum; int sum;

@ -44,6 +44,17 @@ int uclass_bind_device(struct udevice *dev);
int uclass_unbind_device(struct udevice *dev); int uclass_unbind_device(struct udevice *dev);
/** /**
* uclass_pre_probe_child() - Deal with a child that is about to be probed
*
* Perform any pre-processing that is needed by the uclass before it can be
* probed.
*
* @dev: Pointer to the device
* #return 0 on success, -ve on error
*/
int uclass_pre_probe_child(struct udevice *dev);
/**
* uclass_post_probe_device() - Deal with a device that has just been probed * uclass_post_probe_device() - Deal with a device that has just been probed
* *
* Perform any post-processing of a probed device that is needed by the * Perform any post-processing of a probed device that is needed by the

@ -83,6 +83,7 @@ struct uclass_driver {
int (*post_probe)(struct udevice *dev); int (*post_probe)(struct udevice *dev);
int (*pre_remove)(struct udevice *dev); int (*pre_remove)(struct udevice *dev);
int (*child_post_bind)(struct udevice *dev); int (*child_post_bind)(struct udevice *dev);
int (*child_pre_probe)(struct udevice *dev);
int (*init)(struct uclass *class); int (*init)(struct uclass *class);
int (*destroy)(struct uclass *class); int (*destroy)(struct uclass *class);
int priv_auto_alloc_size; int priv_auto_alloc_size;

@ -53,6 +53,15 @@ static int testbus_child_pre_probe(struct udevice *dev)
return 0; return 0;
} }
static int testbus_child_pre_probe_uclass(struct udevice *dev)
{
struct dm_test_priv *priv = dev_get_priv(dev);
priv->uclass_flag++;
return 0;
}
static int testbus_child_post_remove(struct udevice *dev) static int testbus_child_post_remove(struct udevice *dev)
{ {
struct dm_test_parent_data *parent_data = dev_get_parentdata(dev); struct dm_test_parent_data *parent_data = dev_get_parentdata(dev);
@ -91,6 +100,7 @@ UCLASS_DRIVER(testbus) = {
.name = "testbus", .name = "testbus",
.id = UCLASS_TEST_BUS, .id = UCLASS_TEST_BUS,
.flags = DM_UC_FLAG_SEQ_ALIAS, .flags = DM_UC_FLAG_SEQ_ALIAS,
.child_pre_probe = testbus_child_pre_probe_uclass,
}; };
/* Test that we can probe for children */ /* Test that we can probe for children */
@ -469,3 +479,39 @@ static int dm_test_bus_child_post_bind_uclass(struct dm_test_state *dms)
} }
DM_TEST(dm_test_bus_child_post_bind_uclass, DM_TEST(dm_test_bus_child_post_bind_uclass,
DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
/*
* Test that the bus' uclass' child_pre_probe() is called before the
* device's probe() method
*/
static int dm_test_bus_child_pre_probe_uclass(struct dm_test_state *dms)
{
struct udevice *bus, *dev;
int child_count;
/*
* See testfdt_drv_probe() which effectively checks that the uclass
* flag is set before that method is called
*/
ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
for (device_find_first_child(bus, &dev), child_count = 0;
dev;
device_find_next_child(&dev)) {
struct dm_test_priv *priv = dev_get_priv(dev);
/* Check that things happened in the right order */
ut_asserteq_ptr(NULL, priv);
ut_assertok(device_probe(dev));
priv = dev_get_priv(dev);
ut_assert(priv != NULL);
ut_asserteq(1, priv->uclass_flag);
ut_asserteq(1, priv->uclass_total);
child_count++;
}
ut_asserteq(3, child_count);
return 0;
}
DM_TEST(dm_test_bus_child_pre_probe_uclass,
DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);

@ -51,6 +51,13 @@ static int testfdt_drv_probe(struct udevice *dev)
priv->ping_total += DM_TEST_START_TOTAL; priv->ping_total += DM_TEST_START_TOTAL;
/*
* If this device is on a bus, the uclass_flag will be set before
* calling this function. This is used by
* dm_test_bus_child_pre_probe_uclass().
*/
priv->uclass_total += priv->uclass_flag;
return 0; return 0;
} }

Loading…
Cancel
Save