aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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. */