* [PATCHv2] gpio: mvebu: keep resume masks within the irqchip cache
@ 2026-09-15 0:44 Rosen Penev
2026-09-15 6:43 ` Sebastian Andrzej Siewior
2026-09-17 9:52 ` Bartosz Golaszewski
0 siblings, 2 replies; 7+ messages in thread
From: Rosen Penev @ 2026-09-15 0:44 UTC (permalink / raw)
To: linux-gpio
Cc: Linus Walleij, Bartosz Golaszewski, Sebastian Andrzej Siewior,
Clark Williams, Steven Rostedt, open list,
open list:Real-time Linux (PREEMPT_RT):Keyword:PREEMPT_RT
mvebu_gpio_resume() writes the edge/level mask registers saved at
suspend time straight back to hardware, bypassing the irqchip's
mask_cache_priv. genirq skips mask_irq() for a line it already
considers masked, so restoring a bit in hardware that genirq thinks
is still masked leaves that line unmasked behind genirq's back. An
asserted level line then has nobody to ack it, and the moment
interrupts are re-enabled the chained handler storms, hanging resume.
AND the restored mask values with the matching irqchip mask cache so
only lines genirq currently considers unmasked are unmasked again.
Read the caches under gc->lock to keep them consistent with the
mask/unmask handlers.
Tested on Helios4 (armhf): 5 suspend cycles woken by magic packet,
no hang; mvebu_gpio_resume() returns in 6 usecs.
Assisted-by: LLM
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
v2: Unlock spinlock before regmap_write.
drivers/gpio/gpio-mvebu.c | 33 +++++++++++++++++++++++++++------
1 file changed, 27 insertions(+), 6 deletions(-)
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index c57758019e92..267e6d5bacd0 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -1049,6 +1049,8 @@ static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state)
static int mvebu_gpio_resume(struct platform_device *pdev)
{
struct mvebu_gpio_chip *mvchip = platform_get_drvdata(pdev);
+ u32 edge_cache = ~0U, level_cache = ~0U;
+ unsigned long flags;
int i;
regmap_write(mvchip->regs, GPIO_OUT_OFF + mvchip->offset,
@@ -1060,32 +1062,51 @@ static int mvebu_gpio_resume(struct platform_device *pdev)
regmap_write(mvchip->regs, GPIO_IN_POL_OFF + mvchip->offset,
mvchip->in_pol_reg);
+ /*
+ * genirq skips mask_irq() for a line it already considers masked, so
+ * unmasking one behind its back leaves an asserted level line that
+ * nobody masks. Restore only bits the irqchip cache still has set.
+ *
+ * Snapshot the caches under the raw spinlock, but release it before
+ * the regmap writes below: regmap_write() takes a sleepable lock on
+ * PREEMPT_RT.
+ */
+ if (mvchip->domain) {
+ struct irq_chip_generic *gc;
+
+ gc = irq_get_domain_generic_chip(mvchip->domain, 0);
+ raw_spin_lock_irqsave(&gc->lock, flags);
+ level_cache = gc->chip_types[0].mask_cache_priv;
+ edge_cache = gc->chip_types[1].mask_cache_priv;
+ raw_spin_unlock_irqrestore(&gc->lock, flags);
+ }
+
switch (mvchip->soc_variant) {
case MVEBU_GPIO_SOC_VARIANT_ORION:
case MVEBU_GPIO_SOC_VARIANT_A8K:
regmap_write(mvchip->regs, GPIO_EDGE_MASK_OFF + mvchip->offset,
- mvchip->edge_mask_regs[0]);
+ mvchip->edge_mask_regs[0] & edge_cache);
regmap_write(mvchip->regs, GPIO_LEVEL_MASK_OFF + mvchip->offset,
- mvchip->level_mask_regs[0]);
+ mvchip->level_mask_regs[0] & level_cache);
break;
case MVEBU_GPIO_SOC_VARIANT_MV78200:
for (i = 0; i < 2; i++) {
regmap_write(mvchip->regs,
GPIO_EDGE_MASK_MV78200_OFF(i),
- mvchip->edge_mask_regs[i]);
+ mvchip->edge_mask_regs[i] & edge_cache);
regmap_write(mvchip->regs,
GPIO_LEVEL_MASK_MV78200_OFF(i),
- mvchip->level_mask_regs[i]);
+ mvchip->level_mask_regs[i] & level_cache);
}
break;
case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
for (i = 0; i < 4; i++) {
regmap_write(mvchip->regs,
GPIO_EDGE_MASK_ARMADAXP_OFF(i),
- mvchip->edge_mask_regs[i]);
+ mvchip->edge_mask_regs[i] & edge_cache);
regmap_write(mvchip->regs,
GPIO_LEVEL_MASK_ARMADAXP_OFF(i),
- mvchip->level_mask_regs[i]);
+ mvchip->level_mask_regs[i] & level_cache);
}
break;
default:
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCHv2] gpio: mvebu: keep resume masks within the irqchip cache
2026-09-15 0:44 [PATCHv2] gpio: mvebu: keep resume masks within the irqchip cache Rosen Penev
@ 2026-09-15 6:43 ` Sebastian Andrzej Siewior
2026-09-15 22:24 ` Rosen Penev
2026-09-17 9:52 ` Bartosz Golaszewski
1 sibling, 1 reply; 7+ messages in thread
From: Sebastian Andrzej Siewior @ 2026-09-15 6:43 UTC (permalink / raw)
To: Rosen Penev
Cc: linux-gpio, Linus Walleij, Bartosz Golaszewski, Clark Williams,
Steven Rostedt, open list,
open list:Real-time Linux (PREEMPT_RT):Keyword:PREEMPT_RT
On 2026-09-14 17:44:06 [-0700], Rosen Penev wrote:
> mvebu_gpio_resume() writes the edge/level mask registers saved at
> suspend time straight back to hardware, bypassing the irqchip's
> mask_cache_priv. genirq skips mask_irq() for a line it already
> considers masked, so restoring a bit in hardware that genirq thinks
> is still masked leaves that line unmasked behind genirq's back. An
> asserted level line then has nobody to ack it, and the moment
> interrupts are re-enabled the chained handler storms, hanging resume.
Why is the mask value changed after suspend?
Sebastian
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCHv2] gpio: mvebu: keep resume masks within the irqchip cache
2026-09-15 6:43 ` Sebastian Andrzej Siewior
@ 2026-09-15 22:24 ` Rosen Penev
2026-09-16 6:55 ` Sebastian Andrzej Siewior
0 siblings, 1 reply; 7+ messages in thread
From: Rosen Penev @ 2026-09-15 22:24 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: linux-gpio, Linus Walleij, Bartosz Golaszewski, Clark Williams,
Steven Rostedt, open list,
open list:Real-time Linux (PREEMPT_RT):Keyword:PREEMPT_RT
On Mon, Sep 14, 2026 at 11:43 PM Sebastian Andrzej Siewior
<bigeasy@linutronix.de> wrote:
>
> On 2026-09-14 17:44:06 [-0700], Rosen Penev wrote:
> > mvebu_gpio_resume() writes the edge/level mask registers saved at
> > suspend time straight back to hardware, bypassing the irqchip's
> > mask_cache_priv. genirq skips mask_irq() for a line it already
> > considers masked, so restoring a bit in hardware that genirq thinks
> > is still masked leaves that line unmasked behind genirq's back. An
> > asserted level line then has nobody to ack it, and the moment
> > interrupts are re-enabled the chained handler storms, hanging resume.
>
> Why is the mask value changed after suspend?
In order to keep genirq and the hardware in sync.
>
> Sebastian
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCHv2] gpio: mvebu: keep resume masks within the irqchip cache
2026-09-15 22:24 ` Rosen Penev
@ 2026-09-16 6:55 ` Sebastian Andrzej Siewior
0 siblings, 0 replies; 7+ messages in thread
From: Sebastian Andrzej Siewior @ 2026-09-16 6:55 UTC (permalink / raw)
To: Rosen Penev
Cc: linux-gpio, Linus Walleij, Bartosz Golaszewski, Clark Williams,
Steven Rostedt, open list,
open list:Real-time Linux (PREEMPT_RT):Keyword:PREEMPT_RT
On 2026-09-15 15:24:24 [-0700], Rosen Penev wrote:
> On Mon, Sep 14, 2026 at 11:43 PM Sebastian Andrzej Siewior
> <bigeasy@linutronix.de> wrote:
> >
> > On 2026-09-14 17:44:06 [-0700], Rosen Penev wrote:
> > > mvebu_gpio_resume() writes the edge/level mask registers saved at
> > > suspend time straight back to hardware, bypassing the irqchip's
> > > mask_cache_priv. genirq skips mask_irq() for a line it already
> > > considers masked, so restoring a bit in hardware that genirq thinks
> > > is still masked leaves that line unmasked behind genirq's back. An
> > > asserted level line then has nobody to ack it, and the moment
> > > interrupts are re-enabled the chained handler storms, hanging resume.
> >
> > Why is the mask value changed after suspend?
> In order to keep genirq and the hardware in sync.
There seems to be write after suspend took place or before resume.
Sebastian
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCHv2] gpio: mvebu: keep resume masks within the irqchip cache
2026-09-15 0:44 [PATCHv2] gpio: mvebu: keep resume masks within the irqchip cache Rosen Penev
2026-09-15 6:43 ` Sebastian Andrzej Siewior
@ 2026-09-17 9:52 ` Bartosz Golaszewski
2026-09-17 10:04 ` Sebastian Andrzej Siewior
2026-09-17 23:14 ` Rosen Penev
1 sibling, 2 replies; 7+ messages in thread
From: Bartosz Golaszewski @ 2026-09-17 9:52 UTC (permalink / raw)
To: linux-gpio, Rosen Penev
Cc: Bartosz Golaszewski, Linus Walleij, Bartosz Golaszewski,
Sebastian Andrzej Siewior, Clark Williams, Steven Rostedt,
linux-kernel, linux-rt-devel
On Mon, 14 Sep 2026 17:44:06 -0700, Rosen Penev wrote:
> mvebu_gpio_resume() writes the edge/level mask registers saved at
> suspend time straight back to hardware, bypassing the irqchip's
> mask_cache_priv. genirq skips mask_irq() for a line it already
> considers masked, so restoring a bit in hardware that genirq thinks
> is still masked leaves that line unmasked behind genirq's back. An
> asserted level line then has nobody to ack it, and the moment
> interrupts are re-enabled the chained handler storms, hanging resume.
>
> [...]
Applied, thanks!
[1/1] gpio: mvebu: keep resume masks within the irqchip cache
https://git.kernel.org/brgl/c/02af7eac17bc62a72335c1fc8c4af4471654f6cc
Best regards,
--
Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCHv2] gpio: mvebu: keep resume masks within the irqchip cache
2026-09-17 9:52 ` Bartosz Golaszewski
@ 2026-09-17 10:04 ` Sebastian Andrzej Siewior
2026-09-17 23:14 ` Rosen Penev
1 sibling, 0 replies; 7+ messages in thread
From: Sebastian Andrzej Siewior @ 2026-09-17 10:04 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: linux-gpio, Rosen Penev, Linus Walleij, Bartosz Golaszewski,
Clark Williams, Steven Rostedt, linux-kernel, linux-rt-devel
On 2026-09-17 11:52:29 [+0200], Bartosz Golaszewski wrote:
> Applied, thanks!
This looks like a hack with no explanation about the root cause.
> [1/1] gpio: mvebu: keep resume masks within the irqchip cache
> https://git.kernel.org/brgl/c/02af7eac17bc62a72335c1fc8c4af4471654f6cc
Sebastian
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCHv2] gpio: mvebu: keep resume masks within the irqchip cache
2026-09-17 9:52 ` Bartosz Golaszewski
2026-09-17 10:04 ` Sebastian Andrzej Siewior
@ 2026-09-17 23:14 ` Rosen Penev
1 sibling, 0 replies; 7+ messages in thread
From: Rosen Penev @ 2026-09-17 23:14 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: linux-gpio, Linus Walleij, Bartosz Golaszewski,
Sebastian Andrzej Siewior, Clark Williams, Steven Rostedt,
linux-kernel, linux-rt-devel
On Thu, Sep 17, 2026 at 2:52 AM Bartosz Golaszewski
<bartosz.golaszewski@oss.qualcomm.com> wrote:
>
>
> On Mon, 14 Sep 2026 17:44:06 -0700, Rosen Penev wrote:
> > mvebu_gpio_resume() writes the edge/level mask registers saved at
> > suspend time straight back to hardware, bypassing the irqchip's
> > mask_cache_priv. genirq skips mask_irq() for a line it already
> > considers masked, so restoring a bit in hardware that genirq thinks
> > is still masked leaves that line unmasked behind genirq's back. An
> > asserted level line then has nobody to ack it, and the moment
> > interrupts are re-enabled the chained handler storms, hanging resume.
> >
> > [...]
>
> Applied, thanks!
>
> [1/1] gpio: mvebu: keep resume masks within the irqchip cache
> https://git.kernel.org/brgl/c/02af7eac17bc62a72335c1fc8c4af4471654f6cc
hrm unfortunate. I had a v3 ready for this one to fix sashiko's issue.
I guess I'll send it separately.
>
> Best regards,
> --
> Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-09-17 23:14 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-15 0:44 [PATCHv2] gpio: mvebu: keep resume masks within the irqchip cache Rosen Penev
2026-09-15 6:43 ` Sebastian Andrzej Siewior
2026-09-15 22:24 ` Rosen Penev
2026-09-16 6:55 ` Sebastian Andrzej Siewior
2026-09-17 9:52 ` Bartosz Golaszewski
2026-09-17 10:04 ` Sebastian Andrzej Siewior
2026-09-17 23:14 ` Rosen Penev
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox