All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] gpio: mvebu: convert to noirq suspend/resume to prevent interrupt storm on resume
@ 2026-07-07 23:35 Rosen Penev
  2026-07-08 12:11 ` Bartosz Golaszewski
  2026-08-04 15:15 ` kernel test robot
  0 siblings, 2 replies; 5+ messages in thread
From: Rosen Penev @ 2026-07-07 23:35 UTC (permalink / raw)
  To: linux-gpio; +Cc: Linus Walleij, Bartosz Golaszewski, open list

The driver uses the legacy .suspend/.resume callbacks, but sets
IRQCHIP_MASK_ON_SUSPEND on the irq_chip. During resume, the PM core
runs dpm_resume_noirq() first, which calls irq_pm_resume() to unmask
interrupts, and only then runs dpm_resume() which invokes the driver's
.resume callback to restore GPIO registers (GPIO_IN_POL, GPIO_IO_CONF,
mask registers).

This ordering means interrupts are unmasked while the hardware is still
in its reset state, potentially with incorrect polarities, causing
spurious level-triggered interrupts before local IRQs are re-enabled.

Convert the driver from legacy .suspend/.resume callbacks to noirq
callbacks via dev_pm_ops. The noirq phase runs before resume_device_irqs()
on resume and after suspend_device_irqs() on suspend, ensuring GPIO
registers are restored before interrupts are unmasked.

Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
 drivers/gpio/gpio-mvebu.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index a556fdb267a9..1df763e60726 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -979,9 +979,9 @@ static const struct of_device_id mvebu_gpio_of_match[] = {
 	},
 };
 
-static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state)
+static int mvebu_gpio_suspend(struct device *dev)
 {
-	struct mvebu_gpio_chip *mvchip = platform_get_drvdata(pdev);
+	struct mvebu_gpio_chip *mvchip = dev_get_drvdata(dev);
 	int i;
 
 	regmap_read(mvchip->regs, GPIO_OUT_OFF + mvchip->offset,
@@ -1031,9 +1031,9 @@ static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state)
 	return 0;
 }
 
-static int mvebu_gpio_resume(struct platform_device *pdev)
+static int mvebu_gpio_resume(struct device *dev)
 {
-	struct mvebu_gpio_chip *mvchip = platform_get_drvdata(pdev);
+	struct mvebu_gpio_chip *mvchip = dev_get_drvdata(dev);
 	int i;
 
 	regmap_write(mvchip->regs, GPIO_OUT_OFF + mvchip->offset,
@@ -1338,13 +1338,16 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct dev_pm_ops mvebu_gpio_pm_ops = {
+	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mvebu_gpio_suspend, mvebu_gpio_resume)
+};
+
 static struct platform_driver mvebu_gpio_driver = {
 	.driver		= {
 		.name		= "mvebu-gpio",
 		.of_match_table = mvebu_gpio_of_match,
+		.pm		= pm_sleep_ptr(&mvebu_gpio_pm_ops),
 	},
 	.probe		= mvebu_gpio_probe,
-	.suspend        = mvebu_gpio_suspend,
-	.resume         = mvebu_gpio_resume,
 };
 builtin_platform_driver(mvebu_gpio_driver);
-- 
2.55.0


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

* Re: [PATCH] gpio: mvebu: convert to noirq suspend/resume to prevent interrupt storm on resume
  2026-07-07 23:35 [PATCH] gpio: mvebu: convert to noirq suspend/resume to prevent interrupt storm on resume Rosen Penev
@ 2026-07-08 12:11 ` Bartosz Golaszewski
  2026-07-08 19:19   ` Rosen Penev
  2026-08-04 15:15 ` kernel test robot
  1 sibling, 1 reply; 5+ messages in thread
From: Bartosz Golaszewski @ 2026-07-08 12:11 UTC (permalink / raw)
  To: Rosen Penev; +Cc: Linus Walleij, Bartosz Golaszewski, open list, linux-gpio

On Wed, 8 Jul 2026 01:35:11 +0200, Rosen Penev <rosenp@gmail.com> said:
> The driver uses the legacy .suspend/.resume callbacks, but sets
> IRQCHIP_MASK_ON_SUSPEND on the irq_chip. During resume, the PM core
> runs dpm_resume_noirq() first, which calls irq_pm_resume() to unmask
> interrupts, and only then runs dpm_resume() which invokes the driver's
> .resume callback to restore GPIO registers (GPIO_IN_POL, GPIO_IO_CONF,
> mask registers).
>
> This ordering means interrupts are unmasked while the hardware is still
> in its reset state, potentially with incorrect polarities, causing
> spurious level-triggered interrupts before local IRQs are re-enabled.
>
> Convert the driver from legacy .suspend/.resume callbacks to noirq
> callbacks via dev_pm_ops. The noirq phase runs before resume_device_irqs()
> on resume and after suspend_device_irqs() on suspend, ensuring GPIO
> registers are restored before interrupts are unmasked.
>
> Assisted-by: opencode:big-pickle
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
> ---
>  drivers/gpio/gpio-mvebu.c | 15 +++++++++------
>  1 file changed, 9 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
> index a556fdb267a9..1df763e60726 100644
> --- a/drivers/gpio/gpio-mvebu.c
> +++ b/drivers/gpio/gpio-mvebu.c
> @@ -979,9 +979,9 @@ static const struct of_device_id mvebu_gpio_of_match[] = {
>  	},
>  };
>
> -static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state)
> +static int mvebu_gpio_suspend(struct device *dev)

Needs __maybe_unused for SET_NOIRQ_SYSTEM_SLEEP_PM_OPS().

Bart

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

* Re: [PATCH] gpio: mvebu: convert to noirq suspend/resume to prevent interrupt storm on resume
  2026-07-08 12:11 ` Bartosz Golaszewski
@ 2026-07-08 19:19   ` Rosen Penev
  2026-07-09  8:07     ` Bartosz Golaszewski
  0 siblings, 1 reply; 5+ messages in thread
From: Rosen Penev @ 2026-07-08 19:19 UTC (permalink / raw)
  To: Bartosz Golaszewski; +Cc: Linus Walleij, open list, linux-gpio

On Wed, Jul 8, 2026 at 5:11 AM Bartosz Golaszewski <brgl@kernel.org> wrote:
>
> On Wed, 8 Jul 2026 01:35:11 +0200, Rosen Penev <rosenp@gmail.com> said:
> > The driver uses the legacy .suspend/.resume callbacks, but sets
> > IRQCHIP_MASK_ON_SUSPEND on the irq_chip. During resume, the PM core
> > runs dpm_resume_noirq() first, which calls irq_pm_resume() to unmask
> > interrupts, and only then runs dpm_resume() which invokes the driver's
> > .resume callback to restore GPIO registers (GPIO_IN_POL, GPIO_IO_CONF,
> > mask registers).
> >
> > This ordering means interrupts are unmasked while the hardware is still
> > in its reset state, potentially with incorrect polarities, causing
> > spurious level-triggered interrupts before local IRQs are re-enabled.
> >
> > Convert the driver from legacy .suspend/.resume callbacks to noirq
> > callbacks via dev_pm_ops. The noirq phase runs before resume_device_irqs()
> > on resume and after suspend_device_irqs() on suspend, ensuring GPIO
> > registers are restored before interrupts are unmasked.
> >
> > Assisted-by: opencode:big-pickle
> > Signed-off-by: Rosen Penev <rosenp@gmail.com>
> > ---
> >  drivers/gpio/gpio-mvebu.c | 15 +++++++++------
> >  1 file changed, 9 insertions(+), 6 deletions(-)
> >
> > diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
> > index a556fdb267a9..1df763e60726 100644
> > --- a/drivers/gpio/gpio-mvebu.c
> > +++ b/drivers/gpio/gpio-mvebu.c
> > @@ -979,9 +979,9 @@ static const struct of_device_id mvebu_gpio_of_match[] = {
> >       },
> >  };
> >
> > -static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state)
> > +static int mvebu_gpio_suspend(struct device *dev)
>
> Needs __maybe_unused for SET_NOIRQ_SYSTEM_SLEEP_PM_OPS().
I see __maybe_unused and #ifdef for code like this. Which is prefered?
>
> Bart

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

* Re: [PATCH] gpio: mvebu: convert to noirq suspend/resume to prevent interrupt storm on resume
  2026-07-08 19:19   ` Rosen Penev
@ 2026-07-09  8:07     ` Bartosz Golaszewski
  0 siblings, 0 replies; 5+ messages in thread
From: Bartosz Golaszewski @ 2026-07-09  8:07 UTC (permalink / raw)
  To: Rosen Penev; +Cc: Linus Walleij, open list, linux-gpio, Bartosz Golaszewski

On Wed, 8 Jul 2026 21:19:17 +0200, Rosen Penev <rosenp@gmail.com> said:
> On Wed, Jul 8, 2026 at 5:11 AM Bartosz Golaszewski <brgl@kernel.org> wrote:
>>
>> On Wed, 8 Jul 2026 01:35:11 +0200, Rosen Penev <rosenp@gmail.com> said:
>> > The driver uses the legacy .suspend/.resume callbacks, but sets
>> > IRQCHIP_MASK_ON_SUSPEND on the irq_chip. During resume, the PM core
>> > runs dpm_resume_noirq() first, which calls irq_pm_resume() to unmask
>> > interrupts, and only then runs dpm_resume() which invokes the driver's
>> > .resume callback to restore GPIO registers (GPIO_IN_POL, GPIO_IO_CONF,
>> > mask registers).
>> >
>> > This ordering means interrupts are unmasked while the hardware is still
>> > in its reset state, potentially with incorrect polarities, causing
>> > spurious level-triggered interrupts before local IRQs are re-enabled.
>> >
>> > Convert the driver from legacy .suspend/.resume callbacks to noirq
>> > callbacks via dev_pm_ops. The noirq phase runs before resume_device_irqs()
>> > on resume and after suspend_device_irqs() on suspend, ensuring GPIO
>> > registers are restored before interrupts are unmasked.
>> >
>> > Assisted-by: opencode:big-pickle
>> > Signed-off-by: Rosen Penev <rosenp@gmail.com>
>> > ---
>> >  drivers/gpio/gpio-mvebu.c | 15 +++++++++------
>> >  1 file changed, 9 insertions(+), 6 deletions(-)
>> >
>> > diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
>> > index a556fdb267a9..1df763e60726 100644
>> > --- a/drivers/gpio/gpio-mvebu.c
>> > +++ b/drivers/gpio/gpio-mvebu.c
>> > @@ -979,9 +979,9 @@ static const struct of_device_id mvebu_gpio_of_match[] = {
>> >       },
>> >  };
>> >
>> > -static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state)
>> > +static int mvebu_gpio_suspend(struct device *dev)
>>
>> Needs __maybe_unused for SET_NOIRQ_SYSTEM_SLEEP_PM_OPS().
> I see __maybe_unused and #ifdef for code like this. Which is prefered?

__maybe_unused is cleaner. Please add some newlines between quoted parts of
your emails and your responses for better readability. I'm finding myself
looking for where your response starts.

Bart

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

* Re: [PATCH] gpio: mvebu: convert to noirq suspend/resume to prevent interrupt storm on resume
  2026-07-07 23:35 [PATCH] gpio: mvebu: convert to noirq suspend/resume to prevent interrupt storm on resume Rosen Penev
  2026-07-08 12:11 ` Bartosz Golaszewski
@ 2026-08-04 15:15 ` kernel test robot
  1 sibling, 0 replies; 5+ messages in thread
From: kernel test robot @ 2026-08-04 15:15 UTC (permalink / raw)
  To: Rosen Penev, linux-gpio
  Cc: oe-kbuild-all, Linus Walleij, Bartosz Golaszewski, linux-kernel

Hi Rosen,

kernel test robot noticed the following build warnings:

[auto build test WARNING on brgl/gpio/for-next]
[also build test WARNING on linusw-pinctrl/devel linusw-pinctrl/for-next linus/master v7.2-rc6 next-20260803]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Rosen-Penev/gpio-mvebu-convert-to-noirq-suspend-resume-to-prevent-interrupt-storm-on-resume/20260804-155102
base:   https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio/for-next
patch link:    https://lore.kernel.org/r/20260707233511.1272686-1-rosenp%40gmail.com
patch subject: [PATCH] gpio: mvebu: convert to noirq suspend/resume to prevent interrupt storm on resume
config: alpha-allmodconfig (https://download.01.org/0day-ci/archive/20260804/202608042358.6rKawjZd-lkp@intel.com/config)
compiler: alpha-linux-gcc (GCC) 16.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260804/202608042358.6rKawjZd-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202608042358.6rKawjZd-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/gpio/gpio-mvebu.c:1034:12: warning: 'mvebu_gpio_resume' defined but not used [-Wunused-function]
    1034 | static int mvebu_gpio_resume(struct device *dev)
         |            ^~~~~~~~~~~~~~~~~
>> drivers/gpio/gpio-mvebu.c:982:12: warning: 'mvebu_gpio_suspend' defined but not used [-Wunused-function]
     982 | static int mvebu_gpio_suspend(struct device *dev)
         |            ^~~~~~~~~~~~~~~~~~


vim +/mvebu_gpio_resume +1034 drivers/gpio/gpio-mvebu.c

   981	
 > 982	static int mvebu_gpio_suspend(struct device *dev)
   983	{
   984		struct mvebu_gpio_chip *mvchip = dev_get_drvdata(dev);
   985		int i;
   986	
   987		regmap_read(mvchip->regs, GPIO_OUT_OFF + mvchip->offset,
   988			    &mvchip->out_reg);
   989		regmap_read(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset,
   990			    &mvchip->io_conf_reg);
   991		regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset,
   992			    &mvchip->blink_en_reg);
   993		regmap_read(mvchip->regs, GPIO_IN_POL_OFF + mvchip->offset,
   994			    &mvchip->in_pol_reg);
   995	
   996		switch (mvchip->soc_variant) {
   997		case MVEBU_GPIO_SOC_VARIANT_ORION:
   998		case MVEBU_GPIO_SOC_VARIANT_A8K:
   999			regmap_read(mvchip->regs, GPIO_EDGE_MASK_OFF + mvchip->offset,
  1000				    &mvchip->edge_mask_regs[0]);
  1001			regmap_read(mvchip->regs, GPIO_LEVEL_MASK_OFF + mvchip->offset,
  1002				    &mvchip->level_mask_regs[0]);
  1003			break;
  1004		case MVEBU_GPIO_SOC_VARIANT_MV78200:
  1005			for (i = 0; i < 2; i++) {
  1006				regmap_read(mvchip->regs,
  1007					    GPIO_EDGE_MASK_MV78200_OFF(i),
  1008					    &mvchip->edge_mask_regs[i]);
  1009				regmap_read(mvchip->regs,
  1010					    GPIO_LEVEL_MASK_MV78200_OFF(i),
  1011					    &mvchip->level_mask_regs[i]);
  1012			}
  1013			break;
  1014		case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
  1015			for (i = 0; i < 4; i++) {
  1016				regmap_read(mvchip->regs,
  1017					    GPIO_EDGE_MASK_ARMADAXP_OFF(i),
  1018					    &mvchip->edge_mask_regs[i]);
  1019				regmap_read(mvchip->regs,
  1020					    GPIO_LEVEL_MASK_ARMADAXP_OFF(i),
  1021					    &mvchip->level_mask_regs[i]);
  1022			}
  1023			break;
  1024		default:
  1025			BUG();
  1026		}
  1027	
  1028		if (IS_REACHABLE(CONFIG_PWM) && mvchip->mvpwm)
  1029			mvebu_pwm_suspend(mvchip);
  1030	
  1031		return 0;
  1032	}
  1033	
> 1034	static int mvebu_gpio_resume(struct device *dev)
  1035	{
  1036		struct mvebu_gpio_chip *mvchip = dev_get_drvdata(dev);
  1037		int i;
  1038	
  1039		regmap_write(mvchip->regs, GPIO_OUT_OFF + mvchip->offset,
  1040			     mvchip->out_reg);
  1041		regmap_write(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset,
  1042			     mvchip->io_conf_reg);
  1043		regmap_write(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset,
  1044			     mvchip->blink_en_reg);
  1045		regmap_write(mvchip->regs, GPIO_IN_POL_OFF + mvchip->offset,
  1046			     mvchip->in_pol_reg);
  1047	
  1048		switch (mvchip->soc_variant) {
  1049		case MVEBU_GPIO_SOC_VARIANT_ORION:
  1050		case MVEBU_GPIO_SOC_VARIANT_A8K:
  1051			regmap_write(mvchip->regs, GPIO_EDGE_MASK_OFF + mvchip->offset,
  1052				     mvchip->edge_mask_regs[0]);
  1053			regmap_write(mvchip->regs, GPIO_LEVEL_MASK_OFF + mvchip->offset,
  1054				     mvchip->level_mask_regs[0]);
  1055			break;
  1056		case MVEBU_GPIO_SOC_VARIANT_MV78200:
  1057			for (i = 0; i < 2; i++) {
  1058				regmap_write(mvchip->regs,
  1059					     GPIO_EDGE_MASK_MV78200_OFF(i),
  1060					     mvchip->edge_mask_regs[i]);
  1061				regmap_write(mvchip->regs,
  1062					     GPIO_LEVEL_MASK_MV78200_OFF(i),
  1063					     mvchip->level_mask_regs[i]);
  1064			}
  1065			break;
  1066		case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
  1067			for (i = 0; i < 4; i++) {
  1068				regmap_write(mvchip->regs,
  1069					     GPIO_EDGE_MASK_ARMADAXP_OFF(i),
  1070					     mvchip->edge_mask_regs[i]);
  1071				regmap_write(mvchip->regs,
  1072					     GPIO_LEVEL_MASK_ARMADAXP_OFF(i),
  1073					     mvchip->level_mask_regs[i]);
  1074			}
  1075			break;
  1076		default:
  1077			BUG();
  1078		}
  1079	
  1080		if (IS_REACHABLE(CONFIG_PWM) && mvchip->mvpwm)
  1081			mvebu_pwm_resume(mvchip);
  1082	
  1083		return 0;
  1084	}
  1085	

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

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

end of thread, other threads:[~2026-08-04 15:20 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-07 23:35 [PATCH] gpio: mvebu: convert to noirq suspend/resume to prevent interrupt storm on resume Rosen Penev
2026-07-08 12:11 ` Bartosz Golaszewski
2026-07-08 19:19   ` Rosen Penev
2026-07-09  8:07     ` Bartosz Golaszewski
2026-08-04 15:15 ` kernel test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.