From: Mark Brown Date: Thu, 26 Aug 2021 12:40:35 +0000 (+0100) Subject: Merge series "Use raw spinlocks in the ls-extirq driver" from Vladimir Oltean : The ls-extirq irqchip driver accesses regmap inside its implementation of the struct irq_chip :: irq_set_type method, and currently regmap only knows to lock using normal spinlocks. But the method above wants raw spinlock context, so this isn't going to work and triggers a "[ BUG: Invalid wait context ]" splat. The best we can do given the arrangement of the code is to patch regmap and the syscon driver: regmap to support raw spinlocks, and syscon to request them on behalf of its ls-extirq consumer. Link: https://lore.kernel.org/lkml/20210825135438.ubcuxm5vctt6ne2q@skbuf/T/#u Vladimir Oltean (2): regmap: teach regmap to use raw spinlocks if requested in the config mfd: syscon: request a regmap with raw spinlocks for some devices drivers/base/regmap/internal.h | 4 ++++ drivers/base/regmap/regmap.c | 35 +++++++++++++++++++++++++++++----- drivers/mfd/syscon.c | 16 ++++++++++++++++ include/linux/regmap.h | 2 ++ 4 files changed, 52 insertions(+), 5 deletions(-) -- 2.25.1 base-commit: 6efb943b8616ec53a5e444193dccf1af9ad627b5 --- d287801c497151a44e5577fb3bbab673fe52e7b0 diff --combined drivers/base/regmap/regmap.c index 6ad41d0,d851070..21a0c25 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@@ -243,16 -243,6 +243,16 @@@ static void regmap_format_7_9_write(str *out = cpu_to_be16((reg << 9) | val); } +static void regmap_format_7_17_write(struct regmap *map, + unsigned int reg, unsigned int val) +{ + u8 *out = map->work_buf; + + out[2] = val; + out[1] = val >> 8; + out[0] = (val >> 16) | (reg << 1); +} + static void regmap_format_10_14_write(struct regmap *map, unsigned int reg, unsigned int val) { @@@ -533,6 -523,23 +533,23 @@@ __releases(&map->spinlock spin_unlock_irqrestore(&map->spinlock, map->spinlock_flags); } + static void regmap_lock_raw_spinlock(void *__map) + __acquires(&map->raw_spinlock) + { + struct regmap *map = __map; + unsigned long flags; + + raw_spin_lock_irqsave(&map->raw_spinlock, flags); + map->raw_spinlock_flags = flags; + } + + static void regmap_unlock_raw_spinlock(void *__map) + __releases(&map->raw_spinlock) + { + struct regmap *map = __map; + raw_spin_unlock_irqrestore(&map->raw_spinlock, map->raw_spinlock_flags); + } + static void dev_get_regmap_release(struct device *dev, void *res) { /* @@@ -770,11 -777,19 +787,19 @@@ struct regmap *__regmap_init(struct dev } else { if ((bus && bus->fast_io) || config->fast_io) { - spin_lock_init(&map->spinlock); - map->lock = regmap_lock_spinlock; - map->unlock = regmap_unlock_spinlock; - lockdep_set_class_and_name(&map->spinlock, - lock_key, lock_name); + if (config->use_raw_spinlock) { + raw_spin_lock_init(&map->raw_spinlock); + map->lock = regmap_lock_raw_spinlock; + map->unlock = regmap_unlock_raw_spinlock; + lockdep_set_class_and_name(&map->raw_spinlock, + lock_key, lock_name); + } else { + spin_lock_init(&map->spinlock); + map->lock = regmap_lock_spinlock; + map->unlock = regmap_unlock_spinlock; + lockdep_set_class_and_name(&map->spinlock, + lock_key, lock_name); + } } else { mutex_init(&map->mutex); map->lock = regmap_lock_mutex; @@@ -895,9 -910,6 +920,9 @@@ case 9: map->format.format_write = regmap_format_7_9_write; break; + case 17: + map->format.format_write = regmap_format_7_17_write; + break; default: goto err_hwlock; } @@@ -1126,10 -1138,10 +1151,10 @@@ skip_format_initialization /* Make sure, that this register range has no selector or data window within its boundary */ for (j = 0; j < config->num_ranges; j++) { - unsigned sel_reg = config->ranges[j].selector_reg; - unsigned win_min = config->ranges[j].window_start; - unsigned win_max = win_min + - config->ranges[j].window_len - 1; + unsigned int sel_reg = config->ranges[j].selector_reg; + unsigned int win_min = config->ranges[j].window_start; + unsigned int win_max = win_min + + config->ranges[j].window_len - 1; /* Allow data window inside its own virtual range */ if (j == i) @@@ -1298,7 -1310,7 +1323,7 @@@ EXPORT_SYMBOL_GPL(devm_regmap_field_all */ int regmap_field_bulk_alloc(struct regmap *regmap, struct regmap_field **rm_field, - struct reg_field *reg_field, + const struct reg_field *reg_field, int num_fields) { struct regmap_field *rf; @@@ -1334,7 -1346,7 +1359,7 @@@ EXPORT_SYMBOL_GPL(regmap_field_bulk_all int devm_regmap_field_bulk_alloc(struct device *dev, struct regmap *regmap, struct regmap_field **rm_field, - struct reg_field *reg_field, + const struct reg_field *reg_field, int num_fields) { struct regmap_field *rf; @@@ -1509,8 -1521,6 +1534,8 @@@ void regmap_exit(struct regmap *map mutex_destroy(&map->mutex); kfree_const(map->name); kfree(map->patch); + if (map->bus && map->bus->free_on_exit) + kfree(map->bus); kfree(map); } EXPORT_SYMBOL_GPL(regmap_exit); @@@ -1667,7 -1677,7 +1692,7 @@@ static int _regmap_raw_write_impl(struc if (ret) { dev_err(map->dev, "Error in caching of register: %x ret: %d\n", - reg + i, ret); + reg + regmap_get_offset(map, i), ret); return ret; } } diff --combined include/linux/regmap.h index 77755196,ed57b7c..e3c9a25 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@@ -27,7 -27,6 +27,7 @@@ struct device_node struct i2c_client; struct i3c_device; struct irq_domain; +struct mdio_device; struct slim_device; struct spi_device; struct spmi_device; @@@ -344,6 -343,7 +344,7 @@@ typedef void (*regmap_unlock)(void *) * @ranges: Array of configuration entries for virtual address ranges. * @num_ranges: Number of range configuration entries. * @use_hwlock: Indicate if a hardware spinlock should be used. + * @use_raw_spinlock: Indicate if a raw spinlock should be used. * @hwlock_id: Specify the hardware spinlock id. * @hwlock_mode: The hardware spinlock mode, should be HWLOCK_IRQSTATE, * HWLOCK_IRQ or 0. @@@ -403,6 -403,7 +404,7 @@@ struct regmap_config unsigned int num_ranges; bool use_hwlock; + bool use_raw_spinlock; unsigned int hwlock_id; unsigned int hwlock_mode; @@@ -503,7 -504,6 +505,7 @@@ typedef void (*regmap_hw_free_context)( * DEFAULT, BIG is assumed. * @max_raw_read: Max raw read size that can be used on the bus. * @max_raw_write: Max raw write size that can be used on the bus. + * @free_on_exit: kfree this on exit of regmap */ struct regmap_bus { bool fast_io; @@@ -521,7 -521,6 +523,7 @@@ enum regmap_endian val_format_endian_default; size_t max_raw_read; size_t max_raw_write; + bool free_on_exit; }; /* @@@ -541,10 -540,6 +543,10 @@@ struct regmap *__regmap_init_i2c(struc const struct regmap_config *config, struct lock_class_key *lock_key, const char *lock_name); +struct regmap *__regmap_init_mdio(struct mdio_device *mdio_dev, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name); struct regmap *__regmap_init_sccb(struct i2c_client *i2c, const struct regmap_config *config, struct lock_class_key *lock_key, @@@ -601,10 -596,6 +603,10 @@@ struct regmap *__devm_regmap_init_i2c(s const struct regmap_config *config, struct lock_class_key *lock_key, const char *lock_name); +struct regmap *__devm_regmap_init_mdio(struct mdio_device *mdio_dev, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name); struct regmap *__devm_regmap_init_sccb(struct i2c_client *i2c, const struct regmap_config *config, struct lock_class_key *lock_key, @@@ -709,19 -700,6 +711,19 @@@ int regmap_attach_dev(struct device *de i2c, config) /** + * regmap_init_mdio() - Initialise register map + * + * @mdio_dev: Device that will be interacted with + * @config: Configuration for register map + * + * The return value will be an ERR_PTR() on error or a valid pointer to + * a struct regmap. + */ +#define regmap_init_mdio(mdio_dev, config) \ + __regmap_lockdep_wrapper(__regmap_init_mdio, #config, \ + mdio_dev, config) + +/** * regmap_init_sccb() - Initialise register map * * @i2c: Device that will be interacted with @@@ -913,20 -891,6 +915,20 @@@ bool regmap_ac97_default_volatile(struc i2c, config) /** + * devm_regmap_init_mdio() - Initialise managed register map + * + * @mdio_dev: Device that will be interacted with + * @config: Configuration for register map + * + * The return value will be an ERR_PTR() on error or a valid pointer + * to a struct regmap. The regmap will be automatically freed by the + * device management code. + */ +#define devm_regmap_init_mdio(mdio_dev, config) \ + __regmap_lockdep_wrapper(__devm_regmap_init_mdio, #config, \ + mdio_dev, config) + +/** * devm_regmap_init_sccb() - Initialise managed register map * * @i2c: Device that will be interacted with @@@ -1269,13 -1233,12 +1271,13 @@@ void devm_regmap_field_free(struct devi int regmap_field_bulk_alloc(struct regmap *regmap, struct regmap_field **rm_field, - struct reg_field *reg_field, + const struct reg_field *reg_field, int num_fields); void regmap_field_bulk_free(struct regmap_field *field); int devm_regmap_field_bulk_alloc(struct device *dev, struct regmap *regmap, struct regmap_field **field, - struct reg_field *reg_field, int num_fields); + const struct reg_field *reg_field, + int num_fields); void devm_regmap_field_bulk_free(struct device *dev, struct regmap_field *field); @@@ -1450,7 -1413,6 +1452,7 @@@ struct regmap_irq_sub_irq_map * @not_fixed_stride: Used when chip peripherals are not laid out with fixed * stride. Must be used with sub_reg_offsets containing the * offsets to each peripheral. + * @status_invert: Inverted status register: cleared bits are active interrupts. * @runtime_pm: Hold a runtime PM lock on the device when accessing it. * * @num_regs: Number of registers in each control bank. @@@ -1503,7 -1465,6 +1505,7 @@@ struct regmap_irq_chip bool type_in_mask:1; bool clear_on_unmask:1; bool not_fixed_stride:1; + bool status_invert:1; int num_regs;