Re: [PATCH 1/2] platform/x86: amd: pmc: Disable IRQ1 wakeup for RN/CZN

From: Hans de Goede
Date: Mon Jan 23 2023 - 08:56:27 EST


Hi,

On 1/20/23 20:15, Mario Limonciello wrote:
> By default when the system is configured for low power idle in the FADT
> the keyboard is set up as a wake source. This matches the behavior that
> Windows uses for Modern Standby as well.
>
> It has been reported that a variety of AMD based designs there are
> spurious wakeups are happening where two IRQ sources are active.
>
> For example:
> ```
> PM: Triggering wakeup from IRQ 9
> PM: Triggering wakeup from IRQ 1
> ```
>
> In these designs IRQ 9 is the ACPI SCI and IRQ 1 is the keyboard.
> One way to trigger this problem is to suspend the laptop and then unplug
> the AC adapter. The SOC will be in a hardware sleep state and plugging
> in the AC adapter returns control to the kernel's s2idle loop.
>
> Normally if just IRQ 9 was active the s2idle loop would advance any EC
> transactions and no other IRQ being active would cause the s2idle loop
> to put the SOC back into hardware sleep state.
>
> When this bug occurred IRQ 1 is also active even if no keyboard activity
> occurred. This causes the s2idle loop to break and the system to wake.
>
> This is a platform firmware bug triggering IRQ1 without keyboard activity.
> This occurs in Windows as well, but Windows will enter "SW DRIPS" and
> then with no activity enters back into "HW DRIPS" (hardware sleep state).
>
> This issue affects Renoir, Lucienne, Cezanne, and Barcelo platforms. It
> does not happen on newer systems such as Mendocino or Rembrandt.
>
> It's been fixed in newer platform firmware. To avoid triggering the bug
> on older systems check the SMU F/W version and adjust the policy at suspend
> time for s2idle wakeup from keyboard on these systems. A lot of thought
> and experimentation has been given around the timing of disabling IRQ1,
> and to make it work the "suspend" PM callback is restored.
>
> Reported-by: Kai-Heng Feng <kai.heng.feng@xxxxxxxxxxxxx>
> Reported-by: Xaver Hugl <xaver.hugl@xxxxxxxxx>
> Link: https://gitlab.freedesktop.org/drm/amd/-/issues/2115
> Link: https://gitlab.freedesktop.org/drm/amd/-/issues/1951
> Signed-off-by: Mario Limonciello <mario.limonciello@xxxxxxx>

Thank you for your patch-series, I've applied the series to my
review-hans branch:
https://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git/log/?h=review-hans

Note it will show up in my review-hans branch once I've pushed my
local branch there, which might take a while.

Once I've run some tests on this branch the patches there will be
added to the platform-drivers-x86/for-next branch and eventually
will be included in the pdx86 pull-request to Linus for the next
merge-window.

Regards,

Hans


> ---
> drivers/platform/x86/amd/pmc.c | 50 ++++++++++++++++++++++++++++++++++
> 1 file changed, 50 insertions(+)
>
> diff --git a/drivers/platform/x86/amd/pmc.c b/drivers/platform/x86/amd/pmc.c
> index 8d924986381be..be1b49824edbd 100644
> --- a/drivers/platform/x86/amd/pmc.c
> +++ b/drivers/platform/x86/amd/pmc.c
> @@ -22,6 +22,7 @@
> #include <linux/pci.h>
> #include <linux/platform_device.h>
> #include <linux/rtc.h>
> +#include <linux/serio.h>
> #include <linux/suspend.h>
> #include <linux/seq_file.h>
> #include <linux/uaccess.h>
> @@ -653,6 +654,33 @@ static int amd_pmc_get_os_hint(struct amd_pmc_dev *dev)
> return -EINVAL;
> }
>
> +static int amd_pmc_czn_wa_irq1(struct amd_pmc_dev *pdev)
> +{
> + struct device *d;
> + int rc;
> +
> + if (!pdev->major) {
> + rc = amd_pmc_get_smu_version(pdev);
> + if (rc)
> + return rc;
> + }
> +
> + if (pdev->major > 64 || (pdev->major == 64 && pdev->minor > 65))
> + return 0;
> +
> + d = bus_find_device_by_name(&serio_bus, NULL, "serio0");
> + if (!d)
> + return 0;
> + if (device_may_wakeup(d)) {
> + dev_info_once(d, "Disabling IRQ1 wakeup source to avoid platform firmware bug\n");
> + disable_irq_wake(1);
> + device_set_wakeup_enable(d, false);
> + }
> + put_device(d);
> +
> + return 0;
> +}
> +
> static int amd_pmc_verify_czn_rtc(struct amd_pmc_dev *pdev, u32 *arg)
> {
> struct rtc_device *rtc_device;
> @@ -782,6 +810,25 @@ static struct acpi_s2idle_dev_ops amd_pmc_s2idle_dev_ops = {
> .check = amd_pmc_s2idle_check,
> .restore = amd_pmc_s2idle_restore,
> };
> +
> +static int __maybe_unused amd_pmc_suspend_handler(struct device *dev)
> +{
> + struct amd_pmc_dev *pdev = dev_get_drvdata(dev);
> +
> + if (pdev->cpu_id == AMD_CPU_ID_CZN) {
> + int rc = amd_pmc_czn_wa_irq1(pdev);
> +
> + if (rc) {
> + dev_err(pdev->dev, "failed to adjust keyboard wakeup: %d\n", rc);
> + return rc;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(amd_pmc_pm, amd_pmc_suspend_handler, NULL);
> +
> #endif
>
> static const struct pci_device_id pmc_pci_ids[] = {
> @@ -980,6 +1027,9 @@ static struct platform_driver amd_pmc_driver = {
> .name = "amd_pmc",
> .acpi_match_table = amd_pmc_acpi_ids,
> .dev_groups = pmc_groups,
> +#ifdef CONFIG_SUSPEND
> + .pm = &amd_pmc_pm,
> +#endif
> },
> .probe = amd_pmc_probe,
> .remove = amd_pmc_remove,