linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] Fix kernel splats on boot with armada-37xx irqchip driver
@ 2022-07-16 23:37 Vladimir Oltean
  2022-07-16 23:37 ` [PATCH 1/2] pinctrl: armada-37xx: make irq_lock a raw spinlock to avoid invalid wait context Vladimir Oltean
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Vladimir Oltean @ 2022-07-16 23:37 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Linus Walleij, linux-gpio, linux-kernel, Marek Behún,
	Pali Rohár

Due to these splats on boot, lockdep disables itself on Armada 37xx and
we fail to see further useful information about real deadlocks.

For those in doubt, the approach to use raw spinlocks for irqchip
drivers has been previously discussed here and doesn't seem too
controversial.
https://lore.kernel.org/lkml/20210825205041.927788-1-vladimir.oltean@nxp.com/

Tested on the Turris MOX board.

Vladimir Oltean (2):
  pinctrl: armada-37xx: make irq_lock a raw spinlock to avoid invalid
    wait context
  pinctrl: armada-37xx: use raw spinlocks for regmap to avoid invalid
    wait context

 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c | 65 +++++++++++++--------
 1 file changed, 40 insertions(+), 25 deletions(-)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] pinctrl: armada-37xx: make irq_lock a raw spinlock to avoid invalid wait context
  2022-07-16 23:37 [PATCH 0/2] Fix kernel splats on boot with armada-37xx irqchip driver Vladimir Oltean
@ 2022-07-16 23:37 ` Vladimir Oltean
  2022-07-16 23:37 ` [PATCH 2/2] pinctrl: armada-37xx: use raw spinlocks for regmap " Vladimir Oltean
  2022-07-18 13:43 ` [PATCH 0/2] Fix kernel splats on boot with armada-37xx irqchip driver Linus Walleij
  2 siblings, 0 replies; 5+ messages in thread
From: Vladimir Oltean @ 2022-07-16 23:37 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Linus Walleij, linux-gpio, linux-kernel, Marek Behún,
	Pali Rohár

The irqchip->irq_set_type method is called by __irq_set_trigger() under
the desc->lock raw spinlock.

The armada-37xx implementation, armada_37xx_irq_set_type(), takes a
plain spinlock, the kind that becomes sleepable on RT.

Therefore, this is an invalid locking scheme for which we get a kernel
splat stating just that ("[ BUG: Invalid wait context ]"), because the
context in which the plain spinlock may sleep is atomic due to the raw
spinlock. We need to go raw spinlocks all the way.

Replace the driver's irq_lock with a raw spinlock, to disable preemption
even on RT.

Fixes: 2f227605394b ("pinctrl: armada-37xx: Add irqchip support")
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c | 38 ++++++++++-----------
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
index a140b6bfbfaa..8fddc67271b4 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
@@ -102,7 +102,7 @@ struct armada_37xx_pinctrl {
 	struct device			*dev;
 	struct gpio_chip		gpio_chip;
 	struct irq_chip			irq_chip;
-	spinlock_t			irq_lock;
+	raw_spinlock_t			irq_lock;
 	struct pinctrl_desc		pctl;
 	struct pinctrl_dev		*pctl_dev;
 	struct armada_37xx_pin_group	*groups;
@@ -523,9 +523,9 @@ static void armada_37xx_irq_ack(struct irq_data *d)
 	unsigned long flags;
 
 	armada_37xx_irq_update_reg(&reg, d);
-	spin_lock_irqsave(&info->irq_lock, flags);
+	raw_spin_lock_irqsave(&info->irq_lock, flags);
 	writel(d->mask, info->base + reg);
-	spin_unlock_irqrestore(&info->irq_lock, flags);
+	raw_spin_unlock_irqrestore(&info->irq_lock, flags);
 }
 
 static void armada_37xx_irq_mask(struct irq_data *d)
@@ -536,10 +536,10 @@ static void armada_37xx_irq_mask(struct irq_data *d)
 	unsigned long flags;
 
 	armada_37xx_irq_update_reg(&reg, d);
-	spin_lock_irqsave(&info->irq_lock, flags);
+	raw_spin_lock_irqsave(&info->irq_lock, flags);
 	val = readl(info->base + reg);
 	writel(val & ~d->mask, info->base + reg);
-	spin_unlock_irqrestore(&info->irq_lock, flags);
+	raw_spin_unlock_irqrestore(&info->irq_lock, flags);
 }
 
 static void armada_37xx_irq_unmask(struct irq_data *d)
@@ -550,10 +550,10 @@ static void armada_37xx_irq_unmask(struct irq_data *d)
 	unsigned long flags;
 
 	armada_37xx_irq_update_reg(&reg, d);
-	spin_lock_irqsave(&info->irq_lock, flags);
+	raw_spin_lock_irqsave(&info->irq_lock, flags);
 	val = readl(info->base + reg);
 	writel(val | d->mask, info->base + reg);
-	spin_unlock_irqrestore(&info->irq_lock, flags);
+	raw_spin_unlock_irqrestore(&info->irq_lock, flags);
 }
 
 static int armada_37xx_irq_set_wake(struct irq_data *d, unsigned int on)
@@ -564,14 +564,14 @@ static int armada_37xx_irq_set_wake(struct irq_data *d, unsigned int on)
 	unsigned long flags;
 
 	armada_37xx_irq_update_reg(&reg, d);
-	spin_lock_irqsave(&info->irq_lock, flags);
+	raw_spin_lock_irqsave(&info->irq_lock, flags);
 	val = readl(info->base + reg);
 	if (on)
 		val |= (BIT(d->hwirq % GPIO_PER_REG));
 	else
 		val &= ~(BIT(d->hwirq % GPIO_PER_REG));
 	writel(val, info->base + reg);
-	spin_unlock_irqrestore(&info->irq_lock, flags);
+	raw_spin_unlock_irqrestore(&info->irq_lock, flags);
 
 	return 0;
 }
@@ -583,7 +583,7 @@ static int armada_37xx_irq_set_type(struct irq_data *d, unsigned int type)
 	u32 val, reg = IRQ_POL;
 	unsigned long flags;
 
-	spin_lock_irqsave(&info->irq_lock, flags);
+	raw_spin_lock_irqsave(&info->irq_lock, flags);
 	armada_37xx_irq_update_reg(&reg, d);
 	val = readl(info->base + reg);
 	switch (type) {
@@ -607,11 +607,11 @@ static int armada_37xx_irq_set_type(struct irq_data *d, unsigned int type)
 		break;
 	}
 	default:
-		spin_unlock_irqrestore(&info->irq_lock, flags);
+		raw_spin_unlock_irqrestore(&info->irq_lock, flags);
 		return -EINVAL;
 	}
 	writel(val, info->base + reg);
-	spin_unlock_irqrestore(&info->irq_lock, flags);
+	raw_spin_unlock_irqrestore(&info->irq_lock, flags);
 
 	return 0;
 }
@@ -626,7 +626,7 @@ static int armada_37xx_edge_both_irq_swap_pol(struct armada_37xx_pinctrl *info,
 
 	regmap_read(info->regmap, INPUT_VAL + 4*reg_idx, &l);
 
-	spin_lock_irqsave(&info->irq_lock, flags);
+	raw_spin_lock_irqsave(&info->irq_lock, flags);
 	p = readl(info->base + IRQ_POL + 4 * reg_idx);
 	if ((p ^ l) & (1 << bit_num)) {
 		/*
@@ -647,7 +647,7 @@ static int armada_37xx_edge_both_irq_swap_pol(struct armada_37xx_pinctrl *info,
 		ret = -1;
 	}
 
-	spin_unlock_irqrestore(&info->irq_lock, flags);
+	raw_spin_unlock_irqrestore(&info->irq_lock, flags);
 	return ret;
 }
 
@@ -664,11 +664,11 @@ static void armada_37xx_irq_handler(struct irq_desc *desc)
 		u32 status;
 		unsigned long flags;
 
-		spin_lock_irqsave(&info->irq_lock, flags);
+		raw_spin_lock_irqsave(&info->irq_lock, flags);
 		status = readl_relaxed(info->base + IRQ_STATUS + 4 * i);
 		/* Manage only the interrupt that was enabled */
 		status &= readl_relaxed(info->base + IRQ_EN + 4 * i);
-		spin_unlock_irqrestore(&info->irq_lock, flags);
+		raw_spin_unlock_irqrestore(&info->irq_lock, flags);
 		while (status) {
 			u32 hwirq = ffs(status) - 1;
 			u32 virq = irq_find_mapping(d, hwirq +
@@ -695,12 +695,12 @@ static void armada_37xx_irq_handler(struct irq_desc *desc)
 
 update_status:
 			/* Update status in case a new IRQ appears */
-			spin_lock_irqsave(&info->irq_lock, flags);
+			raw_spin_lock_irqsave(&info->irq_lock, flags);
 			status = readl_relaxed(info->base +
 					       IRQ_STATUS + 4 * i);
 			/* Manage only the interrupt that was enabled */
 			status &= readl_relaxed(info->base + IRQ_EN + 4 * i);
-			spin_unlock_irqrestore(&info->irq_lock, flags);
+			raw_spin_unlock_irqrestore(&info->irq_lock, flags);
 		}
 	}
 	chained_irq_exit(chip, desc);
@@ -731,7 +731,7 @@ static int armada_37xx_irqchip_register(struct platform_device *pdev,
 	struct device *dev = &pdev->dev;
 	unsigned int i, nr_irq_parent;
 
-	spin_lock_init(&info->irq_lock);
+	raw_spin_lock_init(&info->irq_lock);
 
 	nr_irq_parent = of_irq_count(np);
 	if (!nr_irq_parent) {
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] pinctrl: armada-37xx: use raw spinlocks for regmap to avoid invalid wait context
  2022-07-16 23:37 [PATCH 0/2] Fix kernel splats on boot with armada-37xx irqchip driver Vladimir Oltean
  2022-07-16 23:37 ` [PATCH 1/2] pinctrl: armada-37xx: make irq_lock a raw spinlock to avoid invalid wait context Vladimir Oltean
@ 2022-07-16 23:37 ` Vladimir Oltean
  2022-07-18 13:43 ` [PATCH 0/2] Fix kernel splats on boot with armada-37xx irqchip driver Linus Walleij
  2 siblings, 0 replies; 5+ messages in thread
From: Vladimir Oltean @ 2022-07-16 23:37 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Linus Walleij, linux-gpio, linux-kernel, Marek Behún,
	Pali Rohár

The irqchip->irq_set_type method is called by __irq_set_trigger() under
the desc->lock raw spinlock.

The armada-37xx implementation, armada_37xx_irq_set_type(), uses an MMIO
regmap created by of_syscon_register(), which uses plain spinlocks
(the kind that are sleepable on RT).

Therefore, this is an invalid locking scheme for which we get a kernel
splat stating just that ("[ BUG: Invalid wait context ]"), because the
context in which the plain spinlock may sleep is atomic due to the raw
spinlock. We need to go raw spinlocks all the way.

Make this driver create its own MMIO regmap, with use_raw_spinlock=true,
and stop relying on syscon to provide it.

This patch depends on commit 67021f25d952 ("regmap: teach regmap to use
raw spinlocks if requested in the config").

Fixes: 2f227605394b ("pinctrl: armada-37xx: Add irqchip support")
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c | 27 ++++++++++++++++-----
 1 file changed, 21 insertions(+), 6 deletions(-)

diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
index 8fddc67271b4..bcde042d29dc 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
@@ -1107,25 +1107,40 @@ static const struct of_device_id armada_37xx_pinctrl_of_match[] = {
 	{ },
 };
 
+static const struct regmap_config armada_37xx_pinctrl_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.use_raw_spinlock = true,
+};
+
 static int __init armada_37xx_pinctrl_probe(struct platform_device *pdev)
 {
 	struct armada_37xx_pinctrl *info;
 	struct device *dev = &pdev->dev;
-	struct device_node *np = dev->of_node;
 	struct regmap *regmap;
+	void __iomem *base;
 	int ret;
 
+	base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(base)) {
+		dev_err(dev, "failed to ioremap base address: %pe\n", base);
+		return PTR_ERR(base);
+	}
+
+	regmap = devm_regmap_init_mmio(dev, base,
+				       &armada_37xx_pinctrl_regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(dev, "failed to create regmap: %pe\n", regmap);
+		return PTR_ERR(regmap);
+	}
+
 	info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
 	if (!info)
 		return -ENOMEM;
 
 	info->dev = dev;
-
-	regmap = syscon_node_to_regmap(np);
-	if (IS_ERR(regmap))
-		return dev_err_probe(dev, PTR_ERR(regmap), "cannot get regmap\n");
 	info->regmap = regmap;
-
 	info->data = of_device_get_match_data(dev);
 
 	ret = armada_37xx_pinctrl_register(pdev, info);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 0/2] Fix kernel splats on boot with armada-37xx irqchip driver
  2022-07-16 23:37 [PATCH 0/2] Fix kernel splats on boot with armada-37xx irqchip driver Vladimir Oltean
  2022-07-16 23:37 ` [PATCH 1/2] pinctrl: armada-37xx: make irq_lock a raw spinlock to avoid invalid wait context Vladimir Oltean
  2022-07-16 23:37 ` [PATCH 2/2] pinctrl: armada-37xx: use raw spinlocks for regmap " Vladimir Oltean
@ 2022-07-18 13:43 ` Linus Walleij
  2022-07-18 14:06   ` Vladimir Oltean
  2 siblings, 1 reply; 5+ messages in thread
From: Linus Walleij @ 2022-07-18 13:43 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: linux-arm-kernel, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, linux-gpio, linux-kernel,
	Marek Behún, Pali Rohár

On Sun, Jul 17, 2022 at 1:38 AM Vladimir Oltean <vladimir.oltean@nxp.com> wrote:

> Due to these splats on boot, lockdep disables itself on Armada 37xx and
> we fail to see further useful information about real deadlocks.
>
> For those in doubt, the approach to use raw spinlocks for irqchip
> drivers has been previously discussed here and doesn't seem too
> controversial.
> https://lore.kernel.org/lkml/20210825205041.927788-1-vladimir.oltean@nxp.com/
>
> Tested on the Turris MOX board.
>
> Vladimir Oltean (2):
>   pinctrl: armada-37xx: make irq_lock a raw spinlock to avoid invalid
>     wait context
>   pinctrl: armada-37xx: use raw spinlocks for regmap to avoid invalid
>     wait context

Patches applied for fixes so they get some rotation in linux-next.

Reviewers have some days to react before I send this to Torvalds.

Should these even be tagged for stable?

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 0/2] Fix kernel splats on boot with armada-37xx irqchip driver
  2022-07-18 13:43 ` [PATCH 0/2] Fix kernel splats on boot with armada-37xx irqchip driver Linus Walleij
@ 2022-07-18 14:06   ` Vladimir Oltean
  0 siblings, 0 replies; 5+ messages in thread
From: Vladimir Oltean @ 2022-07-18 14:06 UTC (permalink / raw)
  To: Linus Walleij
  Cc: linux-arm-kernel, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, linux-gpio, linux-kernel,
	Marek Behún, Pali Rohár

Hi Linus,

On Mon, Jul 18, 2022 at 03:43:19PM +0200, Linus Walleij wrote:
> Patches applied for fixes so they get some rotation in linux-next.
> 
> Reviewers have some days to react before I send this to Torvalds.

Thanks for doing that.

> Should these even be tagged for stable?

They could.

This specific lockdep check was introduced in commit de8f5e4f2dc1
("lockdep: Introduce wait-type checks") which appeared in v5.7.

The fixes depend upon commit 67021f25d952 ("regmap: teach regmap to
use raw spinlocks if requested in the config") which appeared in v5.15.

So at least the stable 5.15 and 5.18 kernels can benefit if lockdep is
being used - that's without any extra burden of backporting the regmap
dependency commit itself any further.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2022-07-18 14:07 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-16 23:37 [PATCH 0/2] Fix kernel splats on boot with armada-37xx irqchip driver Vladimir Oltean
2022-07-16 23:37 ` [PATCH 1/2] pinctrl: armada-37xx: make irq_lock a raw spinlock to avoid invalid wait context Vladimir Oltean
2022-07-16 23:37 ` [PATCH 2/2] pinctrl: armada-37xx: use raw spinlocks for regmap " Vladimir Oltean
2022-07-18 13:43 ` [PATCH 0/2] Fix kernel splats on boot with armada-37xx irqchip driver Linus Walleij
2022-07-18 14:06   ` Vladimir Oltean

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).