aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorDimitris Papastamos <dp@opensource.wolfsonmicro.com>2013-03-15 10:54:35 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2013-03-26 17:38:15 -0400
commit0c7ed8563a0282c032936ae1c667498d59691593 (patch)
tree9c526d8d5cb5ecf4514d93be8071a1ecb66e6389 /drivers/base
parent584de329ca43cc6d73eb74885e1d5d9fc0549423 (diff)
regmap: Cut down on the average # of nodes in the rbtree cache
This patch aims to bring down the average number of nodes in the rbtree cache and increase the average number of registers per node. This should improve general lookup and traversal times. This is achieved by setting the minimum size of a block within the rbnode to the size of the rbnode itself. This will essentially cache possibly non-existent registers so to combat this scenario, we keep a separate bitmap in memory which keeps track of which register exists. The memory overhead of this change is likely in the order of ~5-10%, possibly less depending on the register file layout. On my test system with a bitmap of ~4300 bits and a relatively sparse register layout, the memory requirements for the entire cache did not increase (the cutting down of nodes which was about 50% of the original number compensated the situation). A second patch that can be built on top of this can look at the ratio `sizeof(*rbnode) / map->cache_word_size' in order to suitably adjust the block length of each block. Signed-off-by: Dimitris Papastamos <dp@opensource.wolfsonmicro.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/regmap/regcache-rbtree.c70
1 files changed, 69 insertions, 1 deletions
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
index 045319615608..792a760c8ab1 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -36,6 +36,8 @@ 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;
39}; 41};
40 42
41static inline void regcache_rbtree_get_base_top_reg( 43static inline void regcache_rbtree_get_base_top_reg(
@@ -146,6 +148,7 @@ static int rbtree_show(struct seq_file *s, void *ignored)
146 map->lock(map); 148 map->lock(map);
147 149
148 mem_size = sizeof(*rbtree_ctx); 150 mem_size = sizeof(*rbtree_ctx);
151 mem_size += BITS_TO_LONGS(rbtree_ctx->reg_present_nbits) * sizeof(long);
149 152
150 for (node = rb_first(&rbtree_ctx->root); node != NULL; 153 for (node = rb_first(&rbtree_ctx->root); node != NULL;
151 node = rb_next(node)) { 154 node = rb_next(node)) {
@@ -196,6 +199,44 @@ static void rbtree_debugfs_init(struct regmap *map)
196} 199}
197#endif 200#endif
198 201
202static int enlarge_reg_present_bitmap(struct regmap *map, unsigned int reg)
203{
204 struct regcache_rbtree_ctx *rbtree_ctx;
205 unsigned long *reg_present;
206 unsigned int reg_present_size;
207 unsigned int nregs;
208 int i;
209
210 rbtree_ctx = map->cache;
211 nregs = reg + 1;
212 reg_present_size = BITS_TO_LONGS(nregs);
213 reg_present_size *= sizeof(long);
214
215 if (!rbtree_ctx->reg_present) {
216 reg_present = kmalloc(reg_present_size, GFP_KERNEL);
217 if (!reg_present)
218 return -ENOMEM;
219 bitmap_zero(reg_present, nregs);
220 rbtree_ctx->reg_present = reg_present;
221 rbtree_ctx->reg_present_nbits = nregs;
222 return 0;
223 }
224
225 if (nregs > rbtree_ctx->reg_present_nbits) {
226 reg_present = krealloc(rbtree_ctx->reg_present,
227 reg_present_size, GFP_KERNEL);
228 if (!reg_present)
229 return -ENOMEM;
230 for (i = 0; i < nregs; i++)
231 if (i >= rbtree_ctx->reg_present_nbits)
232 clear_bit(i, reg_present);
233 rbtree_ctx->reg_present = reg_present;
234 rbtree_ctx->reg_present_nbits = nregs;
235 }
236
237 return 0;
238}
239
199static int regcache_rbtree_init(struct regmap *map) 240static int regcache_rbtree_init(struct regmap *map)
200{ 241{
201 struct regcache_rbtree_ctx *rbtree_ctx; 242 struct regcache_rbtree_ctx *rbtree_ctx;
@@ -209,6 +250,8 @@ static int regcache_rbtree_init(struct regmap *map)
209 rbtree_ctx = map->cache; 250 rbtree_ctx = map->cache;
210 rbtree_ctx->root = RB_ROOT; 251 rbtree_ctx->root = RB_ROOT;
211 rbtree_ctx->cached_rbnode = NULL; 252 rbtree_ctx->cached_rbnode = NULL;
253 rbtree_ctx->reg_present = NULL;
254 rbtree_ctx->reg_present_nbits = 0;
212 255
213 for (i = 0; i < map->num_reg_defaults; i++) { 256 for (i = 0; i < map->num_reg_defaults; i++) {
214 ret = regcache_rbtree_write(map, 257 ret = regcache_rbtree_write(map,
@@ -238,6 +281,8 @@ static int regcache_rbtree_exit(struct regmap *map)
238 if (!rbtree_ctx) 281 if (!rbtree_ctx)
239 return 0; 282 return 0;
240 283
284 kfree(rbtree_ctx->reg_present);
285
241 /* free up the rbtree */ 286 /* free up the rbtree */
242 next = rb_first(&rbtree_ctx->root); 287 next = rb_first(&rbtree_ctx->root);
243 while (next) { 288 while (next) {
@@ -255,6 +300,17 @@ static int regcache_rbtree_exit(struct regmap *map)
255 return 0; 300 return 0;
256} 301}
257 302
303static int regcache_reg_present(struct regmap *map, unsigned int reg)
304{
305 struct regcache_rbtree_ctx *rbtree_ctx;
306
307 rbtree_ctx = map->cache;
308 if (!(rbtree_ctx->reg_present[BIT_WORD(reg)] & BIT_MASK(reg)))
309 return 0;
310 return 1;
311
312}
313
258static int regcache_rbtree_read(struct regmap *map, 314static int regcache_rbtree_read(struct regmap *map,
259 unsigned int reg, unsigned int *value) 315 unsigned int reg, unsigned int *value)
260{ 316{
@@ -264,6 +320,8 @@ static int regcache_rbtree_read(struct regmap *map,
264 rbnode = regcache_rbtree_lookup(map, reg); 320 rbnode = regcache_rbtree_lookup(map, reg);
265 if (rbnode) { 321 if (rbnode) {
266 reg_tmp = (reg - rbnode->base_reg) / map->reg_stride; 322 reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
323 if (!regcache_reg_present(map, reg))
324 return -ENOENT;
267 *value = regcache_rbtree_get_register(map, rbnode, reg_tmp); 325 *value = regcache_rbtree_get_register(map, rbnode, reg_tmp);
268 } else { 326 } else {
269 return -ENOENT; 327 return -ENOENT;
@@ -313,6 +371,12 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
313 int ret; 371 int ret;
314 372
315 rbtree_ctx = map->cache; 373 rbtree_ctx = map->cache;
374 /* update the reg_present bitmap, make space if necessary */
375 ret = enlarge_reg_present_bitmap(map, reg);
376 if (ret < 0)
377 return ret;
378 set_bit(reg, rbtree_ctx->reg_present);
379
316 /* if we can't locate it in the cached rbnode we'll have 380 /* if we can't locate it in the cached rbnode we'll have
317 * to traverse the rbtree looking for it. 381 * to traverse the rbtree looking for it.
318 */ 382 */
@@ -354,7 +418,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
354 rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL); 418 rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
355 if (!rbnode) 419 if (!rbnode)
356 return -ENOMEM; 420 return -ENOMEM;
357 rbnode->blklen = 1; 421 rbnode->blklen = sizeof(*rbnode);
358 rbnode->base_reg = reg; 422 rbnode->base_reg = reg;
359 rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size, 423 rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size,
360 GFP_KERNEL); 424 GFP_KERNEL);
@@ -404,6 +468,10 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
404 468
405 for (i = base; i < end; i++) { 469 for (i = base; i < end; i++) {
406 regtmp = rbnode->base_reg + (i * map->reg_stride); 470 regtmp = rbnode->base_reg + (i * map->reg_stride);
471
472 if (!regcache_reg_present(map, regtmp))
473 continue;
474
407 val = regcache_rbtree_get_register(map, rbnode, i); 475 val = regcache_rbtree_get_register(map, rbnode, i);
408 476
409 /* Is this the hardware default? If so skip. */ 477 /* Is this the hardware default? If so skip. */