mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Sander Vanheule <sander@svanheule.net>
To: Mark Brown <broonie@kernel.org>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	"Rafael J. Wysocki" <rafael@kernel.org>,
	linux-kernel@vger.kernel.org
Cc: Sander Vanheule <sander@svanheule.net>
Subject: [PATCH v3] regmap: add cache validity to REGCACHE_FLAT
Date: Thu,  9 Jan 2025 19:02:55 +0100	[thread overview]
Message-ID: <20250109180256.6269-1-sander@svanheule.net> (raw)

The flat regcache will always assume the data in the cache is valid.
Since the cache takes priority over hardware values, this may shadow the
actual state of the device. This is not the case with REGCACHE_RBTREE
for example, which makes these implementation behave differently.

Add a new containing cache structure with the flat data table and a
bitmap indicating cache validity. Use this to provide an implementation
for regcache_ops.drop.

Since this makes the flat cache behave more like other caches, a special
case in the read_writeonly unit test can also be dropped. This reverts
commit d0c99ffe2126 ("regmap: Allow reads from write only registers with
the flat cache"). Furthermore we can now add REGCACHE_FLAG to the table
of sparse_cache tests.

Signed-off-by: Sander Vanheule <sander@svanheule.net>
---
Changes since v2:
Link: https://lore.kernel.org/all/20250109151106.38645-1-sander@svanheule.net/
- Complete renaming of index variables so regcache-flat.c compiles again

Changes since v1:
Link: https://lore.kernel.org/all/20241231100256.194753-1-sander@svanheule.net/
- Fix off-by-one in length for bitmap_clear()
- Add REGCACHE_FLAT to the list of sparse cache tests
---
 drivers/base/regmap/regcache-flat.c | 70 ++++++++++++++++++++++++-----
 drivers/base/regmap/regmap-kunit.c  | 21 ++++-----
 2 files changed, 69 insertions(+), 22 deletions(-)

diff --git a/drivers/base/regmap/regcache-flat.c b/drivers/base/regmap/regcache-flat.c
index f36d3618b67c..a5b9b2b15d3d 100644
--- a/drivers/base/regmap/regcache-flat.c
+++ b/drivers/base/regmap/regcache-flat.c
@@ -6,6 +6,8 @@
 //
 // Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
 
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
@@ -18,34 +20,65 @@ static inline unsigned int regcache_flat_get_index(const struct regmap *map,
 	return regcache_get_index_by_order(map, reg);
 }
 
+struct regcache_flat_data {
+	unsigned int *data;
+	unsigned long *valid;
+};
+
 static int regcache_flat_init(struct regmap *map)
 {
 	int i;
-	unsigned int *cache;
+	unsigned int cache_size;
+	struct regcache_flat_data *cache = NULL;
+	unsigned long *cache_valid = NULL;
+	unsigned int *cache_data = NULL;
 
 	if (!map || map->reg_stride_order < 0 || !map->max_register_is_set)
 		return -EINVAL;
 
-	map->cache = kcalloc(regcache_flat_get_index(map, map->max_register)
-			     + 1, sizeof(unsigned int), map->alloc_flags);
-	if (!map->cache)
+	cache_size = regcache_flat_get_index(map, map->max_register) + 1;
+	cache_data = kcalloc(cache_size, sizeof(unsigned int), map->alloc_flags);
+	if (!cache_data)
 		return -ENOMEM;
 
+	cache_valid = bitmap_zalloc(cache_size, map->alloc_flags);
+	if (!cache_valid)
+		goto err_free_valid;
+
+	map->cache = kmalloc(sizeof(*cache), map->alloc_flags);
+	if (!map->cache)
+		goto err_free;
+
 	cache = map->cache;
+	cache->valid = cache_valid;
+	cache->data = cache_data;
 
 	for (i = 0; i < map->num_reg_defaults; i++) {
 		unsigned int reg = map->reg_defaults[i].reg;
 		unsigned int index = regcache_flat_get_index(map, reg);
 
-		cache[index] = map->reg_defaults[i].def;
+		cache->data[index] = map->reg_defaults[i].def;
+		__set_bit(index, cache->valid);
 	}
 
 	return 0;
+
+err_free:
+	kfree(cache_data);
+err_free_valid:
+	bitmap_free(cache_valid);
+	return -ENOMEM;
 }
 
 static int regcache_flat_exit(struct regmap *map)
 {
-	kfree(map->cache);
+	struct regcache_flat_data *cache = map->cache;
+
+	if (cache) {
+		bitmap_free(cache->valid);
+		kfree(cache->data);
+	}
+	kfree(cache);
 	map->cache = NULL;
 
 	return 0;
@@ -54,10 +87,13 @@ static int regcache_flat_exit(struct regmap *map)
 static int regcache_flat_read(struct regmap *map,
 			      unsigned int reg, unsigned int *value)
 {
-	unsigned int *cache = map->cache;
+	struct regcache_flat_data *cache = map->cache;
 	unsigned int index = regcache_flat_get_index(map, reg);
 
-	*value = cache[index];
+	if (!test_bit(index, cache->valid))
+		return -ENOENT;
+
+	*value = cache->data[index];
 
 	return 0;
 }
@@ -65,10 +101,23 @@ static int regcache_flat_read(struct regmap *map,
 static int regcache_flat_write(struct regmap *map, unsigned int reg,
 			       unsigned int value)
 {
-	unsigned int *cache = map->cache;
+	struct regcache_flat_data *cache = map->cache;
 	unsigned int index = regcache_flat_get_index(map, reg);
 
-	cache[index] = value;
+	cache->data[index] = value;
+	__set_bit(index, cache->valid);
+
+	return 0;
+}
+
+static int regcache_flat_drop(struct regmap *map, unsigned int min,
+			      unsigned int max)
+{
+	struct regcache_flat_data *cache = map->cache;
+	unsigned int bitmap_min = regcache_flat_get_index(map, min);
+	unsigned int bitmap_max = regcache_flat_get_index(map, max);
+
+	bitmap_clear(cache->valid, bitmap_min, bitmap_max + 1 - bitmap_min);
 
 	return 0;
 }
@@ -80,4 +129,5 @@ struct regcache_ops regcache_flat_ops = {
 	.exit = regcache_flat_exit,
 	.read = regcache_flat_read,
 	.write = regcache_flat_write,
+	.drop = regcache_flat_drop,
 };
diff --git a/drivers/base/regmap/regmap-kunit.c b/drivers/base/regmap/regmap-kunit.c
index 64ea340950b6..c9ab1e767505 100644
--- a/drivers/base/regmap/regmap-kunit.c
+++ b/drivers/base/regmap/regmap-kunit.c
@@ -136,6 +136,12 @@ 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_FLAT,   .from_reg = 0 },
+	{ .cache = REGCACHE_FLAT,   .from_reg = 0, .fast_io = true },
+	{ .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 = 0, .fast_io = true },
 	{ .cache = REGCACHE_RBTREE, .from_reg = 0x2001 },
@@ -567,18 +573,9 @@ static void read_writeonly(struct kunit *test)
 	for (i = 0; i < BLOCK_TEST_SIZE; i++)
 		data->read[i] = false;
 
-	/*
-	 * Try to read all the registers, the writeonly one should
-	 * fail if we aren't using the flat cache.
-	 */
-	for (i = 0; i < BLOCK_TEST_SIZE; i++) {
-		if (config.cache_type != REGCACHE_FLAT) {
-			KUNIT_EXPECT_EQ(test, i != 5,
-					regmap_read(map, i, &val) == 0);
-		} else {
-			KUNIT_EXPECT_EQ(test, 0, regmap_read(map, i, &val));
-		}
-	}
+	/* Try to read all the registers, the writeonly one should fail */
+	for (i = 0; i < BLOCK_TEST_SIZE; i++)
+		KUNIT_EXPECT_EQ(test, i != 5, regmap_read(map, i, &val) == 0);
 
 	/* Did we trigger a hardware access? */
 	KUNIT_EXPECT_FALSE(test, data->read[5]);
-- 
2.47.1


             reply	other threads:[~2025-01-09 18:03 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-01-09 18:02 Sander Vanheule [this message]
2025-01-09 20:11 ` Mark Brown
2025-10-16  8:46   ` Sander Vanheule
2025-10-16 11:53     ` Mark Brown
2025-10-16 12:08       ` Sander Vanheule
2025-10-16 13:55         ` Mark Brown
2025-10-16 20:49           ` Sander Vanheule
2025-10-17 13:56             ` Mark Brown
2025-10-22 20:21               ` Sander Vanheule

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250109180256.6269-1-sander@svanheule.net \
    --to=sander@svanheule.net \
    --cc=broonie@kernel.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=rafael@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®