@@ -309,6 +309,20 @@ struct ibm_init_struct {
309
309
struct ibm_struct * data ;
310
310
};
311
311
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
+
312
326
static struct {
313
327
u32 bluetooth :1 ;
314
328
u32 hotkey :1 ;
@@ -338,6 +352,7 @@ static struct {
338
352
u32 hotkey_poll_active :1 ;
339
353
u32 has_adaptive_kbd :1 ;
340
354
u32 kbd_lang :1 ;
355
+ struct quirk_entry * quirks ;
341
356
} tp_features ;
342
357
343
358
static struct {
@@ -4359,52 +4374,168 @@ static void bluetooth_exit(void)
4359
4374
bluetooth_shutdown ();
4360
4375
}
4361
4376
4362
- static const struct dmi_system_id bt_fwbug_list [] __initconst = {
4377
+ static const struct dmi_system_id fwbug_list [] __initconst = {
4363
4378
{
4364
4379
.ident = "ThinkPad E485" ,
4380
+ .driver_data = & quirk_btusb_bug ,
4365
4381
.matches = {
4366
4382
DMI_MATCH (DMI_SYS_VENDOR , "LENOVO" ),
4367
4383
DMI_MATCH (DMI_BOARD_NAME , "20KU" ),
4368
4384
},
4369
4385
},
4370
4386
{
4371
4387
.ident = "ThinkPad E585" ,
4388
+ .driver_data = & quirk_btusb_bug ,
4372
4389
.matches = {
4373
4390
DMI_MATCH (DMI_SYS_VENDOR , "LENOVO" ),
4374
4391
DMI_MATCH (DMI_BOARD_NAME , "20KV" ),
4375
4392
},
4376
4393
},
4377
4394
{
4378
4395
.ident = "ThinkPad A285 - 20MW" ,
4396
+ .driver_data = & quirk_btusb_bug ,
4379
4397
.matches = {
4380
4398
DMI_MATCH (DMI_SYS_VENDOR , "LENOVO" ),
4381
4399
DMI_MATCH (DMI_BOARD_NAME , "20MW" ),
4382
4400
},
4383
4401
},
4384
4402
{
4385
4403
.ident = "ThinkPad A285 - 20MX" ,
4404
+ .driver_data = & quirk_btusb_bug ,
4386
4405
.matches = {
4387
4406
DMI_MATCH (DMI_SYS_VENDOR , "LENOVO" ),
4388
4407
DMI_MATCH (DMI_BOARD_NAME , "20MX" ),
4389
4408
},
4390
4409
},
4391
4410
{
4392
4411
.ident = "ThinkPad A485 - 20MU" ,
4412
+ .driver_data = & quirk_btusb_bug ,
4393
4413
.matches = {
4394
4414
DMI_MATCH (DMI_SYS_VENDOR , "LENOVO" ),
4395
4415
DMI_MATCH (DMI_BOARD_NAME , "20MU" ),
4396
4416
},
4397
4417
},
4398
4418
{
4399
4419
.ident = "ThinkPad A485 - 20MV" ,
4420
+ .driver_data = & quirk_btusb_bug ,
4400
4421
.matches = {
4401
4422
DMI_MATCH (DMI_SYS_VENDOR , "LENOVO" ),
4402
4423
DMI_MATCH (DMI_BOARD_NAME , "20MV" ),
4403
4424
},
4404
4425
},
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
+ },
4405
4498
{}
4406
4499
};
4407
4500
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
+
4408
4539
static const struct pci_device_id fwbug_cards_ids [] __initconst = {
4409
4540
{ PCI_DEVICE (PCI_VENDOR_ID_INTEL , 0x24F3 ) },
4410
4541
{ PCI_DEVICE (PCI_VENDOR_ID_INTEL , 0x24FD ) },
@@ -4419,7 +4550,8 @@ static int __init have_bt_fwbug(void)
4419
4550
* Some AMD based ThinkPads have a firmware bug that calling
4420
4551
* "GBDC" will cause bluetooth on Intel wireless cards blocked
4421
4552
*/
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 )) {
4423
4555
vdbg_printk (TPACPI_DBG_INIT | TPACPI_DBG_RFKILL ,
4424
4556
FW_BUG "disable bluetooth subdriver for Intel cards\n" );
4425
4557
return 1 ;
@@ -8748,24 +8880,27 @@ static int __init fan_init(struct ibm_init_struct *iibm)
8748
8880
fan_status_access_mode = TPACPI_FAN_RD_TPEC ;
8749
8881
if (quirks & TPACPI_FAN_Q1 )
8750
8882
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
- }
8760
8883
/* Try and probe the 2nd fan */
8884
+ tp_features .second_fan = 1 ; /* needed for get_speed to work */
8761
8885
res = fan2_get_speed (& speed );
8762
8886
if (res >= 0 ) {
8763
8887
/* It responded - so let's assume it's there */
8764
8888
tp_features .second_fan = 1 ;
8765
8889
tp_features .second_fan_ctl = 1 ;
8766
8890
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
+ }
8767
8903
}
8768
-
8769
8904
} else {
8770
8905
pr_err ("ThinkPad ACPI EC access misbehaving, fan status and control unavailable\n" );
8771
8906
return - ENODEV ;
@@ -11455,6 +11590,10 @@ static void thinkpad_acpi_module_exit(void)
11455
11590
11456
11591
tpacpi_lifecycle = TPACPI_LIFE_EXITING ;
11457
11592
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
11458
11597
if (tpacpi_hwmon )
11459
11598
hwmon_device_unregister (tpacpi_hwmon );
11460
11599
if (tp_features .sensors_pdrv_registered )
@@ -11496,6 +11635,7 @@ static void thinkpad_acpi_module_exit(void)
11496
11635
11497
11636
static int __init thinkpad_acpi_module_init (void )
11498
11637
{
11638
+ const struct dmi_system_id * dmi_id ;
11499
11639
int ret , i ;
11500
11640
11501
11641
tpacpi_lifecycle = TPACPI_LIFE_INIT ;
@@ -11535,6 +11675,10 @@ static int __init thinkpad_acpi_module_init(void)
11535
11675
return - ENODEV ;
11536
11676
}
11537
11677
11678
+ dmi_id = dmi_first_match (fwbug_list );
11679
+ if (dmi_id )
11680
+ tp_features .quirks = dmi_id -> driver_data ;
11681
+
11538
11682
/* Device initialization */
11539
11683
tpacpi_pdev = platform_device_register_simple (TPACPI_DRVR_NAME , -1 ,
11540
11684
NULL , 0 );
@@ -11623,6 +11767,13 @@ static int __init thinkpad_acpi_module_init(void)
11623
11767
tp_features .input_device_registered = 1 ;
11624
11768
}
11625
11769
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
11626
11777
return 0 ;
11627
11778
}
11628
11779
0 commit comments