[PATCH 17/19] dm: devres: Add tests

Simon Glass sjg at chromium.org
Mon Dec 30 05:19:26 CET 2019


The devres functionality has very few users in U-Boot, but it still should
have tests. Add a few basic tests of the main functions.

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

 drivers/core/devres.c |  13 +++
 include/dm/devres.h   |  20 +++++
 test/dm/Makefile      |   1 +
 test/dm/devres.c      | 178 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 212 insertions(+)
 create mode 100644 test/dm/devres.c

diff --git a/drivers/core/devres.c b/drivers/core/devres.c
index 9c04499c6d..36a8b1eb5f 100644
--- a/drivers/core/devres.c
+++ b/drivers/core/devres.c
@@ -223,6 +223,19 @@ void dm_dump_devres(void)
 	if (root)
 		dump_resources(root, 0);
 }
+
+void devres_get_stats(const struct udevice *dev, struct devres_stats *stats)
+{
+	struct devres *dr;
+
+	stats->allocs = 0;
+	stats->total_size = 0;
+	list_for_each_entry(dr, &dev->devres_head, entry) {
+		stats->allocs++;
+		stats->total_size += dr->size;
+	}
+}
+
 #endif
 
 /*
diff --git a/include/dm/devres.h b/include/dm/devres.h
index 32fbf38054..9c69196054 100644
--- a/include/dm/devres.h
+++ b/include/dm/devres.h
@@ -15,6 +15,17 @@
 typedef void (*dr_release_t)(struct udevice *dev, void *res);
 typedef int (*dr_match_t)(struct udevice *dev, void *res, void *match_data);
 
+/**
+ * struct devres_stats - Information about devres allocations for a device
+ *
+ * @allocs: Number of allocations
+ * @total_size: Total size of allocations in bytes
+ */
+struct devres_stats {
+	int allocs;
+	int total_size;
+};
+
 #ifdef CONFIG_DEVRES
 
 #ifdef CONFIG_DEBUG_DEVRES
@@ -189,6 +200,9 @@ static inline void *devm_kcalloc(struct udevice *dev,
  */
 void devm_kfree(struct udevice *dev, void *ptr);
 
+/* Get basic stats on allocations */
+void devres_get_stats(const struct udevice *dev, struct devres_stats *stats);
+
 #else /* ! CONFIG_DEVRES */
 
 static inline void *devres_alloc(dr_release_t release, size_t size, gfp_t gfp)
@@ -265,5 +279,11 @@ static inline void devm_kfree(struct udevice *dev, void *ptr)
 {
 	kfree(ptr);
 }
+
+static inline void devres_get_stats(const struct udevice *dev,
+				    struct devres_stats *stats)
+{
+}
+
 #endif /* DEVRES */
 #endif /* _DM_DEVRES_H */
diff --git a/test/dm/Makefile b/test/dm/Makefile
index a268783169..85cc0f7fb8 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_BLK) += blk.o
 obj-$(CONFIG_BOARD) += board.o
 obj-$(CONFIG_DM_BOOTCOUNT) += bootcount.o
 obj-$(CONFIG_CLK) += clk.o clk_ccf.o
+obj-$(CONFIG_DEVRES) += devres.o
 obj-$(CONFIG_VIDEO_MIPI_DSI) += dsi_host.o
 obj-$(CONFIG_DM_ETH) += eth.o
 obj-$(CONFIG_FIRMWARE) += firmware.o
diff --git a/test/dm/devres.c b/test/dm/devres.c
new file mode 100644
index 0000000000..c351844db9
--- /dev/null
+++ b/test/dm/devres.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Tests for the devres (
+ *
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <malloc.h>
+#include <dm/device-internal.h>
+#include <dm/test.h>
+#include <dm/uclass-internal.h>
+#include <test/ut.h>
+
+/* Test that devm_kmalloc() allocates memory, free when device is removed */
+static int dm_test_devres_alloc(struct unit_test_state *uts)
+{
+	ulong mem_start, mem_dev, mem_kmalloc;
+	struct udevice *dev;
+	void *ptr;
+
+	mem_start = ut_check_delta(0);
+	ut_assertok(uclass_first_device_err(UCLASS_TEST, &dev));
+	mem_dev = ut_check_delta(mem_start);
+	ut_assert(mem_dev > 0);
+
+	/* This should increase allocated memory */
+	ptr = devm_kmalloc(dev, TEST_DEVRES_SIZE, 0);
+	ut_assert(ptr != NULL);
+	mem_kmalloc = ut_check_delta(mem_dev);
+	ut_assert(mem_kmalloc > 0);
+
+	/* Check that ptr is freed */
+	device_remove(dev, DM_REMOVE_NORMAL);
+	ut_asserteq(0, ut_check_delta(mem_start));
+
+	return 0;
+}
+DM_TEST(dm_test_devres_alloc, DM_TESTF_SCAN_PDATA);
+
+/* Test devm_kfree() can be used to free memory too */
+static int dm_test_devres_free(struct unit_test_state *uts)
+{
+	ulong mem_start, mem_dev, mem_kmalloc;
+	struct udevice *dev;
+	void *ptr;
+
+	mem_start = ut_check_delta(0);
+	ut_assertok(uclass_first_device_err(UCLASS_TEST, &dev));
+	mem_dev = ut_check_delta(mem_start);
+	ut_assert(mem_dev > 0);
+
+	ptr = devm_kmalloc(dev, TEST_DEVRES_SIZE, 0);
+	ut_assert(ptr != NULL);
+	mem_kmalloc = ut_check_delta(mem_dev);
+	ut_assert(mem_kmalloc > 0);
+
+	/* Free the ptr and check that memory usage goes down */
+	devm_kfree(dev, ptr);
+	ut_assert(ut_check_delta(mem_kmalloc) < 0);
+
+	device_remove(dev, DM_REMOVE_NORMAL);
+	ut_asserteq(0, ut_check_delta(mem_start));
+
+	return 0;
+}
+DM_TEST(dm_test_devres_free, DM_TESTF_SCAN_PDATA);
+
+
+/* Test that kzalloc() returns memory that is zeroed */
+static int dm_test_devres_kzalloc(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+	u8 *ptr, val;
+	int i;
+
+	ut_assertok(uclass_first_device_err(UCLASS_TEST, &dev));
+
+	ptr = devm_kzalloc(dev, TEST_DEVRES_SIZE, 0);
+	ut_assert(ptr != NULL);
+	for (val = 0, i = 0; i < TEST_DEVRES_SIZE; i++)
+		val |= *ptr;
+	ut_asserteq(0, val);
+
+	return 0;
+}
+DM_TEST(dm_test_devres_kzalloc, DM_TESTF_SCAN_PDATA);
+
+/* Test that devm_kmalloc_array() allocates an array that can be set */
+static int dm_test_devres_kmalloc_array(struct unit_test_state *uts)
+{
+	ulong mem_start, mem_dev;
+	struct udevice *dev;
+	u8 *ptr;
+
+	mem_start = ut_check_delta(0);
+	ut_assertok(uclass_first_device_err(UCLASS_TEST, &dev));
+	mem_dev = ut_check_delta(mem_start);
+
+	ptr = devm_kmalloc_array(dev, TEST_DEVRES_COUNT, TEST_DEVRES_SIZE, 0);
+	ut_assert(ptr != NULL);
+	memset(ptr, '\xff', TEST_DEVRES_TOTAL);
+	ut_assert(ut_check_delta(mem_dev) > 0);
+
+	device_remove(dev, DM_REMOVE_NORMAL);
+	ut_asserteq(0, ut_check_delta(mem_start));
+
+	return 0;
+}
+DM_TEST(dm_test_devres_kmalloc_array, DM_TESTF_SCAN_PDATA);
+
+/* Test that devm_kcalloc() allocates a zeroed array */
+static int dm_test_devres_kcalloc(struct unit_test_state *uts)
+{
+	ulong mem_start, mem_dev;
+	struct udevice *dev;
+	u8 *ptr, val;
+	int i;
+
+	mem_start = ut_check_delta(0);
+	ut_assertok(uclass_first_device_err(UCLASS_TEST, &dev));
+	mem_dev = ut_check_delta(mem_start);
+	ut_assert(mem_dev > 0);
+
+	/* This should increase allocated memory */
+	ptr = devm_kcalloc(dev, TEST_DEVRES_SIZE, TEST_DEVRES_COUNT, 0);
+	ut_assert(ptr != NULL);
+	ut_assert(ut_check_delta(mem_dev) > 0);
+	for (val = 0, i = 0; i < TEST_DEVRES_TOTAL; i++)
+		val |= *ptr;
+	ut_asserteq(0, val);
+
+	/* Check that ptr is freed */
+	device_remove(dev, DM_REMOVE_NORMAL);
+	ut_asserteq(0, ut_check_delta(mem_start));
+
+	return 0;
+}
+DM_TEST(dm_test_devres_kcalloc, DM_TESTF_SCAN_PDATA);
+
+static int dm_test_devres_phase(struct unit_test_state *uts)
+{
+	struct devres_stats stats;
+	struct udevice *dev;
+
+	/*
+	 * The device is bound already, so find it and check that it has the
+	 * allocation created in the bind() method.
+	 */
+	ut_assertok(uclass_find_first_device(UCLASS_TEST_DEVRES, &dev));
+	devres_get_stats(dev, &stats);
+	ut_asserteq(1, stats.allocs);
+	ut_asserteq(TEST_DEVRES_SIZE, stats.total_size);
+
+	/* Probing the device should add one allocation */
+	ut_assertok(uclass_first_device(UCLASS_TEST_DEVRES, &dev));
+	ut_assert(dev != NULL);
+	devres_get_stats(dev, &stats);
+	ut_asserteq(2, stats.allocs);
+	ut_asserteq(TEST_DEVRES_SIZE + TEST_DEVRES_SIZE2, stats.total_size);
+
+	/* Removing the device should drop one allocation */
+	device_remove(dev, DM_REMOVE_NORMAL);
+	devres_get_stats(dev, &stats);
+	ut_asserteq(1, stats.allocs);
+	ut_asserteq(TEST_DEVRES_SIZE, stats.total_size);
+
+	/* Unbinding removes the other. Note this access a freed pointer */
+	device_unbind(dev);
+	devres_get_stats(dev, &stats);
+	ut_asserteq(0, stats.allocs);
+	ut_asserteq(0, stats.total_size);
+
+	return 0;
+}
+DM_TEST(dm_test_devres_phase, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.24.1.735.g03f4e72817-goog



More information about the U-Boot mailing list