diff options
| author | Paul E. McKenney <paulmck@kernel.org> | 2026-08-14 15:43:51 -0700 |
|---|---|---|
| committer | Paul E. McKenney <paulmck@kernel.org> | 2026-08-14 15:43:51 -0700 |
| commit | 9cc63f8bcd560c760d0b12e15bba8f81c86237cf (patch) | |
| tree | 3b5269b1bcf6714171754946367c51e0590f64da /drivers/base/regmap/regcache-flat.c | |
| download | linux-stable-9cc63f8bcd560c760d0b12e15bba8f81c86237cf.tar.gz linux-stable-9cc63f8bcd560c760d0b12e15bba8f81c86237cf.zip | |
Merge branches 'expcb.2026.07.24a', 'misc.2026.07.30a', 'rcu-tasks.2026.07.30a', 'srcu.2026.08.11a' and 'torture.2026.08.14a' into HEADgrafted
Changes:
Make expedited grace periods expedite normal RCU callbacks
Miscellaneous fixes:
* Improve diagnostic output with character task states.
* Mark accesses to inform KCSAN of concurrency design.
* Move from kmalloc() to kmalloc_obj().
* Documentation updates.
* Improve handling of RCU deferred quiescent states.
* Clean up unused function arguments and structure fields.
* Reduce show_rcu_gp_kthreads() stack space.
Tasks RCU updates:
* Clean up after SRCU re-implementation of Tasks Trace RCU.
* Mark accesses to inform KCSAN of concurrency design.
* Add ->lazy_timer status to diagnostic output.
* Remove an unnecessary memory barrier.
* Fix a data race, courtesy of KCSAN.
* Documentation updates.
* Convert cond_resched_tasks_rcu_qs() from macro to static inline
function.
SRCU updates:
* Add Rust helpers for SRCU.
* Avoid losing queued work at cleanup_srcu_struct() time.
Torture-test updates:
* Preparation work for immediate RCU priority deboosting.
* Test RCU readers from real interrupt handlers (as opposed to softirq).
* Simplify code through use of cpumask_next_wrap().
* Improve diagnostic output with character task states.
* Add rcutorture.nwriters parameter to allow lightweight stall testing,
and rcutorture.stall_only to make doing so easier.
* Test an RCU Tasks Trace grace period implying an RCU grace period.
* Make RCU Tasks Trace torturing track reader batches.
* Fix a data race, courtesy of KCSAN.
* Plug a shuffle_tmp_mask memory leak on kthread spawn failure.
Diffstat (limited to 'drivers/base/regmap/regcache-flat.c')
| -rw-r--r-- | drivers/base/regmap/regcache-flat.c | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/drivers/base/regmap/regcache-flat.c b/drivers/base/regmap/regcache-flat.c new file mode 100644 index 000000000..025e6749b --- /dev/null +++ b/drivers/base/regmap/regcache-flat.c @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Register cache access API - flat caching support +// +// Copyright 2012 Wolfson Microelectronics plc +// +// Author: Mark Brown <broonie@opensource.wolfsonmicro.com> + +#include <linux/bitmap.h> +#include <linux/bitops.h> +#include <linux/device.h> +#include <linux/limits.h> +#include <linux/overflow.h> +#include <linux/seq_file.h> +#include <linux/slab.h> + +#include "internal.h" + +static inline unsigned int regcache_flat_get_index(const struct regmap *map, + unsigned int reg) +{ + return regcache_get_index_by_order(map, reg); +} + +struct regcache_flat_data { + unsigned long *valid; + unsigned int data[]; +}; + +static int regcache_flat_init(struct regmap *map) +{ + unsigned int cache_size; + struct regcache_flat_data *cache; + + if (!map || map->reg_stride_order < 0 || !map->max_register_is_set) + return -EINVAL; + + cache_size = regcache_flat_get_index(map, map->max_register) + 1; + cache = kzalloc_flex(*cache, data, cache_size, map->alloc_flags); + if (!cache) + return -ENOMEM; + + cache->valid = bitmap_zalloc(cache_size, map->alloc_flags); + if (!cache->valid) + goto err_free; + + map->cache = cache; + + return 0; + +err_free: + kfree(cache); + return -ENOMEM; +} + +static int regcache_flat_exit(struct regmap *map) +{ + struct regcache_flat_data *cache = map->cache; + + if (cache) + bitmap_free(cache->valid); + + kfree(cache); + map->cache = NULL; + + return 0; +} + +static int regcache_flat_populate(struct regmap *map) +{ + struct regcache_flat_data *cache = map->cache; + unsigned int i; + + for (i = 0; i < map->num_reg_defaults; i++) { + unsigned int reg = map->reg_defaults[i].reg; + unsigned int index = regcache_flat_get_index(map, reg); + + cache->data[index] = map->reg_defaults[i].def; + __set_bit(index, cache->valid); + } + + if (map->reg_default_cb) { + dev_dbg(map->dev, + "Populating regcache_flat using reg_default_cb callback\n"); + + for (i = 0; i <= map->max_register; i += map->reg_stride) { + unsigned int index = regcache_flat_get_index(map, i); + unsigned int value; + + if (test_bit(index, cache->valid)) + continue; + + if (map->reg_default_cb(map->dev, i, &value)) + continue; + + cache->data[index] = value; + __set_bit(index, cache->valid); + } + } + + return 0; +} + +static int regcache_flat_read(struct regmap *map, + unsigned int reg, unsigned int *value) +{ + struct regcache_flat_data *cache = map->cache; + unsigned int index = regcache_flat_get_index(map, reg); + + /* legacy behavior: ignore validity, but warn the user */ + if (unlikely(!test_bit(index, cache->valid))) + dev_warn_once(map->dev, + "using zero-initialized flat cache, this may cause unexpected behavior"); + + *value = cache->data[index]; + + return 0; +} + +static int regcache_flat_sparse_read(struct regmap *map, + unsigned int reg, unsigned int *value) +{ + struct regcache_flat_data *cache = map->cache; + unsigned int index = regcache_flat_get_index(map, reg); + + if (unlikely(!test_bit(index, cache->valid))) + return -ENOENT; + + *value = cache->data[index]; + + return 0; +} + +static int regcache_flat_write(struct regmap *map, unsigned int reg, + unsigned int value) +{ + struct regcache_flat_data *cache = map->cache; + unsigned int index = regcache_flat_get_index(map, reg); + + cache->data[index] = value; + __set_bit(index, cache->valid); + + return 0; +} + +static int regcache_flat_drop(struct regmap *map, unsigned int min, + unsigned int max) +{ + struct regcache_flat_data *cache = map->cache; + unsigned int bitmap_min = regcache_flat_get_index(map, min); + unsigned int bitmap_max = regcache_flat_get_index(map, max); + + bitmap_clear(cache->valid, bitmap_min, bitmap_max + 1 - bitmap_min); + + return 0; +} + +struct regcache_ops regcache_flat_ops = { + .type = REGCACHE_FLAT, + .name = "flat", + .init = regcache_flat_init, + .exit = regcache_flat_exit, + .populate = regcache_flat_populate, + .read = regcache_flat_read, + .write = regcache_flat_write, +}; + +struct regcache_ops regcache_flat_sparse_ops = { + .type = REGCACHE_FLAT_S, + .name = "flat-sparse", + .init = regcache_flat_init, + .exit = regcache_flat_exit, + .populate = regcache_flat_populate, + .read = regcache_flat_sparse_read, + .write = regcache_flat_write, + .drop = regcache_flat_drop, +}; |
