diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-03-29 19:18:59 +0000 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-03-30 13:49:17 +0000 |
commit | 78493f2d7b51d6f6d03982cee559c62dfab4c292 (patch) | |
tree | 7b7360e51d4e245a0fa2ac611eecc252ea5030fc /drivers/base/regmap/regcache.c | |
parent | 137b833457864091610ca01d7443a67028a2b3ce (diff) |
regmap: cache: Factor out reg_present support from rbtree cache
The idea of maintaining a bitmap of present registers is something that
can usefully be used by other cache types that maintain blocks of cached
registers so move the code out of the rbtree cache and into the generic
regcache code.
Refactor the interface slightly as we go to wrap the set bit and enlarge
bitmap operations (since we never do one without the other) and make it
more robust for reads of uncached registers by bounds checking before we
look at the bitmap.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Reviewed-by: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
Diffstat (limited to 'drivers/base/regmap/regcache.c')
-rw-r--r-- | drivers/base/regmap/regcache.c | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 229c804e409..0fedf4fa011 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -121,6 +121,8 @@ int regcache_init(struct regmap *map, const struct regmap_config *config) map->reg_defaults_raw = config->reg_defaults_raw; map->cache_word_size = DIV_ROUND_UP(config->val_bits, 8); map->cache_size_raw = map->cache_word_size * config->num_reg_defaults_raw; + map->cache_present = NULL; + map->cache_present_nbits = 0; map->cache = NULL; map->cache_ops = cache_types[i]; @@ -179,6 +181,7 @@ void regcache_exit(struct regmap *map) BUG_ON(!map->cache_ops); + kfree(map->cache_present); kfree(map->reg_defaults); if (map->cache_free) kfree(map->reg_defaults_raw); @@ -415,6 +418,42 @@ void regcache_cache_bypass(struct regmap *map, bool enable) } EXPORT_SYMBOL_GPL(regcache_cache_bypass); +int regcache_set_reg_present(struct regmap *map, unsigned int reg) +{ + unsigned long *cache_present; + unsigned int cache_present_size; + unsigned int nregs; + int i; + + nregs = reg + 1; + cache_present_size = BITS_TO_LONGS(nregs); + cache_present_size *= sizeof(long); + + if (!map->cache_present) { + cache_present = kmalloc(cache_present_size, GFP_KERNEL); + if (!cache_present) + return -ENOMEM; + bitmap_zero(cache_present, nregs); + map->cache_present = cache_present; + map->cache_present_nbits = nregs; + } + + if (nregs > map->cache_present_nbits) { + cache_present = krealloc(map->cache_present, + cache_present_size, GFP_KERNEL); + if (!cache_present) + return -ENOMEM; + for (i = 0; i < nregs; i++) + if (i >= map->cache_present_nbits) + clear_bit(i, cache_present); + map->cache_present = cache_present; + map->cache_present_nbits = nregs; + } + + set_bit(reg, map->cache_present); + return 0; +} + bool regcache_set_val(struct regmap *map, void *base, unsigned int idx, unsigned int val) { |