summaryrefslogtreecommitdiff
path: root/drivers/base/regmap/regcache.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-10-31 17:28:48 -1000
committerLinus Torvalds <torvalds@linux-foundation.org>2023-10-31 17:28:48 -1000
commit5cbff4b2d9e2a59f4096af8b8f967e2b30f025f2 (patch)
treeee89801092c1575d506af43ffc6e517acd2b87a3 /drivers/base/regmap/regcache.c
parentb05ddad00903b24931cb4b45516f1bc1b5c288f2 (diff)
parent6bbebcc11a69aef269eb2a33212f76992a4cfb1a (diff)
downloadlinux-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.c30
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);