Commit 8d6320cc4d5cd01e2e7fd01dd635e360cf0a1699

Authored by Simon Glass
1 parent dc12ebbbdb

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 <sjg@chromium.org>

Showing 4 changed files with 212 additions and 0 deletions Side-by-side Diff

drivers/core/devres.c
... ... @@ -223,6 +223,19 @@
223 223 if (root)
224 224 dump_resources(root, 0);
225 225 }
  226 +
  227 +void devres_get_stats(const struct udevice *dev, struct devres_stats *stats)
  228 +{
  229 + struct devres *dr;
  230 +
  231 + stats->allocs = 0;
  232 + stats->total_size = 0;
  233 + list_for_each_entry(dr, &dev->devres_head, entry) {
  234 + stats->allocs++;
  235 + stats->total_size += dr->size;
  236 + }
  237 +}
  238 +
226 239 #endif
227 240  
228 241 /*
... ... @@ -15,6 +15,17 @@
15 15 typedef void (*dr_release_t)(struct udevice *dev, void *res);
16 16 typedef int (*dr_match_t)(struct udevice *dev, void *res, void *match_data);
17 17  
  18 +/**
  19 + * struct devres_stats - Information about devres allocations for a device
  20 + *
  21 + * @allocs: Number of allocations
  22 + * @total_size: Total size of allocations in bytes
  23 + */
  24 +struct devres_stats {
  25 + int allocs;
  26 + int total_size;
  27 +};
  28 +
18 29 #ifdef CONFIG_DEVRES
19 30  
20 31 #ifdef CONFIG_DEBUG_DEVRES
... ... @@ -189,6 +200,9 @@
189 200 */
190 201 void devm_kfree(struct udevice *dev, void *ptr);
191 202  
  203 +/* Get basic stats on allocations */
  204 +void devres_get_stats(const struct udevice *dev, struct devres_stats *stats);
  205 +
192 206 #else /* ! CONFIG_DEVRES */
193 207  
194 208 static inline void *devres_alloc(dr_release_t release, size_t size, gfp_t gfp)
... ... @@ -265,6 +279,12 @@
265 279 {
266 280 kfree(ptr);
267 281 }
  282 +
  283 +static inline void devres_get_stats(const struct udevice *dev,
  284 + struct devres_stats *stats)
  285 +{
  286 +}
  287 +
268 288 #endif /* DEVRES */
269 289 #endif /* _DM_DEVRES_H */
... ... @@ -18,6 +18,7 @@
18 18 obj-$(CONFIG_BOARD) += board.o
19 19 obj-$(CONFIG_DM_BOOTCOUNT) += bootcount.o
20 20 obj-$(CONFIG_CLK) += clk.o clk_ccf.o
  21 +obj-$(CONFIG_DEVRES) += devres.o
21 22 obj-$(CONFIG_VIDEO_MIPI_DSI) += dsi_host.o
22 23 obj-$(CONFIG_DM_ETH) += eth.o
23 24 obj-$(CONFIG_FIRMWARE) += firmware.o
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +/*
  3 + * Tests for the devres (
  4 + *
  5 + * Copyright 2019 Google LLC
  6 + */
  7 +
  8 +#include <common.h>
  9 +#include <errno.h>
  10 +#include <dm.h>
  11 +#include <malloc.h>
  12 +#include <dm/device-internal.h>
  13 +#include <dm/test.h>
  14 +#include <dm/uclass-internal.h>
  15 +#include <test/ut.h>
  16 +
  17 +/* Test that devm_kmalloc() allocates memory, free when device is removed */
  18 +static int dm_test_devres_alloc(struct unit_test_state *uts)
  19 +{
  20 + ulong mem_start, mem_dev, mem_kmalloc;
  21 + struct udevice *dev;
  22 + void *ptr;
  23 +
  24 + mem_start = ut_check_delta(0);
  25 + ut_assertok(uclass_first_device_err(UCLASS_TEST, &dev));
  26 + mem_dev = ut_check_delta(mem_start);
  27 + ut_assert(mem_dev > 0);
  28 +
  29 + /* This should increase allocated memory */
  30 + ptr = devm_kmalloc(dev, TEST_DEVRES_SIZE, 0);
  31 + ut_assert(ptr != NULL);
  32 + mem_kmalloc = ut_check_delta(mem_dev);
  33 + ut_assert(mem_kmalloc > 0);
  34 +
  35 + /* Check that ptr is freed */
  36 + device_remove(dev, DM_REMOVE_NORMAL);
  37 + ut_asserteq(0, ut_check_delta(mem_start));
  38 +
  39 + return 0;
  40 +}
  41 +DM_TEST(dm_test_devres_alloc, DM_TESTF_SCAN_PDATA);
  42 +
  43 +/* Test devm_kfree() can be used to free memory too */
  44 +static int dm_test_devres_free(struct unit_test_state *uts)
  45 +{
  46 + ulong mem_start, mem_dev, mem_kmalloc;
  47 + struct udevice *dev;
  48 + void *ptr;
  49 +
  50 + mem_start = ut_check_delta(0);
  51 + ut_assertok(uclass_first_device_err(UCLASS_TEST, &dev));
  52 + mem_dev = ut_check_delta(mem_start);
  53 + ut_assert(mem_dev > 0);
  54 +
  55 + ptr = devm_kmalloc(dev, TEST_DEVRES_SIZE, 0);
  56 + ut_assert(ptr != NULL);
  57 + mem_kmalloc = ut_check_delta(mem_dev);
  58 + ut_assert(mem_kmalloc > 0);
  59 +
  60 + /* Free the ptr and check that memory usage goes down */
  61 + devm_kfree(dev, ptr);
  62 + ut_assert(ut_check_delta(mem_kmalloc) < 0);
  63 +
  64 + device_remove(dev, DM_REMOVE_NORMAL);
  65 + ut_asserteq(0, ut_check_delta(mem_start));
  66 +
  67 + return 0;
  68 +}
  69 +DM_TEST(dm_test_devres_free, DM_TESTF_SCAN_PDATA);
  70 +
  71 +
  72 +/* Test that kzalloc() returns memory that is zeroed */
  73 +static int dm_test_devres_kzalloc(struct unit_test_state *uts)
  74 +{
  75 + struct udevice *dev;
  76 + u8 *ptr, val;
  77 + int i;
  78 +
  79 + ut_assertok(uclass_first_device_err(UCLASS_TEST, &dev));
  80 +
  81 + ptr = devm_kzalloc(dev, TEST_DEVRES_SIZE, 0);
  82 + ut_assert(ptr != NULL);
  83 + for (val = 0, i = 0; i < TEST_DEVRES_SIZE; i++)
  84 + val |= *ptr;
  85 + ut_asserteq(0, val);
  86 +
  87 + return 0;
  88 +}
  89 +DM_TEST(dm_test_devres_kzalloc, DM_TESTF_SCAN_PDATA);
  90 +
  91 +/* Test that devm_kmalloc_array() allocates an array that can be set */
  92 +static int dm_test_devres_kmalloc_array(struct unit_test_state *uts)
  93 +{
  94 + ulong mem_start, mem_dev;
  95 + struct udevice *dev;
  96 + u8 *ptr;
  97 +
  98 + mem_start = ut_check_delta(0);
  99 + ut_assertok(uclass_first_device_err(UCLASS_TEST, &dev));
  100 + mem_dev = ut_check_delta(mem_start);
  101 +
  102 + ptr = devm_kmalloc_array(dev, TEST_DEVRES_COUNT, TEST_DEVRES_SIZE, 0);
  103 + ut_assert(ptr != NULL);
  104 + memset(ptr, '\xff', TEST_DEVRES_TOTAL);
  105 + ut_assert(ut_check_delta(mem_dev) > 0);
  106 +
  107 + device_remove(dev, DM_REMOVE_NORMAL);
  108 + ut_asserteq(0, ut_check_delta(mem_start));
  109 +
  110 + return 0;
  111 +}
  112 +DM_TEST(dm_test_devres_kmalloc_array, DM_TESTF_SCAN_PDATA);
  113 +
  114 +/* Test that devm_kcalloc() allocates a zeroed array */
  115 +static int dm_test_devres_kcalloc(struct unit_test_state *uts)
  116 +{
  117 + ulong mem_start, mem_dev;
  118 + struct udevice *dev;
  119 + u8 *ptr, val;
  120 + int i;
  121 +
  122 + mem_start = ut_check_delta(0);
  123 + ut_assertok(uclass_first_device_err(UCLASS_TEST, &dev));
  124 + mem_dev = ut_check_delta(mem_start);
  125 + ut_assert(mem_dev > 0);
  126 +
  127 + /* This should increase allocated memory */
  128 + ptr = devm_kcalloc(dev, TEST_DEVRES_SIZE, TEST_DEVRES_COUNT, 0);
  129 + ut_assert(ptr != NULL);
  130 + ut_assert(ut_check_delta(mem_dev) > 0);
  131 + for (val = 0, i = 0; i < TEST_DEVRES_TOTAL; i++)
  132 + val |= *ptr;
  133 + ut_asserteq(0, val);
  134 +
  135 + /* Check that ptr is freed */
  136 + device_remove(dev, DM_REMOVE_NORMAL);
  137 + ut_asserteq(0, ut_check_delta(mem_start));
  138 +
  139 + return 0;
  140 +}
  141 +DM_TEST(dm_test_devres_kcalloc, DM_TESTF_SCAN_PDATA);
  142 +
  143 +static int dm_test_devres_phase(struct unit_test_state *uts)
  144 +{
  145 + struct devres_stats stats;
  146 + struct udevice *dev;
  147 +
  148 + /*
  149 + * The device is bound already, so find it and check that it has the
  150 + * allocation created in the bind() method.
  151 + */
  152 + ut_assertok(uclass_find_first_device(UCLASS_TEST_DEVRES, &dev));
  153 + devres_get_stats(dev, &stats);
  154 + ut_asserteq(1, stats.allocs);
  155 + ut_asserteq(TEST_DEVRES_SIZE, stats.total_size);
  156 +
  157 + /* Probing the device should add one allocation */
  158 + ut_assertok(uclass_first_device(UCLASS_TEST_DEVRES, &dev));
  159 + ut_assert(dev != NULL);
  160 + devres_get_stats(dev, &stats);
  161 + ut_asserteq(2, stats.allocs);
  162 + ut_asserteq(TEST_DEVRES_SIZE + TEST_DEVRES_SIZE2, stats.total_size);
  163 +
  164 + /* Removing the device should drop one allocation */
  165 + device_remove(dev, DM_REMOVE_NORMAL);
  166 + devres_get_stats(dev, &stats);
  167 + ut_asserteq(1, stats.allocs);
  168 + ut_asserteq(TEST_DEVRES_SIZE, stats.total_size);
  169 +
  170 + /* Unbinding removes the other. Note this access a freed pointer */
  171 + device_unbind(dev);
  172 + devres_get_stats(dev, &stats);
  173 + ut_asserteq(0, stats.allocs);
  174 + ut_asserteq(0, stats.total_size);
  175 +
  176 + return 0;
  177 +}
  178 +DM_TEST(dm_test_devres_phase, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);