Commit 21a1f198 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'regmap-fix-v6.17-merge-window' of...

Merge tag 'regmap-fix-v6.17-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap

Pull regmap fixes from Mark Brown:
 "These patches fix a lockdep issue Russell King reported with nested
  regmap-irqs (unusual since regmap is generally for devices on slow
  buses so devices don't get nested), plus add a missing mutex free
  which I noticed while implementing a fix for that issue"

* tag 'regmap-fix-v6.17-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
  regmap: irq: Avoid lockdep warnings with nested regmap-irq chips
  regmap: irq: Free the regmap-irq mutex
parents 25046d5b 76b6e14a
Loading
Loading
Loading
Loading
+21 −9
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@

struct regmap_irq_chip_data {
	struct mutex lock;
	struct lock_class_key lock_key;
	struct irq_chip irq_chip;

	struct regmap *map;
@@ -801,7 +802,13 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
			goto err_alloc;
	}

	mutex_init(&d->lock);
	/*
	 * If one regmap-irq is the parent of another then we'll try
	 * to lock the child with the parent locked, use an explicit
	 * lock_key so lockdep can figure out what's going on.
	 */
	lockdep_register_key(&d->lock_key);
	mutex_init_with_key(&d->lock, &d->lock_key);

	for (i = 0; i < chip->num_irqs; i++)
		d->mask_buf_def[chip->irqs[i].reg_offset / map->reg_stride]
@@ -816,7 +823,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
						     d->mask_buf[i],
						     chip->irq_drv_data);
			if (ret)
				goto err_alloc;
				goto err_mutex;
		}

		if (chip->mask_base && !chip->handle_mask_sync) {
@@ -827,7 +834,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
			if (ret) {
				dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
					reg, ret);
				goto err_alloc;
				goto err_mutex;
			}
		}

@@ -838,7 +845,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
			if (ret) {
				dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
					reg, ret);
				goto err_alloc;
				goto err_mutex;
			}
		}

@@ -855,7 +862,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
			if (ret != 0) {
				dev_err(map->dev, "Failed to read IRQ status: %d\n",
					ret);
				goto err_alloc;
				goto err_mutex;
			}
		}

@@ -879,7 +886,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
			if (ret != 0) {
				dev_err(map->dev, "Failed to ack 0x%x: %d\n",
					reg, ret);
				goto err_alloc;
				goto err_mutex;
			}
		}
	}
@@ -901,7 +908,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
			if (ret != 0) {
				dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
					reg, ret);
				goto err_alloc;
				goto err_mutex;
			}
		}
	}
@@ -910,7 +917,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
	if (chip->status_is_level) {
		ret = read_irq_data(d);
		if (ret < 0)
			goto err_alloc;
			goto err_mutex;

		memcpy(d->prev_status_buf, d->status_buf,
		       array_size(d->chip->num_regs, sizeof(d->prev_status_buf[0])));
@@ -918,7 +925,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,

	ret = regmap_irq_create_domain(fwnode, irq_base, chip, d);
	if (ret)
		goto err_alloc;
		goto err_mutex;

	ret = request_threaded_irq(irq, NULL, regmap_irq_thread,
				   irq_flags | IRQF_ONESHOT,
@@ -935,6 +942,9 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,

err_domain:
	/* Should really dispose of the domain but... */
err_mutex:
	mutex_destroy(&d->lock);
	lockdep_unregister_key(&d->lock_key);
err_alloc:
	kfree(d->type_buf);
	kfree(d->type_buf_def);
@@ -1027,6 +1037,8 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
			kfree(d->config_buf[i]);
		kfree(d->config_buf);
	}
	mutex_destroy(&d->lock);
	lockdep_unregister_key(&d->lock_key);
	kfree(d);
}
EXPORT_SYMBOL_GPL(regmap_del_irq_chip);