Commit 26fda92d authored by Marek Vasut's avatar Marek Vasut Committed by Bjorn Helgaas
Browse files

PCI: tegra: Convert struct tegra_msi mask_lock into raw spinlock



The tegra_msi_irq_unmask() function may be called from a PCI driver
request_threaded_irq() function. This triggers kernel/irq/manage.c
__setup_irq() which locks raw spinlock &desc->lock descriptor lock
and with that descriptor lock held, calls tegra_msi_irq_unmask().

Since the &desc->lock descriptor lock is a raw spinlock, and the tegra_msi
.mask_lock is not a raw spinlock, this setup triggers 'BUG: Invalid wait
context' with CONFIG_PROVE_RAW_LOCK_NESTING=y.

Use scoped_guard() to simplify the locking.

Fixes: 2c99e55f ("PCI: tegra: Convert to MSI domains")
Reported-by: default avatarGeert Uytterhoeven <geert+renesas@glider.be>
Closes: https://patchwork.kernel.org/project/linux-pci/patch/20250909162707.13927-2-marek.vasut+renesas@mailbox.org/#26574451


Signed-off-by: default avatarMarek Vasut <marek.vasut+renesas@mailbox.org>
Signed-off-by: default avatarManivannan Sadhasivam <mani@kernel.org>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20250922150811.88450-1-marek.vasut+renesas@mailbox.org
parent 4f152338
Loading
Loading
Loading
Loading
+13 −14
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
 */

#include <linux/clk.h>
#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/export.h>
@@ -270,7 +271,7 @@ struct tegra_msi {
	DECLARE_BITMAP(used, INT_PCI_MSI_NR);
	struct irq_domain *domain;
	struct mutex map_lock;
	spinlock_t mask_lock;
	raw_spinlock_t mask_lock;
	void *virt;
	dma_addr_t phys;
	int irq;
@@ -1581,14 +1582,13 @@ static void tegra_msi_irq_mask(struct irq_data *d)
	struct tegra_msi *msi = irq_data_get_irq_chip_data(d);
	struct tegra_pcie *pcie = msi_to_pcie(msi);
	unsigned int index = d->hwirq / 32;
	unsigned long flags;
	u32 value;

	spin_lock_irqsave(&msi->mask_lock, flags);
	scoped_guard(raw_spinlock_irqsave, &msi->mask_lock) {
		value = afi_readl(pcie, AFI_MSI_EN_VEC(index));
		value &= ~BIT(d->hwirq % 32);
		afi_writel(pcie, value, AFI_MSI_EN_VEC(index));
	spin_unlock_irqrestore(&msi->mask_lock, flags);
	}
}

static void tegra_msi_irq_unmask(struct irq_data *d)
@@ -1596,14 +1596,13 @@ static void tegra_msi_irq_unmask(struct irq_data *d)
	struct tegra_msi *msi = irq_data_get_irq_chip_data(d);
	struct tegra_pcie *pcie = msi_to_pcie(msi);
	unsigned int index = d->hwirq / 32;
	unsigned long flags;
	u32 value;

	spin_lock_irqsave(&msi->mask_lock, flags);
	scoped_guard(raw_spinlock_irqsave, &msi->mask_lock) {
		value = afi_readl(pcie, AFI_MSI_EN_VEC(index));
		value |= BIT(d->hwirq % 32);
		afi_writel(pcie, value, AFI_MSI_EN_VEC(index));
	spin_unlock_irqrestore(&msi->mask_lock, flags);
	}
}

static void tegra_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
@@ -1711,7 +1710,7 @@ static int tegra_pcie_msi_setup(struct tegra_pcie *pcie)
	int err;

	mutex_init(&msi->map_lock);
	spin_lock_init(&msi->mask_lock);
	raw_spin_lock_init(&msi->mask_lock);

	if (IS_ENABLED(CONFIG_PCI_MSI)) {
		err = tegra_allocate_domains(msi);