platform/x86: Move s2idle quirk from thinkpad-acpi to amd-pmc
authorMario Limonciello <mario.limonciello@amd.com>
Mon, 10 Jul 2023 18:39:33 +0000 (13:39 -0500)
committerHans de Goede <hdegoede@redhat.com>
Tue, 11 Jul 2023 09:34:14 +0000 (11:34 +0200)
It turns out that some-non Lenovo systems can benefit from the quirk
introduced for Lenovo systems in commit 455cd867b85b5 ("platform/x86:
thinkpad_acpi: Add a s2idle resume quirk for a number of laptops").

So move this quirk into running from the amd-pmc driver instead.
No intended functional changes.

Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
Link: https://lore.kernel.org/r/20230710183934.17315-2-mario.limonciello@amd.com
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
drivers/platform/x86/amd/Makefile
drivers/platform/x86/amd/pmc-quirks.c [new file with mode: 0644]
drivers/platform/x86/amd/pmc.c
drivers/platform/x86/amd/pmc.h [new file with mode: 0644]
drivers/platform/x86/thinkpad_acpi.c

index 2c22919..65732f0 100644 (file)
@@ -4,7 +4,7 @@
 # AMD x86 Platform-Specific Drivers
 #
 
-amd-pmc-y                      := pmc.o
+amd-pmc-y                      := pmc.o pmc-quirks.o
 obj-$(CONFIG_AMD_PMC)          += amd-pmc.o
 amd_hsmp-y                     := hsmp.o
 obj-$(CONFIG_AMD_HSMP)         += amd_hsmp.o
diff --git a/drivers/platform/x86/amd/pmc-quirks.c b/drivers/platform/x86/amd/pmc-quirks.c
new file mode 100644 (file)
index 0000000..21a9770
--- /dev/null
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * AMD SoC Power Management Controller Driver Quirks
+ *
+ * Copyright (c) 2023, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Mario Limonciello <mario.limonciello@amd.com>
+ */
+
+#include <linux/dmi.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+
+#include "pmc.h"
+
+struct quirk_entry {
+       u32 s2idle_bug_mmio;
+};
+
+static struct quirk_entry quirk_s2idle_bug = {
+       .s2idle_bug_mmio = 0xfed80380,
+};
+
+static const struct dmi_system_id fwbug_list[] = {
+       {
+               .ident = "L14 Gen2 AMD",
+               .driver_data = &quirk_s2idle_bug,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "20X5"),
+               }
+       },
+       {
+               .ident = "T14s Gen2 AMD",
+               .driver_data = &quirk_s2idle_bug,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "20XF"),
+               }
+       },
+       {
+               .ident = "X13 Gen2 AMD",
+               .driver_data = &quirk_s2idle_bug,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "20XH"),
+               }
+       },
+       {
+               .ident = "T14 Gen2 AMD",
+               .driver_data = &quirk_s2idle_bug,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "20XK"),
+               }
+       },
+       {
+               .ident = "T14 Gen1 AMD",
+               .driver_data = &quirk_s2idle_bug,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "20UD"),
+               }
+       },
+       {
+               .ident = "T14 Gen1 AMD",
+               .driver_data = &quirk_s2idle_bug,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "20UE"),
+               }
+       },
+       {
+               .ident = "T14s Gen1 AMD",
+               .driver_data = &quirk_s2idle_bug,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "20UH"),
+               }
+       },
+       {
+               .ident = "T14s Gen1 AMD",
+               .driver_data = &quirk_s2idle_bug,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "20UJ"),
+               }
+       },
+       {
+               .ident = "P14s Gen1 AMD",
+               .driver_data = &quirk_s2idle_bug,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "20Y1"),
+               }
+       },
+       {
+               .ident = "P14s Gen2 AMD",
+               .driver_data = &quirk_s2idle_bug,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "21A0"),
+               }
+       },
+       {
+               .ident = "P14s Gen2 AMD",
+               .driver_data = &quirk_s2idle_bug,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "21A1"),
+               }
+       },
+       {}
+};
+
+/*
+ * Laptops that run a SMI handler during the D3->D0 transition that occurs
+ * specifically when exiting suspend to idle which can cause
+ * large delays during resume when the IOMMU translation layer is enabled (the default
+ * behavior) for NVME devices:
+ *
+ * To avoid this firmware problem, skip the SMI handler on these machines before the
+ * D0 transition occurs.
+ */
+static void amd_pmc_skip_nvme_smi_handler(u32 s2idle_bug_mmio)
+{
+       struct resource *res;
+       void __iomem *addr;
+       u8 val;
+
+       res = request_mem_region_muxed(s2idle_bug_mmio, 1, "amd_pmc_pm80");
+       if (!res)
+               return;
+
+       addr = ioremap(s2idle_bug_mmio, 1);
+       if (!addr)
+               goto cleanup_resource;
+
+       val = ioread8(addr);
+       iowrite8(val & ~BIT(0), addr);
+
+       iounmap(addr);
+cleanup_resource:
+       release_resource(res);
+       kfree(res);
+}
+
+void amd_pmc_process_restore_quirks(struct amd_pmc_dev *dev)
+{
+       if (dev->quirks && dev->quirks->s2idle_bug_mmio)
+               amd_pmc_skip_nvme_smi_handler(dev->quirks->s2idle_bug_mmio);
+}
+
+void amd_pmc_quirks_init(struct amd_pmc_dev *dev)
+{
+       const struct dmi_system_id *dmi_id;
+
+       dmi_id = dmi_first_match(fwbug_list);
+       if (!dmi_id)
+               return;
+       dev->quirks = dmi_id->driver_data;
+       if (dev->quirks->s2idle_bug_mmio)
+               pr_info("Using s2idle quirk to avoid %s platform firmware bug\n",
+                       dmi_id->ident);
+}
index 7d3d080..a8ca95a 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
 
+#include "pmc.h"
+
 /* SMU communication registers */
 #define AMD_PMC_REGISTER_MESSAGE       0x538
 #define AMD_PMC_REGISTER_RESPONSE      0x980
@@ -146,29 +148,6 @@ static const struct amd_pmc_bit_map soc15_ip_blk[] = {
        {}
 };
 
-struct amd_pmc_dev {
-       void __iomem *regbase;
-       void __iomem *smu_virt_addr;
-       void __iomem *stb_virt_addr;
-       void __iomem *fch_virt_addr;
-       bool msg_port;
-       u32 base_addr;
-       u32 cpu_id;
-       u32 active_ips;
-       u32 dram_size;
-       u32 num_ips;
-       u32 s2d_msg_id;
-/* SMU version information */
-       u8 smu_program;
-       u8 major;
-       u8 minor;
-       u8 rev;
-       struct device *dev;
-       struct pci_dev *rdev;
-       struct mutex lock; /* generic mutex lock */
-       struct dentry *dbgfs_dir;
-};
-
 static bool enable_stb;
 module_param(enable_stb, bool, 0644);
 MODULE_PARM_DESC(enable_stb, "Enable the STB debug mechanism");
@@ -891,6 +870,8 @@ static void amd_pmc_s2idle_restore(void)
 
        /* Notify on failed entry */
        amd_pmc_validate_deepest(pdev);
+
+       amd_pmc_process_restore_quirks(pdev);
 }
 
 static struct acpi_s2idle_dev_ops amd_pmc_s2idle_dev_ops = {
@@ -1087,6 +1068,8 @@ static int amd_pmc_probe(struct platform_device *pdev)
                err = acpi_register_lps0_dev(&amd_pmc_s2idle_dev_ops);
                if (err)
                        dev_warn(dev->dev, "failed to register LPS0 sleep handler, expect increased power consumption\n");
+               if (!disable_workarounds)
+                       amd_pmc_quirks_init(dev);
        }
 
        amd_pmc_dbgfs_register(dev);
diff --git a/drivers/platform/x86/amd/pmc.h b/drivers/platform/x86/amd/pmc.h
new file mode 100644 (file)
index 0000000..c27bd6a
--- /dev/null
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * AMD SoC Power Management Controller Driver
+ *
+ * Copyright (c) 2023, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Mario Limonciello <mario.limonciello@amd.com>
+ */
+
+#ifndef PMC_H
+#define PMC_H
+
+#include <linux/types.h>
+#include <linux/mutex.h>
+
+struct amd_pmc_dev {
+       void __iomem *regbase;
+       void __iomem *smu_virt_addr;
+       void __iomem *stb_virt_addr;
+       void __iomem *fch_virt_addr;
+       bool msg_port;
+       u32 base_addr;
+       u32 cpu_id;
+       u32 active_ips;
+       u32 dram_size;
+       u32 num_ips;
+       u32 s2d_msg_id;
+/* SMU version information */
+       u8 smu_program;
+       u8 major;
+       u8 minor;
+       u8 rev;
+       struct device *dev;
+       struct pci_dev *rdev;
+       struct mutex lock; /* generic mutex lock */
+       struct dentry *dbgfs_dir;
+       struct quirk_entry *quirks;
+};
+
+void amd_pmc_process_restore_quirks(struct amd_pmc_dev *dev);
+void amd_pmc_quirks_init(struct amd_pmc_dev *dev);
+
+#endif /* PMC_H */
index 187018f..ad46041 100644 (file)
@@ -315,17 +315,12 @@ struct ibm_init_struct {
 /* DMI Quirks */
 struct quirk_entry {
        bool btusb_bug;
-       u32 s2idle_bug_mmio;
 };
 
 static struct quirk_entry quirk_btusb_bug = {
        .btusb_bug = true,
 };
 
-static struct quirk_entry quirk_s2idle_bug = {
-       .s2idle_bug_mmio = 0xfed80380,
-};
-
 static struct {
        u32 bluetooth:1;
        u32 hotkey:1;
@@ -4422,136 +4417,9 @@ static const struct dmi_system_id fwbug_list[] __initconst = {
                        DMI_MATCH(DMI_BOARD_NAME, "20MV"),
                },
        },
-       {
-               .ident = "L14 Gen2 AMD",
-               .driver_data = &quirk_s2idle_bug,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "20X5"),
-               }
-       },
-       {
-               .ident = "T14s Gen2 AMD",
-               .driver_data = &quirk_s2idle_bug,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "20XF"),
-               }
-       },
-       {
-               .ident = "X13 Gen2 AMD",
-               .driver_data = &quirk_s2idle_bug,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "20XH"),
-               }
-       },
-       {
-               .ident = "T14 Gen2 AMD",
-               .driver_data = &quirk_s2idle_bug,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "20XK"),
-               }
-       },
-       {
-               .ident = "T14 Gen1 AMD",
-               .driver_data = &quirk_s2idle_bug,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "20UD"),
-               }
-       },
-       {
-               .ident = "T14 Gen1 AMD",
-               .driver_data = &quirk_s2idle_bug,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "20UE"),
-               }
-       },
-       {
-               .ident = "T14s Gen1 AMD",
-               .driver_data = &quirk_s2idle_bug,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "20UH"),
-               }
-       },
-       {
-               .ident = "T14s Gen1 AMD",
-               .driver_data = &quirk_s2idle_bug,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "20UJ"),
-               }
-       },
-       {
-               .ident = "P14s Gen1 AMD",
-               .driver_data = &quirk_s2idle_bug,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "20Y1"),
-               }
-       },
-       {
-               .ident = "P14s Gen2 AMD",
-               .driver_data = &quirk_s2idle_bug,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "21A0"),
-               }
-       },
-       {
-               .ident = "P14s Gen2 AMD",
-               .driver_data = &quirk_s2idle_bug,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "21A1"),
-               }
-       },
        {}
 };
 
-#ifdef CONFIG_SUSPEND
-/*
- * Lenovo laptops from a variety of generations run a SMI handler during the D3->D0
- * transition that occurs specifically when exiting suspend to idle which can cause
- * large delays during resume when the IOMMU translation layer is enabled (the default
- * behavior) for NVME devices:
- *
- * To avoid this firmware problem, skip the SMI handler on these machines before the
- * D0 transition occurs.
- */
-static void thinkpad_acpi_amd_s2idle_restore(void)
-{
-       struct resource *res;
-       void __iomem *addr;
-       u8 val;
-
-       res = request_mem_region_muxed(tp_features.quirks->s2idle_bug_mmio, 1,
-                                       "thinkpad_acpi_pm80");
-       if (!res)
-               return;
-
-       addr = ioremap(tp_features.quirks->s2idle_bug_mmio, 1);
-       if (!addr)
-               goto cleanup_resource;
-
-       val = ioread8(addr);
-       iowrite8(val & ~BIT(0), addr);
-
-       iounmap(addr);
-cleanup_resource:
-       release_resource(res);
-       kfree(res);
-}
-
-static struct acpi_s2idle_dev_ops thinkpad_acpi_s2idle_dev_ops = {
-       .restore = thinkpad_acpi_amd_s2idle_restore,
-};
-#endif
-
 static const struct pci_device_id fwbug_cards_ids[] __initconst = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x24F3) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x24FD) },
@@ -11668,10 +11536,6 @@ static void thinkpad_acpi_module_exit(void)
 
        tpacpi_lifecycle = TPACPI_LIFE_EXITING;
 
-#ifdef CONFIG_SUSPEND
-       if (tp_features.quirks && tp_features.quirks->s2idle_bug_mmio)
-               acpi_unregister_lps0_dev(&thinkpad_acpi_s2idle_dev_ops);
-#endif
        if (tpacpi_hwmon)
                hwmon_device_unregister(tpacpi_hwmon);
        if (tp_features.sensors_pdrv_registered)
@@ -11861,13 +11725,6 @@ static int __init thinkpad_acpi_module_init(void)
                tp_features.input_device_registered = 1;
        }
 
-#ifdef CONFIG_SUSPEND
-       if (tp_features.quirks && tp_features.quirks->s2idle_bug_mmio) {
-               if (!acpi_register_lps0_dev(&thinkpad_acpi_s2idle_dev_ops))
-                       pr_info("Using s2idle quirk to avoid %s platform firmware bug\n",
-                               (dmi_id && dmi_id->ident) ? dmi_id->ident : "");
-       }
-#endif
        return 0;
 }