@@ -309,6 +309,20 @@ struct ibm_init_struct {
309309 struct ibm_struct * data ;
310310};
311311
312+ /* DMI Quirks */
313+ struct quirk_entry {
314+ bool btusb_bug ;
315+ u32 s2idle_bug_mmio ;
316+ };
317+
318+ static struct quirk_entry quirk_btusb_bug = {
319+ .btusb_bug = true,
320+ };
321+
322+ static struct quirk_entry quirk_s2idle_bug = {
323+ .s2idle_bug_mmio = 0xfed80380 ,
324+ };
325+
312326static struct {
313327 u32 bluetooth :1 ;
314328 u32 hotkey :1 ;
@@ -338,6 +352,7 @@ static struct {
338352 u32 hotkey_poll_active :1 ;
339353 u32 has_adaptive_kbd :1 ;
340354 u32 kbd_lang :1 ;
355+ struct quirk_entry * quirks ;
341356} tp_features ;
342357
343358static struct {
@@ -4359,52 +4374,168 @@ static void bluetooth_exit(void)
43594374 bluetooth_shutdown ();
43604375}
43614376
4362- static const struct dmi_system_id bt_fwbug_list [] __initconst = {
4377+ static const struct dmi_system_id fwbug_list [] __initconst = {
43634378 {
43644379 .ident = "ThinkPad E485" ,
4380+ .driver_data = & quirk_btusb_bug ,
43654381 .matches = {
43664382 DMI_MATCH (DMI_SYS_VENDOR , "LENOVO" ),
43674383 DMI_MATCH (DMI_BOARD_NAME , "20KU" ),
43684384 },
43694385 },
43704386 {
43714387 .ident = "ThinkPad E585" ,
4388+ .driver_data = & quirk_btusb_bug ,
43724389 .matches = {
43734390 DMI_MATCH (DMI_SYS_VENDOR , "LENOVO" ),
43744391 DMI_MATCH (DMI_BOARD_NAME , "20KV" ),
43754392 },
43764393 },
43774394 {
43784395 .ident = "ThinkPad A285 - 20MW" ,
4396+ .driver_data = & quirk_btusb_bug ,
43794397 .matches = {
43804398 DMI_MATCH (DMI_SYS_VENDOR , "LENOVO" ),
43814399 DMI_MATCH (DMI_BOARD_NAME , "20MW" ),
43824400 },
43834401 },
43844402 {
43854403 .ident = "ThinkPad A285 - 20MX" ,
4404+ .driver_data = & quirk_btusb_bug ,
43864405 .matches = {
43874406 DMI_MATCH (DMI_SYS_VENDOR , "LENOVO" ),
43884407 DMI_MATCH (DMI_BOARD_NAME , "20MX" ),
43894408 },
43904409 },
43914410 {
43924411 .ident = "ThinkPad A485 - 20MU" ,
4412+ .driver_data = & quirk_btusb_bug ,
43934413 .matches = {
43944414 DMI_MATCH (DMI_SYS_VENDOR , "LENOVO" ),
43954415 DMI_MATCH (DMI_BOARD_NAME , "20MU" ),
43964416 },
43974417 },
43984418 {
43994419 .ident = "ThinkPad A485 - 20MV" ,
4420+ .driver_data = & quirk_btusb_bug ,
44004421 .matches = {
44014422 DMI_MATCH (DMI_SYS_VENDOR , "LENOVO" ),
44024423 DMI_MATCH (DMI_BOARD_NAME , "20MV" ),
44034424 },
44044425 },
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+ },
44054498 {}
44064499};
44074500
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+
44084539static const struct pci_device_id fwbug_cards_ids [] __initconst = {
44094540 { PCI_DEVICE (PCI_VENDOR_ID_INTEL , 0x24F3 ) },
44104541 { PCI_DEVICE (PCI_VENDOR_ID_INTEL , 0x24FD ) },
@@ -4419,7 +4550,8 @@ static int __init have_bt_fwbug(void)
44194550 * Some AMD based ThinkPads have a firmware bug that calling
44204551 * "GBDC" will cause bluetooth on Intel wireless cards blocked
44214552 */
4422- if (dmi_check_system (bt_fwbug_list ) && pci_dev_present (fwbug_cards_ids )) {
4553+ if (tp_features .quirks && tp_features .quirks -> btusb_bug &&
4554+ pci_dev_present (fwbug_cards_ids )) {
44234555 vdbg_printk (TPACPI_DBG_INIT | TPACPI_DBG_RFKILL ,
44244556 FW_BUG "disable bluetooth subdriver for Intel cards\n" );
44254557 return 1 ;
@@ -8748,24 +8880,27 @@ static int __init fan_init(struct ibm_init_struct *iibm)
87488880 fan_status_access_mode = TPACPI_FAN_RD_TPEC ;
87498881 if (quirks & TPACPI_FAN_Q1 )
87508882 fan_quirk1_setup ();
8751- if (quirks & TPACPI_FAN_2FAN ) {
8752- tp_features .second_fan = 1 ;
8753- pr_info ("secondary fan support enabled\n" );
8754- }
8755- if (quirks & TPACPI_FAN_2CTL ) {
8756- tp_features .second_fan = 1 ;
8757- tp_features .second_fan_ctl = 1 ;
8758- pr_info ("secondary fan control enabled\n" );
8759- }
87608883 /* Try and probe the 2nd fan */
8884+ tp_features .second_fan = 1 ; /* needed for get_speed to work */
87618885 res = fan2_get_speed (& speed );
87628886 if (res >= 0 ) {
87638887 /* It responded - so let's assume it's there */
87648888 tp_features .second_fan = 1 ;
87658889 tp_features .second_fan_ctl = 1 ;
87668890 pr_info ("secondary fan control detected & enabled\n" );
8891+ } else {
8892+ /* Fan not auto-detected */
8893+ tp_features .second_fan = 0 ;
8894+ if (quirks & TPACPI_FAN_2FAN ) {
8895+ tp_features .second_fan = 1 ;
8896+ pr_info ("secondary fan support enabled\n" );
8897+ }
8898+ if (quirks & TPACPI_FAN_2CTL ) {
8899+ tp_features .second_fan = 1 ;
8900+ tp_features .second_fan_ctl = 1 ;
8901+ pr_info ("secondary fan control enabled\n" );
8902+ }
87678903 }
8768-
87698904 } else {
87708905 pr_err ("ThinkPad ACPI EC access misbehaving, fan status and control unavailable\n" );
87718906 return - ENODEV ;
@@ -11455,6 +11590,10 @@ static void thinkpad_acpi_module_exit(void)
1145511590
1145611591 tpacpi_lifecycle = TPACPI_LIFE_EXITING ;
1145711592
11593+ #ifdef CONFIG_SUSPEND
11594+ if (tp_features .quirks && tp_features .quirks -> s2idle_bug_mmio )
11595+ acpi_unregister_lps0_dev (& thinkpad_acpi_s2idle_dev_ops );
11596+ #endif
1145811597 if (tpacpi_hwmon )
1145911598 hwmon_device_unregister (tpacpi_hwmon );
1146011599 if (tp_features .sensors_pdrv_registered )
@@ -11496,6 +11635,7 @@ static void thinkpad_acpi_module_exit(void)
1149611635
1149711636static int __init thinkpad_acpi_module_init (void )
1149811637{
11638+ const struct dmi_system_id * dmi_id ;
1149911639 int ret , i ;
1150011640
1150111641 tpacpi_lifecycle = TPACPI_LIFE_INIT ;
@@ -11535,6 +11675,10 @@ static int __init thinkpad_acpi_module_init(void)
1153511675 return - ENODEV ;
1153611676 }
1153711677
11678+ dmi_id = dmi_first_match (fwbug_list );
11679+ if (dmi_id )
11680+ tp_features .quirks = dmi_id -> driver_data ;
11681+
1153811682 /* Device initialization */
1153911683 tpacpi_pdev = platform_device_register_simple (TPACPI_DRVR_NAME , -1 ,
1154011684 NULL , 0 );
@@ -11623,6 +11767,13 @@ static int __init thinkpad_acpi_module_init(void)
1162311767 tp_features .input_device_registered = 1 ;
1162411768 }
1162511769
11770+ #ifdef CONFIG_SUSPEND
11771+ if (tp_features .quirks && tp_features .quirks -> s2idle_bug_mmio ) {
11772+ if (!acpi_register_lps0_dev (& thinkpad_acpi_s2idle_dev_ops ))
11773+ pr_info ("Using s2idle quirk to avoid %s platform firmware bug\n" ,
11774+ (dmi_id && dmi_id -> ident ) ? dmi_id -> ident : "" );
11775+ }
11776+ #endif
1162611777 return 0 ;
1162711778}
1162811779
0 commit comments