Skip to content

Commit 4171a9a

Browse files
committed
Merge tag 'regmap-v6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap
Pull regmap updates from Mark Brown: "Another busy release for regmap with the second half of the maple tree register cache implementation, there's some smaller optimisations that could be done but this should now be able to replace the rbtree cache for most devices. We also had a followup from Aidan MacDonald's refactoring of some of the regmap-irq interfaces, the conversion is complete so the old interfaces are removed. This means that even with the new features for the maple tree cache we'd have a nice negative diffstat were it not for the addition of a bunch more KUnit coverage. There's one GPIO patch in here, it was a dependency for a cleanup of an API in the regmap-irq code for which the gpio-104-dio-48e driver was the only user. Highlights: - The maple tree cache can now load in default values more efficiently, and is capabale of syncing multiple registers in a single write during cache sync - More KUnit coverage, including some coverage for raw I/O and a dummy RAM backed cache to support it - Removal of several old interfaces in regmap-irq now all users have been modernised" * tag 'regmap-v6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap: (23 commits) regmap: Allow reads from write only registers with the flat cache regmap: Drop early readability check regmap: Check for register readability before checking cache during read regmap: Add test to make sure we don't sync to read only registers regmap: Add a test case for write only registers regmap: Add test that writes to write only registers are prevented regmap: Add debugfs file for forcing field writes regmap: Don't check for changes in regcache_set_val() regmap: maple: Implement block sync for the maple tree cache regmap: Provide basic KUnit coverage for the raw register I/O regmap: Provide a ram backed regmap with raw support regmap: Add missing cache_only checks regmap: regmap-irq: Move handle_post_irq to before pm_runtime_put regmap: Load register defaults in blocks rather than register by register regmap: mmio: Allow passing an empty config->reg_stride regmap-irq: Drop backward compatibility for inverted mask/unmask regmap-irq: Minor adjustments to .handle_mask_sync() regmap-irq: Remove support for not_fixed_stride regmap-irq: Remove type registers regmap-irq: Remove virtual registers ...
2 parents 1b2c92a + d0c99ff commit 4171a9a

12 files changed

Lines changed: 835 additions & 302 deletions

File tree

drivers/base/regmap/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
88
obj-$(CONFIG_REGMAP_KUNIT) += regmap-kunit.o
99
obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o
1010
obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
11-
obj-$(CONFIG_REGMAP_RAM) += regmap-ram.o
11+
obj-$(CONFIG_REGMAP_RAM) += regmap-ram.o regmap-raw-ram.o
1212
obj-$(CONFIG_REGMAP_SLIMBUS) += regmap-slimbus.o
1313
obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
1414
obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o

drivers/base/regmap/internal.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ struct regmap {
125125
int reg_stride;
126126
int reg_stride_order;
127127

128+
/* If set, will always write field to HW. */
129+
bool force_write_field;
130+
128131
/* regcache specific members */
129132
const struct regcache_ops *cache_ops;
130133
enum regcache_type cache_type;
@@ -257,6 +260,8 @@ int regcache_sync_block(struct regmap *map, void *block,
257260
unsigned long *cache_present,
258261
unsigned int block_base, unsigned int start,
259262
unsigned int end);
263+
bool regcache_reg_needs_sync(struct regmap *map, unsigned int reg,
264+
unsigned int val);
260265

261266
static inline const void *regcache_get_val_addr(struct regmap *map,
262267
const void *base,
@@ -267,7 +272,7 @@ static inline const void *regcache_get_val_addr(struct regmap *map,
267272

268273
unsigned int regcache_get_val(struct regmap *map, const void *base,
269274
unsigned int idx);
270-
bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
275+
void regcache_set_val(struct regmap *map, void *base, unsigned int idx,
271276
unsigned int val);
272277
int regcache_lookup_reg(struct regmap *map, unsigned int reg);
273278
int regcache_sync_val(struct regmap *map, unsigned int reg, unsigned int val);
@@ -312,6 +317,7 @@ struct regmap_ram_data {
312317
unsigned int *vals; /* Allocatd by caller */
313318
bool *read;
314319
bool *written;
320+
enum regmap_endian reg_endian;
315321
};
316322

317323
/*
@@ -326,5 +332,12 @@ struct regmap *__regmap_init_ram(const struct regmap_config *config,
326332
#define regmap_init_ram(config, data) \
327333
__regmap_lockdep_wrapper(__regmap_init_ram, #config, config, data)
328334

335+
struct regmap *__regmap_init_raw_ram(const struct regmap_config *config,
336+
struct regmap_ram_data *data,
337+
struct lock_class_key *lock_key,
338+
const char *lock_name);
339+
340+
#define regmap_init_raw_ram(config, data) \
341+
__regmap_lockdep_wrapper(__regmap_init_raw_ram, #config, config, data)
329342

330343
#endif

drivers/base/regmap/regcache-maple.c

Lines changed: 128 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,55 @@ static int regcache_maple_drop(struct regmap *map, unsigned int min,
186186
return ret;
187187
}
188188

189+
static int regcache_maple_sync_block(struct regmap *map, unsigned long *entry,
190+
struct ma_state *mas,
191+
unsigned int min, unsigned int max)
192+
{
193+
void *buf;
194+
unsigned long r;
195+
size_t val_bytes = map->format.val_bytes;
196+
int ret = 0;
197+
198+
mas_pause(mas);
199+
rcu_read_unlock();
200+
201+
/*
202+
* Use a raw write if writing more than one register to a
203+
* device that supports raw writes to reduce transaction
204+
* overheads.
205+
*/
206+
if (max - min > 1 && regmap_can_raw_write(map)) {
207+
buf = kmalloc(val_bytes * (max - min), map->alloc_flags);
208+
if (!buf) {
209+
ret = -ENOMEM;
210+
goto out;
211+
}
212+
213+
/* Render the data for a raw write */
214+
for (r = min; r < max; r++) {
215+
regcache_set_val(map, buf, r - min,
216+
entry[r - mas->index]);
217+
}
218+
219+
ret = _regmap_raw_write(map, min, buf, (max - min) * val_bytes,
220+
false);
221+
222+
kfree(buf);
223+
} else {
224+
for (r = min; r < max; r++) {
225+
ret = _regmap_write(map, r,
226+
entry[r - mas->index]);
227+
if (ret != 0)
228+
goto out;
229+
}
230+
}
231+
232+
out:
233+
rcu_read_lock();
234+
235+
return ret;
236+
}
237+
189238
static int regcache_maple_sync(struct regmap *map, unsigned int min,
190239
unsigned int max)
191240
{
@@ -194,27 +243,48 @@ static int regcache_maple_sync(struct regmap *map, unsigned int min,
194243
MA_STATE(mas, mt, min, max);
195244
unsigned long lmin = min;
196245
unsigned long lmax = max;
197-
unsigned int r;
246+
unsigned int r, v, sync_start;
198247
int ret;
248+
bool sync_needed = false;
199249

200250
map->cache_bypass = true;
201251

202252
rcu_read_lock();
203253

204254
mas_for_each(&mas, entry, max) {
205255
for (r = max(mas.index, lmin); r <= min(mas.last, lmax); r++) {
206-
mas_pause(&mas);
207-
rcu_read_unlock();
208-
ret = regcache_sync_val(map, r, entry[r - mas.index]);
256+
v = entry[r - mas.index];
257+
258+
if (regcache_reg_needs_sync(map, r, v)) {
259+
if (!sync_needed) {
260+
sync_start = r;
261+
sync_needed = true;
262+
}
263+
continue;
264+
}
265+
266+
if (!sync_needed)
267+
continue;
268+
269+
ret = regcache_maple_sync_block(map, entry, &mas,
270+
sync_start, r);
271+
if (ret != 0)
272+
goto out;
273+
sync_needed = false;
274+
}
275+
276+
if (sync_needed) {
277+
ret = regcache_maple_sync_block(map, entry, &mas,
278+
sync_start, r);
209279
if (ret != 0)
210280
goto out;
211-
rcu_read_lock();
281+
sync_needed = false;
212282
}
213283
}
214284

285+
out:
215286
rcu_read_unlock();
216287

217-
out:
218288
map->cache_bypass = false;
219289

220290
return ret;
@@ -242,11 +312,41 @@ static int regcache_maple_exit(struct regmap *map)
242312
return 0;
243313
}
244314

315+
static int regcache_maple_insert_block(struct regmap *map, int first,
316+
int last)
317+
{
318+
struct maple_tree *mt = map->cache;
319+
MA_STATE(mas, mt, first, last);
320+
unsigned long *entry;
321+
int i, ret;
322+
323+
entry = kcalloc(last - first + 1, sizeof(unsigned long), GFP_KERNEL);
324+
if (!entry)
325+
return -ENOMEM;
326+
327+
for (i = 0; i < last - first + 1; i++)
328+
entry[i] = map->reg_defaults[first + i].def;
329+
330+
mas_lock(&mas);
331+
332+
mas_set_range(&mas, map->reg_defaults[first].reg,
333+
map->reg_defaults[last].reg);
334+
ret = mas_store_gfp(&mas, entry, GFP_KERNEL);
335+
336+
mas_unlock(&mas);
337+
338+
if (ret)
339+
kfree(entry);
340+
341+
return ret;
342+
}
343+
245344
static int regcache_maple_init(struct regmap *map)
246345
{
247346
struct maple_tree *mt;
248347
int i;
249348
int ret;
349+
int range_start;
250350

251351
mt = kmalloc(sizeof(*mt), GFP_KERNEL);
252352
if (!mt)
@@ -255,14 +355,30 @@ static int regcache_maple_init(struct regmap *map)
255355

256356
mt_init(mt);
257357

258-
for (i = 0; i < map->num_reg_defaults; i++) {
259-
ret = regcache_maple_write(map,
260-
map->reg_defaults[i].reg,
261-
map->reg_defaults[i].def);
262-
if (ret)
263-
goto err;
358+
if (!map->num_reg_defaults)
359+
return 0;
360+
361+
range_start = 0;
362+
363+
/* Scan for ranges of contiguous registers */
364+
for (i = 1; i < map->num_reg_defaults; i++) {
365+
if (map->reg_defaults[i].reg !=
366+
map->reg_defaults[i - 1].reg + 1) {
367+
ret = regcache_maple_insert_block(map, range_start,
368+
i - 1);
369+
if (ret != 0)
370+
goto err;
371+
372+
range_start = i;
373+
}
264374
}
265375

376+
/* Add the last block */
377+
ret = regcache_maple_insert_block(map, range_start,
378+
map->num_reg_defaults - 1);
379+
if (ret != 0)
380+
goto err;
381+
266382
return 0;
267383

268384
err:

drivers/base/regmap/regcache.c

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,8 @@ int regcache_write(struct regmap *map,
279279
return 0;
280280
}
281281

282-
static bool regcache_reg_needs_sync(struct regmap *map, unsigned int reg,
283-
unsigned int val)
282+
bool regcache_reg_needs_sync(struct regmap *map, unsigned int reg,
283+
unsigned int val)
284284
{
285285
int ret;
286286

@@ -561,17 +561,14 @@ void regcache_cache_bypass(struct regmap *map, bool enable)
561561
}
562562
EXPORT_SYMBOL_GPL(regcache_cache_bypass);
563563

564-
bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
564+
void regcache_set_val(struct regmap *map, void *base, unsigned int idx,
565565
unsigned int val)
566566
{
567-
if (regcache_get_val(map, base, idx) == val)
568-
return true;
569-
570567
/* Use device native format if possible */
571568
if (map->format.format_val) {
572569
map->format.format_val(base + (map->cache_word_size * idx),
573570
val, 0);
574-
return false;
571+
return;
575572
}
576573

577574
switch (map->cache_word_size) {
@@ -604,7 +601,6 @@ bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
604601
default:
605602
BUG();
606603
}
607-
return false;
608604
}
609605

610606
unsigned int regcache_get_val(struct regmap *map, const void *base,

drivers/base/regmap/regmap-debugfs.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,17 @@ void regmap_debugfs_init(struct regmap *map)
636636
&regmap_cache_bypass_fops);
637637
}
638638

639+
/*
640+
* This could interfere with driver operation. Therefore, don't provide
641+
* any real compile time configuration option for this feature. One will
642+
* have to modify the source code directly in order to use it.
643+
*/
644+
#undef REGMAP_ALLOW_FORCE_WRITE_FIELD_DEBUGFS
645+
#ifdef REGMAP_ALLOW_FORCE_WRITE_FIELD_DEBUGFS
646+
debugfs_create_bool("force_write_field", 0600, map->debugfs,
647+
&map->force_write_field);
648+
#endif
649+
639650
next = rb_first(&map->range_tree);
640651
while (next) {
641652
range_node = rb_entry(next, struct regmap_range_node, node);

0 commit comments

Comments
 (0)