Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

scsi: ufs: ufs-pci: Fix S0ix/S3 for Intel controllers

Intel platforms with UFS, can support Suspend-to-Idle (S0ix) and
Suspend-to-RAM (S3). For S0ix the link state should be HIBERNATE. For
S3, state is lost, so the link state must be OFF. Driver policy,
expressed by spm_lvl, can be 3 (link HIBERNATE, device SLEEP) for S0ix
but must be changed to 5 (link OFF, device POWEROFF) for S3.

Fix support for S0ix/S3 by switching spm_lvl as needed. During suspend
->prepare(), if the suspend target state is not Suspend-to-Idle, ensure
the spm_lvl is at least 5 to ensure that resume will be possible from
deep sleep states. During suspend ->complete(), restore the spm_lvl to
its original value that is suitable for S0ix.

This fix is first needed in Intel Alder Lake based controllers.

Fixes: 7dc9fb47bc9a ("scsi: ufs: ufs-pci: Add support for Intel ADL")
Cc: stable@vger.kernel.org
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Link: https://patch.msgid.link/20251024085918.31825-2-adrian.hunter@intel.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Adrian Hunter and committed by
Martin K. Petersen
bb44826c f838d624

+65 -2
+65 -2
drivers/ufs/host/ufshcd-pci.c
··· 15 15 #include <linux/pci.h> 16 16 #include <linux/pm_runtime.h> 17 17 #include <linux/pm_qos.h> 18 + #include <linux/suspend.h> 18 19 #include <linux/debugfs.h> 19 20 #include <linux/uuid.h> 20 21 #include <linux/acpi.h> ··· 32 31 u32 dsm_fns; 33 32 u32 active_ltr; 34 33 u32 idle_ltr; 34 + int saved_spm_lvl; 35 35 struct dentry *debugfs_root; 36 36 struct gpio_desc *reset_gpio; 37 37 }; ··· 349 347 host = devm_kzalloc(hba->dev, sizeof(*host), GFP_KERNEL); 350 348 if (!host) 351 349 return -ENOMEM; 350 + host->saved_spm_lvl = -1; 352 351 ufshcd_set_variant(hba, host); 353 352 intel_dsm_init(host, hba->dev); 354 353 if (INTEL_DSM_SUPPORTED(host, RESET)) { ··· 541 538 542 539 return ufshcd_system_resume(dev); 543 540 } 541 + 542 + static int ufs_intel_suspend_prepare(struct device *dev) 543 + { 544 + struct ufs_hba *hba = dev_get_drvdata(dev); 545 + struct intel_host *host = ufshcd_get_variant(hba); 546 + int err; 547 + 548 + /* 549 + * Only s2idle (S0ix) retains link state. Force power-off 550 + * (UFS_PM_LVL_5) for any other case. 551 + */ 552 + if (pm_suspend_target_state != PM_SUSPEND_TO_IDLE && hba->spm_lvl < UFS_PM_LVL_5) { 553 + host->saved_spm_lvl = hba->spm_lvl; 554 + hba->spm_lvl = UFS_PM_LVL_5; 555 + } 556 + 557 + err = ufshcd_suspend_prepare(dev); 558 + 559 + if (err < 0 && host->saved_spm_lvl != -1) { 560 + hba->spm_lvl = host->saved_spm_lvl; 561 + host->saved_spm_lvl = -1; 562 + } 563 + 564 + return err; 565 + } 566 + 567 + static void ufs_intel_resume_complete(struct device *dev) 568 + { 569 + struct ufs_hba *hba = dev_get_drvdata(dev); 570 + struct intel_host *host = ufshcd_get_variant(hba); 571 + 572 + ufshcd_resume_complete(dev); 573 + 574 + if (host->saved_spm_lvl != -1) { 575 + hba->spm_lvl = host->saved_spm_lvl; 576 + host->saved_spm_lvl = -1; 577 + } 578 + } 579 + 580 + static int ufshcd_pci_suspend_prepare(struct device *dev) 581 + { 582 + struct ufs_hba *hba = dev_get_drvdata(dev); 583 + 584 + if (!strcmp(hba->vops->name, "intel-pci")) 585 + return ufs_intel_suspend_prepare(dev); 586 + 587 + return ufshcd_suspend_prepare(dev); 588 + } 589 + 590 + static void ufshcd_pci_resume_complete(struct device *dev) 591 + { 592 + struct ufs_hba *hba = dev_get_drvdata(dev); 593 + 594 + if (!strcmp(hba->vops->name, "intel-pci")) { 595 + ufs_intel_resume_complete(dev); 596 + return; 597 + } 598 + 599 + ufshcd_resume_complete(dev); 600 + } 544 601 #endif 545 602 546 603 /** ··· 674 611 .thaw = ufshcd_system_resume, 675 612 .poweroff = ufshcd_system_suspend, 676 613 .restore = ufshcd_pci_restore, 677 - .prepare = ufshcd_suspend_prepare, 678 - .complete = ufshcd_resume_complete, 614 + .prepare = ufshcd_pci_suspend_prepare, 615 + .complete = ufshcd_pci_resume_complete, 679 616 #endif 680 617 }; 681 618