diff options
author | Mark Brown <broonie@kernel.org> | 2016-09-03 12:10:09 +0100 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-09-03 12:10:09 +0100 |
commit | 787ad90332b3573d502a6c1aff52f708ca141976 (patch) | |
tree | e0e9e28704bfb1b8a975f11926c5610f0c0fde8f /drivers/base | |
parent | f735aa279021149ef600febe07333ad218783d79 (diff) | |
parent | 1bc8da4e143c0fd8807e061a66d91d5972601ab1 (diff) | |
download | linux-787ad90332b3573d502a6c1aff52f708ca141976.tar.gz linux-787ad90332b3573d502a6c1aff52f708ca141976.tar.bz2 linux-787ad90332b3573d502a6c1aff52f708ca141976.zip |
Merge remote-tracking branch 'regmap/fix/rbtree' into regmap-linus
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/regmap/regcache-rbtree.c | 38 |
1 files changed, 28 insertions, 10 deletions
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c index aa56af87d941..b11af3f2c1db 100644 --- a/drivers/base/regmap/regcache-rbtree.c +++ b/drivers/base/regmap/regcache-rbtree.c @@ -404,6 +404,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg, unsigned int new_base_reg, new_top_reg; unsigned int min, max; unsigned int max_dist; + unsigned int dist, best_dist = UINT_MAX; max_dist = map->reg_stride * sizeof(*rbnode_tmp) / map->cache_word_size; @@ -423,24 +424,41 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg, &base_reg, &top_reg); if (base_reg <= max && top_reg >= min) { - new_base_reg = min(reg, base_reg); - new_top_reg = max(reg, top_reg); - } else { - if (max < base_reg) - node = node->rb_left; + if (reg < base_reg) + dist = base_reg - reg; + else if (reg > top_reg) + dist = reg - top_reg; else - node = node->rb_right; - - continue; + dist = 0; + if (dist < best_dist) { + rbnode = rbnode_tmp; + best_dist = dist; + new_base_reg = min(reg, base_reg); + new_top_reg = max(reg, top_reg); + } } - ret = regcache_rbtree_insert_to_block(map, rbnode_tmp, + /* + * Keep looking, we want to choose the closest block, + * otherwise we might end up creating overlapping + * blocks, which breaks the rbtree. + */ + if (reg < base_reg) + node = node->rb_left; + else if (reg > top_reg) + node = node->rb_right; + else + break; + } + + if (rbnode) { + ret = regcache_rbtree_insert_to_block(map, rbnode, new_base_reg, new_top_reg, reg, value); if (ret) return ret; - rbtree_ctx->cached_rbnode = rbnode_tmp; + rbtree_ctx->cached_rbnode = rbnode; return 0; } |