Skip to content

Commit 5cbff4b

Browse files
committed
Merge tag 'regmap-v6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap
Pull regmap updates from Mark Brown: "The main change here is a fix for an issue where we were letting the selector for windowed register ranges get out of sync with the hardware during a cache sync plus associated KUnit tests. This was reported just at the end of the release cycle and only in -next for a day prior to the merge window so it seemed better to hold off for now, the bug had been present for more than a decade so wasn't causing too many practical problems hopefully. There's also a fix for error handling in the debugfs output from Christope Jaillet" * tag 'regmap-v6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap: regmap: Ensure range selector registers are updated after cache sync regmap: kunit: Add test for cache sync interaction with ranges regmap: kunit: Fix marking of the range window as volatile regmap: debugfs: Fix a erroneous check after snprintf()
2 parents b05ddad + 6bbebcc commit 5cbff4b

File tree

3 files changed

+96
-4
lines changed

3 files changed

+96
-4
lines changed

drivers/base/regmap/regcache.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,11 @@ static int regcache_default_sync(struct regmap *map, unsigned int min,
334334
return 0;
335335
}
336336

337+
static int rbtree_all(const void *key, const struct rb_node *node)
338+
{
339+
return 0;
340+
}
341+
337342
/**
338343
* regcache_sync - Sync the register cache with the hardware.
339344
*
@@ -351,6 +356,7 @@ int regcache_sync(struct regmap *map)
351356
unsigned int i;
352357
const char *name;
353358
bool bypass;
359+
struct rb_node *node;
354360

355361
if (WARN_ON(map->cache_type == REGCACHE_NONE))
356362
return -EINVAL;
@@ -392,6 +398,30 @@ int regcache_sync(struct regmap *map)
392398
/* Restore the bypass state */
393399
map->cache_bypass = bypass;
394400
map->no_sync_defaults = false;
401+
402+
/*
403+
* If we did any paging with cache bypassed and a cached
404+
* paging register then the register and cache state might
405+
* have gone out of sync, force writes of all the paging
406+
* registers.
407+
*/
408+
rb_for_each(node, 0, &map->range_tree, rbtree_all) {
409+
struct regmap_range_node *this =
410+
rb_entry(node, struct regmap_range_node, node);
411+
412+
/* If there's nothing in the cache there's nothing to sync */
413+
ret = regcache_read(map, this->selector_reg, &i);
414+
if (ret != 0)
415+
continue;
416+
417+
ret = _regmap_write(map, this->selector_reg, i);
418+
if (ret != 0) {
419+
dev_err(map->dev, "Failed to write %x = %x: %d\n",
420+
this->selector_reg, i, ret);
421+
break;
422+
}
423+
}
424+
395425
map->unlock(map->lock_arg);
396426

397427
regmap_async_complete(map);

drivers/base/regmap/regmap-debugfs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ static ssize_t regmap_name_read_file(struct file *file,
4848
name = map->dev->driver->name;
4949

5050
ret = snprintf(buf, PAGE_SIZE, "%s\n", name);
51-
if (ret < 0) {
51+
if (ret >= PAGE_SIZE) {
5252
kfree(buf);
5353
return ret;
5454
}

drivers/base/regmap/regmap-kunit.c

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -442,10 +442,18 @@ static struct regmap_range_cfg test_range = {
442442
.range_max = 40,
443443
};
444444

445-
static bool test_range_volatile(struct device *dev, unsigned int reg)
445+
static bool test_range_window_volatile(struct device *dev, unsigned int reg)
446446
{
447447
if (reg >= test_range.window_start &&
448-
reg <= test_range.selector_reg + test_range.window_len)
448+
reg <= test_range.window_start + test_range.window_len)
449+
return true;
450+
451+
return false;
452+
}
453+
454+
static bool test_range_all_volatile(struct device *dev, unsigned int reg)
455+
{
456+
if (test_range_window_volatile(dev, reg))
449457
return true;
450458

451459
if (reg >= test_range.range_min && reg <= test_range.range_max)
@@ -465,7 +473,7 @@ static void basic_ranges(struct kunit *test)
465473

466474
config = test_regmap_config;
467475
config.cache_type = t->type;
468-
config.volatile_reg = test_range_volatile;
476+
config.volatile_reg = test_range_all_volatile;
469477
config.ranges = &test_range;
470478
config.num_ranges = 1;
471479
config.max_register = test_range.range_max;
@@ -875,6 +883,59 @@ static void cache_present(struct kunit *test)
875883
regmap_exit(map);
876884
}
877885

886+
/* Check that caching the window register works with sync */
887+
static void cache_range_window_reg(struct kunit *test)
888+
{
889+
struct regcache_types *t = (struct regcache_types *)test->param_value;
890+
struct regmap *map;
891+
struct regmap_config config;
892+
struct regmap_ram_data *data;
893+
unsigned int val;
894+
int i;
895+
896+
config = test_regmap_config;
897+
config.cache_type = t->type;
898+
config.volatile_reg = test_range_window_volatile;
899+
config.ranges = &test_range;
900+
config.num_ranges = 1;
901+
config.max_register = test_range.range_max;
902+
903+
map = gen_regmap(&config, &data);
904+
KUNIT_ASSERT_FALSE(test, IS_ERR(map));
905+
if (IS_ERR(map))
906+
return;
907+
908+
/* Write new values to the entire range */
909+
for (i = test_range.range_min; i <= test_range.range_max; i++)
910+
KUNIT_ASSERT_EQ(test, 0, regmap_write(map, i, 0));
911+
912+
val = data->vals[test_range.selector_reg] & test_range.selector_mask;
913+
KUNIT_ASSERT_EQ(test, val, 2);
914+
915+
/* Write to the first register in the range to reset the page */
916+
KUNIT_ASSERT_EQ(test, 0, regmap_write(map, test_range.range_min, 0));
917+
val = data->vals[test_range.selector_reg] & test_range.selector_mask;
918+
KUNIT_ASSERT_EQ(test, val, 0);
919+
920+
/* Trigger a cache sync */
921+
regcache_mark_dirty(map);
922+
KUNIT_ASSERT_EQ(test, 0, regcache_sync(map));
923+
924+
/* Write to the first register again, the page should be reset */
925+
KUNIT_ASSERT_EQ(test, 0, regmap_write(map, test_range.range_min, 0));
926+
val = data->vals[test_range.selector_reg] & test_range.selector_mask;
927+
KUNIT_ASSERT_EQ(test, val, 0);
928+
929+
/* Trigger another cache sync */
930+
regcache_mark_dirty(map);
931+
KUNIT_ASSERT_EQ(test, 0, regcache_sync(map));
932+
933+
/* Write to the last register again, the page should be reset */
934+
KUNIT_ASSERT_EQ(test, 0, regmap_write(map, test_range.range_max, 0));
935+
val = data->vals[test_range.selector_reg] & test_range.selector_mask;
936+
KUNIT_ASSERT_EQ(test, val, 2);
937+
}
938+
878939
struct raw_test_types {
879940
const char *name;
880941

@@ -1217,6 +1278,7 @@ static struct kunit_case regmap_test_cases[] = {
12171278
KUNIT_CASE_PARAM(cache_sync_patch, real_cache_types_gen_params),
12181279
KUNIT_CASE_PARAM(cache_drop, sparse_cache_types_gen_params),
12191280
KUNIT_CASE_PARAM(cache_present, sparse_cache_types_gen_params),
1281+
KUNIT_CASE_PARAM(cache_range_window_reg, real_cache_types_gen_params),
12201282

12211283
KUNIT_CASE_PARAM(raw_read_defaults_single, raw_test_types_gen_params),
12221284
KUNIT_CASE_PARAM(raw_read_defaults, raw_test_types_gen_params),

0 commit comments

Comments
 (0)