diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-10-31 17:28:48 -1000 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-10-31 17:28:48 -1000 |
commit | 5cbff4b2d9e2a59f4096af8b8f967e2b30f025f2 (patch) | |
tree | ee89801092c1575d506af43ffc6e517acd2b87a3 /drivers/base/regmap/regcache.c | |
parent | b05ddad00903b24931cb4b45516f1bc1b5c288f2 (diff) | |
parent | 6bbebcc11a69aef269eb2a33212f76992a4cfb1a (diff) | |
download | linux-5cbff4b2d9e2a59f4096af8b8f967e2b30f025f2.tar.gz linux-5cbff4b2d9e2a59f4096af8b8f967e2b30f025f2.tar.bz2 linux-5cbff4b2d9e2a59f4096af8b8f967e2b30f025f2.zip |
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()
Diffstat (limited to 'drivers/base/regmap/regcache.c')
-rw-r--r-- | drivers/base/regmap/regcache.c | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index c5d151e9c481..92592f944a3d 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -334,6 +334,11 @@ static int regcache_default_sync(struct regmap *map, unsigned int min, return 0; } +static int rbtree_all(const void *key, const struct rb_node *node) +{ + return 0; +} + /** * regcache_sync - Sync the register cache with the hardware. * @@ -351,6 +356,7 @@ int regcache_sync(struct regmap *map) unsigned int i; const char *name; bool bypass; + struct rb_node *node; if (WARN_ON(map->cache_type == REGCACHE_NONE)) return -EINVAL; @@ -392,6 +398,30 @@ out: /* Restore the bypass state */ map->cache_bypass = bypass; map->no_sync_defaults = false; + + /* + * If we did any paging with cache bypassed and a cached + * paging register then the register and cache state might + * have gone out of sync, force writes of all the paging + * registers. + */ + rb_for_each(node, 0, &map->range_tree, rbtree_all) { + struct regmap_range_node *this = + rb_entry(node, struct regmap_range_node, node); + + /* If there's nothing in the cache there's nothing to sync */ + ret = regcache_read(map, this->selector_reg, &i); + if (ret != 0) + continue; + + ret = _regmap_write(map, this->selector_reg, i); + if (ret != 0) { + dev_err(map->dev, "Failed to write %x = %x: %d\n", + this->selector_reg, i, ret); + break; + } + } + map->unlock(map->lock_arg); regmap_async_complete(map); |