aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/regmap/regcache-rbtree.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/regmap/regcache-rbtree.c')
-rw-r--r--drivers/base/regmap/regcache-rbtree.c100
1 files changed, 46 insertions, 54 deletions
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
index 79f4fca9877a..aa0875f6f1b7 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -47,22 +47,21 @@ static inline void regcache_rbtree_get_base_top_reg(
47 *top = rbnode->base_reg + ((rbnode->blklen - 1) * map->reg_stride); 47 *top = rbnode->base_reg + ((rbnode->blklen - 1) * map->reg_stride);
48} 48}
49 49
50static unsigned int regcache_rbtree_get_register( 50static unsigned int regcache_rbtree_get_register(struct regmap *map,
51 struct regcache_rbtree_node *rbnode, unsigned int idx, 51 struct regcache_rbtree_node *rbnode, unsigned int idx)
52 unsigned int word_size)
53{ 52{
54 return regcache_get_val(rbnode->block, idx, word_size); 53 return regcache_get_val(map, rbnode->block, idx);
55} 54}
56 55
57static void regcache_rbtree_set_register(struct regcache_rbtree_node *rbnode, 56static void regcache_rbtree_set_register(struct regmap *map,
58 unsigned int idx, unsigned int val, 57 struct regcache_rbtree_node *rbnode,
59 unsigned int word_size) 58 unsigned int idx, unsigned int val)
60{ 59{
61 regcache_set_val(rbnode->block, idx, val, word_size); 60 regcache_set_val(map, rbnode->block, idx, val);
62} 61}
63 62
64static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map, 63static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map,
65 unsigned int reg) 64 unsigned int reg)
66{ 65{
67 struct regcache_rbtree_ctx *rbtree_ctx = map->cache; 66 struct regcache_rbtree_ctx *rbtree_ctx = map->cache;
68 struct rb_node *node; 67 struct rb_node *node;
@@ -139,15 +138,21 @@ static int rbtree_show(struct seq_file *s, void *ignored)
139 struct regcache_rbtree_node *n; 138 struct regcache_rbtree_node *n;
140 struct rb_node *node; 139 struct rb_node *node;
141 unsigned int base, top; 140 unsigned int base, top;
141 size_t mem_size;
142 int nodes = 0; 142 int nodes = 0;
143 int registers = 0; 143 int registers = 0;
144 int this_registers, average; 144 int this_registers, average;
145 145
146 map->lock(map); 146 map->lock(map);
147 147
148 mem_size = sizeof(*rbtree_ctx);
149 mem_size += BITS_TO_LONGS(map->cache_present_nbits) * sizeof(long);
150
148 for (node = rb_first(&rbtree_ctx->root); node != NULL; 151 for (node = rb_first(&rbtree_ctx->root); node != NULL;
149 node = rb_next(node)) { 152 node = rb_next(node)) {
150 n = container_of(node, struct regcache_rbtree_node, node); 153 n = container_of(node, struct regcache_rbtree_node, node);
154 mem_size += sizeof(*n);
155 mem_size += (n->blklen * map->cache_word_size);
151 156
152 regcache_rbtree_get_base_top_reg(map, n, &base, &top); 157 regcache_rbtree_get_base_top_reg(map, n, &base, &top);
153 this_registers = ((top - base) / map->reg_stride) + 1; 158 this_registers = ((top - base) / map->reg_stride) + 1;
@@ -162,8 +167,8 @@ static int rbtree_show(struct seq_file *s, void *ignored)
162 else 167 else
163 average = 0; 168 average = 0;
164 169
165 seq_printf(s, "%d nodes, %d registers, average %d registers\n", 170 seq_printf(s, "%d nodes, %d registers, average %d registers, used %zu bytes\n",
166 nodes, registers, average); 171 nodes, registers, average, mem_size);
167 172
168 map->unlock(map); 173 map->unlock(map);
169 174
@@ -260,8 +265,9 @@ static int regcache_rbtree_read(struct regmap *map,
260 rbnode = regcache_rbtree_lookup(map, reg); 265 rbnode = regcache_rbtree_lookup(map, reg);
261 if (rbnode) { 266 if (rbnode) {
262 reg_tmp = (reg - rbnode->base_reg) / map->reg_stride; 267 reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
263 *value = regcache_rbtree_get_register(rbnode, reg_tmp, 268 if (!regcache_reg_present(map, reg))
264 map->cache_word_size); 269 return -ENOENT;
270 *value = regcache_rbtree_get_register(map, rbnode, reg_tmp);
265 } else { 271 } else {
266 return -ENOENT; 272 return -ENOENT;
267 } 273 }
@@ -270,21 +276,23 @@ static int regcache_rbtree_read(struct regmap *map,
270} 276}
271 277
272 278
273static int regcache_rbtree_insert_to_block(struct regcache_rbtree_node *rbnode, 279static int regcache_rbtree_insert_to_block(struct regmap *map,
280 struct regcache_rbtree_node *rbnode,
274 unsigned int pos, unsigned int reg, 281 unsigned int pos, unsigned int reg,
275 unsigned int value, unsigned int word_size) 282 unsigned int value)
276{ 283{
277 u8 *blk; 284 u8 *blk;
278 285
279 blk = krealloc(rbnode->block, 286 blk = krealloc(rbnode->block,
280 (rbnode->blklen + 1) * word_size, GFP_KERNEL); 287 (rbnode->blklen + 1) * map->cache_word_size,
288 GFP_KERNEL);
281 if (!blk) 289 if (!blk)
282 return -ENOMEM; 290 return -ENOMEM;
283 291
284 /* insert the register value in the correct place in the rbnode block */ 292 /* insert the register value in the correct place in the rbnode block */
285 memmove(blk + (pos + 1) * word_size, 293 memmove(blk + (pos + 1) * map->cache_word_size,
286 blk + pos * word_size, 294 blk + pos * map->cache_word_size,
287 (rbnode->blklen - pos) * word_size); 295 (rbnode->blklen - pos) * map->cache_word_size);
288 296
289 /* update the rbnode block, its size and the base register */ 297 /* update the rbnode block, its size and the base register */
290 rbnode->block = blk; 298 rbnode->block = blk;
@@ -292,7 +300,7 @@ static int regcache_rbtree_insert_to_block(struct regcache_rbtree_node *rbnode,
292 if (!pos) 300 if (!pos)
293 rbnode->base_reg = reg; 301 rbnode->base_reg = reg;
294 302
295 regcache_rbtree_set_register(rbnode, pos, value, word_size); 303 regcache_rbtree_set_register(map, rbnode, pos, value);
296 return 0; 304 return 0;
297} 305}
298 306
@@ -302,25 +310,24 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
302 struct regcache_rbtree_ctx *rbtree_ctx; 310 struct regcache_rbtree_ctx *rbtree_ctx;
303 struct regcache_rbtree_node *rbnode, *rbnode_tmp; 311 struct regcache_rbtree_node *rbnode, *rbnode_tmp;
304 struct rb_node *node; 312 struct rb_node *node;
305 unsigned int val;
306 unsigned int reg_tmp; 313 unsigned int reg_tmp;
307 unsigned int pos; 314 unsigned int pos;
308 int i; 315 int i;
309 int ret; 316 int ret;
310 317
311 rbtree_ctx = map->cache; 318 rbtree_ctx = map->cache;
319 /* update the reg_present bitmap, make space if necessary */
320 ret = regcache_set_reg_present(map, reg);
321 if (ret < 0)
322 return ret;
323
312 /* if we can't locate it in the cached rbnode we'll have 324 /* if we can't locate it in the cached rbnode we'll have
313 * to traverse the rbtree looking for it. 325 * to traverse the rbtree looking for it.
314 */ 326 */
315 rbnode = regcache_rbtree_lookup(map, reg); 327 rbnode = regcache_rbtree_lookup(map, reg);
316 if (rbnode) { 328 if (rbnode) {
317 reg_tmp = (reg - rbnode->base_reg) / map->reg_stride; 329 reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
318 val = regcache_rbtree_get_register(rbnode, reg_tmp, 330 regcache_rbtree_set_register(map, rbnode, reg_tmp, value);
319 map->cache_word_size);
320 if (val == value)
321 return 0;
322 regcache_rbtree_set_register(rbnode, reg_tmp, value,
323 map->cache_word_size);
324 } else { 331 } else {
325 /* look for an adjacent register to the one we are about to add */ 332 /* look for an adjacent register to the one we are about to add */
326 for (node = rb_first(&rbtree_ctx->root); node; 333 for (node = rb_first(&rbtree_ctx->root); node;
@@ -337,9 +344,10 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
337 pos = i + 1; 344 pos = i + 1;
338 else 345 else
339 pos = i; 346 pos = i;
340 ret = regcache_rbtree_insert_to_block(rbnode_tmp, pos, 347 ret = regcache_rbtree_insert_to_block(map,
341 reg, value, 348 rbnode_tmp,
342 map->cache_word_size); 349 pos, reg,
350 value);
343 if (ret) 351 if (ret)
344 return ret; 352 return ret;
345 rbtree_ctx->cached_rbnode = rbnode_tmp; 353 rbtree_ctx->cached_rbnode = rbnode_tmp;
@@ -354,7 +362,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
354 rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL); 362 rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
355 if (!rbnode) 363 if (!rbnode)
356 return -ENOMEM; 364 return -ENOMEM;
357 rbnode->blklen = 1; 365 rbnode->blklen = sizeof(*rbnode);
358 rbnode->base_reg = reg; 366 rbnode->base_reg = reg;
359 rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size, 367 rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size,
360 GFP_KERNEL); 368 GFP_KERNEL);
@@ -362,7 +370,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
362 kfree(rbnode); 370 kfree(rbnode);
363 return -ENOMEM; 371 return -ENOMEM;
364 } 372 }
365 regcache_rbtree_set_register(rbnode, 0, value, map->cache_word_size); 373 regcache_rbtree_set_register(map, rbnode, 0, value);
366 regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode); 374 regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode);
367 rbtree_ctx->cached_rbnode = rbnode; 375 rbtree_ctx->cached_rbnode = rbnode;
368 } 376 }
@@ -376,10 +384,8 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
376 struct regcache_rbtree_ctx *rbtree_ctx; 384 struct regcache_rbtree_ctx *rbtree_ctx;
377 struct rb_node *node; 385 struct rb_node *node;
378 struct regcache_rbtree_node *rbnode; 386 struct regcache_rbtree_node *rbnode;
379 unsigned int regtmp;
380 unsigned int val;
381 int ret; 387 int ret;
382 int i, base, end; 388 int base, end;
383 389
384 rbtree_ctx = map->cache; 390 rbtree_ctx = map->cache;
385 for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) { 391 for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
@@ -402,27 +408,13 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
402 else 408 else
403 end = rbnode->blklen; 409 end = rbnode->blklen;
404 410
405 for (i = base; i < end; i++) { 411 ret = regcache_sync_block(map, rbnode->block, rbnode->base_reg,
406 regtmp = rbnode->base_reg + (i * map->reg_stride); 412 base, end);
407 val = regcache_rbtree_get_register(rbnode, i, 413 if (ret != 0)
408 map->cache_word_size); 414 return ret;
409
410 /* Is this the hardware default? If so skip. */
411 ret = regcache_lookup_reg(map, regtmp);
412 if (ret >= 0 && val == map->reg_defaults[ret].def)
413 continue;
414
415 map->cache_bypass = 1;
416 ret = _regmap_write(map, regtmp, val);
417 map->cache_bypass = 0;
418 if (ret)
419 return ret;
420 dev_dbg(map->dev, "Synced register %#x, value %#x\n",
421 regtmp, val);
422 }
423 } 415 }
424 416
425 return 0; 417 return regmap_async_complete(map);
426} 418}
427 419
428struct regcache_ops regcache_rbtree_ops = { 420struct regcache_ops regcache_rbtree_ops = {