From 00bb549d7d63a21532e76e4a334d7807a54d9f31 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 27 Mar 2024 11:44:06 +0000 Subject: regmap: maple: Fix cache corruption in regcache_maple_drop() When keeping the upper end of a cache block entry, the entry[] array must be indexed by the offset from the base register of the block, i.e. max - mas.index. The code was indexing entry[] by only the register address, leading to an out-of-bounds access that copied some part of the kernel memory over the cache contents. This bug was not detected by the regmap KUnit test because it only tests with a block of registers starting at 0, so mas.index == 0. Signed-off-by: Richard Fitzgerald Fixes: f033c26de5a5 ("regmap: Add maple tree based register cache") Link: https://msgid.link/r/20240327114406.976986-1-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/base/regmap/regcache-maple.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/base/regmap') diff --git a/drivers/base/regmap/regcache-maple.c b/drivers/base/regmap/regcache-maple.c index 41edd6a430eb..c1776127a572 100644 --- a/drivers/base/regmap/regcache-maple.c +++ b/drivers/base/regmap/regcache-maple.c @@ -145,7 +145,7 @@ static int regcache_maple_drop(struct regmap *map, unsigned int min, upper_index = max + 1; upper_last = mas.last; - upper = kmemdup(&entry[max + 1], + upper = kmemdup(&entry[max - mas.index + 1], ((mas.last - max) * sizeof(unsigned long)), map->alloc_flags); -- cgit v1.2.3 From eaa03486d932572dfd1c5f64f9dfebe572ad88c0 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 29 Mar 2024 14:46:30 +0000 Subject: regmap: maple: Fix uninitialized symbol 'ret' warnings Fix warnings reported by smatch by initializing local 'ret' variable to 0. drivers/base/regmap/regcache-maple.c:186 regcache_maple_drop() error: uninitialized symbol 'ret'. drivers/base/regmap/regcache-maple.c:290 regcache_maple_sync() error: uninitialized symbol 'ret'. Signed-off-by: Richard Fitzgerald Fixes: f033c26de5a5 ("regmap: Add maple tree based register cache") Link: https://lore.kernel.org/r/20240329144630.1965159-1-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/base/regmap/regcache-maple.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/base/regmap') diff --git a/drivers/base/regmap/regcache-maple.c b/drivers/base/regmap/regcache-maple.c index c1776127a572..55999a50ccc0 100644 --- a/drivers/base/regmap/regcache-maple.c +++ b/drivers/base/regmap/regcache-maple.c @@ -112,7 +112,7 @@ static int regcache_maple_drop(struct regmap *map, unsigned int min, unsigned long *entry, *lower, *upper; unsigned long lower_index, lower_last; unsigned long upper_index, upper_last; - int ret; + int ret = 0; lower = NULL; upper = NULL; @@ -244,7 +244,7 @@ static int regcache_maple_sync(struct regmap *map, unsigned int min, unsigned long lmin = min; unsigned long lmax = max; unsigned int r, v, sync_start; - int ret; + int ret = 0; bool sync_needed = false; map->cache_bypass = true; -- cgit v1.2.3 From 70ee853eec5693fefd8348a2b049d9cb83362e58 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 8 Apr 2024 11:18:00 +0100 Subject: regmap: Add regmap_read_bypassed() Add a regmap_read_bypassed() to allow reads from the hardware registers while the regmap is in cache-only mode. A typical use for this is to keep the cache in cache-only mode until the hardware has reached a valid state, but one or more status registers must be polled to determine when this state is reached. For example, firmware download on the cs35l56 can take several seconds if there are multiple amps sharing limited bus bandwidth. This is too long to block in probe() so it is done as a background task. The device must be soft-reset to reboot the firmware and during this time the registers are not accessible, so the cache should be in cache-only. But the driver must poll a register to detect when reboot has completed. Signed-off-by: Richard Fitzgerald Fixes: 8a731fd37f8b ("ASoC: cs35l56: Move utility functions to shared file") Link: https://msgid.link/r/20240408101803.43183-2-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 37 +++++++++++++++++++++++++++++++++++++ include/linux/regmap.h | 8 ++++++++ 2 files changed, 45 insertions(+) (limited to 'drivers/base/regmap') diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 5cb425f6f02d..0a34dd3c4f38 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -2838,6 +2838,43 @@ int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val) } EXPORT_SYMBOL_GPL(regmap_read); +/** + * regmap_read_bypassed() - Read a value from a single register direct + * from the device, bypassing the cache + * + * @map: Register map to read from + * @reg: Register to be read from + * @val: Pointer to store read value + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ +int regmap_read_bypassed(struct regmap *map, unsigned int reg, unsigned int *val) +{ + int ret; + bool bypass, cache_only; + + if (!IS_ALIGNED(reg, map->reg_stride)) + return -EINVAL; + + map->lock(map->lock_arg); + + bypass = map->cache_bypass; + cache_only = map->cache_only; + map->cache_bypass = true; + map->cache_only = false; + + ret = _regmap_read(map, reg, val); + + map->cache_bypass = bypass; + map->cache_only = cache_only; + + map->unlock(map->lock_arg); + + return ret; +} +EXPORT_SYMBOL_GPL(regmap_read_bypassed); + /** * regmap_raw_read() - Read raw data from the device * diff --git a/include/linux/regmap.h b/include/linux/regmap.h index b743241cfb7c..d470303b1bbb 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -1230,6 +1230,7 @@ int regmap_multi_reg_write_bypassed(struct regmap *map, int regmap_raw_write_async(struct regmap *map, unsigned int reg, const void *val, size_t val_len); int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val); +int regmap_read_bypassed(struct regmap *map, unsigned int reg, unsigned int *val); int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, size_t val_len); int regmap_noinc_read(struct regmap *map, unsigned int reg, @@ -1739,6 +1740,13 @@ static inline int regmap_read(struct regmap *map, unsigned int reg, return -EINVAL; } +static inline int regmap_read_bypassed(struct regmap *map, unsigned int reg, + unsigned int *val) +{ + WARN_ONCE(1, "regmap API is disabled"); + return -EINVAL; +} + static inline int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, size_t val_len) { -- cgit v1.2.3 From 866f70211bf43927ca44d8e98b5266926fd51315 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 8 Apr 2024 15:45:50 +0100 Subject: regmap: kunit: Fix warnings of implicit casts to __le16 and __be16 Fix warnings about implicit casts to __le16 and __be16 types reported by smatch: drivers/base/regmap/regmap-kunit.c:1118:25: warning: cast to restricted __be16 drivers/base/regmap/regmap-kunit.c:1120:25: warning: cast to restricted __le16 drivers/base/regmap/regmap-kunit.c:1187:33: warning: cast to restricted __be16 drivers/base/regmap/regmap-kunit.c:1190:33: warning: cast to restricted __le16 drivers/base/regmap/regmap-kunit.c:1302:33: warning: cast to restricted __be16 drivers/base/regmap/regmap-kunit.c:1305:33: warning: cast to restricted __le16 Perform a __force cast for all these. Signed-off-by: Richard Fitzgerald Link: https://msgid.link/r/20240408144600.230848-2-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-kunit.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/base/regmap') diff --git a/drivers/base/regmap/regmap-kunit.c b/drivers/base/regmap/regmap-kunit.c index bb2ab6129f38..b46a4f28c1a1 100644 --- a/drivers/base/regmap/regmap-kunit.c +++ b/drivers/base/regmap/regmap-kunit.c @@ -1115,12 +1115,12 @@ static void raw_read_defaults(struct kunit *test) for (i = 0; i < config.max_register + 1; i++) { def = config.reg_defaults[i].def; if (config.val_format_endian == REGMAP_ENDIAN_BIG) { - KUNIT_EXPECT_EQ(test, def, be16_to_cpu(rval[i])); + KUNIT_EXPECT_EQ(test, def, be16_to_cpu((__force __be16)rval[i])); } else { - KUNIT_EXPECT_EQ(test, def, le16_to_cpu(rval[i])); + KUNIT_EXPECT_EQ(test, def, le16_to_cpu((__force __le16)rval[i])); } } - + kfree(rval); regmap_exit(map); } @@ -1185,10 +1185,10 @@ static void raw_write(struct kunit *test) case 3: if (config.val_format_endian == REGMAP_ENDIAN_BIG) { KUNIT_EXPECT_EQ(test, rval, - be16_to_cpu(val[i % 2])); + be16_to_cpu((__force __be16)val[i % 2])); } else { KUNIT_EXPECT_EQ(test, rval, - le16_to_cpu(val[i % 2])); + le16_to_cpu((__force __le16)val[i % 2])); } break; default: @@ -1300,10 +1300,10 @@ static void raw_sync(struct kunit *test) case 3: if (config.val_format_endian == REGMAP_ENDIAN_BIG) { KUNIT_EXPECT_EQ(test, rval, - be16_to_cpu(val[i - 2])); + be16_to_cpu((__force __be16)val[i - 2])); } else { KUNIT_EXPECT_EQ(test, rval, - le16_to_cpu(val[i - 2])); + le16_to_cpu((__force __le16)val[i - 2])); } break; case 4: -- cgit v1.2.3 From 7b7982f14315e0f6910e13b22ed38a47144a83ec Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 8 Apr 2024 15:45:51 +0100 Subject: regmap: kunit: Create a struct device for the regmap Use kunit_device_register() to create a real struct device for the regmap instead of leaving it at NULL. The main reason for this is that it allows context data to be passed into the readable_reg/writable_reg/volatile_reg functions by attaching it to the struct device with dev_set_drvdata(). The gen_regmap() and gen_raw_regmap() functions are updated to take a struct kunit * argument. A new struct regmap_test_priv has been created to hold the struct device created by kunit_device_register(). This allows the struct to be extended in the future to hold more private data for the test suite. Signed-off-by: Richard Fitzgerald Link: https://msgid.link/r/20240408144600.230848-3-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/base/regmap/internal.h | 14 +++-- drivers/base/regmap/regmap-kunit.c | 105 ++++++++++++++++++++++++----------- drivers/base/regmap/regmap-ram.c | 5 +- drivers/base/regmap/regmap-raw-ram.c | 5 +- 4 files changed, 87 insertions(+), 42 deletions(-) (limited to 'drivers/base/regmap') diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index bcdb25bec77c..83acccdc1008 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -326,20 +326,22 @@ struct regmap_ram_data { * Create a test register map with data stored in RAM, not intended * for practical use. */ -struct regmap *__regmap_init_ram(const struct regmap_config *config, +struct regmap *__regmap_init_ram(struct device *dev, + const struct regmap_config *config, struct regmap_ram_data *data, struct lock_class_key *lock_key, const char *lock_name); -#define regmap_init_ram(config, data) \ - __regmap_lockdep_wrapper(__regmap_init_ram, #config, config, data) +#define regmap_init_ram(dev, config, data) \ + __regmap_lockdep_wrapper(__regmap_init_ram, #dev, dev, config, data) -struct regmap *__regmap_init_raw_ram(const struct regmap_config *config, +struct regmap *__regmap_init_raw_ram(struct device *dev, + const struct regmap_config *config, struct regmap_ram_data *data, struct lock_class_key *lock_key, const char *lock_name); -#define regmap_init_raw_ram(config, data) \ - __regmap_lockdep_wrapper(__regmap_init_raw_ram, #config, config, data) +#define regmap_init_raw_ram(dev, config, data) \ + __regmap_lockdep_wrapper(__regmap_init_raw_ram, #dev, dev, config, data) #endif diff --git a/drivers/base/regmap/regmap-kunit.c b/drivers/base/regmap/regmap-kunit.c index b46a4f28c1a1..3bc2028fbef7 100644 --- a/drivers/base/regmap/regmap-kunit.c +++ b/drivers/base/regmap/regmap-kunit.c @@ -4,11 +4,16 @@ // // Copyright 2023 Arm Ltd +#include #include #include "internal.h" #define BLOCK_TEST_SIZE 12 +struct regmap_test_priv { + struct device *dev; +}; + static void get_changed_bytes(void *orig, void *new, size_t size) { char *o = orig; @@ -66,9 +71,11 @@ static const struct regcache_types sparse_cache_types_list[] = { KUNIT_ARRAY_PARAM(sparse_cache_types, sparse_cache_types_list, case_to_desc); -static struct regmap *gen_regmap(struct regmap_config *config, +static struct regmap *gen_regmap(struct kunit *test, + struct regmap_config *config, struct regmap_ram_data **data) { + struct regmap_test_priv *priv = test->priv; unsigned int *buf; struct regmap *ret; size_t size = (config->max_register + 1) * sizeof(unsigned int); @@ -103,7 +110,7 @@ static struct regmap *gen_regmap(struct regmap_config *config, } } - ret = regmap_init_ram(config, *data); + ret = regmap_init_ram(priv->dev, config, *data); if (IS_ERR(ret)) { kfree(buf); kfree(*data); @@ -128,7 +135,7 @@ static void basic_read_write(struct kunit *test) config = test_regmap_config; config.cache_type = t->type; - map = gen_regmap(&config, &data); + map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -158,7 +165,7 @@ static void bulk_write(struct kunit *test) config = test_regmap_config; config.cache_type = t->type; - map = gen_regmap(&config, &data); + map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -195,7 +202,7 @@ static void bulk_read(struct kunit *test) config = test_regmap_config; config.cache_type = t->type; - map = gen_regmap(&config, &data); + map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -230,7 +237,7 @@ static void write_readonly(struct kunit *test) config.num_reg_defaults = BLOCK_TEST_SIZE; config.writeable_reg = reg_5_false; - map = gen_regmap(&config, &data); + map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -264,7 +271,7 @@ static void read_writeonly(struct kunit *test) config.cache_type = t->type; config.readable_reg = reg_5_false; - map = gen_regmap(&config, &data); + map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -304,7 +311,7 @@ static void reg_defaults(struct kunit *test) config.cache_type = t->type; config.num_reg_defaults = BLOCK_TEST_SIZE; - map = gen_regmap(&config, &data); + map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -332,7 +339,7 @@ static void reg_defaults_read_dev(struct kunit *test) config.cache_type = t->type; config.num_reg_defaults_raw = BLOCK_TEST_SIZE; - map = gen_regmap(&config, &data); + map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -368,7 +375,7 @@ static void register_patch(struct kunit *test) config.cache_type = t->type; config.num_reg_defaults = BLOCK_TEST_SIZE; - map = gen_regmap(&config, &data); + map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -419,7 +426,7 @@ static void stride(struct kunit *test) config.reg_stride = 2; config.num_reg_defaults = BLOCK_TEST_SIZE / 2; - map = gen_regmap(&config, &data); + map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -495,7 +502,7 @@ static void basic_ranges(struct kunit *test) config.num_ranges = 1; config.max_register = test_range.range_max; - map = gen_regmap(&config, &data); + map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -565,7 +572,7 @@ static void stress_insert(struct kunit *test) config.cache_type = t->type; config.max_register = 300; - map = gen_regmap(&config, &data); + map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -616,7 +623,7 @@ static void cache_bypass(struct kunit *test) config = test_regmap_config; config.cache_type = t->type; - map = gen_regmap(&config, &data); + map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -655,7 +662,7 @@ static void cache_sync(struct kunit *test) config = test_regmap_config; config.cache_type = t->type; - map = gen_regmap(&config, &data); + map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -694,7 +701,7 @@ static void cache_sync_defaults(struct kunit *test) config.cache_type = t->type; config.num_reg_defaults = BLOCK_TEST_SIZE; - map = gen_regmap(&config, &data); + map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -730,7 +737,7 @@ static void cache_sync_readonly(struct kunit *test) config.cache_type = t->type; config.writeable_reg = reg_5_false; - map = gen_regmap(&config, &data); + map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -773,7 +780,7 @@ static void cache_sync_patch(struct kunit *test) config.cache_type = t->type; config.num_reg_defaults = BLOCK_TEST_SIZE; - map = gen_regmap(&config, &data); + map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -832,7 +839,7 @@ static void cache_drop(struct kunit *test) config.cache_type = t->type; config.num_reg_defaults = BLOCK_TEST_SIZE; - map = gen_regmap(&config, &data); + map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -873,7 +880,7 @@ static void cache_present(struct kunit *test) config = test_regmap_config; config.cache_type = t->type; - map = gen_regmap(&config, &data); + map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -917,7 +924,7 @@ static void cache_range_window_reg(struct kunit *test) config.num_ranges = 1; config.max_register = test_range.range_max; - map = gen_regmap(&config, &data); + map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -997,10 +1004,12 @@ static const struct regmap_config raw_regmap_config = { .val_bits = 16, }; -static struct regmap *gen_raw_regmap(struct regmap_config *config, +static struct regmap *gen_raw_regmap(struct kunit *test, + struct regmap_config *config, struct raw_test_types *test_type, struct regmap_ram_data **data) { + struct regmap_test_priv *priv = test->priv; u16 *buf; struct regmap *ret; size_t size = (config->max_register + 1) * config->reg_bits / 8; @@ -1052,7 +1061,7 @@ static struct regmap *gen_raw_regmap(struct regmap_config *config, if (config->cache_type == REGCACHE_NONE) config->num_reg_defaults = 0; - ret = regmap_init_raw_ram(config, *data); + ret = regmap_init_raw_ram(priv->dev, config, *data); if (IS_ERR(ret)) { kfree(buf); kfree(*data); @@ -1072,7 +1081,7 @@ static void raw_read_defaults_single(struct kunit *test) config = raw_regmap_config; - map = gen_raw_regmap(&config, t, &data); + map = gen_raw_regmap(test, &config, t, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -1099,7 +1108,7 @@ static void raw_read_defaults(struct kunit *test) config = raw_regmap_config; - map = gen_raw_regmap(&config, t, &data); + map = gen_raw_regmap(test, &config, t, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -1109,7 +1118,7 @@ static void raw_read_defaults(struct kunit *test) KUNIT_ASSERT_TRUE(test, rval != NULL); if (!rval) return; - + /* Check that we can read the defaults via the API */ KUNIT_EXPECT_EQ(test, 0, regmap_raw_read(map, 0, rval, val_len)); for (i = 0; i < config.max_register + 1; i++) { @@ -1136,7 +1145,7 @@ static void raw_write_read_single(struct kunit *test) config = raw_regmap_config; - map = gen_raw_regmap(&config, t, &data); + map = gen_raw_regmap(test, &config, t, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -1164,7 +1173,7 @@ static void raw_write(struct kunit *test) config = raw_regmap_config; - map = gen_raw_regmap(&config, t, &data); + map = gen_raw_regmap(test, &config, t, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -1228,7 +1237,7 @@ static void raw_noinc_write(struct kunit *test) config.writeable_noinc_reg = reg_zero; config.readable_noinc_reg = reg_zero; - map = gen_raw_regmap(&config, t, &data); + map = gen_raw_regmap(test, &config, t, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -1276,7 +1285,7 @@ static void raw_sync(struct kunit *test) config = raw_regmap_config; - map = gen_raw_regmap(&config, t, &data); + map = gen_raw_regmap(test, &config, t, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -1323,7 +1332,7 @@ static void raw_sync(struct kunit *test) val[2] = cpu_to_be16(val[2]); else val[2] = cpu_to_le16(val[2]); - + /* The values should not appear in the "hardware" */ KUNIT_EXPECT_MEMNEQ(test, &hw_buf[2], &val[0], sizeof(val)); @@ -1356,7 +1365,7 @@ static void raw_ranges(struct kunit *test) config.num_ranges = 1; config.max_register = test_range.range_max; - map = gen_raw_regmap(&config, t, &data); + map = gen_raw_regmap(test, &config, t, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -1437,8 +1446,40 @@ static struct kunit_case regmap_test_cases[] = { {} }; +static int regmap_test_init(struct kunit *test) +{ + struct regmap_test_priv *priv; + struct device *dev; + + priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + test->priv = priv; + + dev = kunit_device_register(test, "regmap_test"); + priv->dev = get_device(dev); + if (!priv->dev) + return -ENODEV; + + dev_set_drvdata(dev, test); + + return 0; +} + +static void regmap_test_exit(struct kunit *test) +{ + struct regmap_test_priv *priv = test->priv; + + /* Destroy the dummy struct device */ + if (priv && priv->dev) + put_device(priv->dev); +} + static struct kunit_suite regmap_test_suite = { .name = "regmap", + .init = regmap_test_init, + .exit = regmap_test_exit, .test_cases = regmap_test_cases, }; kunit_test_suite(regmap_test_suite); diff --git a/drivers/base/regmap/regmap-ram.c b/drivers/base/regmap/regmap-ram.c index 192d6b131dff..5b4cbf982a11 100644 --- a/drivers/base/regmap/regmap-ram.c +++ b/drivers/base/regmap/regmap-ram.c @@ -53,7 +53,8 @@ static const struct regmap_bus regmap_ram = { .free_context = regmap_ram_free_context, }; -struct regmap *__regmap_init_ram(const struct regmap_config *config, +struct regmap *__regmap_init_ram(struct device *dev, + const struct regmap_config *config, struct regmap_ram_data *data, struct lock_class_key *lock_key, const char *lock_name) @@ -75,7 +76,7 @@ struct regmap *__regmap_init_ram(const struct regmap_config *config, if (!data->written) return ERR_PTR(-ENOMEM); - map = __regmap_init(NULL, ®map_ram, data, config, + map = __regmap_init(dev, ®map_ram, data, config, lock_key, lock_name); return map; diff --git a/drivers/base/regmap/regmap-raw-ram.c b/drivers/base/regmap/regmap-raw-ram.c index 93ae07b503fd..69eabfb89eda 100644 --- a/drivers/base/regmap/regmap-raw-ram.c +++ b/drivers/base/regmap/regmap-raw-ram.c @@ -107,7 +107,8 @@ static const struct regmap_bus regmap_raw_ram = { .free_context = regmap_raw_ram_free_context, }; -struct regmap *__regmap_init_raw_ram(const struct regmap_config *config, +struct regmap *__regmap_init_raw_ram(struct device *dev, + const struct regmap_config *config, struct regmap_ram_data *data, struct lock_class_key *lock_key, const char *lock_name) @@ -134,7 +135,7 @@ struct regmap *__regmap_init_raw_ram(const struct regmap_config *config, data->reg_endian = config->reg_format_endian; - map = __regmap_init(NULL, ®map_raw_ram, data, config, + map = __regmap_init(dev, ®map_raw_ram, data, config, lock_key, lock_name); return map; -- cgit v1.2.3 From 48bccea96fead1b212e19e38e50bf8e69287c45d Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 8 Apr 2024 15:45:52 +0100 Subject: regmap: kunit: Introduce struct for test case parameters Add a struct regmap_test_param and use it for all test cases instead of passing various different types of param object depending on the test case. This makes it much easier and cleaner to expand what can be parameterized. Signed-off-by: Richard Fitzgerald Link: https://msgid.link/r/20240408144600.230848-4-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-kunit.c | 211 +++++++++++++++++-------------------- 1 file changed, 95 insertions(+), 116 deletions(-) (limited to 'drivers/base/regmap') diff --git a/drivers/base/regmap/regmap-kunit.c b/drivers/base/regmap/regmap-kunit.c index 3bc2028fbef7..2029135f68fb 100644 --- a/drivers/base/regmap/regmap-kunit.c +++ b/drivers/base/regmap/regmap-kunit.c @@ -14,6 +14,11 @@ struct regmap_test_priv { struct device *dev; }; +struct regmap_test_param { + enum regcache_type cache; + enum regmap_endian val_endian; +}; + static void get_changed_bytes(void *orig, void *new, size_t size) { char *o = orig; @@ -37,44 +42,74 @@ static const struct regmap_config test_regmap_config = { .val_bits = sizeof(unsigned int) * 8, }; -struct regcache_types { - enum regcache_type type; - const char *name; -}; +static const char *regcache_type_name(enum regcache_type type) +{ + switch (type) { + case REGCACHE_NONE: + return "none"; + case REGCACHE_FLAT: + return "flat"; + case REGCACHE_RBTREE: + return "rbtree"; + case REGCACHE_MAPLE: + return "maple"; + default: + return NULL; + } +} + +static const char *regmap_endian_name(enum regmap_endian endian) +{ + switch (endian) { + case REGMAP_ENDIAN_BIG: + return "big"; + case REGMAP_ENDIAN_LITTLE: + return "little"; + case REGMAP_ENDIAN_DEFAULT: + return "default"; + case REGMAP_ENDIAN_NATIVE: + return "native"; + default: + return NULL; + } +} -static void case_to_desc(const struct regcache_types *t, char *desc) +static void param_to_desc(const struct regmap_test_param *param, char *desc) { - strcpy(desc, t->name); + snprintf(desc, KUNIT_PARAM_DESC_SIZE, "%s-%s", + regcache_type_name(param->cache), + regmap_endian_name(param->val_endian)); } -static const struct regcache_types regcache_types_list[] = { - { REGCACHE_NONE, "none" }, - { REGCACHE_FLAT, "flat" }, - { REGCACHE_RBTREE, "rbtree" }, - { REGCACHE_MAPLE, "maple" }, +static const struct regmap_test_param regcache_types_list[] = { + { .cache = REGCACHE_NONE }, + { .cache = REGCACHE_FLAT }, + { .cache = REGCACHE_RBTREE }, + { .cache = REGCACHE_MAPLE }, }; -KUNIT_ARRAY_PARAM(regcache_types, regcache_types_list, case_to_desc); +KUNIT_ARRAY_PARAM(regcache_types, regcache_types_list, param_to_desc); -static const struct regcache_types real_cache_types_list[] = { - { REGCACHE_FLAT, "flat" }, - { REGCACHE_RBTREE, "rbtree" }, - { REGCACHE_MAPLE, "maple" }, +static const struct regmap_test_param real_cache_types_list[] = { + { .cache = REGCACHE_FLAT }, + { .cache = REGCACHE_RBTREE }, + { .cache = REGCACHE_MAPLE }, }; -KUNIT_ARRAY_PARAM(real_cache_types, real_cache_types_list, case_to_desc); +KUNIT_ARRAY_PARAM(real_cache_types, real_cache_types_list, param_to_desc); -static const struct regcache_types sparse_cache_types_list[] = { - { REGCACHE_RBTREE, "rbtree" }, - { REGCACHE_MAPLE, "maple" }, +static const struct regmap_test_param sparse_cache_types_list[] = { + { .cache = REGCACHE_RBTREE }, + { .cache = REGCACHE_MAPLE }, }; -KUNIT_ARRAY_PARAM(sparse_cache_types, sparse_cache_types_list, case_to_desc); +KUNIT_ARRAY_PARAM(sparse_cache_types, sparse_cache_types_list, param_to_desc); static struct regmap *gen_regmap(struct kunit *test, struct regmap_config *config, struct regmap_ram_data **data) { + const struct regmap_test_param *param = test->param_value; struct regmap_test_priv *priv = test->priv; unsigned int *buf; struct regmap *ret; @@ -82,6 +117,7 @@ static struct regmap *gen_regmap(struct kunit *test, int i; struct reg_default *defaults; + config->cache_type = param->cache; config->disable_locking = config->cache_type == REGCACHE_RBTREE || config->cache_type == REGCACHE_MAPLE; @@ -126,14 +162,12 @@ static bool reg_5_false(struct device *context, unsigned int reg) static void basic_read_write(struct kunit *test) { - struct regcache_types *t = (struct regcache_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; unsigned int val, rval; config = test_regmap_config; - config.cache_type = t->type; map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); @@ -148,14 +182,13 @@ static void basic_read_write(struct kunit *test) KUNIT_EXPECT_EQ(test, val, rval); /* If using a cache the cache satisfied the read */ - KUNIT_EXPECT_EQ(test, t->type == REGCACHE_NONE, data->read[0]); + KUNIT_EXPECT_EQ(test, config.cache_type == REGCACHE_NONE, data->read[0]); regmap_exit(map); } static void bulk_write(struct kunit *test) { - struct regcache_types *t = (struct regcache_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -163,7 +196,6 @@ static void bulk_write(struct kunit *test) int i; config = test_regmap_config; - config.cache_type = t->type; map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); @@ -185,14 +217,13 @@ static void bulk_write(struct kunit *test) /* If using a cache the cache satisfied the read */ for (i = 0; i < BLOCK_TEST_SIZE; i++) - KUNIT_EXPECT_EQ(test, t->type == REGCACHE_NONE, data->read[i]); + KUNIT_EXPECT_EQ(test, config.cache_type == REGCACHE_NONE, data->read[i]); regmap_exit(map); } static void bulk_read(struct kunit *test) { - struct regcache_types *t = (struct regcache_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -200,7 +231,6 @@ static void bulk_read(struct kunit *test) int i; config = test_regmap_config; - config.cache_type = t->type; map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); @@ -218,14 +248,13 @@ static void bulk_read(struct kunit *test) /* If using a cache the cache satisfied the read */ for (i = 0; i < BLOCK_TEST_SIZE; i++) - KUNIT_EXPECT_EQ(test, t->type == REGCACHE_NONE, data->read[i]); + KUNIT_EXPECT_EQ(test, config.cache_type == REGCACHE_NONE, data->read[i]); regmap_exit(map); } static void write_readonly(struct kunit *test) { - struct regcache_types *t = (struct regcache_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -233,7 +262,6 @@ static void write_readonly(struct kunit *test) int i; config = test_regmap_config; - config.cache_type = t->type; config.num_reg_defaults = BLOCK_TEST_SIZE; config.writeable_reg = reg_5_false; @@ -260,7 +288,6 @@ static void write_readonly(struct kunit *test) static void read_writeonly(struct kunit *test) { - struct regcache_types *t = (struct regcache_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -268,7 +295,6 @@ static void read_writeonly(struct kunit *test) int i; config = test_regmap_config; - config.cache_type = t->type; config.readable_reg = reg_5_false; map = gen_regmap(test, &config, &data); @@ -284,7 +310,7 @@ static void read_writeonly(struct kunit *test) * fail if we aren't using the flat cache. */ for (i = 0; i < BLOCK_TEST_SIZE; i++) { - if (t->type != REGCACHE_FLAT) { + if (config.cache_type != REGCACHE_FLAT) { KUNIT_EXPECT_EQ(test, i != 5, regmap_read(map, i, &val) == 0); } else { @@ -300,7 +326,6 @@ static void read_writeonly(struct kunit *test) static void reg_defaults(struct kunit *test) { - struct regcache_types *t = (struct regcache_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -308,7 +333,6 @@ static void reg_defaults(struct kunit *test) int i; config = test_regmap_config; - config.cache_type = t->type; config.num_reg_defaults = BLOCK_TEST_SIZE; map = gen_regmap(test, &config, &data); @@ -323,12 +347,11 @@ static void reg_defaults(struct kunit *test) /* The data should have been read from cache if there was one */ for (i = 0; i < BLOCK_TEST_SIZE; i++) - KUNIT_EXPECT_EQ(test, t->type == REGCACHE_NONE, data->read[i]); + KUNIT_EXPECT_EQ(test, config.cache_type == REGCACHE_NONE, data->read[i]); } static void reg_defaults_read_dev(struct kunit *test) { - struct regcache_types *t = (struct regcache_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -336,7 +359,6 @@ static void reg_defaults_read_dev(struct kunit *test) int i; config = test_regmap_config; - config.cache_type = t->type; config.num_reg_defaults_raw = BLOCK_TEST_SIZE; map = gen_regmap(test, &config, &data); @@ -346,7 +368,7 @@ static void reg_defaults_read_dev(struct kunit *test) /* We should have read the cache defaults back from the map */ for (i = 0; i < BLOCK_TEST_SIZE; i++) { - KUNIT_EXPECT_EQ(test, t->type != REGCACHE_NONE, data->read[i]); + KUNIT_EXPECT_EQ(test, config.cache_type != REGCACHE_NONE, data->read[i]); data->read[i] = false; } @@ -357,12 +379,11 @@ static void reg_defaults_read_dev(struct kunit *test) /* The data should have been read from cache if there was one */ for (i = 0; i < BLOCK_TEST_SIZE; i++) - KUNIT_EXPECT_EQ(test, t->type == REGCACHE_NONE, data->read[i]); + KUNIT_EXPECT_EQ(test, config.cache_type == REGCACHE_NONE, data->read[i]); } static void register_patch(struct kunit *test) { - struct regcache_types *t = (struct regcache_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -372,7 +393,6 @@ static void register_patch(struct kunit *test) /* We need defaults so readback works */ config = test_regmap_config; - config.cache_type = t->type; config.num_reg_defaults = BLOCK_TEST_SIZE; map = gen_regmap(test, &config, &data); @@ -414,7 +434,6 @@ static void register_patch(struct kunit *test) static void stride(struct kunit *test) { - struct regcache_types *t = (struct regcache_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -422,7 +441,6 @@ static void stride(struct kunit *test) int i; config = test_regmap_config; - config.cache_type = t->type; config.reg_stride = 2; config.num_reg_defaults = BLOCK_TEST_SIZE / 2; @@ -444,7 +462,7 @@ static void stride(struct kunit *test) } else { KUNIT_EXPECT_EQ(test, 0, regmap_read(map, i, &rval)); KUNIT_EXPECT_EQ(test, data->vals[i], rval); - KUNIT_EXPECT_EQ(test, t->type == REGCACHE_NONE, + KUNIT_EXPECT_EQ(test, config.cache_type == REGCACHE_NONE, data->read[i]); KUNIT_EXPECT_EQ(test, 0, regmap_write(map, i, rval)); @@ -488,7 +506,6 @@ static bool test_range_all_volatile(struct device *dev, unsigned int reg) static void basic_ranges(struct kunit *test) { - struct regcache_types *t = (struct regcache_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -496,7 +513,6 @@ static void basic_ranges(struct kunit *test) int i; config = test_regmap_config; - config.cache_type = t->type; config.volatile_reg = test_range_all_volatile; config.ranges = &test_range; config.num_ranges = 1; @@ -560,7 +576,6 @@ static void basic_ranges(struct kunit *test) /* Try to stress dynamic creation of cache data structures */ static void stress_insert(struct kunit *test) { - struct regcache_types *t = (struct regcache_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -569,7 +584,6 @@ static void stress_insert(struct kunit *test) int i; config = test_regmap_config; - config.cache_type = t->type; config.max_register = 300; map = gen_regmap(test, &config, &data); @@ -606,7 +620,7 @@ static void stress_insert(struct kunit *test) for (i = 0; i < config.max_register; i ++) { KUNIT_EXPECT_EQ(test, 0, regmap_read(map, i, &rval)); KUNIT_EXPECT_EQ(test, rval, vals[i]); - KUNIT_EXPECT_EQ(test, t->type == REGCACHE_NONE, data->read[i]); + KUNIT_EXPECT_EQ(test, config.cache_type == REGCACHE_NONE, data->read[i]); } regmap_exit(map); @@ -614,14 +628,12 @@ static void stress_insert(struct kunit *test) static void cache_bypass(struct kunit *test) { - struct regcache_types *t = (struct regcache_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; unsigned int val, rval; config = test_regmap_config; - config.cache_type = t->type; map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); @@ -652,7 +664,6 @@ static void cache_bypass(struct kunit *test) static void cache_sync(struct kunit *test) { - struct regcache_types *t = (struct regcache_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -660,7 +671,6 @@ static void cache_sync(struct kunit *test) int i; config = test_regmap_config; - config.cache_type = t->type; map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); @@ -690,7 +700,6 @@ static void cache_sync(struct kunit *test) static void cache_sync_defaults(struct kunit *test) { - struct regcache_types *t = (struct regcache_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -698,7 +707,6 @@ static void cache_sync_defaults(struct kunit *test) int i; config = test_regmap_config; - config.cache_type = t->type; config.num_reg_defaults = BLOCK_TEST_SIZE; map = gen_regmap(test, &config, &data); @@ -726,7 +734,6 @@ static void cache_sync_defaults(struct kunit *test) static void cache_sync_readonly(struct kunit *test) { - struct regcache_types *t = (struct regcache_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -734,7 +741,6 @@ static void cache_sync_readonly(struct kunit *test) int i; config = test_regmap_config; - config.cache_type = t->type; config.writeable_reg = reg_5_false; map = gen_regmap(test, &config, &data); @@ -767,7 +773,6 @@ static void cache_sync_readonly(struct kunit *test) static void cache_sync_patch(struct kunit *test) { - struct regcache_types *t = (struct regcache_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -777,7 +782,6 @@ static void cache_sync_patch(struct kunit *test) /* We need defaults so readback works */ config = test_regmap_config; - config.cache_type = t->type; config.num_reg_defaults = BLOCK_TEST_SIZE; map = gen_regmap(test, &config, &data); @@ -828,7 +832,6 @@ static void cache_sync_patch(struct kunit *test) static void cache_drop(struct kunit *test) { - struct regcache_types *t = (struct regcache_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -836,7 +839,6 @@ static void cache_drop(struct kunit *test) int i; config = test_regmap_config; - config.cache_type = t->type; config.num_reg_defaults = BLOCK_TEST_SIZE; map = gen_regmap(test, &config, &data); @@ -870,7 +872,6 @@ static void cache_drop(struct kunit *test) static void cache_present(struct kunit *test) { - struct regcache_types *t = (struct regcache_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -878,7 +879,6 @@ static void cache_present(struct kunit *test) int i; config = test_regmap_config; - config.cache_type = t->type; map = gen_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); @@ -910,7 +910,6 @@ static void cache_present(struct kunit *test) /* Check that caching the window register works with sync */ static void cache_range_window_reg(struct kunit *test) { - struct regcache_types *t = (struct regcache_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -918,7 +917,6 @@ static void cache_range_window_reg(struct kunit *test) int i; config = test_regmap_config; - config.cache_type = t->type; config.volatile_reg = test_range_window_volatile; config.ranges = &test_range; config.num_ranges = 1; @@ -960,41 +958,29 @@ static void cache_range_window_reg(struct kunit *test) KUNIT_ASSERT_EQ(test, val, 2); } -struct raw_test_types { - const char *name; - - enum regcache_type cache_type; - enum regmap_endian val_endian; -}; - -static void raw_to_desc(const struct raw_test_types *t, char *desc) -{ - strcpy(desc, t->name); -} - -static const struct raw_test_types raw_types_list[] = { - { "none-little", REGCACHE_NONE, REGMAP_ENDIAN_LITTLE }, - { "none-big", REGCACHE_NONE, REGMAP_ENDIAN_BIG }, - { "flat-little", REGCACHE_FLAT, REGMAP_ENDIAN_LITTLE }, - { "flat-big", REGCACHE_FLAT, REGMAP_ENDIAN_BIG }, - { "rbtree-little", REGCACHE_RBTREE, REGMAP_ENDIAN_LITTLE }, - { "rbtree-big", REGCACHE_RBTREE, REGMAP_ENDIAN_BIG }, - { "maple-little", REGCACHE_MAPLE, REGMAP_ENDIAN_LITTLE }, - { "maple-big", REGCACHE_MAPLE, REGMAP_ENDIAN_BIG }, +static const struct regmap_test_param raw_types_list[] = { + { .cache = REGCACHE_NONE, .val_endian = REGMAP_ENDIAN_LITTLE }, + { .cache = REGCACHE_NONE, .val_endian = REGMAP_ENDIAN_BIG }, + { .cache = REGCACHE_FLAT, .val_endian = REGMAP_ENDIAN_LITTLE }, + { .cache = REGCACHE_FLAT, .val_endian = REGMAP_ENDIAN_BIG }, + { .cache = REGCACHE_RBTREE, .val_endian = REGMAP_ENDIAN_LITTLE }, + { .cache = REGCACHE_RBTREE, .val_endian = REGMAP_ENDIAN_BIG }, + { .cache = REGCACHE_MAPLE, .val_endian = REGMAP_ENDIAN_LITTLE }, + { .cache = REGCACHE_MAPLE, .val_endian = REGMAP_ENDIAN_BIG }, }; -KUNIT_ARRAY_PARAM(raw_test_types, raw_types_list, raw_to_desc); +KUNIT_ARRAY_PARAM(raw_test_types, raw_types_list, param_to_desc); -static const struct raw_test_types raw_cache_types_list[] = { - { "flat-little", REGCACHE_FLAT, REGMAP_ENDIAN_LITTLE }, - { "flat-big", REGCACHE_FLAT, REGMAP_ENDIAN_BIG }, - { "rbtree-little", REGCACHE_RBTREE, REGMAP_ENDIAN_LITTLE }, - { "rbtree-big", REGCACHE_RBTREE, REGMAP_ENDIAN_BIG }, - { "maple-little", REGCACHE_MAPLE, REGMAP_ENDIAN_LITTLE }, - { "maple-big", REGCACHE_MAPLE, REGMAP_ENDIAN_BIG }, +static const struct regmap_test_param raw_cache_types_list[] = { + { .cache = REGCACHE_FLAT, .val_endian = REGMAP_ENDIAN_LITTLE }, + { .cache = REGCACHE_FLAT, .val_endian = REGMAP_ENDIAN_BIG }, + { .cache = REGCACHE_RBTREE, .val_endian = REGMAP_ENDIAN_LITTLE }, + { .cache = REGCACHE_RBTREE, .val_endian = REGMAP_ENDIAN_BIG }, + { .cache = REGCACHE_MAPLE, .val_endian = REGMAP_ENDIAN_LITTLE }, + { .cache = REGCACHE_MAPLE, .val_endian = REGMAP_ENDIAN_BIG }, }; -KUNIT_ARRAY_PARAM(raw_test_cache_types, raw_cache_types_list, raw_to_desc); +KUNIT_ARRAY_PARAM(raw_test_cache_types, raw_cache_types_list, param_to_desc); static const struct regmap_config raw_regmap_config = { .max_register = BLOCK_TEST_SIZE, @@ -1006,18 +992,18 @@ static const struct regmap_config raw_regmap_config = { static struct regmap *gen_raw_regmap(struct kunit *test, struct regmap_config *config, - struct raw_test_types *test_type, struct regmap_ram_data **data) { struct regmap_test_priv *priv = test->priv; + const struct regmap_test_param *param = test->param_value; u16 *buf; struct regmap *ret; size_t size = (config->max_register + 1) * config->reg_bits / 8; int i; struct reg_default *defaults; - config->cache_type = test_type->cache_type; - config->val_format_endian = test_type->val_endian; + config->cache_type = param->cache; + config->val_format_endian = param->val_endian; config->disable_locking = config->cache_type == REGCACHE_RBTREE || config->cache_type == REGCACHE_MAPLE; @@ -1042,7 +1028,7 @@ static struct regmap *gen_raw_regmap(struct kunit *test, for (i = 0; i < config->num_reg_defaults; i++) { defaults[i].reg = i; - switch (test_type->val_endian) { + switch (param->val_endian) { case REGMAP_ENDIAN_LITTLE: defaults[i].def = le16_to_cpu(buf[i]); break; @@ -1072,7 +1058,6 @@ static struct regmap *gen_raw_regmap(struct kunit *test, static void raw_read_defaults_single(struct kunit *test) { - struct raw_test_types *t = (struct raw_test_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -1081,7 +1066,7 @@ static void raw_read_defaults_single(struct kunit *test) config = raw_regmap_config; - map = gen_raw_regmap(test, &config, t, &data); + map = gen_raw_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -1097,7 +1082,6 @@ static void raw_read_defaults_single(struct kunit *test) static void raw_read_defaults(struct kunit *test) { - struct raw_test_types *t = (struct raw_test_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -1108,7 +1092,7 @@ static void raw_read_defaults(struct kunit *test) config = raw_regmap_config; - map = gen_raw_regmap(test, &config, t, &data); + map = gen_raw_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -1136,7 +1120,6 @@ static void raw_read_defaults(struct kunit *test) static void raw_write_read_single(struct kunit *test) { - struct raw_test_types *t = (struct raw_test_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -1145,7 +1128,7 @@ static void raw_write_read_single(struct kunit *test) config = raw_regmap_config; - map = gen_raw_regmap(test, &config, t, &data); + map = gen_raw_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -1162,7 +1145,6 @@ static void raw_write_read_single(struct kunit *test) static void raw_write(struct kunit *test) { - struct raw_test_types *t = (struct raw_test_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -1173,7 +1155,7 @@ static void raw_write(struct kunit *test) config = raw_regmap_config; - map = gen_raw_regmap(test, &config, t, &data); + map = gen_raw_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -1224,7 +1206,6 @@ static bool ram_reg_zero(struct regmap_ram_data *data, unsigned int reg) static void raw_noinc_write(struct kunit *test) { - struct raw_test_types *t = (struct raw_test_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -1237,7 +1218,7 @@ static void raw_noinc_write(struct kunit *test) config.writeable_noinc_reg = reg_zero; config.readable_noinc_reg = reg_zero; - map = gen_raw_regmap(test, &config, t, &data); + map = gen_raw_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -1274,7 +1255,6 @@ static void raw_noinc_write(struct kunit *test) static void raw_sync(struct kunit *test) { - struct raw_test_types *t = (struct raw_test_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -1285,7 +1265,7 @@ static void raw_sync(struct kunit *test) config = raw_regmap_config; - map = gen_raw_regmap(test, &config, t, &data); + map = gen_raw_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; @@ -1352,7 +1332,6 @@ static void raw_sync(struct kunit *test) static void raw_ranges(struct kunit *test) { - struct raw_test_types *t = (struct raw_test_types *)test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -1365,7 +1344,7 @@ static void raw_ranges(struct kunit *test) config.num_ranges = 1; config.max_register = test_range.range_max; - map = gen_raw_regmap(test, &config, t, &data); + map = gen_raw_regmap(test, &config, &data); KUNIT_ASSERT_FALSE(test, IS_ERR(map)); if (IS_ERR(map)) return; -- cgit v1.2.3 From 710915743d53d19a1baf0326302aa1f743ab018e Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 8 Apr 2024 15:45:53 +0100 Subject: regmap: kunit: Run sparse cache tests at non-zero register addresses Run the cache_drop() and cache_present() tests at blocks of addresses that don't start at zero. This adds a from_reg parameter to struct regmap_test_param. This is used to set the base address of the register defaults created by gen_regmap(). Extra entries are added to sparse_cache_types_list[] to test at non-zero from_reg values. The cache_drop() and cache_present() tests are updated to test at the given offset. The aim here is to add test cases to cache_drop() for the bug fixed by commit 00bb549d7d63 ("regmap: maple: Fix cache corruption in regcache_maple_drop()") But the same parameter table is used by the cache_present() test so let's also update that to use from_reg. Signed-off-by: Richard Fitzgerald Link: https://msgid.link/r/20240408144600.230848-5-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-kunit.c | 67 +++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 22 deletions(-) (limited to 'drivers/base/regmap') diff --git a/drivers/base/regmap/regmap-kunit.c b/drivers/base/regmap/regmap-kunit.c index 2029135f68fb..ae147fc8509b 100644 --- a/drivers/base/regmap/regmap-kunit.c +++ b/drivers/base/regmap/regmap-kunit.c @@ -17,6 +17,8 @@ struct regmap_test_priv { struct regmap_test_param { enum regcache_type cache; enum regmap_endian val_endian; + + unsigned int from_reg; }; static void get_changed_bytes(void *orig, void *new, size_t size) @@ -37,7 +39,6 @@ static void get_changed_bytes(void *orig, void *new, size_t size) } static const struct regmap_config test_regmap_config = { - .max_register = BLOCK_TEST_SIZE, .reg_stride = 1, .val_bits = sizeof(unsigned int) * 8, }; @@ -76,9 +77,10 @@ static const char *regmap_endian_name(enum regmap_endian endian) static void param_to_desc(const struct regmap_test_param *param, char *desc) { - snprintf(desc, KUNIT_PARAM_DESC_SIZE, "%s-%s", + snprintf(desc, KUNIT_PARAM_DESC_SIZE, "%s-%s @%#x", regcache_type_name(param->cache), - regmap_endian_name(param->val_endian)); + regmap_endian_name(param->val_endian), + param->from_reg); } static const struct regmap_test_param regcache_types_list[] = { @@ -99,8 +101,16 @@ static const struct regmap_test_param real_cache_types_list[] = { KUNIT_ARRAY_PARAM(real_cache_types, real_cache_types_list, param_to_desc); static const struct regmap_test_param sparse_cache_types_list[] = { - { .cache = REGCACHE_RBTREE }, - { .cache = REGCACHE_MAPLE }, + { .cache = REGCACHE_RBTREE, .from_reg = 0 }, + { .cache = REGCACHE_RBTREE, .from_reg = 0x2001 }, + { .cache = REGCACHE_RBTREE, .from_reg = 0x2002 }, + { .cache = REGCACHE_RBTREE, .from_reg = 0x2003 }, + { .cache = REGCACHE_RBTREE, .from_reg = 0x2004 }, + { .cache = REGCACHE_MAPLE, .from_reg = 0 }, + { .cache = REGCACHE_MAPLE, .from_reg = 0x2001 }, + { .cache = REGCACHE_MAPLE, .from_reg = 0x2002 }, + { .cache = REGCACHE_MAPLE, .from_reg = 0x2003 }, + { .cache = REGCACHE_MAPLE, .from_reg = 0x2004 }, }; KUNIT_ARRAY_PARAM(sparse_cache_types, sparse_cache_types_list, param_to_desc); @@ -113,7 +123,7 @@ static struct regmap *gen_regmap(struct kunit *test, struct regmap_test_priv *priv = test->priv; unsigned int *buf; struct regmap *ret; - size_t size = (config->max_register + 1) * sizeof(unsigned int); + size_t size; int i; struct reg_default *defaults; @@ -121,6 +131,16 @@ static struct regmap *gen_regmap(struct kunit *test, config->disable_locking = config->cache_type == REGCACHE_RBTREE || config->cache_type == REGCACHE_MAPLE; + if (config->max_register == 0) { + config->max_register = param->from_reg; + if (config->num_reg_defaults) + config->max_register += (config->num_reg_defaults - 1) * + config->reg_stride; + else + config->max_register += (BLOCK_TEST_SIZE * config->reg_stride); + } + + size = (config->max_register + 1) * sizeof(unsigned int); buf = kmalloc(size, GFP_KERNEL); if (!buf) return ERR_PTR(-ENOMEM); @@ -141,8 +161,8 @@ static struct regmap *gen_regmap(struct kunit *test, config->reg_defaults = defaults; for (i = 0; i < config->num_reg_defaults; i++) { - defaults[i].reg = i * config->reg_stride; - defaults[i].def = buf[i * config->reg_stride]; + defaults[i].reg = param->from_reg + (i * config->reg_stride); + defaults[i].def = buf[param->from_reg + (i * config->reg_stride)]; } } @@ -832,6 +852,7 @@ static void cache_sync_patch(struct kunit *test) static void cache_drop(struct kunit *test) { + const struct regmap_test_param *param = test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -848,30 +869,32 @@ static void cache_drop(struct kunit *test) /* Ensure the data is read from the cache */ for (i = 0; i < BLOCK_TEST_SIZE; i++) - data->read[i] = false; - KUNIT_EXPECT_EQ(test, 0, regmap_bulk_read(map, 0, rval, + data->read[param->from_reg + i] = false; + KUNIT_EXPECT_EQ(test, 0, regmap_bulk_read(map, param->from_reg, rval, BLOCK_TEST_SIZE)); for (i = 0; i < BLOCK_TEST_SIZE; i++) { - KUNIT_EXPECT_FALSE(test, data->read[i]); - data->read[i] = false; + KUNIT_EXPECT_FALSE(test, data->read[param->from_reg + i]); + data->read[param->from_reg + i] = false; } - KUNIT_EXPECT_MEMEQ(test, data->vals, rval, sizeof(rval)); + KUNIT_EXPECT_MEMEQ(test, &data->vals[param->from_reg], rval, sizeof(rval)); /* Drop some registers */ - KUNIT_EXPECT_EQ(test, 0, regcache_drop_region(map, 3, 5)); + KUNIT_EXPECT_EQ(test, 0, regcache_drop_region(map, param->from_reg + 3, + param->from_reg + 5)); /* Reread and check only the dropped registers hit the device. */ - KUNIT_EXPECT_EQ(test, 0, regmap_bulk_read(map, 0, rval, + KUNIT_EXPECT_EQ(test, 0, regmap_bulk_read(map, param->from_reg, rval, BLOCK_TEST_SIZE)); for (i = 0; i < BLOCK_TEST_SIZE; i++) - KUNIT_EXPECT_EQ(test, data->read[i], i >= 3 && i <= 5); - KUNIT_EXPECT_MEMEQ(test, data->vals, rval, sizeof(rval)); + KUNIT_EXPECT_EQ(test, data->read[param->from_reg + i], i >= 3 && i <= 5); + KUNIT_EXPECT_MEMEQ(test, &data->vals[param->from_reg], rval, sizeof(rval)); regmap_exit(map); } static void cache_present(struct kunit *test) { + const struct regmap_test_param *param = test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -886,23 +909,23 @@ static void cache_present(struct kunit *test) return; for (i = 0; i < BLOCK_TEST_SIZE; i++) - data->read[i] = false; + data->read[param->from_reg + i] = false; /* No defaults so no registers cached. */ for (i = 0; i < BLOCK_TEST_SIZE; i++) - KUNIT_ASSERT_FALSE(test, regcache_reg_cached(map, i)); + KUNIT_ASSERT_FALSE(test, regcache_reg_cached(map, param->from_reg + i)); /* We didn't trigger any reads */ for (i = 0; i < BLOCK_TEST_SIZE; i++) - KUNIT_ASSERT_FALSE(test, data->read[i]); + KUNIT_ASSERT_FALSE(test, data->read[param->from_reg + i]); /* Fill the cache */ for (i = 0; i < BLOCK_TEST_SIZE; i++) - KUNIT_EXPECT_EQ(test, 0, regmap_read(map, i, &val)); + KUNIT_EXPECT_EQ(test, 0, regmap_read(map, param->from_reg + i, &val)); /* Now everything should be cached */ for (i = 0; i < BLOCK_TEST_SIZE; i++) - KUNIT_ASSERT_TRUE(test, regcache_reg_cached(map, i)); + KUNIT_ASSERT_TRUE(test, regcache_reg_cached(map, param->from_reg + i)); regmap_exit(map); } -- cgit v1.2.3 From ac4394bf9c5e065919a0e491bfd95e2106b1b9b2 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 8 Apr 2024 15:45:54 +0100 Subject: regmap: kunit: Run non-sparse cache tests at non-zero register addresses Change the tests parameterized by real_cache_types_list[] to test at some register addresses that are not 0. The cache_range_window_reg() test has hardcoded address assumptions that are not present in any other tests using real_cache_types_list[] table. So it has been given a separate parameter table, real_cache_types_only_list[], that preserves the original parameterization. Signed-off-by: Richard Fitzgerald Link: https://msgid.link/r/20240408144600.230848-6-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-kunit.c | 86 +++++++++++++++++++++++++------------- 1 file changed, 57 insertions(+), 29 deletions(-) (limited to 'drivers/base/regmap') diff --git a/drivers/base/regmap/regmap-kunit.c b/drivers/base/regmap/regmap-kunit.c index ae147fc8509b..873161b58de9 100644 --- a/drivers/base/regmap/regmap-kunit.c +++ b/drivers/base/regmap/regmap-kunit.c @@ -92,12 +92,32 @@ static const struct regmap_test_param regcache_types_list[] = { KUNIT_ARRAY_PARAM(regcache_types, regcache_types_list, param_to_desc); -static const struct regmap_test_param real_cache_types_list[] = { +static const struct regmap_test_param real_cache_types_only_list[] = { { .cache = REGCACHE_FLAT }, { .cache = REGCACHE_RBTREE }, { .cache = REGCACHE_MAPLE }, }; +KUNIT_ARRAY_PARAM(real_cache_types_only, real_cache_types_only_list, param_to_desc); + +static const struct regmap_test_param real_cache_types_list[] = { + { .cache = REGCACHE_FLAT, .from_reg = 0 }, + { .cache = REGCACHE_FLAT, .from_reg = 0x2001 }, + { .cache = REGCACHE_FLAT, .from_reg = 0x2002 }, + { .cache = REGCACHE_FLAT, .from_reg = 0x2003 }, + { .cache = REGCACHE_FLAT, .from_reg = 0x2004 }, + { .cache = REGCACHE_RBTREE, .from_reg = 0 }, + { .cache = REGCACHE_RBTREE, .from_reg = 0x2001 }, + { .cache = REGCACHE_RBTREE, .from_reg = 0x2002 }, + { .cache = REGCACHE_RBTREE, .from_reg = 0x2003 }, + { .cache = REGCACHE_RBTREE, .from_reg = 0x2004 }, + { .cache = REGCACHE_MAPLE, .from_reg = 0 }, + { .cache = REGCACHE_MAPLE, .from_reg = 0x2001 }, + { .cache = REGCACHE_MAPLE, .from_reg = 0x2002 }, + { .cache = REGCACHE_MAPLE, .from_reg = 0x2003 }, + { .cache = REGCACHE_MAPLE, .from_reg = 0x2004 }, +}; + KUNIT_ARRAY_PARAM(real_cache_types, real_cache_types_list, param_to_desc); static const struct regmap_test_param sparse_cache_types_list[] = { @@ -175,9 +195,12 @@ static struct regmap *gen_regmap(struct kunit *test, return ret; } -static bool reg_5_false(struct device *context, unsigned int reg) +static bool reg_5_false(struct device *dev, unsigned int reg) { - return reg != 5; + struct kunit *test = dev_get_drvdata(dev); + const struct regmap_test_param *param = test->param_value; + + return reg != (param->from_reg + 5); } static void basic_read_write(struct kunit *test) @@ -648,6 +671,7 @@ static void stress_insert(struct kunit *test) static void cache_bypass(struct kunit *test) { + const struct regmap_test_param *param = test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -663,20 +687,20 @@ static void cache_bypass(struct kunit *test) get_random_bytes(&val, sizeof(val)); /* Ensure the cache has a value in it */ - KUNIT_EXPECT_EQ(test, 0, regmap_write(map, 0, val)); + KUNIT_EXPECT_EQ(test, 0, regmap_write(map, param->from_reg, val)); /* Bypass then write a different value */ regcache_cache_bypass(map, true); - KUNIT_EXPECT_EQ(test, 0, regmap_write(map, 0, val + 1)); + KUNIT_EXPECT_EQ(test, 0, regmap_write(map, param->from_reg, val + 1)); /* Read the bypassed value */ - KUNIT_EXPECT_EQ(test, 0, regmap_read(map, 0, &rval)); + KUNIT_EXPECT_EQ(test, 0, regmap_read(map, param->from_reg, &rval)); KUNIT_EXPECT_EQ(test, val + 1, rval); - KUNIT_EXPECT_EQ(test, data->vals[0], rval); + KUNIT_EXPECT_EQ(test, data->vals[param->from_reg], rval); /* Disable bypass, the cache should still return the original value */ regcache_cache_bypass(map, false); - KUNIT_EXPECT_EQ(test, 0, regmap_read(map, 0, &rval)); + KUNIT_EXPECT_EQ(test, 0, regmap_read(map, param->from_reg, &rval)); KUNIT_EXPECT_EQ(test, val, rval); regmap_exit(map); @@ -684,6 +708,7 @@ static void cache_bypass(struct kunit *test) static void cache_sync(struct kunit *test) { + const struct regmap_test_param *param = test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -700,10 +725,10 @@ static void cache_sync(struct kunit *test) get_random_bytes(&val, sizeof(val)); /* Put some data into the cache */ - KUNIT_EXPECT_EQ(test, 0, regmap_bulk_write(map, 0, val, + KUNIT_EXPECT_EQ(test, 0, regmap_bulk_write(map, param->from_reg, val, BLOCK_TEST_SIZE)); for (i = 0; i < BLOCK_TEST_SIZE; i++) - data->written[i] = false; + data->written[param->from_reg + i] = false; /* Trash the data on the device itself then resync */ regcache_mark_dirty(map); @@ -711,15 +736,16 @@ static void cache_sync(struct kunit *test) KUNIT_EXPECT_EQ(test, 0, regcache_sync(map)); /* Did we just write the correct data out? */ - KUNIT_EXPECT_MEMEQ(test, data->vals, val, sizeof(val)); + KUNIT_EXPECT_MEMEQ(test, &data->vals[param->from_reg], val, sizeof(val)); for (i = 0; i < BLOCK_TEST_SIZE; i++) - KUNIT_EXPECT_EQ(test, true, data->written[i]); + KUNIT_EXPECT_EQ(test, true, data->written[param->from_reg + i]); regmap_exit(map); } static void cache_sync_defaults(struct kunit *test) { + const struct regmap_test_param *param = test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -737,23 +763,24 @@ static void cache_sync_defaults(struct kunit *test) get_random_bytes(&val, sizeof(val)); /* Change the value of one register */ - KUNIT_EXPECT_EQ(test, 0, regmap_write(map, 2, val)); + KUNIT_EXPECT_EQ(test, 0, regmap_write(map, param->from_reg + 2, val)); /* Resync */ regcache_mark_dirty(map); for (i = 0; i < BLOCK_TEST_SIZE; i++) - data->written[i] = false; + data->written[param->from_reg + i] = false; KUNIT_EXPECT_EQ(test, 0, regcache_sync(map)); /* Did we just sync the one register we touched? */ for (i = 0; i < BLOCK_TEST_SIZE; i++) - KUNIT_EXPECT_EQ(test, i == 2, data->written[i]); + KUNIT_EXPECT_EQ(test, i == 2, data->written[param->from_reg + i]); regmap_exit(map); } static void cache_sync_readonly(struct kunit *test) { + const struct regmap_test_param *param = test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -770,29 +797,30 @@ static void cache_sync_readonly(struct kunit *test) /* Read all registers to fill the cache */ for (i = 0; i < BLOCK_TEST_SIZE; i++) - KUNIT_EXPECT_EQ(test, 0, regmap_read(map, i, &val)); + KUNIT_EXPECT_EQ(test, 0, regmap_read(map, param->from_reg + i, &val)); /* Change the value of all registers, readonly should fail */ get_random_bytes(&val, sizeof(val)); regcache_cache_only(map, true); for (i = 0; i < BLOCK_TEST_SIZE; i++) - KUNIT_EXPECT_EQ(test, i != 5, regmap_write(map, i, val) == 0); + KUNIT_EXPECT_EQ(test, i != 5, regmap_write(map, param->from_reg + i, val) == 0); regcache_cache_only(map, false); /* Resync */ for (i = 0; i < BLOCK_TEST_SIZE; i++) - data->written[i] = false; + data->written[param->from_reg + i] = false; KUNIT_EXPECT_EQ(test, 0, regcache_sync(map)); /* Did that match what we see on the device? */ for (i = 0; i < BLOCK_TEST_SIZE; i++) - KUNIT_EXPECT_EQ(test, i != 5, data->written[i]); + KUNIT_EXPECT_EQ(test, i != 5, data->written[param->from_reg + i]); regmap_exit(map); } static void cache_sync_patch(struct kunit *test) { + const struct regmap_test_param *param = test->param_value; struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; @@ -810,14 +838,14 @@ static void cache_sync_patch(struct kunit *test) return; /* Stash the original values */ - KUNIT_EXPECT_EQ(test, 0, regmap_bulk_read(map, 0, rval, + KUNIT_EXPECT_EQ(test, 0, regmap_bulk_read(map, param->from_reg, rval, BLOCK_TEST_SIZE)); /* Patch a couple of values */ - patch[0].reg = 2; + patch[0].reg = param->from_reg + 2; patch[0].def = rval[2] + 1; patch[0].delay_us = 0; - patch[1].reg = 5; + patch[1].reg = param->from_reg + 5; patch[1].def = rval[5] + 1; patch[1].delay_us = 0; KUNIT_EXPECT_EQ(test, 0, regmap_register_patch(map, patch, @@ -826,23 +854,23 @@ static void cache_sync_patch(struct kunit *test) /* Sync the cache */ regcache_mark_dirty(map); for (i = 0; i < BLOCK_TEST_SIZE; i++) - data->written[i] = false; + data->written[param->from_reg + i] = false; KUNIT_EXPECT_EQ(test, 0, regcache_sync(map)); /* The patch should be on the device but not in the cache */ for (i = 0; i < BLOCK_TEST_SIZE; i++) { - KUNIT_EXPECT_EQ(test, 0, regmap_read(map, i, &val)); + KUNIT_EXPECT_EQ(test, 0, regmap_read(map, param->from_reg + i, &val)); KUNIT_EXPECT_EQ(test, val, rval[i]); switch (i) { case 2: case 5: - KUNIT_EXPECT_EQ(test, true, data->written[i]); - KUNIT_EXPECT_EQ(test, data->vals[i], rval[i] + 1); + KUNIT_EXPECT_EQ(test, true, data->written[param->from_reg + i]); + KUNIT_EXPECT_EQ(test, data->vals[param->from_reg + i], rval[i] + 1); break; default: - KUNIT_EXPECT_EQ(test, false, data->written[i]); - KUNIT_EXPECT_EQ(test, data->vals[i], rval[i]); + KUNIT_EXPECT_EQ(test, false, data->written[param->from_reg + i]); + KUNIT_EXPECT_EQ(test, data->vals[param->from_reg + i], rval[i]); break; } } @@ -1436,7 +1464,7 @@ static struct kunit_case regmap_test_cases[] = { KUNIT_CASE_PARAM(cache_sync_patch, real_cache_types_gen_params), KUNIT_CASE_PARAM(cache_drop, sparse_cache_types_gen_params), KUNIT_CASE_PARAM(cache_present, sparse_cache_types_gen_params), - KUNIT_CASE_PARAM(cache_range_window_reg, real_cache_types_gen_params), + KUNIT_CASE_PARAM(cache_range_window_reg, real_cache_types_only_gen_params), KUNIT_CASE_PARAM(raw_read_defaults_single, raw_test_types_gen_params), KUNIT_CASE_PARAM(raw_read_defaults, raw_test_types_gen_params), -- cgit v1.2.3 From 7dd52d301cfcff9a67be19d00289e03d80d05e46 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 8 Apr 2024 15:45:55 +0100 Subject: regmap: kunit: Add more cache-drop tests Extend the testing of cache-drop. - Added cache_drop_all_and_sync_marked_dirty(). If all registers are dropped from the cache a regcache_mark_dirty() followed by regcache_sync() should not write anything because the cache is empty. - Added cache_drop_all_and_sync_no_defaults(). This is similar to cache_drop_all_and_sync_marked_dirty() except that regcache_mark_dirty() is NOT called. All registers were dropped so regcache_sync() should not write anything. - Added cache_drop_all_and_sync_has_defaults(). This is the same as cache_drop_all_and_sync_no_defaults() except that the regmap has a table of default values. Signed-off-by: Richard Fitzgerald Link: https://msgid.link/r/20240408144600.230848-7-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-kunit.c | 135 +++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) (limited to 'drivers/base/regmap') diff --git a/drivers/base/regmap/regmap-kunit.c b/drivers/base/regmap/regmap-kunit.c index 873161b58de9..3201f5f6406b 100644 --- a/drivers/base/regmap/regmap-kunit.c +++ b/drivers/base/regmap/regmap-kunit.c @@ -920,6 +920,138 @@ static void cache_drop(struct kunit *test) regmap_exit(map); } +static void cache_drop_all_and_sync_marked_dirty(struct kunit *test) +{ + const struct regmap_test_param *param = test->param_value; + struct regmap *map; + struct regmap_config config; + struct regmap_ram_data *data; + unsigned int rval[BLOCK_TEST_SIZE]; + int i; + + config = test_regmap_config; + config.num_reg_defaults = BLOCK_TEST_SIZE; + + map = gen_regmap(test, &config, &data); + KUNIT_ASSERT_FALSE(test, IS_ERR(map)); + if (IS_ERR(map)) + return; + + /* Ensure the data is read from the cache */ + for (i = 0; i < BLOCK_TEST_SIZE; i++) + data->read[param->from_reg + i] = false; + KUNIT_EXPECT_EQ(test, 0, regmap_bulk_read(map, param->from_reg, rval, + BLOCK_TEST_SIZE)); + KUNIT_EXPECT_MEMEQ(test, &data->vals[param->from_reg], rval, sizeof(rval)); + + /* Change all values in cache from defaults */ + for (i = 0; i < BLOCK_TEST_SIZE; i++) + KUNIT_EXPECT_EQ(test, 0, regmap_write(map, param->from_reg + i, rval[i] + 1)); + + /* Drop all registers */ + KUNIT_EXPECT_EQ(test, 0, regcache_drop_region(map, 0, config.max_register)); + + /* Mark dirty and cache sync should not write anything. */ + regcache_mark_dirty(map); + for (i = 0; i < BLOCK_TEST_SIZE; i++) + data->written[param->from_reg + i] = false; + + KUNIT_EXPECT_EQ(test, 0, regcache_sync(map)); + for (i = 0; i <= config.max_register; i++) + KUNIT_EXPECT_FALSE(test, data->written[i]); + + regmap_exit(map); +} + +static void cache_drop_all_and_sync_no_defaults(struct kunit *test) +{ + const struct regmap_test_param *param = test->param_value; + struct regmap *map; + struct regmap_config config; + struct regmap_ram_data *data; + unsigned int rval[BLOCK_TEST_SIZE]; + int i; + + config = test_regmap_config; + + map = gen_regmap(test, &config, &data); + KUNIT_ASSERT_FALSE(test, IS_ERR(map)); + if (IS_ERR(map)) + return; + + /* Ensure the data is read from the cache */ + for (i = 0; i < BLOCK_TEST_SIZE; i++) + data->read[param->from_reg + i] = false; + KUNIT_EXPECT_EQ(test, 0, regmap_bulk_read(map, param->from_reg, rval, + BLOCK_TEST_SIZE)); + KUNIT_EXPECT_MEMEQ(test, &data->vals[param->from_reg], rval, sizeof(rval)); + + /* Change all values in cache */ + for (i = 0; i < BLOCK_TEST_SIZE; i++) + KUNIT_EXPECT_EQ(test, 0, regmap_write(map, param->from_reg + i, rval[i] + 1)); + + /* Drop all registers */ + KUNIT_EXPECT_EQ(test, 0, regcache_drop_region(map, 0, config.max_register)); + + /* + * Sync cache without marking it dirty. All registers were dropped + * so the cache should not have any entries to write out. + */ + for (i = 0; i < BLOCK_TEST_SIZE; i++) + data->written[param->from_reg + i] = false; + + KUNIT_EXPECT_EQ(test, 0, regcache_sync(map)); + for (i = 0; i <= config.max_register; i++) + KUNIT_EXPECT_FALSE(test, data->written[i]); + + regmap_exit(map); +} + +static void cache_drop_all_and_sync_has_defaults(struct kunit *test) +{ + const struct regmap_test_param *param = test->param_value; + struct regmap *map; + struct regmap_config config; + struct regmap_ram_data *data; + unsigned int rval[BLOCK_TEST_SIZE]; + int i; + + config = test_regmap_config; + config.num_reg_defaults = BLOCK_TEST_SIZE; + + map = gen_regmap(test, &config, &data); + KUNIT_ASSERT_FALSE(test, IS_ERR(map)); + if (IS_ERR(map)) + return; + + /* Ensure the data is read from the cache */ + for (i = 0; i < BLOCK_TEST_SIZE; i++) + data->read[param->from_reg + i] = false; + KUNIT_EXPECT_EQ(test, 0, regmap_bulk_read(map, param->from_reg, rval, + BLOCK_TEST_SIZE)); + KUNIT_EXPECT_MEMEQ(test, &data->vals[param->from_reg], rval, sizeof(rval)); + + /* Change all values in cache from defaults */ + for (i = 0; i < BLOCK_TEST_SIZE; i++) + KUNIT_EXPECT_EQ(test, 0, regmap_write(map, param->from_reg + i, rval[i] + 1)); + + /* Drop all registers */ + KUNIT_EXPECT_EQ(test, 0, regcache_drop_region(map, 0, config.max_register)); + + /* + * Sync cache without marking it dirty. All registers were dropped + * so the cache should not have any entries to write out. + */ + for (i = 0; i < BLOCK_TEST_SIZE; i++) + data->written[param->from_reg + i] = false; + + KUNIT_EXPECT_EQ(test, 0, regcache_sync(map)); + for (i = 0; i <= config.max_register; i++) + KUNIT_EXPECT_FALSE(test, data->written[i]); + + regmap_exit(map); +} + static void cache_present(struct kunit *test) { const struct regmap_test_param *param = test->param_value; @@ -1463,6 +1595,9 @@ static struct kunit_case regmap_test_cases[] = { KUNIT_CASE_PARAM(cache_sync_readonly, real_cache_types_gen_params), KUNIT_CASE_PARAM(cache_sync_patch, real_cache_types_gen_params), KUNIT_CASE_PARAM(cache_drop, sparse_cache_types_gen_params), + KUNIT_CASE_PARAM(cache_drop_all_and_sync_marked_dirty, sparse_cache_types_gen_params), + KUNIT_CASE_PARAM(cache_drop_all_and_sync_no_defaults, sparse_cache_types_gen_params), + KUNIT_CASE_PARAM(cache_drop_all_and_sync_has_defaults, sparse_cache_types_gen_params), KUNIT_CASE_PARAM(cache_present, sparse_cache_types_gen_params), KUNIT_CASE_PARAM(cache_range_window_reg, real_cache_types_only_gen_params), -- cgit v1.2.3 From 7903d15f008056c8c152f2aa3b36217917853264 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 8 Apr 2024 15:45:56 +0100 Subject: regmap: kunit: Add more cache-sync tests Extend the testing of cache-sync. - cache_sync() renamed cache_sync_marked_dirty() for clarity of what conditions it is testing. - cache_sync_defaults() renamed cache_sync_defaults_marked_dirty() for clarity. Added code to write the register back to its default value to check that a dirty sync doesn't write out the default value. - Added cache_sync_after_cache_only(). Tests syncing the cache without calling regcache_mark_dirty(). A register written while in cache-only should be written out by regcache_sync(). - Added cache_sync_default_after_cache_only. This is similar to cache_sync_after_cache_only(), but the register is changed to its default value while in cache-only. Because regcache_mark_dirty() was NOT called, regacache_sync() should write out the register. Signed-off-by: Richard Fitzgerald Link: https://msgid.link/r/20240408144600.230848-8-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-kunit.c | 126 +++++++++++++++++++++++++++++++++++-- 1 file changed, 122 insertions(+), 4 deletions(-) (limited to 'drivers/base/regmap') diff --git a/drivers/base/regmap/regmap-kunit.c b/drivers/base/regmap/regmap-kunit.c index 3201f5f6406b..1b34f92b1aaf 100644 --- a/drivers/base/regmap/regmap-kunit.c +++ b/drivers/base/regmap/regmap-kunit.c @@ -706,7 +706,7 @@ static void cache_bypass(struct kunit *test) regmap_exit(map); } -static void cache_sync(struct kunit *test) +static void cache_sync_marked_dirty(struct kunit *test) { const struct regmap_test_param *param = test->param_value; struct regmap *map; @@ -743,7 +743,58 @@ static void cache_sync(struct kunit *test) regmap_exit(map); } -static void cache_sync_defaults(struct kunit *test) +static void cache_sync_after_cache_only(struct kunit *test) +{ + const struct regmap_test_param *param = test->param_value; + struct regmap *map; + struct regmap_config config; + struct regmap_ram_data *data; + unsigned int val[BLOCK_TEST_SIZE]; + unsigned int val_mask; + int i; + + config = test_regmap_config; + + map = gen_regmap(test, &config, &data); + KUNIT_ASSERT_FALSE(test, IS_ERR(map)); + if (IS_ERR(map)) + return; + + val_mask = GENMASK(config.val_bits - 1, 0); + get_random_bytes(&val, sizeof(val)); + + /* Put some data into the cache */ + KUNIT_EXPECT_EQ(test, 0, regmap_bulk_write(map, param->from_reg, val, + BLOCK_TEST_SIZE)); + for (i = 0; i < BLOCK_TEST_SIZE; i++) + data->written[param->from_reg + i] = false; + + /* Set cache-only and change the values */ + regcache_cache_only(map, true); + for (i = 0; i < ARRAY_SIZE(val); ++i) + val[i] = ~val[i] & val_mask; + + KUNIT_EXPECT_EQ(test, 0, regmap_bulk_write(map, param->from_reg, val, + BLOCK_TEST_SIZE)); + for (i = 0; i < BLOCK_TEST_SIZE; i++) + KUNIT_EXPECT_FALSE(test, data->written[param->from_reg + i]); + + KUNIT_EXPECT_MEMNEQ(test, &data->vals[param->from_reg], val, sizeof(val)); + + /* Exit cache-only and sync the cache without marking hardware registers dirty */ + regcache_cache_only(map, false); + + KUNIT_EXPECT_EQ(test, 0, regcache_sync(map)); + + /* Did we just write the correct data out? */ + KUNIT_EXPECT_MEMEQ(test, &data->vals[param->from_reg], val, sizeof(val)); + for (i = 0; i < BLOCK_TEST_SIZE; i++) + KUNIT_EXPECT_TRUE(test, data->written[param->from_reg + i]); + + regmap_exit(map); +} + +static void cache_sync_defaults_marked_dirty(struct kunit *test) { const struct regmap_test_param *param = test->param_value; struct regmap *map; @@ -775,6 +826,71 @@ static void cache_sync_defaults(struct kunit *test) for (i = 0; i < BLOCK_TEST_SIZE; i++) KUNIT_EXPECT_EQ(test, i == 2, data->written[param->from_reg + i]); + /* Rewrite registers back to their defaults */ + for (i = 0; i < config.num_reg_defaults; ++i) + KUNIT_EXPECT_EQ(test, 0, regmap_write(map, config.reg_defaults[i].reg, + config.reg_defaults[i].def)); + + /* + * Resync after regcache_mark_dirty() should not write out registers + * that are at default value + */ + for (i = 0; i < BLOCK_TEST_SIZE; i++) + data->written[param->from_reg + i] = false; + regcache_mark_dirty(map); + KUNIT_EXPECT_EQ(test, 0, regcache_sync(map)); + for (i = 0; i < BLOCK_TEST_SIZE; i++) + KUNIT_EXPECT_FALSE(test, data->written[param->from_reg + i]); + + regmap_exit(map); +} + +static void cache_sync_default_after_cache_only(struct kunit *test) +{ + const struct regmap_test_param *param = test->param_value; + struct regmap *map; + struct regmap_config config; + struct regmap_ram_data *data; + unsigned int orig_val; + int i; + + config = test_regmap_config; + config.num_reg_defaults = BLOCK_TEST_SIZE; + + map = gen_regmap(test, &config, &data); + KUNIT_ASSERT_FALSE(test, IS_ERR(map)); + if (IS_ERR(map)) + return; + + KUNIT_EXPECT_EQ(test, 0, regmap_read(map, param->from_reg + 2, &orig_val)); + + /* Enter cache-only and change the value of one register */ + regcache_cache_only(map, true); + KUNIT_EXPECT_EQ(test, 0, regmap_write(map, param->from_reg + 2, orig_val + 1)); + + /* Exit cache-only and resync, should write out the changed register */ + regcache_cache_only(map, false); + for (i = 0; i < BLOCK_TEST_SIZE; i++) + data->written[param->from_reg + i] = false; + KUNIT_EXPECT_EQ(test, 0, regcache_sync(map)); + + /* Was the register written out? */ + KUNIT_EXPECT_TRUE(test, data->written[param->from_reg + 2]); + KUNIT_EXPECT_EQ(test, data->vals[param->from_reg + 2], orig_val + 1); + + /* Enter cache-only and write register back to its default value */ + regcache_cache_only(map, true); + KUNIT_EXPECT_EQ(test, 0, regmap_write(map, param->from_reg + 2, orig_val)); + + /* Resync should write out the new value */ + regcache_cache_only(map, false); + for (i = 0; i < BLOCK_TEST_SIZE; i++) + data->written[param->from_reg + i] = false; + + KUNIT_EXPECT_EQ(test, 0, regcache_sync(map)); + KUNIT_EXPECT_TRUE(test, data->written[param->from_reg + 2]); + KUNIT_EXPECT_EQ(test, data->vals[param->from_reg + 2], orig_val); + regmap_exit(map); } @@ -1590,8 +1706,10 @@ static struct kunit_case regmap_test_cases[] = { KUNIT_CASE_PARAM(basic_ranges, regcache_types_gen_params), KUNIT_CASE_PARAM(stress_insert, regcache_types_gen_params), KUNIT_CASE_PARAM(cache_bypass, real_cache_types_gen_params), - KUNIT_CASE_PARAM(cache_sync, real_cache_types_gen_params), - KUNIT_CASE_PARAM(cache_sync_defaults, real_cache_types_gen_params), + KUNIT_CASE_PARAM(cache_sync_marked_dirty, real_cache_types_gen_params), + KUNIT_CASE_PARAM(cache_sync_after_cache_only, real_cache_types_gen_params), + KUNIT_CASE_PARAM(cache_sync_defaults_marked_dirty, real_cache_types_gen_params), + KUNIT_CASE_PARAM(cache_sync_default_after_cache_only, real_cache_types_gen_params), KUNIT_CASE_PARAM(cache_sync_readonly, real_cache_types_gen_params), KUNIT_CASE_PARAM(cache_sync_patch, real_cache_types_gen_params), KUNIT_CASE_PARAM(cache_drop, sparse_cache_types_gen_params), -- cgit v1.2.3 From ce75e06eea9cfdddaa0082cef663cf2d4aa5ed1d Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 8 Apr 2024 15:45:57 +0100 Subject: regmap: kunit: Use a KUnit action to call regmap_exit() Registert a KUnit action handler to call regmap_exit() when a test terminates. This ensures that regmap_exit() will be called if a test function returns early or aborts. Signed-off-by: Richard Fitzgerald Link: https://msgid.link/r/20240408144600.230848-9-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-kunit.c | 62 +++++--------------------------------- 1 file changed, 7 insertions(+), 55 deletions(-) (limited to 'drivers/base/regmap') diff --git a/drivers/base/regmap/regmap-kunit.c b/drivers/base/regmap/regmap-kunit.c index 1b34f92b1aaf..e21028cbddc3 100644 --- a/drivers/base/regmap/regmap-kunit.c +++ b/drivers/base/regmap/regmap-kunit.c @@ -5,11 +5,14 @@ // Copyright 2023 Arm Ltd #include +#include #include #include "internal.h" #define BLOCK_TEST_SIZE 12 +KUNIT_DEFINE_ACTION_WRAPPER(regmap_exit_action, regmap_exit, struct regmap *); + struct regmap_test_priv { struct device *dev; }; @@ -190,6 +193,8 @@ static struct regmap *gen_regmap(struct kunit *test, if (IS_ERR(ret)) { kfree(buf); kfree(*data); + } else { + kunit_add_action(test, regmap_exit_action, ret); } return ret; @@ -226,8 +231,6 @@ static void basic_read_write(struct kunit *test) /* If using a cache the cache satisfied the read */ KUNIT_EXPECT_EQ(test, config.cache_type == REGCACHE_NONE, data->read[0]); - - regmap_exit(map); } static void bulk_write(struct kunit *test) @@ -261,8 +264,6 @@ static void bulk_write(struct kunit *test) /* If using a cache the cache satisfied the read */ for (i = 0; i < BLOCK_TEST_SIZE; i++) KUNIT_EXPECT_EQ(test, config.cache_type == REGCACHE_NONE, data->read[i]); - - regmap_exit(map); } static void bulk_read(struct kunit *test) @@ -292,8 +293,6 @@ static void bulk_read(struct kunit *test) /* If using a cache the cache satisfied the read */ for (i = 0; i < BLOCK_TEST_SIZE; i++) KUNIT_EXPECT_EQ(test, config.cache_type == REGCACHE_NONE, data->read[i]); - - regmap_exit(map); } static void write_readonly(struct kunit *test) @@ -325,8 +324,6 @@ static void write_readonly(struct kunit *test) /* Did that match what we see on the device? */ for (i = 0; i < BLOCK_TEST_SIZE; i++) KUNIT_EXPECT_EQ(test, i != 5, data->written[i]); - - regmap_exit(map); } static void read_writeonly(struct kunit *test) @@ -363,8 +360,6 @@ static void read_writeonly(struct kunit *test) /* Did we trigger a hardware access? */ KUNIT_EXPECT_FALSE(test, data->read[5]); - - regmap_exit(map); } static void reg_defaults(struct kunit *test) @@ -471,8 +466,6 @@ static void register_patch(struct kunit *test) break; } } - - regmap_exit(map); } static void stride(struct kunit *test) @@ -512,8 +505,6 @@ static void stride(struct kunit *test) KUNIT_EXPECT_TRUE(test, data->written[i]); } } - - regmap_exit(map); } static struct regmap_range_cfg test_range = { @@ -612,8 +603,6 @@ static void basic_ranges(struct kunit *test) KUNIT_EXPECT_FALSE(test, data->read[i]); KUNIT_EXPECT_FALSE(test, data->written[i]); } - - regmap_exit(map); } /* Try to stress dynamic creation of cache data structures */ @@ -665,8 +654,6 @@ static void stress_insert(struct kunit *test) KUNIT_EXPECT_EQ(test, rval, vals[i]); KUNIT_EXPECT_EQ(test, config.cache_type == REGCACHE_NONE, data->read[i]); } - - regmap_exit(map); } static void cache_bypass(struct kunit *test) @@ -702,8 +689,6 @@ static void cache_bypass(struct kunit *test) regcache_cache_bypass(map, false); KUNIT_EXPECT_EQ(test, 0, regmap_read(map, param->from_reg, &rval)); KUNIT_EXPECT_EQ(test, val, rval); - - regmap_exit(map); } static void cache_sync_marked_dirty(struct kunit *test) @@ -739,8 +724,6 @@ static void cache_sync_marked_dirty(struct kunit *test) KUNIT_EXPECT_MEMEQ(test, &data->vals[param->from_reg], val, sizeof(val)); for (i = 0; i < BLOCK_TEST_SIZE; i++) KUNIT_EXPECT_EQ(test, true, data->written[param->from_reg + i]); - - regmap_exit(map); } static void cache_sync_after_cache_only(struct kunit *test) @@ -790,8 +773,6 @@ static void cache_sync_after_cache_only(struct kunit *test) KUNIT_EXPECT_MEMEQ(test, &data->vals[param->from_reg], val, sizeof(val)); for (i = 0; i < BLOCK_TEST_SIZE; i++) KUNIT_EXPECT_TRUE(test, data->written[param->from_reg + i]); - - regmap_exit(map); } static void cache_sync_defaults_marked_dirty(struct kunit *test) @@ -841,8 +822,6 @@ static void cache_sync_defaults_marked_dirty(struct kunit *test) KUNIT_EXPECT_EQ(test, 0, regcache_sync(map)); for (i = 0; i < BLOCK_TEST_SIZE; i++) KUNIT_EXPECT_FALSE(test, data->written[param->from_reg + i]); - - regmap_exit(map); } static void cache_sync_default_after_cache_only(struct kunit *test) @@ -890,8 +869,6 @@ static void cache_sync_default_after_cache_only(struct kunit *test) KUNIT_EXPECT_EQ(test, 0, regcache_sync(map)); KUNIT_EXPECT_TRUE(test, data->written[param->from_reg + 2]); KUNIT_EXPECT_EQ(test, data->vals[param->from_reg + 2], orig_val); - - regmap_exit(map); } static void cache_sync_readonly(struct kunit *test) @@ -930,8 +907,6 @@ static void cache_sync_readonly(struct kunit *test) /* Did that match what we see on the device? */ for (i = 0; i < BLOCK_TEST_SIZE; i++) KUNIT_EXPECT_EQ(test, i != 5, data->written[param->from_reg + i]); - - regmap_exit(map); } static void cache_sync_patch(struct kunit *test) @@ -990,8 +965,6 @@ static void cache_sync_patch(struct kunit *test) break; } } - - regmap_exit(map); } static void cache_drop(struct kunit *test) @@ -1032,8 +1005,6 @@ static void cache_drop(struct kunit *test) for (i = 0; i < BLOCK_TEST_SIZE; i++) KUNIT_EXPECT_EQ(test, data->read[param->from_reg + i], i >= 3 && i <= 5); KUNIT_EXPECT_MEMEQ(test, &data->vals[param->from_reg], rval, sizeof(rval)); - - regmap_exit(map); } static void cache_drop_all_and_sync_marked_dirty(struct kunit *test) @@ -1075,8 +1046,6 @@ static void cache_drop_all_and_sync_marked_dirty(struct kunit *test) KUNIT_EXPECT_EQ(test, 0, regcache_sync(map)); for (i = 0; i <= config.max_register; i++) KUNIT_EXPECT_FALSE(test, data->written[i]); - - regmap_exit(map); } static void cache_drop_all_and_sync_no_defaults(struct kunit *test) @@ -1119,8 +1088,6 @@ static void cache_drop_all_and_sync_no_defaults(struct kunit *test) KUNIT_EXPECT_EQ(test, 0, regcache_sync(map)); for (i = 0; i <= config.max_register; i++) KUNIT_EXPECT_FALSE(test, data->written[i]); - - regmap_exit(map); } static void cache_drop_all_and_sync_has_defaults(struct kunit *test) @@ -1164,8 +1131,6 @@ static void cache_drop_all_and_sync_has_defaults(struct kunit *test) KUNIT_EXPECT_EQ(test, 0, regcache_sync(map)); for (i = 0; i <= config.max_register; i++) KUNIT_EXPECT_FALSE(test, data->written[i]); - - regmap_exit(map); } static void cache_present(struct kunit *test) @@ -1202,8 +1167,6 @@ static void cache_present(struct kunit *test) /* Now everything should be cached */ for (i = 0; i < BLOCK_TEST_SIZE; i++) KUNIT_ASSERT_TRUE(test, regcache_reg_cached(map, param->from_reg + i)); - - regmap_exit(map); } /* Check that caching the window register works with sync */ @@ -1350,6 +1313,8 @@ static struct regmap *gen_raw_regmap(struct kunit *test, if (IS_ERR(ret)) { kfree(buf); kfree(*data); + } else { + kunit_add_action(test, regmap_exit_action, ret); } return ret; @@ -1375,8 +1340,6 @@ static void raw_read_defaults_single(struct kunit *test) KUNIT_EXPECT_EQ(test, 0, regmap_read(map, i, &rval)); KUNIT_EXPECT_EQ(test, config.reg_defaults[i].def, rval); } - - regmap_exit(map); } static void raw_read_defaults(struct kunit *test) @@ -1414,7 +1377,6 @@ static void raw_read_defaults(struct kunit *test) } kfree(rval); - regmap_exit(map); } static void raw_write_read_single(struct kunit *test) @@ -1438,8 +1400,6 @@ static void raw_write_read_single(struct kunit *test) KUNIT_EXPECT_EQ(test, 0, regmap_write(map, 0, val)); KUNIT_EXPECT_EQ(test, 0, regmap_read(map, 0, &rval)); KUNIT_EXPECT_EQ(test, val, rval); - - regmap_exit(map); } static void raw_write(struct kunit *test) @@ -1489,8 +1449,6 @@ static void raw_write(struct kunit *test) /* The values should appear in the "hardware" */ KUNIT_EXPECT_MEMEQ(test, &hw_buf[2], val, sizeof(val)); - - regmap_exit(map); } static bool reg_zero(struct device *dev, unsigned int reg) @@ -1548,8 +1506,6 @@ static void raw_noinc_write(struct kunit *test) /* Make sure we didn't touch the register after the noinc register */ KUNIT_EXPECT_EQ(test, 0, regmap_read(map, 1, &val)); KUNIT_ASSERT_EQ(test, val_test, val); - - regmap_exit(map); } static void raw_sync(struct kunit *test) @@ -1625,8 +1581,6 @@ static void raw_sync(struct kunit *test) /* The values should now appear in the "hardware" */ KUNIT_EXPECT_MEMEQ(test, &hw_buf[2], &val[0], sizeof(val)); - - regmap_exit(map); } static void raw_ranges(struct kunit *test) @@ -1689,8 +1643,6 @@ static void raw_ranges(struct kunit *test) KUNIT_EXPECT_FALSE(test, data->read[i]); KUNIT_EXPECT_FALSE(test, data->written[i]); } - - regmap_exit(map); } static struct kunit_case regmap_test_cases[] = { -- cgit v1.2.3 From d6f2fd7adcb5f25ac661808be9409f846b1de6fe Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 8 Apr 2024 15:45:58 +0100 Subject: regmap: kunit: Replace a kmalloc/kfree() pair with KUnit-managed alloc Replace the kmalloc() and kfree() in raw_read_defaults() with a kunit_kmalloc() so that KUnit will free it automatically. Signed-off-by: Richard Fitzgerald Link: https://msgid.link/r/20240408144600.230848-10-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-kunit.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/base/regmap') diff --git a/drivers/base/regmap/regmap-kunit.c b/drivers/base/regmap/regmap-kunit.c index e21028cbddc3..4c29d2db4d20 100644 --- a/drivers/base/regmap/regmap-kunit.c +++ b/drivers/base/regmap/regmap-kunit.c @@ -1360,7 +1360,7 @@ static void raw_read_defaults(struct kunit *test) return; val_len = sizeof(*rval) * (config.max_register + 1); - rval = kmalloc(val_len, GFP_KERNEL); + rval = kunit_kmalloc(test, val_len, GFP_KERNEL); KUNIT_ASSERT_TRUE(test, rval != NULL); if (!rval) return; @@ -1375,8 +1375,6 @@ static void raw_read_defaults(struct kunit *test) KUNIT_EXPECT_EQ(test, def, le16_to_cpu((__force __le16)rval[i])); } } - - kfree(rval); } static void raw_write_read_single(struct kunit *test) -- cgit v1.2.3 From 468d277e6fb112e7a5e816ef5f1f6bd86c29bea6 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 8 Apr 2024 15:45:59 +0100 Subject: regmap: kunit: Add cache-drop test with multiple cache blocks Add a test case for dropping only some cache blocks and leaving others unchanged. The regmap is divided into 8 register ranges, and only 4 of these are written with values. This creates 4 non-contiguous ranges of registers with cached values. One whole range is then dropped, and part of another range. A cache sync is then performed to check that the correct registers were written, and the correct values were written to these registers. Signed-off-by: Richard Fitzgerald Link: https://msgid.link/r/20240408144600.230848-11-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-kunit.c | 103 +++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) (limited to 'drivers/base/regmap') diff --git a/drivers/base/regmap/regmap-kunit.c b/drivers/base/regmap/regmap-kunit.c index 4c29d2db4d20..6e469609c82c 100644 --- a/drivers/base/regmap/regmap-kunit.c +++ b/drivers/base/regmap/regmap-kunit.c @@ -1007,6 +1007,108 @@ static void cache_drop(struct kunit *test) KUNIT_EXPECT_MEMEQ(test, &data->vals[param->from_reg], rval, sizeof(rval)); } +static void cache_drop_with_non_contiguous_ranges(struct kunit *test) +{ + const struct regmap_test_param *param = test->param_value; + struct regmap *map; + struct regmap_config config; + struct regmap_ram_data *data; + unsigned int val[4][BLOCK_TEST_SIZE]; + unsigned int reg; + const int num_ranges = ARRAY_SIZE(val) * 2; + int rangeidx, i; + + static_assert(ARRAY_SIZE(val) == 4); + + config = test_regmap_config; + config.max_register = param->from_reg + (num_ranges * BLOCK_TEST_SIZE); + + map = gen_regmap(test, &config, &data); + KUNIT_ASSERT_FALSE(test, IS_ERR(map)); + if (IS_ERR(map)) + return; + + for (i = 0; i < config.max_register + 1; i++) + data->written[i] = false; + + /* Create non-contiguous cache blocks by writing every other range */ + get_random_bytes(&val, sizeof(val)); + for (rangeidx = 0; rangeidx < num_ranges; rangeidx += 2) { + reg = param->from_reg + (rangeidx * BLOCK_TEST_SIZE); + KUNIT_EXPECT_EQ(test, 0, regmap_bulk_write(map, reg, + &val[rangeidx / 2], + BLOCK_TEST_SIZE)); + KUNIT_EXPECT_MEMEQ(test, &data->vals[reg], + &val[rangeidx / 2], sizeof(val[rangeidx / 2])); + } + + /* Check that odd ranges weren't written */ + for (rangeidx = 1; rangeidx < num_ranges; rangeidx += 2) { + reg = param->from_reg + (rangeidx * BLOCK_TEST_SIZE); + for (i = 0; i < BLOCK_TEST_SIZE; i++) + KUNIT_EXPECT_FALSE(test, data->written[reg + i]); + } + + /* Drop range 2 */ + reg = param->from_reg + (2 * BLOCK_TEST_SIZE); + KUNIT_EXPECT_EQ(test, 0, regcache_drop_region(map, reg, reg + BLOCK_TEST_SIZE - 1)); + + /* Drop part of range 4 */ + reg = param->from_reg + (4 * BLOCK_TEST_SIZE); + KUNIT_EXPECT_EQ(test, 0, regcache_drop_region(map, reg + 3, reg + 5)); + + /* Mark dirty and reset mock registers to 0 */ + regcache_mark_dirty(map); + for (i = 0; i < config.max_register + 1; i++) { + data->vals[i] = 0; + data->written[i] = false; + } + + /* The registers that were dropped from range 4 should now remain at 0 */ + val[4 / 2][3] = 0; + val[4 / 2][4] = 0; + val[4 / 2][5] = 0; + + /* Sync and check that the expected register ranges were written */ + KUNIT_EXPECT_EQ(test, 0, regcache_sync(map)); + + /* Check that odd ranges weren't written */ + for (rangeidx = 1; rangeidx < num_ranges; rangeidx += 2) { + reg = param->from_reg + (rangeidx * BLOCK_TEST_SIZE); + for (i = 0; i < BLOCK_TEST_SIZE; i++) + KUNIT_EXPECT_FALSE(test, data->written[reg + i]); + } + + /* Check that even ranges (except 2 and 4) were written */ + for (rangeidx = 0; rangeidx < num_ranges; rangeidx += 2) { + if ((rangeidx == 2) || (rangeidx == 4)) + continue; + + reg = param->from_reg + (rangeidx * BLOCK_TEST_SIZE); + for (i = 0; i < BLOCK_TEST_SIZE; i++) + KUNIT_EXPECT_TRUE(test, data->written[reg + i]); + + KUNIT_EXPECT_MEMEQ(test, &data->vals[reg], + &val[rangeidx / 2], sizeof(val[rangeidx / 2])); + } + + /* Check that range 2 wasn't written */ + reg = param->from_reg + (2 * BLOCK_TEST_SIZE); + for (i = 0; i < BLOCK_TEST_SIZE; i++) + KUNIT_EXPECT_FALSE(test, data->written[reg + i]); + + /* Check that range 4 was partially written */ + reg = param->from_reg + (4 * BLOCK_TEST_SIZE); + for (i = 0; i < BLOCK_TEST_SIZE; i++) + KUNIT_EXPECT_EQ(test, data->written[reg + i], i < 3 || i > 5); + + KUNIT_EXPECT_MEMEQ(test, &data->vals[reg], &val[4 / 2], sizeof(val[4 / 2])); + + /* Nothing before param->from_reg should have been written */ + for (i = 0; i < param->from_reg; i++) + KUNIT_EXPECT_FALSE(test, data->written[i]); +} + static void cache_drop_all_and_sync_marked_dirty(struct kunit *test) { const struct regmap_test_param *param = test->param_value; @@ -1663,6 +1765,7 @@ static struct kunit_case regmap_test_cases[] = { KUNIT_CASE_PARAM(cache_sync_readonly, real_cache_types_gen_params), KUNIT_CASE_PARAM(cache_sync_patch, real_cache_types_gen_params), KUNIT_CASE_PARAM(cache_drop, sparse_cache_types_gen_params), + KUNIT_CASE_PARAM(cache_drop_with_non_contiguous_ranges, sparse_cache_types_gen_params), KUNIT_CASE_PARAM(cache_drop_all_and_sync_marked_dirty, sparse_cache_types_gen_params), KUNIT_CASE_PARAM(cache_drop_all_and_sync_no_defaults, sparse_cache_types_gen_params), KUNIT_CASE_PARAM(cache_drop_all_and_sync_has_defaults, sparse_cache_types_gen_params), -- cgit v1.2.3 From f63eb9ae085dc6da27eebfe35317e07a6a02a160 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 8 Apr 2024 15:46:00 +0100 Subject: regmap: kunit: Add test cases for regmap_read_bypassed() This adds test cases to prove that regmap_read_bypassed() reads the hardware value while the regmap is in cache-only. Signed-off-by: Richard Fitzgerald Link: https://msgid.link/r/20240408144600.230848-12-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-kunit.c | 131 +++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) (limited to 'drivers/base/regmap') diff --git a/drivers/base/regmap/regmap-kunit.c b/drivers/base/regmap/regmap-kunit.c index 6e469609c82c..44265dc2313d 100644 --- a/drivers/base/regmap/regmap-kunit.c +++ b/drivers/base/regmap/regmap-kunit.c @@ -295,6 +295,135 @@ static void bulk_read(struct kunit *test) KUNIT_EXPECT_EQ(test, config.cache_type == REGCACHE_NONE, data->read[i]); } +static void read_bypassed(struct kunit *test) +{ + const struct regmap_test_param *param = test->param_value; + struct regmap *map; + struct regmap_config config; + struct regmap_ram_data *data; + unsigned int val[BLOCK_TEST_SIZE], rval; + int i; + + config = test_regmap_config; + + map = gen_regmap(test, &config, &data); + KUNIT_ASSERT_FALSE(test, IS_ERR(map)); + if (IS_ERR(map)) + return; + + KUNIT_EXPECT_FALSE(test, map->cache_bypass); + + get_random_bytes(&val, sizeof(val)); + + /* Write some test values */ + KUNIT_EXPECT_EQ(test, 0, regmap_bulk_write(map, param->from_reg, val, ARRAY_SIZE(val))); + + regcache_cache_only(map, true); + + /* + * While in cache-only regmap_read_bypassed() should return the register + * value and leave the map in cache-only. + */ + for (i = 0; i < ARRAY_SIZE(val); i++) { + /* Put inverted bits in rval to prove we really read the value */ + rval = ~val[i]; + KUNIT_EXPECT_EQ(test, 0, regmap_read(map, param->from_reg + i, &rval)); + KUNIT_EXPECT_EQ(test, val[i], rval); + + rval = ~val[i]; + KUNIT_EXPECT_EQ(test, 0, regmap_read_bypassed(map, param->from_reg + i, &rval)); + KUNIT_EXPECT_EQ(test, val[i], rval); + KUNIT_EXPECT_TRUE(test, map->cache_only); + KUNIT_EXPECT_FALSE(test, map->cache_bypass); + } + + /* + * Change the underlying register values to prove it is returning + * real values not cached values. + */ + for (i = 0; i < ARRAY_SIZE(val); i++) { + val[i] = ~val[i]; + data->vals[param->from_reg + i] = val[i]; + } + + for (i = 0; i < ARRAY_SIZE(val); i++) { + rval = ~val[i]; + KUNIT_EXPECT_EQ(test, 0, regmap_read(map, param->from_reg + i, &rval)); + KUNIT_EXPECT_NE(test, val[i], rval); + + rval = ~val[i]; + KUNIT_EXPECT_EQ(test, 0, regmap_read_bypassed(map, param->from_reg + i, &rval)); + KUNIT_EXPECT_EQ(test, val[i], rval); + KUNIT_EXPECT_TRUE(test, map->cache_only); + KUNIT_EXPECT_FALSE(test, map->cache_bypass); + } +} + +static void read_bypassed_volatile(struct kunit *test) +{ + const struct regmap_test_param *param = test->param_value; + struct regmap *map; + struct regmap_config config; + struct regmap_ram_data *data; + unsigned int val[BLOCK_TEST_SIZE], rval; + int i; + + config = test_regmap_config; + /* All registers except #5 volatile */ + config.volatile_reg = reg_5_false; + + map = gen_regmap(test, &config, &data); + KUNIT_ASSERT_FALSE(test, IS_ERR(map)); + if (IS_ERR(map)) + return; + + KUNIT_EXPECT_FALSE(test, map->cache_bypass); + + get_random_bytes(&val, sizeof(val)); + + /* Write some test values */ + KUNIT_EXPECT_EQ(test, 0, regmap_bulk_write(map, param->from_reg, val, ARRAY_SIZE(val))); + + regcache_cache_only(map, true); + + /* + * While in cache-only regmap_read_bypassed() should return the register + * value and leave the map in cache-only. + */ + for (i = 0; i < ARRAY_SIZE(val); i++) { + /* Register #5 is non-volatile so should read from cache */ + KUNIT_EXPECT_EQ(test, (i == 5) ? 0 : -EBUSY, + regmap_read(map, param->from_reg + i, &rval)); + + /* Put inverted bits in rval to prove we really read the value */ + rval = ~val[i]; + KUNIT_EXPECT_EQ(test, 0, regmap_read_bypassed(map, param->from_reg + i, &rval)); + KUNIT_EXPECT_EQ(test, val[i], rval); + KUNIT_EXPECT_TRUE(test, map->cache_only); + KUNIT_EXPECT_FALSE(test, map->cache_bypass); + } + + /* + * Change the underlying register values to prove it is returning + * real values not cached values. + */ + for (i = 0; i < ARRAY_SIZE(val); i++) { + val[i] = ~val[i]; + data->vals[param->from_reg + i] = val[i]; + } + + for (i = 0; i < ARRAY_SIZE(val); i++) { + if (i == 5) + continue; + + rval = ~val[i]; + KUNIT_EXPECT_EQ(test, 0, regmap_read_bypassed(map, param->from_reg + i, &rval)); + KUNIT_EXPECT_EQ(test, val[i], rval); + KUNIT_EXPECT_TRUE(test, map->cache_only); + KUNIT_EXPECT_FALSE(test, map->cache_bypass); + } +} + static void write_readonly(struct kunit *test) { struct regmap *map; @@ -1747,6 +1876,8 @@ static void raw_ranges(struct kunit *test) static struct kunit_case regmap_test_cases[] = { KUNIT_CASE_PARAM(basic_read_write, regcache_types_gen_params), + KUNIT_CASE_PARAM(read_bypassed, real_cache_types_gen_params), + KUNIT_CASE_PARAM(read_bypassed_volatile, real_cache_types_gen_params), KUNIT_CASE_PARAM(bulk_write, regcache_types_gen_params), KUNIT_CASE_PARAM(bulk_read, regcache_types_gen_params), KUNIT_CASE_PARAM(write_readonly, regcache_types_gen_params), -- cgit v1.2.3