Merge branches 'acpi-bus' and 'acpi-video'
[linux-block.git] / drivers / base / regmap / regcache-rbtree.c
CommitLineData
37613fa5
GKH
1// SPDX-License-Identifier: GPL-2.0
2//
3// Register cache access API - rbtree caching support
4//
5// Copyright 2011 Wolfson Microelectronics plc
6//
7// Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
28644c80 8
bad2ab4b 9#include <linux/debugfs.h>
e39be3a3 10#include <linux/device.h>
28644c80 11#include <linux/rbtree.h>
bad2ab4b 12#include <linux/seq_file.h>
e39be3a3 13#include <linux/slab.h>
28644c80
DP
14
15#include "internal.h"
16
17static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
18 unsigned int value);
462a185c 19static int regcache_rbtree_exit(struct regmap *map);
28644c80
DP
20
21struct regcache_rbtree_node {
28644c80
DP
22 /* block of adjacent registers */
23 void *block;
3f4ff561
LPC
24 /* Which registers are present */
25 long *cache_present;
70d383b7
JCP
26 /* base register handled by this block */
27 unsigned int base_reg;
28644c80
DP
28 /* number of registers available in the block */
29 unsigned int blklen;
70d383b7
JCP
30 /* the actual rbtree node holding this block */
31 struct rb_node node;
435bba0f 32};
28644c80
DP
33
34struct regcache_rbtree_ctx {
35 struct rb_root root;
36 struct regcache_rbtree_node *cached_rbnode;
37};
38
39static inline void regcache_rbtree_get_base_top_reg(
f01ee60f 40 struct regmap *map,
28644c80
DP
41 struct regcache_rbtree_node *rbnode,
42 unsigned int *base, unsigned int *top)
43{
44 *base = rbnode->base_reg;
f01ee60f 45 *top = rbnode->base_reg + ((rbnode->blklen - 1) * map->reg_stride);
28644c80
DP
46}
47
879082c9
MB
48static unsigned int regcache_rbtree_get_register(struct regmap *map,
49 struct regcache_rbtree_node *rbnode, unsigned int idx)
28644c80 50{
879082c9 51 return regcache_get_val(map, rbnode->block, idx);
28644c80
DP
52}
53
879082c9
MB
54static void regcache_rbtree_set_register(struct regmap *map,
55 struct regcache_rbtree_node *rbnode,
56 unsigned int idx, unsigned int val)
28644c80 57{
3f4ff561 58 set_bit(idx, rbnode->cache_present);
879082c9 59 regcache_set_val(map, rbnode->block, idx, val);
28644c80
DP
60}
61
3405addd 62static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map,
879082c9 63 unsigned int reg)
28644c80 64{
3405addd 65 struct regcache_rbtree_ctx *rbtree_ctx = map->cache;
28644c80
DP
66 struct rb_node *node;
67 struct regcache_rbtree_node *rbnode;
68 unsigned int base_reg, top_reg;
69
3405addd
LPC
70 rbnode = rbtree_ctx->cached_rbnode;
71 if (rbnode) {
f01ee60f
SW
72 regcache_rbtree_get_base_top_reg(map, rbnode, &base_reg,
73 &top_reg);
3405addd
LPC
74 if (reg >= base_reg && reg <= top_reg)
75 return rbnode;
76 }
77
78 node = rbtree_ctx->root.rb_node;
28644c80 79 while (node) {
671a911b 80 rbnode = rb_entry(node, struct regcache_rbtree_node, node);
f01ee60f
SW
81 regcache_rbtree_get_base_top_reg(map, rbnode, &base_reg,
82 &top_reg);
3405addd
LPC
83 if (reg >= base_reg && reg <= top_reg) {
84 rbtree_ctx->cached_rbnode = rbnode;
28644c80 85 return rbnode;
3405addd 86 } else if (reg > top_reg) {
28644c80 87 node = node->rb_right;
3405addd 88 } else if (reg < base_reg) {
28644c80 89 node = node->rb_left;
3405addd 90 }
28644c80
DP
91 }
92
93 return NULL;
94}
95
f01ee60f 96static int regcache_rbtree_insert(struct regmap *map, struct rb_root *root,
28644c80
DP
97 struct regcache_rbtree_node *rbnode)
98{
99 struct rb_node **new, *parent;
100 struct regcache_rbtree_node *rbnode_tmp;
101 unsigned int base_reg_tmp, top_reg_tmp;
102 unsigned int base_reg;
103
104 parent = NULL;
105 new = &root->rb_node;
106 while (*new) {
671a911b 107 rbnode_tmp = rb_entry(*new, struct regcache_rbtree_node, node);
28644c80 108 /* base and top registers of the current rbnode */
f01ee60f 109 regcache_rbtree_get_base_top_reg(map, rbnode_tmp, &base_reg_tmp,
28644c80
DP
110 &top_reg_tmp);
111 /* base register of the rbnode to be added */
112 base_reg = rbnode->base_reg;
113 parent = *new;
114 /* if this register has already been inserted, just return */
115 if (base_reg >= base_reg_tmp &&
116 base_reg <= top_reg_tmp)
117 return 0;
118 else if (base_reg > top_reg_tmp)
119 new = &((*new)->rb_right);
120 else if (base_reg < base_reg_tmp)
121 new = &((*new)->rb_left);
122 }
123
124 /* insert the node into the rbtree */
125 rb_link_node(&rbnode->node, parent, new);
126 rb_insert_color(&rbnode->node, root);
127
128 return 1;
129}
130
bad2ab4b
MB
131#ifdef CONFIG_DEBUG_FS
132static int rbtree_show(struct seq_file *s, void *ignored)
133{
134 struct regmap *map = s->private;
135 struct regcache_rbtree_ctx *rbtree_ctx = map->cache;
136 struct regcache_rbtree_node *n;
137 struct rb_node *node;
138 unsigned int base, top;
a42277c7 139 size_t mem_size;
bad2ab4b
MB
140 int nodes = 0;
141 int registers = 0;
f01ee60f 142 int this_registers, average;
bad2ab4b 143
f20c783c 144 map->lock(map->lock_arg);
bad2ab4b 145
a42277c7
DP
146 mem_size = sizeof(*rbtree_ctx);
147
bad2ab4b
MB
148 for (node = rb_first(&rbtree_ctx->root); node != NULL;
149 node = rb_next(node)) {
671a911b 150 n = rb_entry(node, struct regcache_rbtree_node, node);
a42277c7
DP
151 mem_size += sizeof(*n);
152 mem_size += (n->blklen * map->cache_word_size);
3f4ff561 153 mem_size += BITS_TO_LONGS(n->blklen) * sizeof(long);
bad2ab4b 154
f01ee60f
SW
155 regcache_rbtree_get_base_top_reg(map, n, &base, &top);
156 this_registers = ((top - base) / map->reg_stride) + 1;
157 seq_printf(s, "%x-%x (%d)\n", base, top, this_registers);
bad2ab4b
MB
158
159 nodes++;
f01ee60f 160 registers += this_registers;
bad2ab4b
MB
161 }
162
c04c1b9e
SW
163 if (nodes)
164 average = registers / nodes;
165 else
166 average = 0;
167
a42277c7
DP
168 seq_printf(s, "%d nodes, %d registers, average %d registers, used %zu bytes\n",
169 nodes, registers, average, mem_size);
bad2ab4b 170
f20c783c 171 map->unlock(map->lock_arg);
bad2ab4b
MB
172
173 return 0;
174}
175
32fa7b85 176DEFINE_SHOW_ATTRIBUTE(rbtree);
cce585ce
MB
177
178static void rbtree_debugfs_init(struct regmap *map)
179{
180 debugfs_create_file("rbtree", 0400, map->debugfs, map, &rbtree_fops);
181}
bad2ab4b
MB
182#endif
183
28644c80
DP
184static int regcache_rbtree_init(struct regmap *map)
185{
186 struct regcache_rbtree_ctx *rbtree_ctx;
187 int i;
188 int ret;
189
190 map->cache = kmalloc(sizeof *rbtree_ctx, GFP_KERNEL);
191 if (!map->cache)
192 return -ENOMEM;
193
194 rbtree_ctx = map->cache;
195 rbtree_ctx->root = RB_ROOT;
196 rbtree_ctx->cached_rbnode = NULL;
197
198 for (i = 0; i < map->num_reg_defaults; i++) {
199 ret = regcache_rbtree_write(map,
200 map->reg_defaults[i].reg,
201 map->reg_defaults[i].def);
202 if (ret)
203 goto err;
204 }
205
206 return 0;
207
208err:
462a185c 209 regcache_rbtree_exit(map);
28644c80
DP
210 return ret;
211}
212
213static int regcache_rbtree_exit(struct regmap *map)
214{
215 struct rb_node *next;
216 struct regcache_rbtree_ctx *rbtree_ctx;
217 struct regcache_rbtree_node *rbtree_node;
218
219 /* if we've already been called then just return */
220 rbtree_ctx = map->cache;
221 if (!rbtree_ctx)
222 return 0;
223
224 /* free up the rbtree */
225 next = rb_first(&rbtree_ctx->root);
226 while (next) {
227 rbtree_node = rb_entry(next, struct regcache_rbtree_node, node);
228 next = rb_next(&rbtree_node->node);
229 rb_erase(&rbtree_node->node, &rbtree_ctx->root);
3f4ff561 230 kfree(rbtree_node->cache_present);
28644c80
DP
231 kfree(rbtree_node->block);
232 kfree(rbtree_node);
233 }
234
235 /* release the resources */
236 kfree(map->cache);
237 map->cache = NULL;
238
239 return 0;
240}
241
242static int regcache_rbtree_read(struct regmap *map,
243 unsigned int reg, unsigned int *value)
244{
28644c80 245 struct regcache_rbtree_node *rbnode;
28644c80
DP
246 unsigned int reg_tmp;
247
3405addd 248 rbnode = regcache_rbtree_lookup(map, reg);
28644c80 249 if (rbnode) {
f01ee60f 250 reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
3f4ff561 251 if (!test_bit(reg_tmp, rbnode->cache_present))
0c7ed856 252 return -ENOENT;
879082c9 253 *value = regcache_rbtree_get_register(map, rbnode, reg_tmp);
28644c80 254 } else {
6e6ace00 255 return -ENOENT;
28644c80
DP
256 }
257
258 return 0;
259}
260
261
879082c9
MB
262static int regcache_rbtree_insert_to_block(struct regmap *map,
263 struct regcache_rbtree_node *rbnode,
472fdec7
LPC
264 unsigned int base_reg,
265 unsigned int top_reg,
266 unsigned int reg,
879082c9 267 unsigned int value)
28644c80 268{
472fdec7
LPC
269 unsigned int blklen;
270 unsigned int pos, offset;
3f4ff561 271 unsigned long *present;
28644c80
DP
272 u8 *blk;
273
472fdec7
LPC
274 blklen = (top_reg - base_reg) / map->reg_stride + 1;
275 pos = (reg - base_reg) / map->reg_stride;
276 offset = (rbnode->base_reg - base_reg) / map->reg_stride;
277
28644c80 278 blk = krealloc(rbnode->block,
472fdec7 279 blklen * map->cache_word_size,
879082c9 280 GFP_KERNEL);
28644c80
DP
281 if (!blk)
282 return -ENOMEM;
283
55e6d803
YY
284 rbnode->block = blk;
285
8ef9724b
GR
286 if (BITS_TO_LONGS(blklen) > BITS_TO_LONGS(rbnode->blklen)) {
287 present = krealloc(rbnode->cache_present,
288 BITS_TO_LONGS(blklen) * sizeof(*present),
289 GFP_KERNEL);
55e6d803 290 if (!present)
8ef9724b 291 return -ENOMEM;
8ef9724b
GR
292
293 memset(present + BITS_TO_LONGS(rbnode->blklen), 0,
294 (BITS_TO_LONGS(blklen) - BITS_TO_LONGS(rbnode->blklen))
295 * sizeof(*present));
296 } else {
297 present = rbnode->cache_present;
3f4ff561
LPC
298 }
299
28644c80 300 /* insert the register value in the correct place in the rbnode block */
3f4ff561 301 if (pos == 0) {
472fdec7
LPC
302 memmove(blk + offset * map->cache_word_size,
303 blk, rbnode->blklen * map->cache_word_size);
328f494d 304 bitmap_shift_left(present, present, offset, blklen);
3f4ff561 305 }
28644c80
DP
306
307 /* update the rbnode block, its size and the base register */
472fdec7
LPC
308 rbnode->blklen = blklen;
309 rbnode->base_reg = base_reg;
3f4ff561 310 rbnode->cache_present = present;
28644c80 311
879082c9 312 regcache_rbtree_set_register(map, rbnode, pos, value);
28644c80
DP
313 return 0;
314}
315
0186645d
MB
316static struct regcache_rbtree_node *
317regcache_rbtree_node_alloc(struct regmap *map, unsigned int reg)
318{
319 struct regcache_rbtree_node *rbnode;
7278af5f
MB
320 const struct regmap_range *range;
321 int i;
0186645d
MB
322
323 rbnode = kzalloc(sizeof(*rbnode), GFP_KERNEL);
324 if (!rbnode)
325 return NULL;
326
7278af5f
MB
327 /* If there is a read table then use it to guess at an allocation */
328 if (map->rd_table) {
329 for (i = 0; i < map->rd_table->n_yes_ranges; i++) {
330 if (regmap_reg_in_range(reg,
331 &map->rd_table->yes_ranges[i]))
332 break;
333 }
334
335 if (i != map->rd_table->n_yes_ranges) {
336 range = &map->rd_table->yes_ranges[i];
b6752123
LPC
337 rbnode->blklen = (range->range_max - range->range_min) /
338 map->reg_stride + 1;
7278af5f
MB
339 rbnode->base_reg = range->range_min;
340 }
341 }
342
343 if (!rbnode->blklen) {
4e67fb5f 344 rbnode->blklen = 1;
7278af5f
MB
345 rbnode->base_reg = reg;
346 }
347
549e08a0 348 rbnode->block = kmalloc_array(rbnode->blklen, map->cache_word_size,
349 GFP_KERNEL);
3f4ff561
LPC
350 if (!rbnode->block)
351 goto err_free;
352
eeda1bd6 353 rbnode->cache_present = kcalloc(BITS_TO_LONGS(rbnode->blklen),
354 sizeof(*rbnode->cache_present),
355 GFP_KERNEL);
3f4ff561
LPC
356 if (!rbnode->cache_present)
357 goto err_free_block;
0186645d
MB
358
359 return rbnode;
3f4ff561
LPC
360
361err_free_block:
362 kfree(rbnode->block);
363err_free:
364 kfree(rbnode);
365 return NULL;
0186645d
MB
366}
367
28644c80
DP
368static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
369 unsigned int value)
370{
371 struct regcache_rbtree_ctx *rbtree_ctx;
372 struct regcache_rbtree_node *rbnode, *rbnode_tmp;
373 struct rb_node *node;
28644c80 374 unsigned int reg_tmp;
28644c80
DP
375 int ret;
376
377 rbtree_ctx = map->cache;
0c7ed856 378
28644c80
DP
379 /* if we can't locate it in the cached rbnode we'll have
380 * to traverse the rbtree looking for it.
381 */
3405addd 382 rbnode = regcache_rbtree_lookup(map, reg);
28644c80 383 if (rbnode) {
f01ee60f 384 reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
879082c9 385 regcache_rbtree_set_register(map, rbnode, reg_tmp, value);
28644c80 386 } else {
472fdec7
LPC
387 unsigned int base_reg, top_reg;
388 unsigned int new_base_reg, new_top_reg;
389 unsigned int min, max;
390 unsigned int max_dist;
1bc8da4e 391 unsigned int dist, best_dist = UINT_MAX;
472fdec7
LPC
392
393 max_dist = map->reg_stride * sizeof(*rbnode_tmp) /
394 map->cache_word_size;
395 if (reg < max_dist)
396 min = 0;
397 else
398 min = reg - max_dist;
399 max = reg + max_dist;
400
28644c80 401 /* look for an adjacent register to the one we are about to add */
6399aea6
NO
402 node = rbtree_ctx->root.rb_node;
403 while (node) {
f01ee60f
SW
404 rbnode_tmp = rb_entry(node, struct regcache_rbtree_node,
405 node);
194c753a
LPC
406
407 regcache_rbtree_get_base_top_reg(map, rbnode_tmp,
408 &base_reg, &top_reg);
409
472fdec7 410 if (base_reg <= max && top_reg >= min) {
1bc8da4e
LPC
411 if (reg < base_reg)
412 dist = base_reg - reg;
413 else if (reg > top_reg)
414 dist = reg - top_reg;
6399aea6 415 else
1bc8da4e
LPC
416 dist = 0;
417 if (dist < best_dist) {
418 rbnode = rbnode_tmp;
419 best_dist = dist;
420 new_base_reg = min(reg, base_reg);
421 new_top_reg = max(reg, top_reg);
422 }
28644c80 423 }
194c753a 424
1bc8da4e
LPC
425 /*
426 * Keep looking, we want to choose the closest block,
427 * otherwise we might end up creating overlapping
428 * blocks, which breaks the rbtree.
429 */
430 if (reg < base_reg)
431 node = node->rb_left;
432 else if (reg > top_reg)
433 node = node->rb_right;
434 else
435 break;
436 }
437
438 if (rbnode) {
439 ret = regcache_rbtree_insert_to_block(map, rbnode,
472fdec7
LPC
440 new_base_reg,
441 new_top_reg, reg,
442 value);
194c753a
LPC
443 if (ret)
444 return ret;
1bc8da4e 445 rbtree_ctx->cached_rbnode = rbnode;
194c753a 446 return 0;
28644c80 447 }
0186645d
MB
448
449 /* We did not manage to find a place to insert it in
450 * an existing block so create a new rbnode.
28644c80 451 */
0186645d 452 rbnode = regcache_rbtree_node_alloc(map, reg);
28644c80
DP
453 if (!rbnode)
454 return -ENOMEM;
0186645d
MB
455 regcache_rbtree_set_register(map, rbnode,
456 reg - rbnode->base_reg, value);
f01ee60f 457 regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode);
28644c80
DP
458 rbtree_ctx->cached_rbnode = rbnode;
459 }
460
461 return 0;
462}
463
ac8d91c8
MB
464static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
465 unsigned int max)
28644c80
DP
466{
467 struct regcache_rbtree_ctx *rbtree_ctx;
468 struct rb_node *node;
469 struct regcache_rbtree_node *rbnode;
b6752123
LPC
470 unsigned int base_reg, top_reg;
471 unsigned int start, end;
28644c80 472 int ret;
28644c80 473
b460a522
MB
474 map->async = true;
475
28644c80
DP
476 rbtree_ctx = map->cache;
477 for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
478 rbnode = rb_entry(node, struct regcache_rbtree_node, node);
ac8d91c8 479
b6752123
LPC
480 regcache_rbtree_get_base_top_reg(map, rbnode, &base_reg,
481 &top_reg);
482 if (base_reg > max)
ac8d91c8 483 break;
b6752123 484 if (top_reg < min)
ac8d91c8
MB
485 continue;
486
b6752123
LPC
487 if (min > base_reg)
488 start = (min - base_reg) / map->reg_stride;
ac8d91c8 489 else
b6752123 490 start = 0;
ac8d91c8 491
b6752123
LPC
492 if (max < top_reg)
493 end = (max - base_reg) / map->reg_stride + 1;
ac8d91c8
MB
494 else
495 end = rbnode->blklen;
496
3f4ff561
LPC
497 ret = regcache_sync_block(map, rbnode->block,
498 rbnode->cache_present,
499 rbnode->base_reg, start, end);
f8bd822c
MB
500 if (ret != 0)
501 return ret;
28644c80
DP
502 }
503
b460a522
MB
504 map->async = false;
505
f8bd822c 506 return regmap_async_complete(map);
28644c80
DP
507}
508
3f4ff561
LPC
509static int regcache_rbtree_drop(struct regmap *map, unsigned int min,
510 unsigned int max)
511{
512 struct regcache_rbtree_ctx *rbtree_ctx;
513 struct regcache_rbtree_node *rbnode;
514 struct rb_node *node;
515 unsigned int base_reg, top_reg;
516 unsigned int start, end;
517
518 rbtree_ctx = map->cache;
519 for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
520 rbnode = rb_entry(node, struct regcache_rbtree_node, node);
521
522 regcache_rbtree_get_base_top_reg(map, rbnode, &base_reg,
523 &top_reg);
524 if (base_reg > max)
525 break;
526 if (top_reg < min)
527 continue;
528
529 if (min > base_reg)
530 start = (min - base_reg) / map->reg_stride;
531 else
532 start = 0;
533
534 if (max < top_reg)
535 end = (max - base_reg) / map->reg_stride + 1;
536 else
537 end = rbnode->blklen;
538
539 bitmap_clear(rbnode->cache_present, start, end - start);
540 }
541
542 return 0;
543}
544
28644c80
DP
545struct regcache_ops regcache_rbtree_ops = {
546 .type = REGCACHE_RBTREE,
547 .name = "rbtree",
548 .init = regcache_rbtree_init,
549 .exit = regcache_rbtree_exit,
5e0cbe78
LPC
550#ifdef CONFIG_DEBUG_FS
551 .debugfs_init = rbtree_debugfs_init,
552#endif
28644c80
DP
553 .read = regcache_rbtree_read,
554 .write = regcache_rbtree_write,
3f4ff561
LPC
555 .sync = regcache_rbtree_sync,
556 .drop = regcache_rbtree_drop,
28644c80 557};