Skip to contentSkip to conversation

regcache updates

PATCH Applied Dimitris Papastamos 2 participants 12 messages Sep 27, 2011

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover regcache updates

Various regcache updates. This patch series has only been build tested on my machine so any testers are highly appreciated.

Dimitris Papastamos (5):
regmap: Fix signed/unsigned comparison
regmap: Implement regcache_cache_bypass helper function
regmap: Implement generic syncing functionality
regmap: Remove redundant member `word_size' from regcache_rbtree_node
regmap: Ensure we scream if we enable cache bypass/only at the same
time

 drivers/base/regmap/regcache-indexed.c |    2 +-
 drivers/base/regmap/regcache-rbtree.c  |   53 +++++++++++++++++-------------
 drivers/base/regmap/regcache.c         |   54 +++++++++++++++++++++++++++----
 include/linux/regmap.h                 |    1 +
 4 files changed, 79 insertions(+), 31 deletions(-)
Signature · 1 line
1.7.6.4
#1 lore raw

PATCH 1/5 regmap: Fix signed/unsigned comparison

---
 drivers/base/regmap/regcache-indexed.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/base/regmap/regcache-indexed.c +1 -1
index ff8b44c..268497a 100644
@@ -41,7 +41,7 @@ static int regcache_indexed_write(struct regmap *map, unsigned int reg,
 
 static int regcache_indexed_sync(struct regmap *map)
 {
-	int i;
+	unsigned int i;
 	int ret;
 
 	for (i = 0; i < map->num_reg_defaults; i++) {
Signature · 1 line
1.7.6.4
#3 lore raw

PATCH 2/5 regmap: Implement regcache_cache_bypass helper function

In reply to Dimitris Papastamos

Ensure we've got a function so users can enable/disable the cache bypass option.

---
 drivers/base/regmap/regcache.c |   17 +++++++++++++++++
 include/linux/regmap.h         |    1 +
 2 files changed, 18 insertions(+), 0 deletions(-)
drivers/base/regmap/regcache.c +17 -0
index e2b172b..f2d1a5e 100644
@@ -258,6 +258,23 @@ void regcache_cache_only(struct regmap *map, bool enable)
 }
 EXPORT_SYMBOL_GPL(regcache_cache_only);
 
+/**
+ * regcache_cache_bypass: Put a register map into cache bypass mode
+ *
+ * @map: map to configure
+ * @cache_only: flag if changes should not be written to the hardware
+ *
+ * When a register map is marked with the cache bypass option, writes
+ * to the register map API will only update the hardware and not the
+ * the cache directly.  This is useful when syncing the cache back to
+ * the hardware.
+ */
+void regcache_cache_bypass(struct regmap *map, bool enable)
+{
+	map->cache_bypass = enable;
+}
+EXPORT_SYMBOL_GPL(regcache_cache_bypass);
+
 bool regcache_set_val(void *base, unsigned int idx,
 		      unsigned int val, unsigned int word_size)
 {
include/linux/regmap.h +1 -0
index 76ac255..3daac2d 100644
@@ -142,5 +142,6 @@ int regmap_update_bits(struct regmap *map, unsigned int reg,
 
 int regcache_sync(struct regmap *map);
 void regcache_cache_only(struct regmap *map, bool enable);
+void regcache_cache_bypass(struct regmap *map, bool enable);
 
 #endif
Signature · 1 line
1.7.6.4
#4 lore raw

Re: [PATCH 2/5] regmap: Implement regcache_cache_bypass helper function

Quoted 2 lines · Dimitris Papastamos

Ensure we've got a function so users can enable/disable the cache bypass option.

Given that the sync code is fiddling about with this value internally without taking care to preserve the external state I don't think we can expose this to users yet. We need to make sure it plays nicely with the sync code somehow, probably by preserving the state at the start of the sync and restoring it afterwards.

#5 lore raw

PATCH 3/5 regmap: Implement generic syncing functionality

In reply to Dimitris Papastamos

In the absence of a sync callback, do it manually. This of course can't take advantange of the specific optimizations of each cache type but it will do well enough in most cases.

---
 drivers/base/regmap/regcache.c |   33 ++++++++++++++++++++++++++-------
 1 files changed, 26 insertions(+), 7 deletions(-)
drivers/base/regmap/regcache.c +26 -7
index f2d1a5e..2628e42 100644
@@ -223,20 +223,39 @@ EXPORT_SYMBOL_GPL(regcache_write);
  */
 int regcache_sync(struct regmap *map)
 {
-	int ret;
+	int ret = 0;
+	unsigned int val;
+	unsigned int i;
 	const char *name;
 
 	BUG_ON(!map->cache_ops);
 
+	dev_dbg(map->dev, "Syncing %s cache\n",
+		map->cache_ops->name);
+	name = map->cache_ops->name;
+	trace_regcache_sync(map->dev, name, "start");
 	if (map->cache_ops->sync) {
-		dev_dbg(map->dev, "Syncing %s cache\n",
-			map->cache_ops->name);
-		name = map->cache_ops->name;
-		trace_regcache_sync(map->dev, name, "start");
 		ret = map->cache_ops->sync(map);
-		trace_regcache_sync(map->dev, name, "stop");
+	} else {
+		for (i = 0; i < map->num_reg_defaults; i++) {
+			ret = regcache_read(map, i, &val);
+			if (ret < 0)
+				goto out;
+			regcache_cache_bypass(map, true);
+			ret = regcache_write(map, i, val);
+			regcache_cache_bypass(map, false);
+			if (ret < 0)
+				goto out;
+			dev_dbg(map->dev, "Synced register %#x, value %#x\n",
+				map->reg_defaults[i].reg,
+				map->reg_defaults[i].def);
+		}
+
 	}
-	return 0;
+out:
+	trace_regcache_sync(map->dev, name, "stop");
+
+	return ret;
 }
 EXPORT_SYMBOL_GPL(regcache_sync);
 
Signature · 1 line
1.7.6.4
Applied
#6 lore raw

Re: [PATCH 3/5] regmap: Implement generic syncing functionality

Quoted 3 lines · Dimitris Papastamos

In the absence of a sync callback, do it manually. This of course can't take advantange of the specific optimizations of each cache type but it will do well enough in most cases.

Applied, thanks.

#7 lore raw

PATCH 4/5 regmap: Remove redundant member `word_size' from regcache_rbtree_node

In reply to Dimitris Papastamos
---
 drivers/base/regmap/regcache-rbtree.c |   53 ++++++++++++++++++--------------
 1 files changed, 30 insertions(+), 23 deletions(-)
drivers/base/regmap/regcache-rbtree.c +30 -23
index 4d7ba45..dd1b937 100644
@@ -23,8 +23,6 @@ struct regcache_rbtree_node {
 	struct rb_node node;
 	/* base register handled by this block */
 	unsigned int base_reg;
-	/* number of bytes needed to represent the register index */
-	unsigned int word_size;
 	/* block of adjacent registers */
 	void *block;
 	/* number of registers available in the block */
@@ -45,11 +43,12 @@ static inline void regcache_rbtree_get_base_top_reg(
 }
 
 static unsigned int regcache_rbtree_get_register(
-	struct regcache_rbtree_node *rbnode, unsigned int idx)
+	struct regcache_rbtree_node *rbnode, unsigned int idx,
+	unsigned int word_size)
 {
 	unsigned int val;
 
-	switch (rbnode->word_size) {
+	switch (word_size) {
 	case 1: {
 		u8 *p = rbnode->block;
 		val = p[idx];
@@ -68,9 +67,10 @@ static unsigned int regcache_rbtree_get_register(
 }
 
 static void regcache_rbtree_set_register(struct regcache_rbtree_node *rbnode,
-					 unsigned int idx, unsigned int val)
+					 unsigned int idx, unsigned int val,
+					 unsigned int word_size)
 {
-	switch (rbnode->word_size) {
+	switch (word_size) {
 	case 1: {
 		u8 *p = rbnode->block;
 		p[idx] = val;
@@ -217,7 +217,8 @@ static int regcache_rbtree_read(struct regmap *map,
 		regcache_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
 		if (reg >= base_reg && reg <= top_reg) {
 			reg_tmp = reg - base_reg;
-			*value = regcache_rbtree_get_register(rbnode, reg_tmp);
+			*value = regcache_rbtree_get_register(rbnode, reg_tmp,
+							      map->cache_word_size);
 			return 0;
 		}
 	}
@@ -227,7 +228,8 @@ static int regcache_rbtree_read(struct regmap *map,
 	rbnode = regcache_rbtree_lookup(&rbtree_ctx->root, reg);
 	if (rbnode) {
 		reg_tmp = reg - rbnode->base_reg;
-		*value = regcache_rbtree_get_register(rbnode, reg_tmp);
+		*value = regcache_rbtree_get_register(rbnode, reg_tmp,
+						      map->cache_word_size);
 		rbtree_ctx->cached_rbnode = rbnode;
 	} else {
 		/* uninitialized registers default to 0 */
@@ -240,19 +242,19 @@ static int regcache_rbtree_read(struct regmap *map,
 
 static int regcache_rbtree_insert_to_block(struct regcache_rbtree_node *rbnode,
 					   unsigned int pos, unsigned int reg,
-					   unsigned int value)
+					   unsigned int value, unsigned int word_size)
 {
 	u8 *blk;
 
 	blk = krealloc(rbnode->block,
-		       (rbnode->blklen + 1) * rbnode->word_size, GFP_KERNEL);
+		       (rbnode->blklen + 1) * word_size, GFP_KERNEL);
 	if (!blk)
 		return -ENOMEM;
 
 	/* insert the register value in the correct place in the rbnode block */
-	memmove(blk + (pos + 1) * rbnode->word_size,
-		blk + pos * rbnode->word_size,
-		(rbnode->blklen - pos) * rbnode->word_size);
+	memmove(blk + (pos + 1) * word_size,
+		blk + pos * word_size,
+		(rbnode->blklen - pos) * word_size);
 
 	/* update the rbnode block, its size and the base register */
 	rbnode->block = blk;
@@ -260,7 +262,7 @@ static int regcache_rbtree_insert_to_block(struct regcache_rbtree_node *rbnode,
 	if (!pos)
 		rbnode->base_reg = reg;
 
-	regcache_rbtree_set_register(rbnode, pos, value);
+	regcache_rbtree_set_register(rbnode, pos, value, word_size);
 	return 0;
 }
 
@@ -284,10 +286,12 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
 		regcache_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
 		if (reg >= base_reg && reg <= top_reg) {
 			reg_tmp = reg - base_reg;
-			val = regcache_rbtree_get_register(rbnode, reg_tmp);
+			val = regcache_rbtree_get_register(rbnode, reg_tmp,
+							   map->cache_word_size);
 			if (val == value)
 				return 0;
-			regcache_rbtree_set_register(rbnode, reg_tmp, value);
+			regcache_rbtree_set_register(rbnode, reg_tmp, value,
+						     map->cache_word_size);
 			return 0;
 		}
 	}
@@ -297,10 +301,12 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
 	rbnode = regcache_rbtree_lookup(&rbtree_ctx->root, reg);
 	if (rbnode) {
 		reg_tmp = reg - rbnode->base_reg;
-		val = regcache_rbtree_get_register(rbnode, reg_tmp);
+		val = regcache_rbtree_get_register(rbnode, reg_tmp,
+						   map->cache_word_size);
 		if (val == value)
 			return 0;
-		regcache_rbtree_set_register(rbnode, reg_tmp, value);
+		regcache_rbtree_set_register(rbnode, reg_tmp, value,
+					     map->cache_word_size);
 		rbtree_ctx->cached_rbnode = rbnode;
 	} else {
 		/* bail out early, no need to create the rbnode yet */
@@ -320,7 +326,8 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
 				else
 					pos = i;
 				ret = regcache_rbtree_insert_to_block(rbnode_tmp, pos,
-								      reg, value);
+								      reg, value,
+								      map->cache_word_size);
 				if (ret)
 					return ret;
 				rbtree_ctx->cached_rbnode = rbnode_tmp;
@@ -337,14 +344,13 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
 			return -ENOMEM;
 		rbnode->blklen = 1;
 		rbnode->base_reg = reg;
-		rbnode->word_size = map->cache_word_size;
-		rbnode->block = kmalloc(rbnode->blklen * rbnode->word_size,
+		rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size,
 					GFP_KERNEL);
 		if (!rbnode->block) {
 			kfree(rbnode);
 			return -ENOMEM;
 		}
-		regcache_rbtree_set_register(rbnode, 0, value);
+		regcache_rbtree_set_register(rbnode, 0, value, map->cache_word_size);
 		regcache_rbtree_insert(&rbtree_ctx->root, rbnode);
 		rbtree_ctx->cached_rbnode = rbnode;
 	}
@@ -367,7 +373,8 @@ static int regcache_rbtree_sync(struct regmap *map)
 		rbnode = rb_entry(node, struct regcache_rbtree_node, node);
 		for (i = 0; i < rbnode->blklen; i++) {
 			regtmp = rbnode->base_reg + i;
-			val = regcache_rbtree_get_register(rbnode, i);
+			val = regcache_rbtree_get_register(rbnode, i,
+							   map->cache_word_size);
 			ret = regcache_lookup_reg(map, i);
 			if (ret < 0)
 				def = 0;
Signature · 1 line
1.7.6.4
#10 lore raw

PATCH 5/5 regmap: Ensure we scream if we enable cache bypass/only at the same time

In reply to Dimitris Papastamos
---
 drivers/base/regmap/regcache.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)
drivers/base/regmap/regcache.c +4 -0
index 2628e42..9f445bd 100644
@@ -273,6 +273,8 @@ EXPORT_SYMBOL_GPL(regcache_sync);
  */
 void regcache_cache_only(struct regmap *map, bool enable)
 {
+	BUG_ON(map->cache_bypass && enable);
+
 	map->cache_only = enable;
 }
 EXPORT_SYMBOL_GPL(regcache_cache_only);
@@ -290,6 +292,8 @@ EXPORT_SYMBOL_GPL(regcache_cache_only);
  */
 void regcache_cache_bypass(struct regmap *map, bool enable)
 {
+	BUG_ON(map->cache_only && enable);
+
 	map->cache_bypass = enable;
 }
 EXPORT_SYMBOL_GPL(regcache_cache_bypass);
Signature · 1 line
1.7.6.4