2019-12-30 04:19:26 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
|
|
|
/*
|
|
|
|
* Tests for the devres (
|
|
|
|
*
|
|
|
|
* Copyright 2019 Google LLC
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <common.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <dm.h>
|
2020-05-10 17:40:05 +00:00
|
|
|
#include <log.h>
|
2019-12-30 04:19:26 +00:00
|
|
|
#include <malloc.h>
|
|
|
|
#include <dm/device-internal.h>
|
2020-02-03 14:36:15 +00:00
|
|
|
#include <dm/devres.h>
|
2019-12-30 04:19:26 +00:00
|
|
|
#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);
|
|
|
|
|
2019-12-30 04:19:28 +00:00
|
|
|
/* Test devres releases resources automatically as expected */
|
2019-12-30 04:19:26 +00:00
|
|
|
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);
|
|
|
|
|
2019-12-30 04:19:28 +00:00
|
|
|
/* 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);
|
|
|
|
|
2019-12-30 04:19:26 +00:00
|
|
|
/* 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);
|
2019-12-30 04:19:28 +00:00
|
|
|
ut_asserteq(3, stats.allocs);
|
|
|
|
ut_asserteq(TEST_DEVRES_SIZE + TEST_DEVRES_SIZE2 + TEST_DEVRES_SIZE3,
|
|
|
|
stats.total_size);
|
2019-12-30 04:19:26 +00:00
|
|
|
|
2019-12-30 04:19:28 +00:00
|
|
|
/* Removing the device should drop both those allocations */
|
2019-12-30 04:19:26 +00:00
|
|
|
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);
|