Commit ba1401f9 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents edd2b983 6985defd
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -186,6 +186,7 @@ struct regcache_ops {
	enum regcache_type type;
	int (*init)(struct regmap *map);
	int (*exit)(struct regmap *map);
	int (*populate)(struct regmap *map);
#ifdef CONFIG_DEBUG_FS
	void (*debugfs_init)(struct regmap *map);
#endif
@@ -288,6 +289,7 @@ enum regmap_endian regmap_get_val_endian(struct device *dev,
					 const struct regmap_bus *bus,
					 const struct regmap_config *config);

extern struct regcache_ops regcache_flat_sparse_ops;
extern struct regcache_ops regcache_rbtree_ops;
extern struct regcache_ops regcache_maple_ops;
extern struct regcache_ops regcache_flat_ops;
+91 −16
Original line number Diff line number Diff line
@@ -6,7 +6,11 @@
//
// 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>

@@ -18,46 +22,92 @@ static inline unsigned int regcache_flat_get_index(const struct regmap *map,
	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)
{
	int i;
	unsigned int *cache;
	unsigned int cache_size;
	struct regcache_flat_data *cache;

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

	map->cache = kcalloc(regcache_flat_get_index(map, map->max_register)
			     + 1, sizeof(unsigned int), map->alloc_flags);
	if (!map->cache)
	cache_size = regcache_flat_get_index(map, map->max_register) + 1;
	cache = kzalloc(struct_size(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;

	cache = map->cache;
	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[index] = map->reg_defaults[i].def;
		cache->data[index] = map->reg_defaults[i].def;
		__set_bit(index, cache->valid);
	}

	return 0;
}

static int regcache_flat_exit(struct regmap *map)
static int regcache_flat_read(struct regmap *map,
			      unsigned int reg, unsigned int *value)
{
	kfree(map->cache);
	map->cache = NULL;
	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_read(struct regmap *map,
static int regcache_flat_sparse_read(struct regmap *map,
				     unsigned int reg, unsigned int *value)
{
	unsigned int *cache = map->cache;
	struct regcache_flat_data *cache = map->cache;
	unsigned int index = regcache_flat_get_index(map, reg);

	*value = cache[index];
	if (unlikely(!test_bit(index, cache->valid)))
		return -ENOENT;

	*value = cache->data[index];

	return 0;
}
@@ -65,10 +115,23 @@ static int regcache_flat_read(struct regmap *map,
static int regcache_flat_write(struct regmap *map, unsigned int reg,
			       unsigned int value)
{
	unsigned int *cache = map->cache;
	struct regcache_flat_data *cache = map->cache;
	unsigned int index = regcache_flat_get_index(map, reg);

	cache[index] = value;
	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;
}
@@ -78,6 +141,18 @@ struct regcache_ops regcache_flat_ops = {
	.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,
};
+21 −26
Original line number Diff line number Diff line
@@ -289,6 +289,23 @@ static int regcache_maple_sync(struct regmap *map, unsigned int min,
	return ret;
}

static int regcache_maple_init(struct regmap *map)
{
	struct maple_tree *mt;

	mt = kmalloc(sizeof(*mt), map->alloc_flags);
	if (!mt)
		return -ENOMEM;
	map->cache = mt;

	mt_init(mt);

	if (!mt_external_lock(mt) && map->lock_key)
		lockdep_set_class_and_subclass(&mt->ma_lock, map->lock_key, 1);

	return 0;
}

static int regcache_maple_exit(struct regmap *map)
{
	struct maple_tree *mt = map->cache;
@@ -340,26 +357,12 @@ static int regcache_maple_insert_block(struct regmap *map, int first,
	return ret;
}

static int regcache_maple_init(struct regmap *map)
static int regcache_maple_populate(struct regmap *map)
{
	struct maple_tree *mt;
	int i;
	int ret;
	int range_start;

	mt = kmalloc(sizeof(*mt), map->alloc_flags);
	if (!mt)
		return -ENOMEM;
	map->cache = mt;

	mt_init(mt);

	if (!mt_external_lock(mt) && map->lock_key)
		lockdep_set_class_and_subclass(&mt->ma_lock, map->lock_key, 1);

	if (!map->num_reg_defaults)
		return 0;

	range_start = 0;

	/* Scan for ranges of contiguous registers */
@@ -369,23 +372,14 @@ static int regcache_maple_init(struct regmap *map)
			ret = regcache_maple_insert_block(map, range_start,
							  i - 1);
			if (ret != 0)
				goto err;
				return ret;

			range_start = i;
		}
	}

	/* Add the last block */
	ret = regcache_maple_insert_block(map, range_start,
					  map->num_reg_defaults - 1);
	if (ret != 0)
		goto err;

	return 0;

err:
	regcache_maple_exit(map);
	return ret;
	return regcache_maple_insert_block(map, range_start, map->num_reg_defaults - 1);
}

struct regcache_ops regcache_maple_ops = {
@@ -393,6 +387,7 @@ struct regcache_ops regcache_maple_ops = {
	.name = "maple",
	.init = regcache_maple_init,
	.exit = regcache_maple_exit,
	.populate = regcache_maple_populate,
	.read = regcache_maple_read,
	.write = regcache_maple_write,
	.drop = regcache_maple_drop,
+17 −14
Original line number Diff line number Diff line
@@ -184,8 +184,6 @@ static void rbtree_debugfs_init(struct regmap *map)
static int regcache_rbtree_init(struct regmap *map)
{
	struct regcache_rbtree_ctx *rbtree_ctx;
	int i;
	int ret;

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

	for (i = 0; i < map->num_reg_defaults; i++) {
		ret = regcache_rbtree_write(map,
					    map->reg_defaults[i].reg,
					    map->reg_defaults[i].def);
		if (ret)
			goto err;
	}

	return 0;

err:
	regcache_rbtree_exit(map);
	return ret;
}

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

static int regcache_rbtree_populate(struct regmap *map)
{
	unsigned int i;
	int ret;

	for (i = 0; i < map->num_reg_defaults; i++) {
		ret = regcache_rbtree_write(map,
					    map->reg_defaults[i].reg,
					    map->reg_defaults[i].def);
		if (ret)
			return ret;
	}

	return 0;
}

static int regcache_rbtree_read(struct regmap *map,
				unsigned int reg, unsigned int *value)
{
@@ -546,6 +548,7 @@ struct regcache_ops regcache_rbtree_ops = {
	.name = "rbtree",
	.init = regcache_rbtree_init,
	.exit = regcache_rbtree_exit,
	.populate = regcache_rbtree_populate,
#ifdef CONFIG_DEBUG_FS
	.debugfs_init = rbtree_debugfs_init,
#endif
+17 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include "internal.h"

static const struct regcache_ops *cache_types[] = {
	&regcache_flat_sparse_ops,
	&regcache_rbtree_ops,
	&regcache_maple_ops,
	&regcache_flat_ops,
@@ -221,8 +222,24 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
		if (ret)
			goto err_free;
	}

	if (map->num_reg_defaults && map->cache_ops->populate) {
		dev_dbg(map->dev, "Populating %s cache\n", map->cache_ops->name);
		map->lock(map->lock_arg);
		ret = map->cache_ops->populate(map);
		map->unlock(map->lock_arg);
		if (ret)
			goto err_exit;
	}
	return 0;

err_exit:
	if (map->cache_ops->exit) {
		dev_dbg(map->dev, "Destroying %s cache\n", map->cache_ops->name);
		map->lock(map->lock_arg);
		ret = map->cache_ops->exit(map);
		map->unlock(map->lock_arg);
	}
err_free:
	kfree(map->reg_defaults);
	if (map->cache_free)
Loading