Skip to content

Commit

Permalink
Merge tag 'regmap-v6.5' of git://git.kernel.org/pub/scm/linux/kernel/…
Browse files Browse the repository at this point in the history
…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
  ...
  • Loading branch information
torvalds committed Jun 28, 2023
2 parents 1b2c92a + d0c99ff commit 4171a9a
Show file tree
Hide file tree
Showing 12 changed files with 835 additions and 302 deletions.
2 changes: 1 addition & 1 deletion drivers/base/regmap/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
obj-$(CONFIG_REGMAP_KUNIT) += regmap-kunit.o
obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o
obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
obj-$(CONFIG_REGMAP_RAM) += regmap-ram.o
obj-$(CONFIG_REGMAP_RAM) += regmap-ram.o regmap-raw-ram.o
obj-$(CONFIG_REGMAP_SLIMBUS) += regmap-slimbus.o
obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o
Expand Down
15 changes: 14 additions & 1 deletion drivers/base/regmap/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ struct regmap {
int reg_stride;
int reg_stride_order;

/* If set, will always write field to HW. */
bool force_write_field;

/* regcache specific members */
const struct regcache_ops *cache_ops;
enum regcache_type cache_type;
Expand Down Expand Up @@ -257,6 +260,8 @@ int regcache_sync_block(struct regmap *map, void *block,
unsigned long *cache_present,
unsigned int block_base, unsigned int start,
unsigned int end);
bool regcache_reg_needs_sync(struct regmap *map, unsigned int reg,
unsigned int val);

static inline const void *regcache_get_val_addr(struct regmap *map,
const void *base,
Expand All @@ -267,7 +272,7 @@ static inline const void *regcache_get_val_addr(struct regmap *map,

unsigned int regcache_get_val(struct regmap *map, const void *base,
unsigned int idx);
bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
void regcache_set_val(struct regmap *map, void *base, unsigned int idx,
unsigned int val);
int regcache_lookup_reg(struct regmap *map, unsigned int reg);
int regcache_sync_val(struct regmap *map, unsigned int reg, unsigned int val);
Expand Down Expand Up @@ -312,6 +317,7 @@ struct regmap_ram_data {
unsigned int *vals; /* Allocatd by caller */
bool *read;
bool *written;
enum regmap_endian reg_endian;
};

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

struct regmap *__regmap_init_raw_ram(const struct regmap_config *config,
struct regmap_ram_data *data,
struct lock_class_key *lock_key,
const char *lock_name);

#define regmap_init_raw_ram(config, data) \
__regmap_lockdep_wrapper(__regmap_init_raw_ram, #config, config, data)

#endif
140 changes: 128 additions & 12 deletions drivers/base/regmap/regcache-maple.c
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,55 @@ static int regcache_maple_drop(struct regmap *map, unsigned int min,
return ret;
}

static int regcache_maple_sync_block(struct regmap *map, unsigned long *entry,
struct ma_state *mas,
unsigned int min, unsigned int max)
{
void *buf;
unsigned long r;
size_t val_bytes = map->format.val_bytes;
int ret = 0;

mas_pause(mas);
rcu_read_unlock();

/*
* Use a raw write if writing more than one register to a
* device that supports raw writes to reduce transaction
* overheads.
*/
if (max - min > 1 && regmap_can_raw_write(map)) {
buf = kmalloc(val_bytes * (max - min), map->alloc_flags);
if (!buf) {
ret = -ENOMEM;
goto out;
}

/* Render the data for a raw write */
for (r = min; r < max; r++) {
regcache_set_val(map, buf, r - min,
entry[r - mas->index]);
}

ret = _regmap_raw_write(map, min, buf, (max - min) * val_bytes,
false);

kfree(buf);
} else {
for (r = min; r < max; r++) {
ret = _regmap_write(map, r,
entry[r - mas->index]);
if (ret != 0)
goto out;
}
}

out:
rcu_read_lock();

return ret;
}

static int regcache_maple_sync(struct regmap *map, unsigned int min,
unsigned int max)
{
Expand All @@ -194,27 +243,48 @@ static int regcache_maple_sync(struct regmap *map, unsigned int min,
MA_STATE(mas, mt, min, max);
unsigned long lmin = min;
unsigned long lmax = max;
unsigned int r;
unsigned int r, v, sync_start;
int ret;
bool sync_needed = false;

map->cache_bypass = true;

rcu_read_lock();

mas_for_each(&mas, entry, max) {
for (r = max(mas.index, lmin); r <= min(mas.last, lmax); r++) {
mas_pause(&mas);
rcu_read_unlock();
ret = regcache_sync_val(map, r, entry[r - mas.index]);
v = entry[r - mas.index];

if (regcache_reg_needs_sync(map, r, v)) {
if (!sync_needed) {
sync_start = r;
sync_needed = true;
}
continue;
}

if (!sync_needed)
continue;

ret = regcache_maple_sync_block(map, entry, &mas,
sync_start, r);
if (ret != 0)
goto out;
sync_needed = false;
}

if (sync_needed) {
ret = regcache_maple_sync_block(map, entry, &mas,
sync_start, r);
if (ret != 0)
goto out;
rcu_read_lock();
sync_needed = false;
}
}

out:
rcu_read_unlock();

out:
map->cache_bypass = false;

return ret;
Expand Down Expand Up @@ -242,11 +312,41 @@ static int regcache_maple_exit(struct regmap *map)
return 0;
}

static int regcache_maple_insert_block(struct regmap *map, int first,
int last)
{
struct maple_tree *mt = map->cache;
MA_STATE(mas, mt, first, last);
unsigned long *entry;
int i, ret;

entry = kcalloc(last - first + 1, sizeof(unsigned long), GFP_KERNEL);
if (!entry)
return -ENOMEM;

for (i = 0; i < last - first + 1; i++)
entry[i] = map->reg_defaults[first + i].def;

mas_lock(&mas);

mas_set_range(&mas, map->reg_defaults[first].reg,
map->reg_defaults[last].reg);
ret = mas_store_gfp(&mas, entry, GFP_KERNEL);

mas_unlock(&mas);

if (ret)
kfree(entry);

return ret;
}

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

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

mt_init(mt);

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

range_start = 0;

/* Scan for ranges of contiguous registers */
for (i = 1; i < map->num_reg_defaults; i++) {
if (map->reg_defaults[i].reg !=
map->reg_defaults[i - 1].reg + 1) {
ret = regcache_maple_insert_block(map, range_start,
i - 1);
if (ret != 0)
goto err;

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:
Expand Down
12 changes: 4 additions & 8 deletions drivers/base/regmap/regcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,8 @@ int regcache_write(struct regmap *map,
return 0;
}

static bool regcache_reg_needs_sync(struct regmap *map, unsigned int reg,
unsigned int val)
bool regcache_reg_needs_sync(struct regmap *map, unsigned int reg,
unsigned int val)
{
int ret;

Expand Down Expand Up @@ -561,17 +561,14 @@ void regcache_cache_bypass(struct regmap *map, bool enable)
}
EXPORT_SYMBOL_GPL(regcache_cache_bypass);

bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
void regcache_set_val(struct regmap *map, void *base, unsigned int idx,
unsigned int val)
{
if (regcache_get_val(map, base, idx) == val)
return true;

/* Use device native format if possible */
if (map->format.format_val) {
map->format.format_val(base + (map->cache_word_size * idx),
val, 0);
return false;
return;
}

switch (map->cache_word_size) {
Expand Down Expand Up @@ -604,7 +601,6 @@ bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
default:
BUG();
}
return false;
}

unsigned int regcache_get_val(struct regmap *map, const void *base,
Expand Down
11 changes: 11 additions & 0 deletions drivers/base/regmap/regmap-debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,17 @@ void regmap_debugfs_init(struct regmap *map)
&regmap_cache_bypass_fops);
}

/*
* This could interfere with driver operation. Therefore, don't provide
* any real compile time configuration option for this feature. One will
* have to modify the source code directly in order to use it.
*/
#undef REGMAP_ALLOW_FORCE_WRITE_FIELD_DEBUGFS
#ifdef REGMAP_ALLOW_FORCE_WRITE_FIELD_DEBUGFS
debugfs_create_bool("force_write_field", 0600, map->debugfs,
&map->force_write_field);
#endif

next = rb_first(&map->range_tree);
while (next) {
range_node = rb_entry(next, struct regmap_range_node, node);
Expand Down
Loading

0 comments on commit 4171a9a

Please sign in to comment.