Skip to content

Commit ba1401f

Browse files
committed
Merge tag 'regmap-v6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap
Pull regmap updates from Mark Brown: "Another small update for regmap, we have one new feature plus a little bit of cleanup: - Support for sparseness information in the flat cache, allowing users that really need the performance properties it provides to benefit from the interface and startup time improvements that sparsness provides without needing to go all the way to a more fancy data structure - Cleanup work from Andy Shevchenko, refactoring the cache interface in preparation for some future stuff he's working on" * tag 'regmap-v6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap: regmap: sdw-mbq: Reorder regmap_mbq_context struct for better packing regmap: i3c: Use ARRAY_SIZE() regcache: maple: Split ->populate() from ->init() regcache: flat: Split ->populate() from ->init() regcache: flat: Remove unneeded check and error message for -ENOMEM regcache: rbtree: Split ->populate() from ->init() regcache: Add ->populate() callback to separate from ->init() regmap: warn users about uninitialized flat cache regmap: add flat cache with sparse validity
2 parents edd2b98 + 6985def commit ba1401f

9 files changed

Lines changed: 186 additions & 65 deletions

File tree

drivers/base/regmap/internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ struct regcache_ops {
186186
enum regcache_type type;
187187
int (*init)(struct regmap *map);
188188
int (*exit)(struct regmap *map);
189+
int (*populate)(struct regmap *map);
189190
#ifdef CONFIG_DEBUG_FS
190191
void (*debugfs_init)(struct regmap *map);
191192
#endif
@@ -288,6 +289,7 @@ enum regmap_endian regmap_get_val_endian(struct device *dev,
288289
const struct regmap_bus *bus,
289290
const struct regmap_config *config);
290291

292+
extern struct regcache_ops regcache_flat_sparse_ops;
291293
extern struct regcache_ops regcache_rbtree_ops;
292294
extern struct regcache_ops regcache_maple_ops;
293295
extern struct regcache_ops regcache_flat_ops;

drivers/base/regmap/regcache-flat.c

Lines changed: 91 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66
//
77
// Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
88

9+
#include <linux/bitmap.h>
10+
#include <linux/bitops.h>
911
#include <linux/device.h>
12+
#include <linux/limits.h>
13+
#include <linux/overflow.h>
1014
#include <linux/seq_file.h>
1115
#include <linux/slab.h>
1216

@@ -18,57 +22,116 @@ static inline unsigned int regcache_flat_get_index(const struct regmap *map,
1822
return regcache_get_index_by_order(map, reg);
1923
}
2024

25+
struct regcache_flat_data {
26+
unsigned long *valid;
27+
unsigned int data[];
28+
};
29+
2130
static int regcache_flat_init(struct regmap *map)
2231
{
23-
int i;
24-
unsigned int *cache;
32+
unsigned int cache_size;
33+
struct regcache_flat_data *cache;
2534

2635
if (!map || map->reg_stride_order < 0 || !map->max_register_is_set)
2736
return -EINVAL;
2837

29-
map->cache = kcalloc(regcache_flat_get_index(map, map->max_register)
30-
+ 1, sizeof(unsigned int), map->alloc_flags);
31-
if (!map->cache)
38+
cache_size = regcache_flat_get_index(map, map->max_register) + 1;
39+
cache = kzalloc(struct_size(cache, data, cache_size), map->alloc_flags);
40+
if (!cache)
3241
return -ENOMEM;
3342

34-
cache = map->cache;
43+
cache->valid = bitmap_zalloc(cache_size, map->alloc_flags);
44+
if (!cache->valid)
45+
goto err_free;
46+
47+
map->cache = cache;
48+
49+
return 0;
50+
51+
err_free:
52+
kfree(cache);
53+
return -ENOMEM;
54+
}
55+
56+
static int regcache_flat_exit(struct regmap *map)
57+
{
58+
struct regcache_flat_data *cache = map->cache;
59+
60+
if (cache)
61+
bitmap_free(cache->valid);
62+
63+
kfree(cache);
64+
map->cache = NULL;
65+
66+
return 0;
67+
}
68+
69+
static int regcache_flat_populate(struct regmap *map)
70+
{
71+
struct regcache_flat_data *cache = map->cache;
72+
unsigned int i;
3573

3674
for (i = 0; i < map->num_reg_defaults; i++) {
3775
unsigned int reg = map->reg_defaults[i].reg;
3876
unsigned int index = regcache_flat_get_index(map, reg);
3977

40-
cache[index] = map->reg_defaults[i].def;
78+
cache->data[index] = map->reg_defaults[i].def;
79+
__set_bit(index, cache->valid);
4180
}
4281

4382
return 0;
4483
}
4584

46-
static int regcache_flat_exit(struct regmap *map)
85+
static int regcache_flat_read(struct regmap *map,
86+
unsigned int reg, unsigned int *value)
4787
{
48-
kfree(map->cache);
49-
map->cache = NULL;
88+
struct regcache_flat_data *cache = map->cache;
89+
unsigned int index = regcache_flat_get_index(map, reg);
90+
91+
/* legacy behavior: ignore validity, but warn the user */
92+
if (unlikely(!test_bit(index, cache->valid)))
93+
dev_warn_once(map->dev,
94+
"using zero-initialized flat cache, this may cause unexpected behavior");
95+
96+
*value = cache->data[index];
5097

5198
return 0;
5299
}
53100

54-
static int regcache_flat_read(struct regmap *map,
55-
unsigned int reg, unsigned int *value)
101+
static int regcache_flat_sparse_read(struct regmap *map,
102+
unsigned int reg, unsigned int *value)
56103
{
57-
unsigned int *cache = map->cache;
104+
struct regcache_flat_data *cache = map->cache;
58105
unsigned int index = regcache_flat_get_index(map, reg);
59106

60-
*value = cache[index];
107+
if (unlikely(!test_bit(index, cache->valid)))
108+
return -ENOENT;
109+
110+
*value = cache->data[index];
61111

62112
return 0;
63113
}
64114

65115
static int regcache_flat_write(struct regmap *map, unsigned int reg,
66116
unsigned int value)
67117
{
68-
unsigned int *cache = map->cache;
118+
struct regcache_flat_data *cache = map->cache;
69119
unsigned int index = regcache_flat_get_index(map, reg);
70120

71-
cache[index] = value;
121+
cache->data[index] = value;
122+
__set_bit(index, cache->valid);
123+
124+
return 0;
125+
}
126+
127+
static int regcache_flat_drop(struct regmap *map, unsigned int min,
128+
unsigned int max)
129+
{
130+
struct regcache_flat_data *cache = map->cache;
131+
unsigned int bitmap_min = regcache_flat_get_index(map, min);
132+
unsigned int bitmap_max = regcache_flat_get_index(map, max);
133+
134+
bitmap_clear(cache->valid, bitmap_min, bitmap_max + 1 - bitmap_min);
72135

73136
return 0;
74137
}
@@ -78,6 +141,18 @@ struct regcache_ops regcache_flat_ops = {
78141
.name = "flat",
79142
.init = regcache_flat_init,
80143
.exit = regcache_flat_exit,
144+
.populate = regcache_flat_populate,
81145
.read = regcache_flat_read,
82146
.write = regcache_flat_write,
83147
};
148+
149+
struct regcache_ops regcache_flat_sparse_ops = {
150+
.type = REGCACHE_FLAT_S,
151+
.name = "flat-sparse",
152+
.init = regcache_flat_init,
153+
.exit = regcache_flat_exit,
154+
.populate = regcache_flat_populate,
155+
.read = regcache_flat_sparse_read,
156+
.write = regcache_flat_write,
157+
.drop = regcache_flat_drop,
158+
};

drivers/base/regmap/regcache-maple.c

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,23 @@ static int regcache_maple_sync(struct regmap *map, unsigned int min,
289289
return ret;
290290
}
291291

292+
static int regcache_maple_init(struct regmap *map)
293+
{
294+
struct maple_tree *mt;
295+
296+
mt = kmalloc(sizeof(*mt), map->alloc_flags);
297+
if (!mt)
298+
return -ENOMEM;
299+
map->cache = mt;
300+
301+
mt_init(mt);
302+
303+
if (!mt_external_lock(mt) && map->lock_key)
304+
lockdep_set_class_and_subclass(&mt->ma_lock, map->lock_key, 1);
305+
306+
return 0;
307+
}
308+
292309
static int regcache_maple_exit(struct regmap *map)
293310
{
294311
struct maple_tree *mt = map->cache;
@@ -340,26 +357,12 @@ static int regcache_maple_insert_block(struct regmap *map, int first,
340357
return ret;
341358
}
342359

343-
static int regcache_maple_init(struct regmap *map)
360+
static int regcache_maple_populate(struct regmap *map)
344361
{
345-
struct maple_tree *mt;
346362
int i;
347363
int ret;
348364
int range_start;
349365

350-
mt = kmalloc(sizeof(*mt), map->alloc_flags);
351-
if (!mt)
352-
return -ENOMEM;
353-
map->cache = mt;
354-
355-
mt_init(mt);
356-
357-
if (!mt_external_lock(mt) && map->lock_key)
358-
lockdep_set_class_and_subclass(&mt->ma_lock, map->lock_key, 1);
359-
360-
if (!map->num_reg_defaults)
361-
return 0;
362-
363366
range_start = 0;
364367

365368
/* Scan for ranges of contiguous registers */
@@ -369,30 +372,22 @@ static int regcache_maple_init(struct regmap *map)
369372
ret = regcache_maple_insert_block(map, range_start,
370373
i - 1);
371374
if (ret != 0)
372-
goto err;
375+
return ret;
373376

374377
range_start = i;
375378
}
376379
}
377380

378381
/* Add the last block */
379-
ret = regcache_maple_insert_block(map, range_start,
380-
map->num_reg_defaults - 1);
381-
if (ret != 0)
382-
goto err;
383-
384-
return 0;
385-
386-
err:
387-
regcache_maple_exit(map);
388-
return ret;
382+
return regcache_maple_insert_block(map, range_start, map->num_reg_defaults - 1);
389383
}
390384

391385
struct regcache_ops regcache_maple_ops = {
392386
.type = REGCACHE_MAPLE,
393387
.name = "maple",
394388
.init = regcache_maple_init,
395389
.exit = regcache_maple_exit,
390+
.populate = regcache_maple_populate,
396391
.read = regcache_maple_read,
397392
.write = regcache_maple_write,
398393
.drop = regcache_maple_drop,

drivers/base/regmap/regcache-rbtree.c

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,6 @@ static void rbtree_debugfs_init(struct regmap *map)
184184
static int regcache_rbtree_init(struct regmap *map)
185185
{
186186
struct regcache_rbtree_ctx *rbtree_ctx;
187-
int i;
188-
int ret;
189187

190188
map->cache = kmalloc(sizeof *rbtree_ctx, map->alloc_flags);
191189
if (!map->cache)
@@ -195,19 +193,7 @@ static int regcache_rbtree_init(struct regmap *map)
195193
rbtree_ctx->root = RB_ROOT;
196194
rbtree_ctx->cached_rbnode = NULL;
197195

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-
206196
return 0;
207-
208-
err:
209-
regcache_rbtree_exit(map);
210-
return ret;
211197
}
212198

213199
static int regcache_rbtree_exit(struct regmap *map)
@@ -239,6 +225,22 @@ static int regcache_rbtree_exit(struct regmap *map)
239225
return 0;
240226
}
241227

228+
static int regcache_rbtree_populate(struct regmap *map)
229+
{
230+
unsigned int i;
231+
int ret;
232+
233+
for (i = 0; i < map->num_reg_defaults; i++) {
234+
ret = regcache_rbtree_write(map,
235+
map->reg_defaults[i].reg,
236+
map->reg_defaults[i].def);
237+
if (ret)
238+
return ret;
239+
}
240+
241+
return 0;
242+
}
243+
242244
static int regcache_rbtree_read(struct regmap *map,
243245
unsigned int reg, unsigned int *value)
244246
{
@@ -546,6 +548,7 @@ struct regcache_ops regcache_rbtree_ops = {
546548
.name = "rbtree",
547549
.init = regcache_rbtree_init,
548550
.exit = regcache_rbtree_exit,
551+
.populate = regcache_rbtree_populate,
549552
#ifdef CONFIG_DEBUG_FS
550553
.debugfs_init = rbtree_debugfs_init,
551554
#endif

drivers/base/regmap/regcache.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "internal.h"
1717

1818
static const struct regcache_ops *cache_types[] = {
19+
&regcache_flat_sparse_ops,
1920
&regcache_rbtree_ops,
2021
&regcache_maple_ops,
2122
&regcache_flat_ops,
@@ -221,8 +222,24 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
221222
if (ret)
222223
goto err_free;
223224
}
225+
226+
if (map->num_reg_defaults && map->cache_ops->populate) {
227+
dev_dbg(map->dev, "Populating %s cache\n", map->cache_ops->name);
228+
map->lock(map->lock_arg);
229+
ret = map->cache_ops->populate(map);
230+
map->unlock(map->lock_arg);
231+
if (ret)
232+
goto err_exit;
233+
}
224234
return 0;
225235

236+
err_exit:
237+
if (map->cache_ops->exit) {
238+
dev_dbg(map->dev, "Destroying %s cache\n", map->cache_ops->name);
239+
map->lock(map->lock_arg);
240+
ret = map->cache_ops->exit(map);
241+
map->unlock(map->lock_arg);
242+
}
226243
err_free:
227244
kfree(map->reg_defaults);
228245
if (map->cache_free)

drivers/base/regmap/regmap-i3c.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// SPDX-License-Identifier: GPL-2.0
22
// Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
33

4+
#include <linux/array_size.h>
45
#include <linux/regmap.h>
56
#include <linux/i3c/device.h>
67
#include <linux/i3c/master.h>
@@ -18,7 +19,7 @@ static int regmap_i3c_write(void *context, const void *data, size_t count)
1819
},
1920
};
2021

21-
return i3c_device_do_priv_xfers(i3c, xfers, 1);
22+
return i3c_device_do_priv_xfers(i3c, xfers, ARRAY_SIZE(xfers));
2223
}
2324

2425
static int regmap_i3c_read(void *context,
@@ -37,7 +38,7 @@ static int regmap_i3c_read(void *context,
3738
xfers[1].len = val_size;
3839
xfers[1].data.in = val;
3940

40-
return i3c_device_do_priv_xfers(i3c, xfers, 2);
41+
return i3c_device_do_priv_xfers(i3c, xfers, ARRAY_SIZE(xfers));
4142
}
4243

4344
static const struct regmap_bus regmap_i3c = {

0 commit comments

Comments
 (0)