From 8109863f535e0851b50a333d4e7fdaa2006ac019 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 29 Dec 2019 21:19:23 -0700 Subject: test: Add functions to find the amount of allocated memory The malloc() implementations provides a way of finding out the approximate amount of memory that is allocated. Add helper functions to make it easier to access this and see changes over time. This is useful for tests that want to check if memory has been allocated or freed. Signed-off-by: Simon Glass --- test/ut.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'test') diff --git a/test/ut.c b/test/ut.c index 5579804..265da4a 100644 --- a/test/ut.c +++ b/test/ut.c @@ -6,6 +6,7 @@ */ #include +#include #include #include @@ -32,3 +33,16 @@ void ut_failf(struct unit_test_state *uts, const char *fname, int line, putc('\n'); uts->fail_count++; } + +ulong ut_check_free(void) +{ + struct mallinfo info = mallinfo(); + + return info.uordblks; +} + +long ut_check_delta(ulong last) +{ + return ut_check_free() - last; +} + -- cgit v1.1 From dc12ebbbdb765153805d2b17d18edf5fe0813d5a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 29 Dec 2019 21:19:25 -0700 Subject: dm: test: Add a test driver for devres Add a driver which does devres allocations so that we can write tests for devres. Signed-off-by: Simon Glass --- test/dm/test-fdt.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'test') diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c index 1fb8b5c..bbac377 100644 --- a/test/dm/test-fdt.c +++ b/test/dm/test-fdt.c @@ -153,6 +153,53 @@ UCLASS_DRIVER(testprobe) = { .flags = DM_UC_FLAG_SEQ_ALIAS, }; +struct dm_testdevres_pdata { + void *ptr; +}; + +struct dm_testdevres_priv { + void *ptr; +}; + +static int testdevres_drv_bind(struct udevice *dev) +{ + struct dm_testdevres_pdata *pdata = dev_get_platdata(dev); + + pdata->ptr = devm_kmalloc(dev, TEST_DEVRES_SIZE, 0); + + return 0; +} + +static int testdevres_drv_probe(struct udevice *dev) +{ + struct dm_testdevres_priv *priv = dev_get_priv(dev); + + priv->ptr = devm_kmalloc(dev, TEST_DEVRES_SIZE2, 0); + + return 0; +} + +static const struct udevice_id testdevres_ids[] = { + { .compatible = "denx,u-boot-devres-test" }, + { } +}; + +U_BOOT_DRIVER(testdevres_drv) = { + .name = "testdevres_drv", + .of_match = testdevres_ids, + .id = UCLASS_TEST_DEVRES, + .bind = testdevres_drv_bind, + .probe = testdevres_drv_probe, + .platdata_auto_alloc_size = sizeof(struct dm_testdevres_pdata), + .priv_auto_alloc_size = sizeof(struct dm_testdevres_priv), +}; + +UCLASS_DRIVER(testdevres) = { + .name = "testdevres", + .id = UCLASS_TEST_DEVRES, + .flags = DM_UC_FLAG_SEQ_ALIAS, +}; + int dm_check_devices(struct unit_test_state *uts, int num_devices) { struct udevice *dev; -- cgit v1.1 From 8d6320cc4d5cd01e2e7fd01dd635e360cf0a1699 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 29 Dec 2019 21:19:26 -0700 Subject: dm: devres: Add tests 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 --- test/dm/Makefile | 1 + test/dm/devres.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+) create mode 100644 test/dm/devres.c (limited to 'test') diff --git a/test/dm/Makefile b/test/dm/Makefile index a268783..85cc0f7 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 0000000..c351844 --- /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 +#include +#include +#include +#include +#include +#include +#include + +/* 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); -- cgit v1.1 From 42a0ce576f33ad413662e7178f05db2f36de9896 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 29 Dec 2019 21:19:28 -0700 Subject: dm: devres: Add a new OFDATA phase Since the ofdata_to_platdata() method can allocate resources, add it as a new devres phase. Signed-off-by: Simon Glass --- test/dm/devres.c | 14 +++++++++++--- test/dm/test-fdt.c | 11 +++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/test/dm/devres.c b/test/dm/devres.c index c351844..e733189 100644 --- a/test/dm/devres.c +++ b/test/dm/devres.c @@ -140,6 +140,7 @@ static int dm_test_devres_kcalloc(struct unit_test_state *uts) } DM_TEST(dm_test_devres_kcalloc, DM_TESTF_SCAN_PDATA); +/* Test devres releases resources automatically as expected */ static int dm_test_devres_phase(struct unit_test_state *uts) { struct devres_stats stats; @@ -154,14 +155,21 @@ static int dm_test_devres_phase(struct unit_test_state *uts) ut_asserteq(1, stats.allocs); ut_asserteq(TEST_DEVRES_SIZE, stats.total_size); + /* Getting platdata should add one allocation */ + ut_assertok(device_ofdata_to_platdata(dev)); + devres_get_stats(dev, &stats); + ut_asserteq(2, stats.allocs); + ut_asserteq(TEST_DEVRES_SIZE + TEST_DEVRES_SIZE3, 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); + ut_asserteq(3, stats.allocs); + ut_asserteq(TEST_DEVRES_SIZE + TEST_DEVRES_SIZE2 + TEST_DEVRES_SIZE3, + stats.total_size); - /* Removing the device should drop one allocation */ + /* Removing the device should drop both those allocations */ device_remove(dev, DM_REMOVE_NORMAL); devres_get_stats(dev, &stats); ut_asserteq(1, stats.allocs); diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c index bbac377..d59c449 100644 --- a/test/dm/test-fdt.c +++ b/test/dm/test-fdt.c @@ -159,6 +159,7 @@ struct dm_testdevres_pdata { struct dm_testdevres_priv { void *ptr; + void *ptr_ofdata; }; static int testdevres_drv_bind(struct udevice *dev) @@ -170,6 +171,15 @@ static int testdevres_drv_bind(struct udevice *dev) return 0; } +static int testdevres_drv_ofdata_to_platdata(struct udevice *dev) +{ + struct dm_testdevres_priv *priv = dev_get_priv(dev); + + priv->ptr_ofdata = devm_kmalloc(dev, TEST_DEVRES_SIZE3, 0); + + return 0; +} + static int testdevres_drv_probe(struct udevice *dev) { struct dm_testdevres_priv *priv = dev_get_priv(dev); @@ -189,6 +199,7 @@ U_BOOT_DRIVER(testdevres_drv) = { .of_match = testdevres_ids, .id = UCLASS_TEST_DEVRES, .bind = testdevres_drv_bind, + .ofdata_to_platdata = testdevres_drv_ofdata_to_platdata, .probe = testdevres_drv_probe, .platdata_auto_alloc_size = sizeof(struct dm_testdevres_pdata), .priv_auto_alloc_size = sizeof(struct dm_testdevres_priv), -- cgit v1.1