summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/core/device-remove.c4
-rw-r--r--drivers/core/device.c4
-rw-r--r--include/dm/uclass.h4
-rw-r--r--test/dm/bus.c31
4 files changed, 41 insertions, 2 deletions
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)
{