regcache updates
Subsystems (2)
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
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
@@ -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
Mark Brown
AppliedRe: [PATCH 1/5] regmap: Fix signed/unsigned comparison
Quoted 1 line · Dimitris Papastamos
Signed-off-by Dimitris Papastamos <[email protected]>
Applied, thanks.
PATCH 2/5 regmap: Implement regcache_cache_bypass helper function
In reply to Dimitris PapastamosEnsure 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
@@ -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
@@ -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
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.
PATCH 3/5 regmap: Implement generic syncing functionality
In reply to Dimitris PapastamosIn 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
@@ -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
Mark Brown
AppliedRe: [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.
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
@@ -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
Mark Brown
AppliedRe: [PATCH 4/5] regmap: Remove redundant member `word_size' from regcache_rbtree_node
Quoted 1 line · Dimitris Papastamos
Signed-off-by Dimitris Papastamos <[email protected]>
Applied, thanks.
Re: [PATCH 4/5] regmap: Remove redundant member `word_size' from regcache_rbtree_node
In reply to Dimitris PapastamosQuoted 1 line · Dimitris Papastamos
Signed-off-by Dimitris Papastamos <[email protected]>
Eh, no I didn't - this change is already there in the current code.
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
@@ -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
Mark Brown
AppliedRe: [PATCH 5/5] regmap: Ensure we scream if we enable cache bypass/only at the same time
Quoted 1 line · Dimitris Papastamos
Signed-off-by Dimitris Papastamos <[email protected]>
Applied, thanks.