diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c index 56c358a0ec..3a5f48df7a 100644 --- a/drivers/core/device-remove.c +++ b/drivers/core/device-remove.c @@ -126,6 +126,10 @@ void device_free(struct udevice *dev) } if (dev->parent) { size = dev->parent->driver->per_child_auto_alloc_size; + if (!size) { + size = dev->parent->uclass->uc_drv-> + per_child_auto_alloc_size; + } if (size) { free(dev->parent_priv); dev->parent_priv = NULL; diff --git a/drivers/core/device.c b/drivers/core/device.c index f78b78a299..78bc460d35 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -201,6 +201,10 @@ int device_probe_child(struct udevice *dev, void *parent_priv) /* Ensure all parents are probed */ if (dev->parent) { size = dev->parent->driver->per_child_auto_alloc_size; + if (!size) { + size = dev->parent->uclass->uc_drv-> + per_child_auto_alloc_size; + } if (size) { dev->parent_priv = calloc(1, size); if (!dev->parent_priv) { diff --git a/include/dm/uclass.h b/include/dm/uclass.h index 9000b22c38..ac6c85072c 100644 --- a/include/dm/uclass.h +++ b/include/dm/uclass.h @@ -63,6 +63,9 @@ struct udevice; * @per_device_auto_alloc_size: Each device can hold private data owned * by the uclass. If required this will be automatically allocated if this * value is non-zero. + * @per_child_auto_alloc_size: Each child device (of a parent in this + * uclass) can hold parent data for the device/uclass. This value is only + * used as a falback if this member is 0 in the driver. * @per_child_platdata_auto_alloc_size: A bus likes to store information about * its children. If non-zero this is the size of this data, to be allocated * in the child device's parent_platdata pointer. This value is only used as @@ -82,6 +85,7 @@ struct uclass_driver { int (*destroy)(struct uclass *class); int priv_auto_alloc_size; int per_device_auto_alloc_size; + int per_child_auto_alloc_size; int per_child_platdata_auto_alloc_size; const void *ops; uint32_t flags; diff --git a/test/dm/bus.c b/test/dm/bus.c index 972c449790..e909697062 100644 --- a/test/dm/bus.c +++ b/test/dm/bus.c @@ -192,7 +192,7 @@ DM_TEST(dm_test_bus_children_iterators, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); /* Test that the bus can store data about each child */ -static int dm_test_bus_parent_data(struct dm_test_state *dms) +static int test_bus_parent_data(struct dm_test_state *dms) { struct dm_test_parent_data *parent_data; struct udevice *bus, *dev; @@ -251,9 +251,36 @@ static int dm_test_bus_parent_data(struct dm_test_state *dms) return 0; } - +/* Test that the bus can store data about each child */ +static int dm_test_bus_parent_data(struct dm_test_state *dms) +{ + return test_bus_parent_data(dms); +} DM_TEST(dm_test_bus_parent_data, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); +/* As above but the size is controlled by the uclass */ +static int dm_test_bus_parent_data_uclass(struct dm_test_state *dms) +{ + struct udevice *bus; + int size; + int ret; + + /* Set the driver size to 0 so that the uclass size is used */ + ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus)); + size = bus->driver->per_child_auto_alloc_size; + bus->uclass->uc_drv->per_child_auto_alloc_size = size; + bus->driver->per_child_auto_alloc_size = 0; + ret = test_bus_parent_data(dms); + if (ret) + return ret; + bus->uclass->uc_drv->per_child_auto_alloc_size = 0; + bus->driver->per_child_auto_alloc_size = size; + + return 0; +} +DM_TEST(dm_test_bus_parent_data_uclass, + DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + /* Test that the bus ops are called when a child is probed/removed */ static int dm_test_bus_parent_ops(struct dm_test_state *dms) {