aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2013-03-29 15:18:59 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2013-03-30 09:49:17 -0400
commit78493f2d7b51d6f6d03982cee559c62dfab4c292 (patch)
tree7b7360e51d4e245a0fa2ac611eecc252ea5030fc /drivers
parent137b833457864091610ca01d7443a67028a2b3ce (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')
-rw-r--r--drivers/base/regmap/internal.h13
-rw-r--r--drivers/base/regmap/regcache-rbtree.c60
-rw-r--r--drivers/base/regmap/regcache.c39
3 files changed, 54 insertions, 58 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 95d46a5ea7e7..b01fe59fbfe8 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -126,6 +126,9 @@ struct regmap {
126 void *cache; 126 void *cache;
127 u32 cache_dirty; 127 u32 cache_dirty;
128 128
129 unsigned long *cache_present;
130 unsigned int cache_present_nbits;
131
129 struct reg_default *patch; 132 struct reg_default *patch;
130 int patch_regs; 133 int patch_regs;
131 134
@@ -201,6 +204,16 @@ unsigned int regcache_get_val(struct regmap *map, const void *base,
201bool regcache_set_val(struct regmap *map, void *base, unsigned int idx, 204bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
202 unsigned int val); 205 unsigned int val);
203int regcache_lookup_reg(struct regmap *map, unsigned int reg); 206int regcache_lookup_reg(struct regmap *map, unsigned int reg);
207int regcache_set_reg_present(struct regmap *map, unsigned int reg);
208
209static inline bool regcache_reg_present(struct regmap *map, unsigned int reg)
210{
211 if (!map->cache_present)
212 return true;
213 if (reg > map->cache_present_nbits)
214 return false;
215 return map->cache_present[BIT_WORD(reg)] & BIT_MASK(reg);
216}
204 217
205int _regmap_raw_write(struct regmap *map, unsigned int reg, 218int _regmap_raw_write(struct regmap *map, unsigned int reg,
206 const void *val, size_t val_len, bool async); 219 const void *val, size_t val_len, bool async);
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
index 382a6deb3ca8..00c3506f542f 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -36,8 +36,6 @@ struct regcache_rbtree_node {
36struct regcache_rbtree_ctx { 36struct regcache_rbtree_ctx {
37 struct rb_root root; 37 struct rb_root root;
38 struct regcache_rbtree_node *cached_rbnode; 38 struct regcache_rbtree_node *cached_rbnode;
39 unsigned long *reg_present;
40 unsigned int reg_present_nbits;
41}; 39};
42 40
43static inline void regcache_rbtree_get_base_top_reg( 41static inline void regcache_rbtree_get_base_top_reg(
@@ -154,7 +152,7 @@ static int rbtree_show(struct seq_file *s, void *ignored)
154 map->lock(map); 152 map->lock(map);
155 153
156 mem_size = sizeof(*rbtree_ctx); 154 mem_size = sizeof(*rbtree_ctx);
157 mem_size += BITS_TO_LONGS(rbtree_ctx->reg_present_nbits) * sizeof(long); 155 mem_size += BITS_TO_LONGS(map->cache_present_nbits) * sizeof(long);
158 156
159 for (node = rb_first(&rbtree_ctx->root); node != NULL; 157 for (node = rb_first(&rbtree_ctx->root); node != NULL;
160 node = rb_next(node)) { 158 node = rb_next(node)) {
@@ -205,44 +203,6 @@ static void rbtree_debugfs_init(struct regmap *map)
205} 203}
206#endif 204#endif
207 205
208static int enlarge_reg_present_bitmap(struct regmap *map, unsigned int reg)
209{
210 struct regcache_rbtree_ctx *rbtree_ctx;
211 unsigned long *reg_present;
212 unsigned int reg_present_size;
213 unsigned int nregs;
214 int i;
215
216 rbtree_ctx = map->cache;
217 nregs = reg + 1;
218 reg_present_size = BITS_TO_LONGS(nregs);
219 reg_present_size *= sizeof(long);
220
221 if (!rbtree_ctx->reg_present) {
222 reg_present = kmalloc(reg_present_size, GFP_KERNEL);
223 if (!reg_present)
224 return -ENOMEM;
225 bitmap_zero(reg_present, nregs);
226 rbtree_ctx->reg_present = reg_present;
227 rbtree_ctx->reg_present_nbits = nregs;
228 return 0;
229 }
230
231 if (nregs > rbtree_ctx->reg_present_nbits) {
232 reg_present = krealloc(rbtree_ctx->reg_present,
233 reg_present_size, GFP_KERNEL);
234 if (!reg_present)
235 return -ENOMEM;
236 for (i = 0; i < nregs; i++)
237 if (i >= rbtree_ctx->reg_present_nbits)
238 clear_bit(i, reg_present);
239 rbtree_ctx->reg_present = reg_present;
240 rbtree_ctx->reg_present_nbits = nregs;
241 }
242
243 return 0;
244}
245
246static int regcache_rbtree_init(struct regmap *map) 206static int regcache_rbtree_init(struct regmap *map)
247{ 207{
248 struct regcache_rbtree_ctx *rbtree_ctx; 208 struct regcache_rbtree_ctx *rbtree_ctx;
@@ -256,8 +216,6 @@ static int regcache_rbtree_init(struct regmap *map)
256 rbtree_ctx = map->cache; 216 rbtree_ctx = map->cache;
257 rbtree_ctx->root = RB_ROOT; 217 rbtree_ctx->root = RB_ROOT;
258 rbtree_ctx->cached_rbnode = NULL; 218 rbtree_ctx->cached_rbnode = NULL;
259 rbtree_ctx->reg_present = NULL;
260 rbtree_ctx->reg_present_nbits = 0;
261 219
262 for (i = 0; i < map->num_reg_defaults; i++) { 220 for (i = 0; i < map->num_reg_defaults; i++) {
263 ret = regcache_rbtree_write(map, 221 ret = regcache_rbtree_write(map,
@@ -287,8 +245,6 @@ static int regcache_rbtree_exit(struct regmap *map)
287 if (!rbtree_ctx) 245 if (!rbtree_ctx)
288 return 0; 246 return 0;
289 247
290 kfree(rbtree_ctx->reg_present);
291
292 /* free up the rbtree */ 248 /* free up the rbtree */
293 next = rb_first(&rbtree_ctx->root); 249 next = rb_first(&rbtree_ctx->root);
294 while (next) { 250 while (next) {
@@ -306,17 +262,6 @@ static int regcache_rbtree_exit(struct regmap *map)
306 return 0; 262 return 0;
307} 263}
308 264
309static int regcache_reg_present(struct regmap *map, unsigned int reg)
310{
311 struct regcache_rbtree_ctx *rbtree_ctx;
312
313 rbtree_ctx = map->cache;
314 if (!(rbtree_ctx->reg_present[BIT_WORD(reg)] & BIT_MASK(reg)))
315 return 0;
316 return 1;
317
318}
319
320static int regcache_rbtree_read(struct regmap *map, 265static int regcache_rbtree_read(struct regmap *map,
321 unsigned int reg, unsigned int *value) 266 unsigned int reg, unsigned int *value)
322{ 267{
@@ -378,10 +323,9 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
378 323
379 rbtree_ctx = map->cache; 324 rbtree_ctx = map->cache;
380 /* update the reg_present bitmap, make space if necessary */ 325 /* update the reg_present bitmap, make space if necessary */
381 ret = enlarge_reg_present_bitmap(map, reg); 326 ret = regcache_set_reg_present(map, reg);
382 if (ret < 0) 327 if (ret < 0)
383 return ret; 328 return ret;
384 set_bit(reg, rbtree_ctx->reg_present);
385 329
386 /* if we can't locate it in the cached rbnode we'll have 330 /* if we can't locate it in the cached rbnode we'll have
387 * to traverse the rbtree looking for it. 331 * to traverse the rbtree looking for it.
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 229c804e409e..0fedf4fa0116 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)
121 map->reg_defaults_raw = config->reg_defaults_raw; 121 map->reg_defaults_raw = config->reg_defaults_raw;
122 map->cache_word_size = DIV_ROUND_UP(config->val_bits, 8); 122 map->cache_word_size = DIV_ROUND_UP(config->val_bits, 8);
123 map->cache_size_raw = map->cache_word_size * config->num_reg_defaults_raw; 123 map->cache_size_raw = map->cache_word_size * config->num_reg_defaults_raw;
124 map->cache_present = NULL;
125 map->cache_present_nbits = 0;
124 126
125 map->cache = NULL; 127 map->cache = NULL;
126 map->cache_ops = cache_types[i]; 128 map->cache_ops = cache_types[i];
@@ -179,6 +181,7 @@ void regcache_exit(struct regmap *map)
179 181
180 BUG_ON(!map->cache_ops); 182 BUG_ON(!map->cache_ops);
181 183
184 kfree(map->cache_present);
182 kfree(map->reg_defaults); 185 kfree(map->reg_defaults);
183 if (map->cache_free) 186 if (map->cache_free)
184 kfree(map->reg_defaults_raw); 187 kfree(map->reg_defaults_raw);
@@ -415,6 +418,42 @@ void regcache_cache_bypass(struct regmap *map, bool enable)
415} 418}
416EXPORT_SYMBOL_GPL(regcache_cache_bypass); 419EXPORT_SYMBOL_GPL(regcache_cache_bypass);
417 420
421int regcache_set_reg_present(struct regmap *map, unsigned int reg)
422{
423 unsigned long *cache_present;
424 unsigned int cache_present_size;
425 unsigned int nregs;
426 int i;
427
428 nregs = reg + 1;
429 cache_present_size = BITS_TO_LONGS(nregs);
430 cache_present_size *= sizeof(long);
431
432 if (!map->cache_present) {
433 cache_present = kmalloc(cache_present_size, GFP_KERNEL);
434 if (!cache_present)
435 return -ENOMEM;
436 bitmap_zero(cache_present, nregs);
437 map->cache_present = cache_present;
438 map->cache_present_nbits = nregs;
439 }
440
441 if (nregs > map->cache_present_nbits) {
442 cache_present = krealloc(map->cache_present,
443 cache_present_size, GFP_KERNEL);
444 if (!cache_present)
445 return -ENOMEM;
446 for (i = 0; i < nregs; i++)
447 if (i >= map->cache_present_nbits)
448 clear_bit(i, cache_present);
449 map->cache_present = cache_present;
450 map->cache_present_nbits = nregs;
451 }
452
453 set_bit(reg, map->cache_present);
454 return 0;
455}
456
418bool regcache_set_val(struct regmap *map, void *base, unsigned int idx, 457bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
419 unsigned int val) 458 unsigned int val)
420{ 459{