mirror of https://gitee.com/openkylin/linux.git
regmap: Fixes for v4.8
Several fixes here, the main one being the change from Lars-Peter which I'd been letting soak in -next since the merge window in case it uncovered further issues as it's a minimal fix rather than a change addressing the root cause of the problems (which would've been too invasive for -rc): - The biggest change is a fix from Lars-Peter to ensure that we don't create overlapping rbtree nodes which in turn avoids returning corrupt cache values to users, fixing some issues that were exposed by some recent optimisations with certain access patterns but had been present for a long time. - A fix from Elaine Zhang to stop us updating the cache if we get an I/O error when writing to the hardware. - A fix fromm Maarten ter Huurne to avoid uninitialized defaults in cases where we have non-readable registers but are initializing the cache by reading from the device. -----BEGIN PGP SIGNATURE----- iQEwBAABCAAaBQJXzrAXExxicm9vbmllQGtlcm5lbC5vcmcACgkQJNaLcl1Uh9DK 6Af/eRh/gD5Bp6DheOkrCNNj/jx0QlkAlgtkFzZBVp4AetirO3UZ3hwUyFCGyLWw n2Ohmt54s3BHsvqy+YTrVD57AueI+chAOvKWJ6sYHxiPByy8KuVH+KmffhDHXjyd gpIHPAMYnlYknTwitagbyWPA1vuAd4JWCqmJ7Nd/Fxl+Q9fY3PhsXSBXdcejWTtm Su8XIhCtykTCTGijg4I/ZNeOLk1xPEWMiX+P/0knOpgE+9ATWq33UIWInoXe02bs xITHse40BQUKCfoJKZjJGX3uSnluKpOvojIbcJhcHFYjJpeoU+4kj1Gd4UHMQ8vB n8OpZYDKU3KdEHjIZBqbk0wFDw== =cYjC -----END PGP SIGNATURE----- Merge tag 'regmap-fix-v4.8-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap Pull regmap fixes from Mark Brown: "Several fixes here, the main one being the change from Lars-Peter which I'd been letting soak in -next since the merge window in case it uncovered further issues as it's a minimal fix rather than a change addressing the root cause of the problems (which would've been too invasive for -rc): - The biggest change is a fix from Lars-Peter to ensure that we don't create overlapping rbtree nodes which in turn avoids returning corrupt cache values to users, fixing some issues that were exposed by some recent optimisations with certain access patterns but had been present for a long time. - A fix from Elaine Zhang to stop us updating the cache if we get an I/O error when writing to the hardware. - A fix fromm Maarten ter Huurne to avoid uninitialized defaults in cases where we have non-readable registers but are initializing the cache by reading from the device" * tag 'regmap-fix-v4.8-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap: regmap: drop cache if the bus transfer error regmap: rbtree: Avoid overlapping nodes regmap: cache: Fix num_reg_defaults computation from reg_defaults_raw
This commit is contained in:
commit
ec9a03d47e
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,10 +38,11 @@ static int regcache_hw_init(struct regmap *map)
|
|||
|
||||
/* calculate the size of reg_defaults */
|
||||
for (count = 0, i = 0; i < map->num_reg_defaults_raw; i++)
|
||||
if (!regmap_volatile(map, i * map->reg_stride))
|
||||
if (regmap_readable(map, i * map->reg_stride) &&
|
||||
!regmap_volatile(map, i * map->reg_stride))
|
||||
count++;
|
||||
|
||||
/* all registers are volatile, so just bypass */
|
||||
/* all registers are unreadable or volatile, so just bypass */
|
||||
if (!count) {
|
||||
map->cache_bypass = true;
|
||||
return 0;
|
||||
|
|
|
@ -1474,6 +1474,8 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
|
|||
ret = map->bus->write(map->bus_context, buf, len);
|
||||
|
||||
kfree(buf);
|
||||
} else if (ret != 0 && !map->cache_bypass && map->format.parse_val) {
|
||||
regcache_drop_region(map, reg, reg + 1);
|
||||
}
|
||||
|
||||
trace_regmap_hw_write_done(map, reg, val_len / map->format.val_bytes);
|
||||
|
|
Loading…
Reference in New Issue