Skip to content

Commit 67021f2

Browse files
vladimirolteanbroonie
authored andcommitted
regmap: teach regmap to use raw spinlocks if requested in the config
Some drivers might access regmap in a context where a raw spinlock is held. An example is drivers/irqchip/irq-ls-extirq.c, which calls regmap_update_bits() from struct irq_chip :: irq_set_type, which is a method called by __irq_set_trigger() under the desc->lock raw spin lock. Since desc->lock is a raw spin lock and the regmap internal lock for mmio is a plain spinlock (which can become sleepable on RT), this is an invalid locking scheme and we get a splat stating that this is a "[ BUG: Invalid wait context ]". It seems reasonable for regmap to have an option use a raw spinlock too, so add that in the config such that drivers can request it. Suggested-by: Mark Brown <[email protected]> Signed-off-by: Vladimir Oltean <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent 6efb943 commit 67021f2

File tree

3 files changed

+36
-5
lines changed

3 files changed

+36
-5
lines changed

drivers/base/regmap/internal.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ struct regmap {
5353
spinlock_t spinlock;
5454
unsigned long spinlock_flags;
5555
};
56+
struct {
57+
raw_spinlock_t raw_spinlock;
58+
unsigned long raw_spinlock_flags;
59+
};
5660
};
5761
regmap_lock lock;
5862
regmap_unlock unlock;

drivers/base/regmap/regmap.c

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,23 @@ __releases(&map->spinlock)
523523
spin_unlock_irqrestore(&map->spinlock, map->spinlock_flags);
524524
}
525525

526+
static void regmap_lock_raw_spinlock(void *__map)
527+
__acquires(&map->raw_spinlock)
528+
{
529+
struct regmap *map = __map;
530+
unsigned long flags;
531+
532+
raw_spin_lock_irqsave(&map->raw_spinlock, flags);
533+
map->raw_spinlock_flags = flags;
534+
}
535+
536+
static void regmap_unlock_raw_spinlock(void *__map)
537+
__releases(&map->raw_spinlock)
538+
{
539+
struct regmap *map = __map;
540+
raw_spin_unlock_irqrestore(&map->raw_spinlock, map->raw_spinlock_flags);
541+
}
542+
526543
static void dev_get_regmap_release(struct device *dev, void *res)
527544
{
528545
/*
@@ -760,11 +777,19 @@ struct regmap *__regmap_init(struct device *dev,
760777
} else {
761778
if ((bus && bus->fast_io) ||
762779
config->fast_io) {
763-
spin_lock_init(&map->spinlock);
764-
map->lock = regmap_lock_spinlock;
765-
map->unlock = regmap_unlock_spinlock;
766-
lockdep_set_class_and_name(&map->spinlock,
767-
lock_key, lock_name);
780+
if (config->use_raw_spinlock) {
781+
raw_spin_lock_init(&map->raw_spinlock);
782+
map->lock = regmap_lock_raw_spinlock;
783+
map->unlock = regmap_unlock_raw_spinlock;
784+
lockdep_set_class_and_name(&map->raw_spinlock,
785+
lock_key, lock_name);
786+
} else {
787+
spin_lock_init(&map->spinlock);
788+
map->lock = regmap_lock_spinlock;
789+
map->unlock = regmap_unlock_spinlock;
790+
lockdep_set_class_and_name(&map->spinlock,
791+
lock_key, lock_name);
792+
}
768793
} else {
769794
mutex_init(&map->mutex);
770795
map->lock = regmap_lock_mutex;

include/linux/regmap.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ typedef void (*regmap_unlock)(void *);
343343
* @ranges: Array of configuration entries for virtual address ranges.
344344
* @num_ranges: Number of range configuration entries.
345345
* @use_hwlock: Indicate if a hardware spinlock should be used.
346+
* @use_raw_spinlock: Indicate if a raw spinlock should be used.
346347
* @hwlock_id: Specify the hardware spinlock id.
347348
* @hwlock_mode: The hardware spinlock mode, should be HWLOCK_IRQSTATE,
348349
* HWLOCK_IRQ or 0.
@@ -402,6 +403,7 @@ struct regmap_config {
402403
unsigned int num_ranges;
403404

404405
bool use_hwlock;
406+
bool use_raw_spinlock;
405407
unsigned int hwlock_id;
406408
unsigned int hwlock_mode;
407409

0 commit comments

Comments
 (0)