regmap: Fixes for v7.3

The main thing here is a fix for lockdep warnings with MMIO regmaps that
 use a raw spinlock and a cache, some other lockdep fixes we'd done for
 the benefit of the maple tree on sleeping buses meant that we were doing
 allocations for those MMIO regmaps under a raw spinlock.  While fixing
 that Michael Reeves also noticed that the debugfs files were briefly
 available without the cache structures backing them.
 
 There's also a fix for interrupt freeing on error in regmap-irq which
 had been hanging around because it's not super urgent.
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQReagvpf3TrrA7BoYYv73Ows9A4iQUCatS/PwAKCRAv73Ows9A4
 idqeAP4y6bdFUzY0e9Ntiixana3IyzJ2dxzrjHIFHcOZl02UhwD8D2jWwFIw0CIs
 izZUkBabg5UyIeM1NkzZWtmDhkZTaAk=
 =AS9J
 -----END PGP SIGNATURE-----

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

Pull regmap fixes from Mark Brown:
 "The main thing here is a fix for lockdep warnings with MMIO regmaps
  that use a raw spinlock and a cache, some other lockdep fixes we'd
  done for the benefit of the maple tree on sleeping buses meant that we
  were doing allocations for those MMIO regmaps under a raw spinlock.

  While fixing that Michael Reeves also noticed that the debugfs files
  were briefly available without the cache structures backing them.

  There's also a fix for interrupt freeing on error in regmap-irq which
  had been hanging around because it's not super urgent"

* tag 'regmap-fix-v7.3-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
  regmap: Drop map lock during cache init and exit
  regmap: Remove debugfs before cache teardown
  regmap: irq: Free the irqdomain we create
This commit is contained in:
Linus Torvalds 2026-10-18 08:36:29 -10:00
commit 3d679a244e
6 changed files with 22 additions and 15 deletions

View File

@ -312,16 +312,21 @@ static void regcache_maple_exit(struct regmap *map)
struct maple_tree *mt = map->cache;
MA_STATE(mas, mt, 0, UINT_MAX);
unsigned int *entry;
unsigned long flags;
/* if we've already been called then just return */
if (!mt)
return;
mas_lock(&mas);
/*
* Register access may take the Maple lock from hard IRQ context, so
* preserve its IRQ-safe lockdep state during teardown.
*/
mas_lock_irqsave(&mas, flags);
mas_for_each(&mas, entry, UINT_MAX)
kfree(entry);
__mt_destroy(mt);
mas_unlock(&mas);
mas_unlock_irqrestore(&mas, flags);
kfree(mt);
map->cache = NULL;

View File

@ -225,9 +225,7 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
if (map->cache_ops->init) {
dev_dbg(map->dev, "Initializing %s cache\n",
map->cache_ops->name);
map->lock(map->lock_arg);
ret = map->cache_ops->init(map);
map->unlock(map->lock_arg);
if (ret)
goto err_free_reg_defaults;
}
@ -259,9 +257,7 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
err_exit:
if (map->cache_ops->exit) {
dev_dbg(map->dev, "Destroying %s cache\n", map->cache_ops->name);
map->lock(map->lock_arg);
map->cache_ops->exit(map);
map->unlock(map->lock_arg);
}
err_free_reg_defaults:
kfree(map->reg_defaults);
@ -281,9 +277,7 @@ void regcache_exit(struct regmap *map)
if (map->cache_ops->exit) {
dev_dbg(map->dev, "Destroying %s cache\n",
map->cache_ops->name);
map->lock(map->lock_arg);
map->cache_ops->exit(map);
map->unlock(map->lock_arg);
}
kfree(map->reg_defaults);

View File

@ -664,6 +664,7 @@ void regmap_debugfs_exit(struct regmap *map)
{
if (map->debugfs) {
debugfs_remove_recursive(map->debugfs);
map->debugfs = NULL;
mutex_lock(&map->cache_lock);
regmap_debugfs_free_dump_cache(map);
mutex_unlock(&map->cache_lock);

View File

@ -963,7 +963,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
return 0;
err_domain:
/* Should really dispose of the domain but... */
irq_domain_remove(d->domain);
err_mutex:
mutex_destroy(&d->lock);
lockdep_unregister_key(&d->lock_key);

View File

@ -1422,8 +1422,8 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
{
int ret;
regcache_exit(map);
regmap_debugfs_exit(map);
regcache_exit(map);
map->max_register = config->max_register;
map->max_register_is_set = map->max_register ?: config->max_register_is_0;
@ -1440,12 +1440,16 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
if (ret)
return ret;
regmap_debugfs_init(map);
map->cache_bypass = false;
map->cache_only = false;
return regcache_init(map, config);
ret = regcache_init(map, config);
if (ret)
return ret;
regmap_debugfs_init(map);
return 0;
}
EXPORT_SYMBOL_GPL(regmap_reinit_cache);
@ -1459,9 +1463,8 @@ void regmap_exit(struct regmap *map)
struct regmap_async *async;
regmap_detach_dev(map->dev, map);
regcache_exit(map);
regmap_debugfs_exit(map);
regcache_exit(map);
regmap_range_exit(map);
if (map->bus && map->bus->free_context)
map->bus->free_context(map->bus_context);

View File

@ -507,9 +507,13 @@ struct ma_wr_state {
};
#define mas_lock(mas) spin_lock(&((mas)->tree->ma_lock))
#define mas_lock_irqsave(mas, flags) \
spin_lock_irqsave(&((mas)->tree->ma_lock), flags)
#define mas_lock_nested(mas, subclass) \
spin_lock_nested(&((mas)->tree->ma_lock), subclass)
#define mas_unlock(mas) spin_unlock(&((mas)->tree->ma_lock))
#define mas_unlock_irqrestore(mas, flags) \
spin_unlock_irqrestore(&((mas)->tree->ma_lock), flags)
/*
* Special values for ma_state.node.