Merge tag 'regmap-fix-v7.2-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap

Pull regmap fixes from Mark Brown:
 "These fix some issues which were noticed in some drivers where caches
  were not fully resynced after suspend. Drivers are supposed to be
  sorting the table of register defaults they provide to the core and
  the core was relying on that but it turns out there are many cases
  where this does not happen, it's easy to get wrong when using named
  defines for registers rather than numbers. It is more robust to remove
  the requirement for sorting and instead have the core ensure
  everything it needs sorting is sorted so do that.

  There will be patches during the merge window sorting the tables in
  drivers since it is more efficient to do that but this will just be a
  minor performance win rather than a correctness fix"

* tag 'regmap-fix-v7.2-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
  regcache: Sort the local copy of an unsorted reg_defaults array
  regcache: Use a consistent sort for defaults table
This commit is contained in:
Linus Torvalds
2026-08-10 09:15:27 -07:00
+17 -10
View File
@@ -123,6 +123,8 @@ static void regcache_hw_exit(struct regmap *map)
int regcache_init(struct regmap *map, const struct regmap_config *config)
{
bool sort_defaults = false;
unsigned int reg_prev = 0;
int count = 0;
int ret;
int i;
@@ -149,10 +151,16 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
return -EINVAL;
}
for (i = 0; i < config->num_reg_defaults; i++)
for (i = 0; i < config->num_reg_defaults; i++) {
if (config->reg_defaults[i].reg % map->reg_stride)
return -EINVAL;
if (reg_prev > config->reg_defaults[i].reg)
sort_defaults = true;
reg_prev = config->reg_defaults[i].reg;
}
for (i = 0; i < ARRAY_SIZE(cache_types); i++)
if (cache_types[i]->type == map->cache_type)
break;
@@ -186,6 +194,13 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
sizeof(*map->reg_defaults), GFP_KERNEL);
if (!tmp_buf)
return -ENOMEM;
/* regcache_lookup_reg() bsearch()es this array */
if (sort_defaults) {
dev_warn(map->dev,
"Driver needs fixing: Unsorted reg_defaults, sorting the copy\n");
regcache_sort_defaults(tmp_buf, map->num_reg_defaults);
}
map->reg_defaults = tmp_buf;
} else if (map->num_reg_defaults_raw) {
count = regcache_count_cacheable_registers(map);
@@ -727,14 +742,6 @@ unsigned int regcache_get_val(struct regmap *map, const void *base,
return -1;
}
static int regcache_default_cmp(const void *a, const void *b)
{
const struct reg_default *_a = a;
const struct reg_default *_b = b;
return _a->reg - _b->reg;
}
int regcache_lookup_reg(struct regmap *map, unsigned int reg)
{
struct reg_default key;
@@ -744,7 +751,7 @@ int regcache_lookup_reg(struct regmap *map, unsigned int reg)
key.def = 0;
r = bsearch(&key, map->reg_defaults, map->num_reg_defaults,
sizeof(struct reg_default), regcache_default_cmp);
sizeof(struct reg_default), regcache_defaults_cmp);
if (r)
return r - map->reg_defaults;