On 10/28/2021 8:15 PM, Mario Limonciello wrote: > On some Lenovo AMD Gen2 platforms the IRQ for the SCI and pinctrl drivers > are shared. Due to how the s2idle loop handling works, this case needs > an extra explicit check whether the interrupt was caused by SCI or by > the GPIO controller. > > To fix this rework the existing IRQ handler function to function as a > checker and an IRQ handler depending on the calling arguments. > > Cc: stable@xxxxxxxxxx > BugLink: https://gitlab.freedesktop.org/drm/amd/-/issues/1738 > Reported-by: Joerie de Gram <j.de.gram@xxxxxxxxx> > Signed-off-by: Mario Limonciello <mario.limonciello@xxxxxxx> > --- > Note: > This is *possibly* a fix from fdde0ff8590b, 56b991849009 or other > changes in the acpi_s2idle_wake handling, but AMD didn't support > s2idle across the kernel widely until 5.14 or later. This is the > reason for lack of a fixes tag. > Changes from v4->v5: > * Correct debugging statement that was obfuscated by kernel %p behavior. > * Instead show actual GPIO number, which is much more useful for debugging > * Target to stable as well > Changes from v3->v4: > * Adjust to reverse xmas for newly added variable > * Add a debugging line to show the values in the register that caused system > wake to allow for debugging of spurious wakeups > Changes from v2->v3: > * Add new precursor patch for fixing missing ACPI function stubs > * Add __maybe_unused for unused function when set with COMPILE_TEST > Changes from v1->v2: > * drop Kconfig changes to drop COMPILE_TEST, instead #ifdef CONFIG_ACPI > * fix a logic error during wakeup > * Use IRQ_RETVAL() > drivers/pinctrl/pinctrl-amd.c | 31 ++++++++++++++++++++++++++++--- > 1 file changed, 28 insertions(+), 3 deletions(-) > > diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c > index d19974aceb2e..83fbcdad0904 100644 > --- a/drivers/pinctrl/pinctrl-amd.c > +++ b/drivers/pinctrl/pinctrl-amd.c > @@ -598,14 +598,14 @@ static struct irq_chip amd_gpio_irqchip = { > > #define PIN_IRQ_PENDING (BIT(INTERRUPT_STS_OFF) | BIT(WAKE_STS_OFF)) > > -static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id) > +static bool _amd_gpio_irq_handler(int irq, void *dev_id) > { > struct amd_gpio *gpio_dev = dev_id; > struct gpio_chip *gc = &gpio_dev->gc; > - irqreturn_t ret = IRQ_NONE; > unsigned int i, irqnr; > unsigned long flags; > u32 __iomem *regs; > + bool ret = false; > u32 regval; > u64 status, mask; > > @@ -627,6 +627,16 @@ static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id) > /* Each status bit covers four pins */ > for (i = 0; i < 4; i++) { > regval = readl(regs + i); > + /* called from resume context on a shared IRQ, just > + * checking wake source. > + */ > + if (irq < 0 && (regval & BIT(WAKE_STS_OFF))) { > + dev_dbg(&gpio_dev->pdev->dev, > + "Waking due to GPIO %ld: 0x%x", > + regs + i - ((u32 __iomem *)gpio_dev->base), regval); > + return true; > + } > + > if (!(regval & PIN_IRQ_PENDING) || > !(regval & BIT(INTERRUPT_MASK_OFF))) > continue; > @@ -652,9 +662,12 @@ static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id) > } > writel(regval, regs + i); > raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); > - ret = IRQ_HANDLED; > + ret = true; > } > } > + /* called from resume context on shared IRQ but didn't cause wake */ > + if (irq < 0) > + return false; > > /* Signal EOI to the GPIO unit */ > raw_spin_lock_irqsave(&gpio_dev->lock, flags); > @@ -666,6 +679,16 @@ static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id) > return ret; > } > > +static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id) > +{ > + return IRQ_RETVAL(_amd_gpio_irq_handler(irq, dev_id)); > +} > + > +static bool __maybe_unused amd_gpio_check_wake(void *dev_id) > +{ > + return _amd_gpio_irq_handler(-1, dev_id); > +} > + > static int amd_get_groups_count(struct pinctrl_dev *pctldev) > { > struct amd_gpio *gpio_dev = pinctrl_dev_get_drvdata(pctldev); > @@ -1004,6 +1027,7 @@ static int amd_gpio_probe(struct platform_device *pdev) > goto out2; > > platform_set_drvdata(pdev, gpio_dev); > + acpi_register_wakeup_handler(gpio_dev->irq, amd_gpio_check_wake, gpio_dev); > > dev_dbg(&pdev->dev, "amd gpio driver loaded\n"); > return ret; > @@ -1021,6 +1045,7 @@ static int amd_gpio_remove(struct platform_device *pdev) > gpio_dev = platform_get_drvdata(pdev); > > gpiochip_remove(&gpio_dev->gc); > + acpi_unregister_wakeup_handler(amd_gpio_check_wake, gpio_dev); > > return 0; > } Looks good to me Acked-by: Basavaraj Natikar <Basavaraj.Natikar@xxxxxxx> Thanks, Basavaraj