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.

platform/x86: intel/pmc: Ignore all LTRs during suspend

Add support to ignore all LTRs before suspend and restore the previous
LTR values after suspend. This feature could be turned off with module
parameter ltr_ignore_all_suspend.

LTR value is a mechanism for a device to indicate tolerance to access
the corresponding resource. When system suspends, the resource is not
available and therefore the LTR value could be ignored. Ignoring all
LTR values prevents problematic device from blocking the system to get
to the deepest package state during suspend.

Suggested-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Xi Pardee <xi.pardee@intel.com>
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Link: https://lore.kernel.org/r/20240906184016.268153-1-xi.pardee@linux.intel.com
Signed-off-by: Hans de Goede <hdegoede@redhat.com>

authored by

Xi Pardee and committed by
Hans de Goede
cedf2335 f5dd17e3

+55
+53
drivers/platform/x86/intel/pmc/core.c
··· 714 714 } 715 715 DEFINE_SHOW_ATTRIBUTE(pmc_core_s0ix_blocker); 716 716 717 + static void pmc_core_ltr_ignore_all(struct pmc_dev *pmcdev) 718 + { 719 + unsigned int i; 720 + 721 + for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); i++) { 722 + struct pmc *pmc; 723 + u32 ltr_ign; 724 + 725 + pmc = pmcdev->pmcs[i]; 726 + if (!pmc) 727 + continue; 728 + 729 + guard(mutex)(&pmcdev->lock); 730 + pmc->ltr_ign = pmc_core_reg_read(pmc, pmc->map->ltr_ignore_offset); 731 + 732 + /* ltr_ignore_max is the max index value for LTR ignore register */ 733 + ltr_ign = pmc->ltr_ign | GENMASK(pmc->map->ltr_ignore_max, 0); 734 + pmc_core_reg_write(pmc, pmc->map->ltr_ignore_offset, ltr_ign); 735 + } 736 + 737 + /* 738 + * Ignoring ME during suspend is blocking platforms with ADL PCH to get to 739 + * deeper S0ix substate. 740 + */ 741 + pmc_core_send_ltr_ignore(pmcdev, 6, 0); 742 + } 743 + 744 + static void pmc_core_ltr_restore_all(struct pmc_dev *pmcdev) 745 + { 746 + unsigned int i; 747 + 748 + for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); i++) { 749 + struct pmc *pmc; 750 + 751 + pmc = pmcdev->pmcs[i]; 752 + if (!pmc) 753 + continue; 754 + 755 + guard(mutex)(&pmcdev->lock); 756 + pmc_core_reg_write(pmc, pmc->map->ltr_ignore_offset, pmc->ltr_ign); 757 + } 758 + } 759 + 717 760 static inline u64 adjust_lpm_residency(struct pmc *pmc, u32 offset, 718 761 const int lpm_adj_x2) 719 762 { ··· 1528 1485 module_param(warn_on_s0ix_failures, bool, 0644); 1529 1486 MODULE_PARM_DESC(warn_on_s0ix_failures, "Check and warn for S0ix failures"); 1530 1487 1488 + static bool ltr_ignore_all_suspend = true; 1489 + module_param(ltr_ignore_all_suspend, bool, 0644); 1490 + MODULE_PARM_DESC(ltr_ignore_all_suspend, "Ignore all LTRs during suspend"); 1491 + 1531 1492 static __maybe_unused int pmc_core_suspend(struct device *dev) 1532 1493 { 1533 1494 struct pmc_dev *pmcdev = dev_get_drvdata(dev); ··· 1540 1493 1541 1494 if (pmcdev->suspend) 1542 1495 pmcdev->suspend(pmcdev); 1496 + 1497 + if (ltr_ignore_all_suspend) 1498 + pmc_core_ltr_ignore_all(pmcdev); 1543 1499 1544 1500 /* Check if the syspend will actually use S0ix */ 1545 1501 if (pm_suspend_via_firmware()) ··· 1649 1599 static __maybe_unused int pmc_core_resume(struct device *dev) 1650 1600 { 1651 1601 struct pmc_dev *pmcdev = dev_get_drvdata(dev); 1602 + 1603 + if (ltr_ignore_all_suspend) 1604 + pmc_core_ltr_restore_all(pmcdev); 1652 1605 1653 1606 if (pmcdev->resume) 1654 1607 return pmcdev->resume(pmcdev);
+2
drivers/platform/x86/intel/pmc/core.h
··· 372 372 * @map: pointer to pmc_reg_map struct that contains platform 373 373 * specific attributes 374 374 * @lpm_req_regs: List of substate requirements 375 + * @ltr_ign: Holds LTR ignore data while suspended 375 376 * 376 377 * pmc contains info about one power management controller device. 377 378 */ ··· 381 380 void __iomem *regbase; 382 381 const struct pmc_reg_map *map; 383 382 u32 *lpm_req_regs; 383 + u32 ltr_ign; 384 384 }; 385 385 386 386 /**