Skip to content

Commit 455cd86

Browse files
superm1jwrdegoede
authored andcommitted
platform/x86: thinkpad_acpi: Add a s2idle resume quirk for a number of laptops
Lenovo laptops that contain NVME SSDs across a variety of generations have trouble resuming from suspend to idle when the IOMMU translation layer is active for the NVME storage device. This generally manifests as a large resume delay or page faults. These delays and page faults occur as a result of a Lenovo BIOS specific SMI that runs during the D3->D0 transition on NVME devices. This SMI occurs because of a flag that is set during resume by Lenovo firmware: ``` OperationRegion (PM80, SystemMemory, 0xFED80380, 0x10) Field (PM80, AnyAcc, NoLock, Preserve) { SI3R, 1 } Method (_ON, 0, NotSerialized) // _ON_: Power On { TPST (0x60D0) If ((DAS3 == 0x00)) { If (SI3R) { TPST (0x60E0) M020 (NBRI, 0x00, 0x00, 0x04, (NCMD | 0x06)) M020 (NBRI, 0x00, 0x00, 0x10, NBAR) APMC = HDSI /* \HDSI */ SLPS = 0x01 SI3R = 0x00 TPST (0x60E1) } D0NV = 0x01 } } ``` Create a quirk that will run early in the resume process to prevent this SMI from running. As any of these machines are fixed, they can be peeled back from this quirk or narrowed down to individual firmware versions. Link: https://gitlab.freedesktop.org/drm/amd/-/issues/1910 Link: https://gitlab.freedesktop.org/drm/amd/-/issues/1689 Signed-off-by: Mario Limonciello <mario.limonciello@amd.com> Tested-by: Mark Pearson <markpearson@lenvo.com> Link: https://lore.kernel.org/r/20220429030501.1909-3-mario.limonciello@amd.com Reviewed-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
1 parent c25d7f3 commit 455cd86

1 file changed

Lines changed: 126 additions & 0 deletions

File tree

drivers/platform/x86/thinkpad_acpi.c

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,12 +312,17 @@ struct ibm_init_struct {
312312
/* DMI Quirks */
313313
struct quirk_entry {
314314
bool btusb_bug;
315+
u32 s2idle_bug_mmio;
315316
};
316317

317318
static struct quirk_entry quirk_btusb_bug = {
318319
.btusb_bug = true,
319320
};
320321

322+
static struct quirk_entry quirk_s2idle_bug = {
323+
.s2idle_bug_mmio = 0xfed80380,
324+
};
325+
321326
static struct {
322327
u32 bluetooth:1;
323328
u32 hotkey:1;
@@ -4418,9 +4423,119 @@ static const struct dmi_system_id fwbug_list[] __initconst = {
44184423
DMI_MATCH(DMI_BOARD_NAME, "20MV"),
44194424
},
44204425
},
4426+
{
4427+
.ident = "L14 Gen2 AMD",
4428+
.driver_data = &quirk_s2idle_bug,
4429+
.matches = {
4430+
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
4431+
DMI_MATCH(DMI_PRODUCT_NAME, "20X5"),
4432+
}
4433+
},
4434+
{
4435+
.ident = "T14s Gen2 AMD",
4436+
.driver_data = &quirk_s2idle_bug,
4437+
.matches = {
4438+
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
4439+
DMI_MATCH(DMI_PRODUCT_NAME, "20XF"),
4440+
}
4441+
},
4442+
{
4443+
.ident = "X13 Gen2 AMD",
4444+
.driver_data = &quirk_s2idle_bug,
4445+
.matches = {
4446+
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
4447+
DMI_MATCH(DMI_PRODUCT_NAME, "20XH"),
4448+
}
4449+
},
4450+
{
4451+
.ident = "T14 Gen2 AMD",
4452+
.driver_data = &quirk_s2idle_bug,
4453+
.matches = {
4454+
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
4455+
DMI_MATCH(DMI_PRODUCT_NAME, "20XK"),
4456+
}
4457+
},
4458+
{
4459+
.ident = "T14 Gen1 AMD",
4460+
.driver_data = &quirk_s2idle_bug,
4461+
.matches = {
4462+
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
4463+
DMI_MATCH(DMI_PRODUCT_NAME, "20UD"),
4464+
}
4465+
},
4466+
{
4467+
.ident = "T14 Gen1 AMD",
4468+
.driver_data = &quirk_s2idle_bug,
4469+
.matches = {
4470+
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
4471+
DMI_MATCH(DMI_PRODUCT_NAME, "20UE"),
4472+
}
4473+
},
4474+
{
4475+
.ident = "T14s Gen1 AMD",
4476+
.driver_data = &quirk_s2idle_bug,
4477+
.matches = {
4478+
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
4479+
DMI_MATCH(DMI_PRODUCT_NAME, "20UH"),
4480+
}
4481+
},
4482+
{
4483+
.ident = "P14s Gen1 AMD",
4484+
.driver_data = &quirk_s2idle_bug,
4485+
.matches = {
4486+
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
4487+
DMI_MATCH(DMI_PRODUCT_NAME, "20Y1"),
4488+
}
4489+
},
4490+
{
4491+
.ident = "P14s Gen2 AMD",
4492+
.driver_data = &quirk_s2idle_bug,
4493+
.matches = {
4494+
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
4495+
DMI_MATCH(DMI_PRODUCT_NAME, "21A0"),
4496+
}
4497+
},
44214498
{}
44224499
};
44234500

4501+
#ifdef CONFIG_SUSPEND
4502+
/*
4503+
* Lenovo laptops from a variety of generations run a SMI handler during the D3->D0
4504+
* transition that occurs specifically when exiting suspend to idle which can cause
4505+
* large delays during resume when the IOMMU translation layer is enabled (the default
4506+
* behavior) for NVME devices:
4507+
*
4508+
* To avoid this firmware problem, skip the SMI handler on these machines before the
4509+
* D0 transition occurs.
4510+
*/
4511+
static void thinkpad_acpi_amd_s2idle_restore(void)
4512+
{
4513+
struct resource *res;
4514+
void __iomem *addr;
4515+
u8 val;
4516+
4517+
res = request_mem_region_muxed(tp_features.quirks->s2idle_bug_mmio, 1,
4518+
"thinkpad_acpi_pm80");
4519+
if (!res)
4520+
return;
4521+
4522+
addr = ioremap(tp_features.quirks->s2idle_bug_mmio, 1);
4523+
if (!addr)
4524+
goto cleanup_resource;
4525+
4526+
val = ioread8(addr);
4527+
iowrite8(val & ~BIT(0), addr);
4528+
4529+
iounmap(addr);
4530+
cleanup_resource:
4531+
release_resource(res);
4532+
}
4533+
4534+
static struct acpi_s2idle_dev_ops thinkpad_acpi_s2idle_dev_ops = {
4535+
.restore = thinkpad_acpi_amd_s2idle_restore,
4536+
};
4537+
#endif
4538+
44244539
static const struct pci_device_id fwbug_cards_ids[] __initconst = {
44254540
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x24F3) },
44264541
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x24FD) },
@@ -11472,6 +11587,10 @@ static void thinkpad_acpi_module_exit(void)
1147211587

1147311588
tpacpi_lifecycle = TPACPI_LIFE_EXITING;
1147411589

11590+
#ifdef CONFIG_SUSPEND
11591+
if (tp_features.quirks && tp_features.quirks->s2idle_bug_mmio)
11592+
acpi_unregister_lps0_dev(&thinkpad_acpi_s2idle_dev_ops);
11593+
#endif
1147511594
if (tpacpi_hwmon)
1147611595
hwmon_device_unregister(tpacpi_hwmon);
1147711596
if (tp_features.sensors_pdrv_registered)
@@ -11645,6 +11764,13 @@ static int __init thinkpad_acpi_module_init(void)
1164511764
tp_features.input_device_registered = 1;
1164611765
}
1164711766

11767+
#ifdef CONFIG_SUSPEND
11768+
if (tp_features.quirks && tp_features.quirks->s2idle_bug_mmio) {
11769+
if (!acpi_register_lps0_dev(&thinkpad_acpi_s2idle_dev_ops))
11770+
pr_info("Using s2idle quirk to avoid %s platform firmware bug\n",
11771+
(dmi_id && dmi_id->ident) ? dmi_id->ident : "");
11772+
}
11773+
#endif
1164811774
return 0;
1164911775
}
1165011776

0 commit comments

Comments
 (0)