|
@@ -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)) {
|
|
@@ -402,27 +408,13 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
|
|
|
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 = {
|