diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-29 16:31:26 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-29 16:31:26 -0700 |
commit | 7b053842b95914119f132fdac294fb2591b2e9a8 (patch) | |
tree | 9d17379a2ed7c8a3119489168adf695a44543960 /drivers/base/regmap/regcache-rbtree.c | |
parent | 5415ba99c229105a6939a7f9effe21045b8b2e5b (diff) | |
parent | 38a817965d2d624b0db68f3bf5ae783ad7f2087a (diff) |
Merge tag 'regmap-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap
Pull regmap updates from Mark Brown:
"In user visible terms just a couple of enhancements here, though there
was a moderate amount of refactoring required in order to support the
register cache sync performance improvements.
- Support for block and asynchronous I/O during register cache
syncing; this provides a use case dependant performance
improvement.
- Additional debugfs information on the memory consuption and
register set"
* tag 'regmap-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap: (23 commits)
regmap: don't corrupt work buffer in _regmap_raw_write()
regmap: cache: Fix format specifier in dev_dbg
regmap: cache: Make regcache_sync_block_raw static
regmap: cache: Write consecutive registers in a single block write
regmap: cache: Split raw and non-raw syncs
regmap: cache: Factor out block sync
regmap: cache: Factor out reg_present support from rbtree cache
regmap: cache: Use raw I/O to sync rbtrees if we can
regmap: core: Provide regmap_can_raw_write() operation
regmap: cache: Provide a get address of value operation
regmap: Cut down on the average # of nodes in the rbtree cache
regmap: core: Make raw write available to regcache
regmap: core: Warn on invalid operation combinations
regmap: irq: Clarify error message when we fail to request primary IRQ
regmap: rbtree Expose total memory consumption in the rbtree debugfs entry
regmap: debugfs: Add a registers `range' file
regmap: debugfs: Simplify calculation of `c->max_reg'
regmap: cache: Store caches in native register format where possible
regmap: core: Split out in place value parsing
regmap: cache: Use regcache_get_value() to check if we updated
...
Diffstat (limited to 'drivers/base/regmap/regcache-rbtree.c')
-rw-r--r-- | drivers/base/regmap/regcache-rbtree.c | 100 |
1 files changed, 46 insertions, 54 deletions
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c index 79f4fca9877a..aa0875f6f1b7 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)) { @@ -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 = { |