aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2013-08-29 04:26:33 -0400
committerMark Brown <broonie@linaro.org>2013-08-29 08:32:40 -0400
commit472fdec7380cec483e241fa696d9b90bc37ddd4c (patch)
treed85e8d1fe6d2bd9fc5eb3a461338b2f4735166e4
parent194c753a214ba7f1497552dd530021884d164146 (diff)
regmap: rbtree: Reduce number of nodes, take 2
Support for reducing the number of nodes and memory consumption of the rbtree cache by allowing for small unused holes in the node's register cache block was initially added in commit 0c7ed856 ("regmap: Cut down on the average # of nodes in the rbtree cache"). But the commit had problems and so its effect was reverted again in commit 4e67fb5 ("regmap: rbtree: Fix overlapping rbnodes."). This patch brings the feature back of reducing the average number of nodes, which will speedup node look-up, while at the same time also reducing the memory usage of the rbtree cache. This patch takes a slightly different approach than the original patch though. It modifies the adjacent node look-up to not only consider nodes that are just one to the left or the right of the register but any node that falls in a certain range around the register. The range is calculated based on how much memory it would take to allocate a new node compared to how much memory it takes adding a set of unused registers to an existing node. E.g. if a node takes up 24 bytes and each register in a block uses 1 byte the range will be from the register address - 24 to the register address + 24. If we find a node that falls within this range it is cheaper or as expensive to add the register to the existing node and have a couple of unused registers in the node's cache compared to allocating a new node. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Mark Brown <broonie@linaro.org>
-rw-r--r--drivers/base/regmap/regcache-rbtree.c53
1 files changed, 36 insertions, 17 deletions
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
index dbe5ea12c79b..c06478c364b6 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -278,27 +278,34 @@ static int regcache_rbtree_read(struct regmap *map,
278 278
279static int regcache_rbtree_insert_to_block(struct regmap *map, 279static int regcache_rbtree_insert_to_block(struct regmap *map,
280 struct regcache_rbtree_node *rbnode, 280 struct regcache_rbtree_node *rbnode,
281 unsigned int pos, unsigned int reg, 281 unsigned int base_reg,
282 unsigned int top_reg,
283 unsigned int reg,
282 unsigned int value) 284 unsigned int value)
283{ 285{
286 unsigned int blklen;
287 unsigned int pos, offset;
284 u8 *blk; 288 u8 *blk;
285 289
290 blklen = (top_reg - base_reg) / map->reg_stride + 1;
291 pos = (reg - base_reg) / map->reg_stride;
292 offset = (rbnode->base_reg - base_reg) / map->reg_stride;
293
286 blk = krealloc(rbnode->block, 294 blk = krealloc(rbnode->block,
287 (rbnode->blklen + 1) * map->cache_word_size, 295 blklen * map->cache_word_size,
288 GFP_KERNEL); 296 GFP_KERNEL);
289 if (!blk) 297 if (!blk)
290 return -ENOMEM; 298 return -ENOMEM;
291 299
292 /* insert the register value in the correct place in the rbnode block */ 300 /* insert the register value in the correct place in the rbnode block */
293 memmove(blk + (pos + 1) * map->cache_word_size, 301 if (pos == 0)
294 blk + pos * map->cache_word_size, 302 memmove(blk + offset * map->cache_word_size,
295 (rbnode->blklen - pos) * map->cache_word_size); 303 blk, rbnode->blklen * map->cache_word_size);
296 304
297 /* update the rbnode block, its size and the base register */ 305 /* update the rbnode block, its size and the base register */
298 rbnode->block = blk; 306 rbnode->block = blk;
299 rbnode->blklen++; 307 rbnode->blklen = blklen;
300 if (!pos) 308 rbnode->base_reg = base_reg;
301 rbnode->base_reg = reg;
302 309
303 regcache_rbtree_set_register(map, rbnode, pos, value); 310 regcache_rbtree_set_register(map, rbnode, pos, value);
304 return 0; 311 return 0;
@@ -352,9 +359,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
352 struct regcache_rbtree_ctx *rbtree_ctx; 359 struct regcache_rbtree_ctx *rbtree_ctx;
353 struct regcache_rbtree_node *rbnode, *rbnode_tmp; 360 struct regcache_rbtree_node *rbnode, *rbnode_tmp;
354 struct rb_node *node; 361 struct rb_node *node;
355 unsigned int base_reg, top_reg;
356 unsigned int reg_tmp; 362 unsigned int reg_tmp;
357 unsigned int pos;
358 int ret; 363 int ret;
359 364
360 rbtree_ctx = map->cache; 365 rbtree_ctx = map->cache;
@@ -371,6 +376,19 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
371 reg_tmp = (reg - rbnode->base_reg) / map->reg_stride; 376 reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
372 regcache_rbtree_set_register(map, rbnode, reg_tmp, value); 377 regcache_rbtree_set_register(map, rbnode, reg_tmp, value);
373 } else { 378 } else {
379 unsigned int base_reg, top_reg;
380 unsigned int new_base_reg, new_top_reg;
381 unsigned int min, max;
382 unsigned int max_dist;
383
384 max_dist = map->reg_stride * sizeof(*rbnode_tmp) /
385 map->cache_word_size;
386 if (reg < max_dist)
387 min = 0;
388 else
389 min = reg - max_dist;
390 max = reg + max_dist;
391
374 /* look for an adjacent register to the one we are about to add */ 392 /* look for an adjacent register to the one we are about to add */
375 for (node = rb_first(&rbtree_ctx->root); node; 393 for (node = rb_first(&rbtree_ctx->root); node;
376 node = rb_next(node)) { 394 node = rb_next(node)) {
@@ -380,16 +398,17 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
380 regcache_rbtree_get_base_top_reg(map, rbnode_tmp, 398 regcache_rbtree_get_base_top_reg(map, rbnode_tmp,
381 &base_reg, &top_reg); 399 &base_reg, &top_reg);
382 400
383 /* decide where in the block to place our register */ 401 if (base_reg <= max && top_reg >= min) {
384 if (base_reg > 0 && reg == base_reg - map->reg_stride) 402 new_base_reg = min(reg, base_reg);
385 pos = 0; 403 new_top_reg = max(reg, top_reg);
386 else if (reg > 0 && reg - map->reg_stride == top_reg) 404 } else {
387 pos = rbnode_tmp->blklen;
388 else
389 continue; 405 continue;
406 }
390 407
391 ret = regcache_rbtree_insert_to_block(map, rbnode_tmp, 408 ret = regcache_rbtree_insert_to_block(map, rbnode_tmp,
392 pos, reg, value); 409 new_base_reg,
410 new_top_reg, reg,
411 value);
393 if (ret) 412 if (ret)
394 return ret; 413 return ret;
395 rbtree_ctx->cached_rbnode = rbnode_tmp; 414 rbtree_ctx->cached_rbnode = rbnode_tmp;