Skip to content

Commit 0118637

Browse files
committed
platform/x86: intel/pmc: Ignore all LTRs during suspend
JIRA: https://issues.redhat.com/browse/RHEL-65816 commit cedf233 Author: Xi Pardee <xi.pardee@intel.com> Date: Fri Sep 6 11:40:03 2024 -0700 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> Signed-off-by: David Arcari <darcari@redhat.com>
1 parent 2a2f46f commit 0118637

File tree

2 files changed

+55
-0
lines changed

2 files changed

+55
-0
lines changed

drivers/platform/x86/intel/pmc/core.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,49 @@ static int pmc_core_s0ix_blocker_show(struct seq_file *s, void *unused)
715715
}
716716
DEFINE_SHOW_ATTRIBUTE(pmc_core_s0ix_blocker);
717717

718+
static void pmc_core_ltr_ignore_all(struct pmc_dev *pmcdev)
719+
{
720+
unsigned int i;
721+
722+
for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); i++) {
723+
struct pmc *pmc;
724+
u32 ltr_ign;
725+
726+
pmc = pmcdev->pmcs[i];
727+
if (!pmc)
728+
continue;
729+
730+
guard(mutex)(&pmcdev->lock);
731+
pmc->ltr_ign = pmc_core_reg_read(pmc, pmc->map->ltr_ignore_offset);
732+
733+
/* ltr_ignore_max is the max index value for LTR ignore register */
734+
ltr_ign = pmc->ltr_ign | GENMASK(pmc->map->ltr_ignore_max, 0);
735+
pmc_core_reg_write(pmc, pmc->map->ltr_ignore_offset, ltr_ign);
736+
}
737+
738+
/*
739+
* Ignoring ME during suspend is blocking platforms with ADL PCH to get to
740+
* deeper S0ix substate.
741+
*/
742+
pmc_core_send_ltr_ignore(pmcdev, 6, 0);
743+
}
744+
745+
static void pmc_core_ltr_restore_all(struct pmc_dev *pmcdev)
746+
{
747+
unsigned int i;
748+
749+
for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); i++) {
750+
struct pmc *pmc;
751+
752+
pmc = pmcdev->pmcs[i];
753+
if (!pmc)
754+
continue;
755+
756+
guard(mutex)(&pmcdev->lock);
757+
pmc_core_reg_write(pmc, pmc->map->ltr_ignore_offset, pmc->ltr_ign);
758+
}
759+
}
760+
718761
static inline u64 adjust_lpm_residency(struct pmc *pmc, u32 offset,
719762
const int lpm_adj_x2)
720763
{
@@ -1530,6 +1573,10 @@ static bool warn_on_s0ix_failures;
15301573
module_param(warn_on_s0ix_failures, bool, 0644);
15311574
MODULE_PARM_DESC(warn_on_s0ix_failures, "Check and warn for S0ix failures");
15321575

1576+
static bool ltr_ignore_all_suspend = true;
1577+
module_param(ltr_ignore_all_suspend, bool, 0644);
1578+
MODULE_PARM_DESC(ltr_ignore_all_suspend, "Ignore all LTRs during suspend");
1579+
15331580
static __maybe_unused int pmc_core_suspend(struct device *dev)
15341581
{
15351582
struct pmc_dev *pmcdev = dev_get_drvdata(dev);
@@ -1539,6 +1586,9 @@ static __maybe_unused int pmc_core_suspend(struct device *dev)
15391586
if (pmcdev->suspend)
15401587
pmcdev->suspend(pmcdev);
15411588

1589+
if (ltr_ignore_all_suspend)
1590+
pmc_core_ltr_ignore_all(pmcdev);
1591+
15421592
/* Check if the syspend will actually use S0ix */
15431593
if (pm_suspend_via_firmware())
15441594
return 0;
@@ -1645,6 +1695,9 @@ static __maybe_unused int pmc_core_resume(struct device *dev)
16451695
{
16461696
struct pmc_dev *pmcdev = dev_get_drvdata(dev);
16471697

1698+
if (ltr_ignore_all_suspend)
1699+
pmc_core_ltr_restore_all(pmcdev);
1700+
16481701
if (pmcdev->resume)
16491702
return pmcdev->resume(pmcdev);
16501703

drivers/platform/x86/intel/pmc/core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,7 @@ struct pmc_info {
378378
* @map: pointer to pmc_reg_map struct that contains platform
379379
* specific attributes
380380
* @lpm_req_regs: List of substate requirements
381+
* @ltr_ign: Holds LTR ignore data while suspended
381382
*
382383
* pmc contains info about one power management controller device.
383384
*/
@@ -386,6 +387,7 @@ struct pmc {
386387
void __iomem *regbase;
387388
const struct pmc_reg_map *map;
388389
u32 *lpm_req_regs;
390+
u32 ltr_ign;
389391
};
390392

391393
/**

0 commit comments

Comments
 (0)