aboutsummaryrefslogtreecommitdiff
path: root/drivers/base/regmap/regcache-rbtree.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/regmap/regcache-rbtree.c')
-rw-r--r--drivers/base/regmap/regcache-rbtree.c102
1 files changed, 47 insertions, 55 deletions
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
index e6732cf7c06..aa0875f6f1b 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -47,22 +47,21 @@ static inline void regcache_rbtree_get_base_top_reg(
*top = rbnode->base_reg + ((rbnode->blklen - 1) * map->reg_stride);
}
-static unsigned int regcache_rbtree_get_register(
- struct regcache_rbtree_node *rbnode, unsigned int idx,
- unsigned int word_size)
+static unsigned int regcache_rbtree_get_register(struct regmap *map,
+ struct regcache_rbtree_node *rbnode, unsigned int idx)
{
- return regcache_get_val(rbnode->block, idx, word_size);
+ return regcache_get_val(map, rbnode->block, idx);
}
-static void regcache_rbtree_set_register(struct regcache_rbtree_node *rbnode,
- unsigned int idx, unsigned int val,
- unsigned int word_size)
+static void regcache_rbtree_set_register(struct regmap *map,
+ struct regcache_rbtree_node *rbnode,
+ unsigned int idx, unsigned int val)
{
- regcache_set_val(rbnode->block, idx, val, word_size);
+ regcache_set_val(map, rbnode->block, idx, val);
}
static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map,
- unsigned int reg)
+ unsigned int reg)
{
struct regcache_rbtree_ctx *rbtree_ctx = map->cache;
struct rb_node *node;
@@ -139,15 +138,21 @@ static int rbtree_show(struct seq_file *s, void *ignored)
struct regcache_rbtree_node *n;
struct rb_node *node;
unsigned int base, top;
+ size_t mem_size;
int nodes = 0;
int registers = 0;
int this_registers, average;
map->lock(map);
+ mem_size = sizeof(*rbtree_ctx);
+ mem_size += BITS_TO_LONGS(map->cache_present_nbits) * sizeof(long);
+
for (node = rb_first(&rbtree_ctx->root); node != NULL;
node = rb_next(node)) {
n = container_of(node, struct regcache_rbtree_node, node);
+ mem_size += sizeof(*n);
+ mem_size += (n->blklen * map->cache_word_size);
regcache_rbtree_get_base_top_reg(map, n, &base, &top);
this_registers = ((top - base) / map->reg_stride) + 1;
@@ -162,8 +167,8 @@ static int rbtree_show(struct seq_file *s, void *ignored)
else
average = 0;
- seq_printf(s, "%d nodes, %d registers, average %d registers\n",
- nodes, registers, average);
+ seq_printf(s, "%d nodes, %d registers, average %d registers, used %zu bytes\n",
+ nodes, registers, average, mem_size);
map->unlock(map);
@@ -260,8 +265,9 @@ static int regcache_rbtree_read(struct regmap *map,
rbnode = regcache_rbtree_lookup(map, reg);
if (rbnode) {
reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
- *value = regcache_rbtree_get_register(rbnode, reg_tmp,
- map->cache_word_size);
+ if (!regcache_reg_present(map, reg))
+ return -ENOENT;
+ *value = regcache_rbtree_get_register(map, rbnode, reg_tmp);
} else {
return -ENOENT;
}
@@ -270,21 +276,23 @@ static int regcache_rbtree_read(struct regmap *map,
}
-static int regcache_rbtree_insert_to_block(struct regcache_rbtree_node *rbnode,
+static int regcache_rbtree_insert_to_block(struct regmap *map,
+ struct regcache_rbtree_node *rbnode,
unsigned int pos, unsigned int reg,
- unsigned int value, unsigned int word_size)
+ unsigned int value)
{
u8 *blk;
blk = krealloc(rbnode->block,
- (rbnode->blklen + 1) * word_size, GFP_KERNEL);
+ (rbnode->blklen + 1) * map->cache_word_size,
+ GFP_KERNEL);
if (!blk)
return -ENOMEM;
/* insert the register value in the correct place in the rbnode block */
- memmove(blk + (pos + 1) * word_size,
- blk + pos * word_size,
- (rbnode->blklen - pos) * word_size);
+ memmove(blk + (pos + 1) * map->cache_word_size,
+ blk + pos * map->cache_word_size,
+ (rbnode->blklen - pos) * map->cache_word_size);
/* update the rbnode block, its size and the base register */
rbnode->block = blk;
@@ -292,7 +300,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, word_size);
+ regcache_rbtree_set_register(map, rbnode, pos, value);
return 0;
}
@@ -302,25 +310,24 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
struct regcache_rbtree_ctx *rbtree_ctx;
struct regcache_rbtree_node *rbnode, *rbnode_tmp;
struct rb_node *node;
- unsigned int val;
unsigned int reg_tmp;
unsigned int pos;
int i;
int ret;
rbtree_ctx = map->cache;
+ /* update the reg_present bitmap, make space if necessary */
+ ret = regcache_set_reg_present(map, reg);
+ if (ret < 0)
+ return ret;
+
/* if we can't locate it in the cached rbnode we'll have
* to traverse the rbtree looking for it.
*/
rbnode = regcache_rbtree_lookup(map, reg);
if (rbnode) {
reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
- 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,
- map->cache_word_size);
+ regcache_rbtree_set_register(map, rbnode, reg_tmp, value);
} else {
/* look for an adjacent register to the one we are about to add */
for (node = rb_first(&rbtree_ctx->root); node;
@@ -337,9 +344,10 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
pos = i + 1;
else
pos = i;
- ret = regcache_rbtree_insert_to_block(rbnode_tmp, pos,
- reg, value,
- map->cache_word_size);
+ ret = regcache_rbtree_insert_to_block(map,
+ rbnode_tmp,
+ pos, reg,
+ value);
if (ret)
return ret;
rbtree_ctx->cached_rbnode = rbnode_tmp;
@@ -354,7 +362,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
if (!rbnode)
return -ENOMEM;
- rbnode->blklen = 1;
+ rbnode->blklen = sizeof(*rbnode);
rbnode->base_reg = reg;
rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size,
GFP_KERNEL);
@@ -362,7 +370,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
kfree(rbnode);
return -ENOMEM;
}
- regcache_rbtree_set_register(rbnode, 0, value, map->cache_word_size);
+ regcache_rbtree_set_register(map, rbnode, 0, value);
regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode);
rbtree_ctx->cached_rbnode = rbnode;
}
@@ -376,10 +384,8 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
struct regcache_rbtree_ctx *rbtree_ctx;
struct rb_node *node;
struct regcache_rbtree_node *rbnode;
- unsigned int regtmp;
- unsigned int val;
int ret;
- int i, base, end;
+ int base, end;
rbtree_ctx = map->cache;
for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
@@ -398,31 +404,17 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
base = 0;
if (max < rbnode->base_reg + rbnode->blklen)
- end = rbnode->base_reg + rbnode->blklen - max;
+ end = max - rbnode->base_reg + 1;
else
end = rbnode->blklen;
- for (i = base; i < end; i++) {
- regtmp = rbnode->base_reg + (i * map->reg_stride);
- val = regcache_rbtree_get_register(rbnode, i,
- map->cache_word_size);
-
- /* Is this the hardware default? If so skip. */
- ret = regcache_lookup_reg(map, regtmp);
- if (ret >= 0 && val == map->reg_defaults[ret].def)
- continue;
-
- map->cache_bypass = 1;
- ret = _regmap_write(map, regtmp, val);
- map->cache_bypass = 0;
- if (ret)
- return ret;
- dev_dbg(map->dev, "Synced register %#x, value %#x\n",
- regtmp, val);
- }
+ ret = regcache_sync_block(map, rbnode->block, rbnode->base_reg,
+ base, end);
+ if (ret != 0)
+ return ret;
}
- return 0;
+ return regmap_async_complete(map);
}
struct regcache_ops regcache_rbtree_ops = {