* [PATCH v3 06/12] amd-pstate: Add sysfs support for floor_freq and floor_count
From: Gautham R. Shenoy @ 2026-03-20 14:43 UTC (permalink / raw)
To: Mario Limonciello, Rafael J . Wysocki, Viresh Kumar,
K Prateek Nayak
Cc: linux-kernel, linux-pm, Gautham R. Shenoy
In-Reply-To: <20260320144321.18543-1-gautham.shenoy@amd.com>
When Floor Performance feature is supported by the platform, expose
two sysfs files:
* amd_pstate_floor_freq to allow userspace to request the floor
frequency for each CPU.
* amd_pstate_floor_count which advertises the number of distinct
levels of floor frequencies supported on this platform.
Reset the floor_perf to bios_floor_perf in the suspend, offline, and
exit paths, and restore the value to the cached user-request
floor_freq on the resume and online paths mirroring how bios_min_perf
is handled for MSR_AMD_CPPC_REQ.
Signed-off-by: Gautham R. Shenoy <gautham.shenoy@amd.com>
---
drivers/cpufreq/amd-pstate.c | 93 +++++++++++++++++++++++++++++++++---
drivers/cpufreq/amd-pstate.h | 2 +
2 files changed, 89 insertions(+), 6 deletions(-)
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
index 53b8173ff183..a068c4457a8f 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -383,8 +383,10 @@ static int amd_pstate_init_floor_perf(struct cpufreq_policy *policy)
return ret;
}
- cpudata->bios_floor_perf = floor_perf;
+ cpudata->bios_floor_perf = floor_perf;
+ cpudata->floor_freq = perf_to_freq(cpudata->perf, cpudata->nominal_freq,
+ floor_perf);
return 0;
}
@@ -1288,6 +1290,46 @@ static ssize_t show_energy_performance_preference(
return sysfs_emit(buf, "%s\n", energy_perf_strings[preference]);
}
+static ssize_t store_amd_pstate_floor_freq(struct cpufreq_policy *policy,
+ const char *buf, size_t count)
+{
+ struct amd_cpudata *cpudata = policy->driver_data;
+ union perf_cached perf = READ_ONCE(cpudata->perf);
+ unsigned int freq;
+ u8 floor_perf;
+ int ret;
+
+ ret = kstrtouint(buf, 0, &freq);
+ if (ret)
+ return ret;
+
+ if (freq < policy->cpuinfo.min_freq || freq > policy->max)
+ return -EINVAL;
+
+ floor_perf = freq_to_perf(perf, cpudata->nominal_freq, freq);
+ ret = amd_pstate_set_floor_perf(policy, floor_perf);
+
+ if (!ret)
+ cpudata->floor_freq = freq;
+
+ return ret ?: count;
+}
+
+static ssize_t show_amd_pstate_floor_freq(struct cpufreq_policy *policy, char *buf)
+{
+ struct amd_cpudata *cpudata = policy->driver_data;
+
+ return sysfs_emit(buf, "%u\n", cpudata->floor_freq);
+}
+
+static ssize_t show_amd_pstate_floor_count(struct cpufreq_policy *policy, char *buf)
+{
+ struct amd_cpudata *cpudata = policy->driver_data;
+ u8 count = cpudata->floor_perf_cnt;
+
+ return sysfs_emit(buf, "%u\n", count);
+}
+
cpufreq_freq_attr_ro(amd_pstate_max_freq);
cpufreq_freq_attr_ro(amd_pstate_lowest_nonlinear_freq);
@@ -1296,6 +1338,8 @@ cpufreq_freq_attr_ro(amd_pstate_prefcore_ranking);
cpufreq_freq_attr_ro(amd_pstate_hw_prefcore);
cpufreq_freq_attr_rw(energy_performance_preference);
cpufreq_freq_attr_ro(energy_performance_available_preferences);
+cpufreq_freq_attr_rw(amd_pstate_floor_freq);
+cpufreq_freq_attr_ro(amd_pstate_floor_count);
struct freq_attr_visibility {
struct freq_attr *attr;
@@ -1320,6 +1364,12 @@ static bool epp_visibility(void)
return cppc_state == AMD_PSTATE_ACTIVE;
}
+/* Determines whether amd_pstate_floor_freq related attributes should be visible */
+static bool floor_freq_visibility(void)
+{
+ return cpu_feature_enabled(X86_FEATURE_CPPC_PERF_PRIO);
+}
+
static struct freq_attr_visibility amd_pstate_attr_visibility[] = {
{&amd_pstate_max_freq, always_visible},
{&amd_pstate_lowest_nonlinear_freq, always_visible},
@@ -1328,6 +1378,8 @@ static struct freq_attr_visibility amd_pstate_attr_visibility[] = {
{&amd_pstate_hw_prefcore, prefcore_visibility},
{&energy_performance_preference, epp_visibility},
{&energy_performance_available_preferences, epp_visibility},
+ {&amd_pstate_floor_freq, floor_freq_visibility},
+ {&amd_pstate_floor_count, floor_freq_visibility},
};
static struct freq_attr **get_freq_attrs(void)
@@ -1748,24 +1800,39 @@ static int amd_pstate_epp_set_policy(struct cpufreq_policy *policy)
static int amd_pstate_cpu_online(struct cpufreq_policy *policy)
{
- return amd_pstate_cppc_enable(policy);
+ struct amd_cpudata *cpudata = policy->driver_data;
+ union perf_cached perf = READ_ONCE(cpudata->perf);
+ u8 cached_floor_perf;
+ int ret;
+
+ ret = amd_pstate_cppc_enable(policy);
+ if (ret)
+ return ret;
+
+ cached_floor_perf = freq_to_perf(perf, cpudata->nominal_freq, cpudata->floor_freq);
+ return amd_pstate_set_floor_perf(policy, cached_floor_perf);
}
static int amd_pstate_cpu_offline(struct cpufreq_policy *policy)
{
struct amd_cpudata *cpudata = policy->driver_data;
union perf_cached perf = READ_ONCE(cpudata->perf);
+ int ret;
/*
* Reset CPPC_REQ MSR to the BIOS value, this will allow us to retain the BIOS specified
* min_perf value across kexec reboots. If this CPU is just onlined normally after this, the
* limits, epp and desired perf will get reset to the cached values in cpudata struct
*/
- return amd_pstate_update_perf(policy, perf.bios_min_perf,
+ ret = amd_pstate_update_perf(policy, perf.bios_min_perf,
FIELD_GET(AMD_CPPC_DES_PERF_MASK, cpudata->cppc_req_cached),
FIELD_GET(AMD_CPPC_MAX_PERF_MASK, cpudata->cppc_req_cached),
FIELD_GET(AMD_CPPC_EPP_PERF_MASK, cpudata->cppc_req_cached),
false);
+ if (ret)
+ return ret;
+
+ return amd_pstate_set_floor_perf(policy, cpudata->bios_floor_perf);
}
static int amd_pstate_suspend(struct cpufreq_policy *policy)
@@ -1787,6 +1854,10 @@ static int amd_pstate_suspend(struct cpufreq_policy *policy)
if (ret)
return ret;
+ ret = amd_pstate_set_floor_perf(policy, cpudata->bios_floor_perf);
+ if (ret)
+ return ret;
+
/* set this flag to avoid setting core offline*/
cpudata->suspended = true;
@@ -1798,15 +1869,24 @@ static int amd_pstate_resume(struct cpufreq_policy *policy)
struct amd_cpudata *cpudata = policy->driver_data;
union perf_cached perf = READ_ONCE(cpudata->perf);
int cur_perf = freq_to_perf(perf, cpudata->nominal_freq, policy->cur);
+ u8 cached_floor_perf;
+ int ret;
/* Set CPPC_REQ to last sane value until the governor updates it */
- return amd_pstate_update_perf(policy, perf.min_limit_perf, cur_perf, perf.max_limit_perf,
- 0U, false);
+ ret = amd_pstate_update_perf(policy, perf.min_limit_perf, cur_perf, perf.max_limit_perf,
+ 0U, false);
+ if (ret)
+ return ret;
+
+ cached_floor_perf = freq_to_perf(perf, cpudata->nominal_freq, cpudata->floor_freq);
+ return amd_pstate_set_floor_perf(policy, cached_floor_perf);
}
static int amd_pstate_epp_resume(struct cpufreq_policy *policy)
{
struct amd_cpudata *cpudata = policy->driver_data;
+ union perf_cached perf = READ_ONCE(cpudata->perf);
+ u8 cached_floor_perf;
if (cpudata->suspended) {
int ret;
@@ -1819,7 +1899,8 @@ static int amd_pstate_epp_resume(struct cpufreq_policy *policy)
cpudata->suspended = false;
}
- return 0;
+ cached_floor_perf = freq_to_perf(perf, cpudata->nominal_freq, cpudata->floor_freq);
+ return amd_pstate_set_floor_perf(policy, cached_floor_perf);
}
static struct cpufreq_driver amd_pstate_driver = {
diff --git a/drivers/cpufreq/amd-pstate.h b/drivers/cpufreq/amd-pstate.h
index f04561da4518..2f7a96836fcd 100644
--- a/drivers/cpufreq/amd-pstate.h
+++ b/drivers/cpufreq/amd-pstate.h
@@ -72,6 +72,7 @@ struct amd_aperf_mperf {
* @max_limit_freq: Cached value of policy->max (in khz)
* @nominal_freq: the frequency (in khz) that mapped to nominal_perf
* @lowest_nonlinear_freq: the frequency (in khz) that mapped to lowest_nonlinear_perf
+ * @floor_freq: Cached value of the user requested floor_freq
* @cur: Difference of Aperf/Mperf/tsc count between last and current sample
* @prev: Last Aperf/Mperf/tsc count value read from register
* @freq: current cpu frequency value (in khz)
@@ -101,6 +102,7 @@ struct amd_cpudata {
u32 max_limit_freq;
u32 nominal_freq;
u32 lowest_nonlinear_freq;
+ u32 floor_freq;
struct amd_aperf_mperf cur;
struct amd_aperf_mperf prev;
--
2.34.1
^ permalink raw reply related
* [PATCH v3 05/12] amd-pstate: Add support for CPPC_REQ2 and FLOOR_PERF
From: Gautham R. Shenoy @ 2026-03-20 14:43 UTC (permalink / raw)
To: Mario Limonciello, Rafael J . Wysocki, Viresh Kumar,
K Prateek Nayak
Cc: linux-kernel, linux-pm, Gautham R. Shenoy
In-Reply-To: <20260320144321.18543-1-gautham.shenoy@amd.com>
Some future AMD processors have feature named "CPPC Performance
Priority" which lets userspace specify different floor performance
levels for different CPUs. The platform firmware takes these different
floor performance levels into consideration while throttling the CPUs
under power/thermal constraints. The presence of this feature is
indicated by bit 16 of the EDX register for CPUID leaf
0x80000007. More details can be found in AMD Publication titled "AMD64
Collaborative Processor Performance Control (CPPC) Performance
Priority" Revision 1.10.
The number of distinct floor performance levels supported on the
platform will be advertised through the bits 32:39 of the
MSR_AMD_CPPC_CAP1. Bits 0:7 of a new MSR MSR_AMD_CPPC_REQ2
(0xc00102b5) will be used to specify the desired floor performance
level for that CPU.
Add support for the aforementioned MSR_AMD_CPPC_REQ2, and macros for
parsing and updating the relevant bits from MSR_AMD_CPPC_CAP1 and
MSR_AMD_CPPC_REQ2.
On boot if the default value of the MSR_AMD_CPPC_REQ2[7:0] (Floor
Perf) is lower than CPPC.lowest_perf, and thus invalid, initialize it
to MSR_AMD_CPPC_CAP1.nominal_perf which is a sane default value.
Save the boot-time floor_perf during amd_pstate_init_floor_perf(). In
a subsequent patch it will be restored in the suspend, offline, and
exit paths, mirroring how bios_min_perf is handled for
MSR_AMD_CPPC_REQ.
Link: https://docs.amd.com/v/u/en-US/69206_1.10_AMD64_CPPC_PUB
Signed-off-by: Gautham R. Shenoy <gautham.shenoy@amd.com>
---
arch/x86/include/asm/msr-index.h | 5 ++
drivers/cpufreq/amd-pstate.c | 78 +++++++++++++++++++++++++++++++-
drivers/cpufreq/amd-pstate.h | 6 +++
3 files changed, 88 insertions(+), 1 deletion(-)
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 6673601246b3..e126c7fb69cf 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -765,12 +765,14 @@
#define MSR_AMD_CPPC_CAP2 0xc00102b2
#define MSR_AMD_CPPC_REQ 0xc00102b3
#define MSR_AMD_CPPC_STATUS 0xc00102b4
+#define MSR_AMD_CPPC_REQ2 0xc00102b5
/* Masks for use with MSR_AMD_CPPC_CAP1 */
#define AMD_CPPC_LOWEST_PERF_MASK GENMASK(7, 0)
#define AMD_CPPC_LOWNONLIN_PERF_MASK GENMASK(15, 8)
#define AMD_CPPC_NOMINAL_PERF_MASK GENMASK(23, 16)
#define AMD_CPPC_HIGHEST_PERF_MASK GENMASK(31, 24)
+#define AMD_CPPC_FLOOR_PERF_CNT_MASK GENMASK_ULL(39, 32)
/* Masks for use with MSR_AMD_CPPC_REQ */
#define AMD_CPPC_MAX_PERF_MASK GENMASK(7, 0)
@@ -778,6 +780,9 @@
#define AMD_CPPC_DES_PERF_MASK GENMASK(23, 16)
#define AMD_CPPC_EPP_PERF_MASK GENMASK(31, 24)
+/* Masks for use with MSR_AMD_CPPC_REQ2 */
+#define AMD_CPPC_FLOOR_PERF_MASK GENMASK(7, 0)
+
/* AMD Performance Counter Global Status and Control MSRs */
#define MSR_AMD64_PERF_CNTR_GLOBAL_STATUS 0xc0000300
#define MSR_AMD64_PERF_CNTR_GLOBAL_CTL 0xc0000301
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
index 4de2037a414c..53b8173ff183 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -329,6 +329,65 @@ static inline int amd_pstate_set_epp(struct cpufreq_policy *policy, u8 epp)
return static_call(amd_pstate_set_epp)(policy, epp);
}
+static int amd_pstate_set_floor_perf(struct cpufreq_policy *policy, u8 perf)
+{
+ struct amd_cpudata *cpudata = policy->driver_data;
+ u64 value, prev;
+ int ret;
+
+ if (!cpu_feature_enabled(X86_FEATURE_CPPC_PERF_PRIO))
+ return 0;
+
+ value = prev = READ_ONCE(cpudata->cppc_req2_cached);
+ FIELD_MODIFY(AMD_CPPC_FLOOR_PERF_MASK, &value, perf);
+
+ if (value == prev)
+ return 0;
+
+ ret = wrmsrq_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ2, value);
+ if (ret) {
+ pr_err("failed to set CPPC REQ2 value. Error (%d)\n", ret);
+ return ret;
+ }
+
+ WRITE_ONCE(cpudata->cppc_req2_cached, value);
+
+ return ret;
+}
+
+static int amd_pstate_init_floor_perf(struct cpufreq_policy *policy)
+{
+ struct amd_cpudata *cpudata = policy->driver_data;
+ u8 floor_perf;
+ u64 value;
+ int ret;
+
+ if (!cpu_feature_enabled(X86_FEATURE_CPPC_PERF_PRIO))
+ return 0;
+
+ ret = rdmsrq_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ2, &value);
+ if (ret) {
+ pr_err("failed to read CPPC REQ2 value. Error (%d)\n", ret);
+ return ret;
+ }
+
+ WRITE_ONCE(cpudata->cppc_req2_cached, value);
+ floor_perf = FIELD_GET(AMD_CPPC_FLOOR_PERF_MASK,
+ cpudata->cppc_req2_cached);
+
+ /* Set a sane value for floor_perf if the default value is invalid */
+ if (floor_perf < cpudata->perf.lowest_perf) {
+ floor_perf = cpudata->perf.nominal_perf;
+ ret = amd_pstate_set_floor_perf(policy, floor_perf);
+ if (ret)
+ return ret;
+ }
+
+ cpudata->bios_floor_perf = floor_perf;
+
+ return 0;
+}
+
static int shmem_set_epp(struct cpufreq_policy *policy, u8 epp)
{
struct amd_cpudata *cpudata = policy->driver_data;
@@ -426,6 +485,7 @@ static int msr_init_perf(struct amd_cpudata *cpudata)
perf.lowest_perf = FIELD_GET(AMD_CPPC_LOWEST_PERF_MASK, cap1);
WRITE_ONCE(cpudata->perf, perf);
WRITE_ONCE(cpudata->prefcore_ranking, FIELD_GET(AMD_CPPC_HIGHEST_PERF_MASK, cap1));
+ WRITE_ONCE(cpudata->floor_perf_cnt, FIELD_GET(AMD_CPPC_FLOOR_PERF_CNT_MASK, cap1));
return 0;
}
@@ -1024,6 +1084,7 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
cpudata->nominal_freq,
perf.highest_perf);
+ policy->driver_data = cpudata;
ret = amd_pstate_cppc_enable(policy);
if (ret)
goto free_cpudata1;
@@ -1036,6 +1097,12 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
if (cpu_feature_enabled(X86_FEATURE_CPPC))
policy->fast_switch_possible = true;
+ ret = amd_pstate_init_floor_perf(policy);
+ if (ret) {
+ dev_err(dev, "Failed to initialize Floor Perf (%d)\n", ret);
+ goto free_cpudata1;
+ }
+
ret = freq_qos_add_request(&policy->constraints, &cpudata->req[0],
FREQ_QOS_MIN, FREQ_QOS_MIN_DEFAULT_VALUE);
if (ret < 0) {
@@ -1050,7 +1117,6 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
goto free_cpudata2;
}
- policy->driver_data = cpudata;
if (!current_pstate_driver->adjust_perf)
current_pstate_driver->adjust_perf = amd_pstate_adjust_perf;
@@ -1062,6 +1128,7 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
free_cpudata1:
pr_warn("Failed to initialize CPU %d: %d\n", policy->cpu, ret);
kfree(cpudata);
+ policy->driver_data = NULL;
return ret;
}
@@ -1072,6 +1139,7 @@ static void amd_pstate_cpu_exit(struct cpufreq_policy *policy)
/* Reset CPPC_REQ MSR to the BIOS value */
amd_pstate_update_perf(policy, perf.bios_min_perf, 0U, 0U, 0U, false);
+ amd_pstate_set_floor_perf(policy, cpudata->bios_floor_perf);
freq_qos_remove_request(&cpudata->req[1]);
freq_qos_remove_request(&cpudata->req[0]);
@@ -1598,6 +1666,12 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
if (ret)
goto free_cpudata1;
+ ret = amd_pstate_init_floor_perf(policy);
+ if (ret) {
+ dev_err(dev, "Failed to initialize Floor Perf (%d)\n", ret);
+ goto free_cpudata1;
+ }
+
current_pstate_driver->adjust_perf = NULL;
return 0;
@@ -1605,6 +1679,7 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
free_cpudata1:
pr_warn("Failed to initialize CPU %d: %d\n", policy->cpu, ret);
kfree(cpudata);
+ policy->driver_data = NULL;
return ret;
}
@@ -1617,6 +1692,7 @@ static void amd_pstate_epp_cpu_exit(struct cpufreq_policy *policy)
/* Reset CPPC_REQ MSR to the BIOS value */
amd_pstate_update_perf(policy, perf.bios_min_perf, 0U, 0U, 0U, false);
+ amd_pstate_set_floor_perf(policy, cpudata->bios_floor_perf);
kfree(cpudata);
policy->driver_data = NULL;
diff --git a/drivers/cpufreq/amd-pstate.h b/drivers/cpufreq/amd-pstate.h
index cb45fdca27a6..f04561da4518 100644
--- a/drivers/cpufreq/amd-pstate.h
+++ b/drivers/cpufreq/amd-pstate.h
@@ -62,9 +62,12 @@ struct amd_aperf_mperf {
* @cpu: CPU number
* @req: constraint request to apply
* @cppc_req_cached: cached performance request hints
+ * @cppc_req2_cached: cached value of MSR_AMD_CPPC_REQ2
* @perf: cached performance-related data
* @prefcore_ranking: the preferred core ranking, the higher value indicates a higher
* priority.
+ * @floor_perf_cnt: Cached value of the number of distinct floor
+ * performance levels supported
* @min_limit_freq: Cached value of policy->min (in khz)
* @max_limit_freq: Cached value of policy->max (in khz)
* @nominal_freq: the frequency (in khz) that mapped to nominal_perf
@@ -87,10 +90,13 @@ struct amd_cpudata {
struct freq_qos_request req[2];
u64 cppc_req_cached;
+ u64 cppc_req2_cached;
union perf_cached perf;
u8 prefcore_ranking;
+ u8 floor_perf_cnt;
+ u8 bios_floor_perf;
u32 min_limit_freq;
u32 max_limit_freq;
u32 nominal_freq;
--
2.34.1
^ permalink raw reply related
* [PATCH v3 04/12] x86/cpufeatures: Add AMD CPPC Performance Priority feature.
From: Gautham R. Shenoy @ 2026-03-20 14:43 UTC (permalink / raw)
To: Mario Limonciello, Rafael J . Wysocki, Viresh Kumar,
K Prateek Nayak
Cc: linux-kernel, linux-pm, Gautham R. Shenoy, H. Peter Anvin,
Borislav Petkov, Dave Hansen, Thomas Gleixner, Ingo Molnar, x86
In-Reply-To: <20260320144321.18543-1-gautham.shenoy@amd.com>
Some future AMD processors have feature named "CPPC Performance
Priority" which lets userspace specify different floor performance
levels for different CPUs. The platform firmware takes these different
floor performance levels into consideration while throttling the CPUs
under power/thermal constraints. The presence of this feature is
indicated by bit 16 of the EDX register for CPUID leaf
0x80000007. More details can be found in AMD Publication titled "AMD64
Collaborative Processor Performance Control (CPPC) Performance
Priority" Revision 1.10.
Define a new feature bit named X86_FEATURE_CPPC_PERF_PRIO to map to
CPUID 0x80000007.EDX[16].
Reviewed-by: Borislav Petkov (AMD) <bp@alien8.de>
Signed-off-by: Gautham R. Shenoy <gautham.shenoy@amd.com>
---
arch/x86/include/asm/cpufeatures.h | 2 +-
arch/x86/kernel/cpu/scattered.c | 1 +
tools/arch/x86/include/asm/cpufeatures.h | 2 +-
3 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index dbe104df339b..86d17b195e79 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -415,7 +415,7 @@
*/
#define X86_FEATURE_OVERFLOW_RECOV (17*32+ 0) /* "overflow_recov" MCA overflow recovery support */
#define X86_FEATURE_SUCCOR (17*32+ 1) /* "succor" Uncorrectable error containment and recovery */
-
+#define X86_FEATURE_CPPC_PERF_PRIO (17*32+ 2) /* CPPC Floor Perf support */
#define X86_FEATURE_SMCA (17*32+ 3) /* "smca" Scalable MCA */
/* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */
diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c
index 42c7eac0c387..837d6a4b0c28 100644
--- a/arch/x86/kernel/cpu/scattered.c
+++ b/arch/x86/kernel/cpu/scattered.c
@@ -52,6 +52,7 @@ static const struct cpuid_bit cpuid_bits[] = {
{ X86_FEATURE_CPB, CPUID_EDX, 9, 0x80000007, 0 },
{ X86_FEATURE_PROC_FEEDBACK, CPUID_EDX, 11, 0x80000007, 0 },
{ X86_FEATURE_AMD_FAST_CPPC, CPUID_EDX, 15, 0x80000007, 0 },
+ { X86_FEATURE_CPPC_PERF_PRIO, CPUID_EDX, 16, 0x80000007, 0 },
{ X86_FEATURE_MBA, CPUID_EBX, 6, 0x80000008, 0 },
{ X86_FEATURE_X2AVIC_EXT, CPUID_ECX, 6, 0x8000000a, 0 },
{ X86_FEATURE_COHERENCY_SFW_NO, CPUID_EBX, 31, 0x8000001f, 0 },
diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h
index dbe104df339b..86d17b195e79 100644
--- a/tools/arch/x86/include/asm/cpufeatures.h
+++ b/tools/arch/x86/include/asm/cpufeatures.h
@@ -415,7 +415,7 @@
*/
#define X86_FEATURE_OVERFLOW_RECOV (17*32+ 0) /* "overflow_recov" MCA overflow recovery support */
#define X86_FEATURE_SUCCOR (17*32+ 1) /* "succor" Uncorrectable error containment and recovery */
-
+#define X86_FEATURE_CPPC_PERF_PRIO (17*32+ 2) /* CPPC Floor Perf support */
#define X86_FEATURE_SMCA (17*32+ 3) /* "smca" Scalable MCA */
/* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */
--
2.34.1
^ permalink raw reply related
* [PATCH v3 03/12] amd-pstate: Make certain freq_attrs conditionally visible
From: Gautham R. Shenoy @ 2026-03-20 14:43 UTC (permalink / raw)
To: Mario Limonciello, Rafael J . Wysocki, Viresh Kumar,
K Prateek Nayak
Cc: linux-kernel, linux-pm, Gautham R. Shenoy, Mario Limonciello
In-Reply-To: <20260320144321.18543-1-gautham.shenoy@amd.com>
Certain amd_pstate freq_attrs such as amd_pstate_hw_prefcore and
amd_pstate_prefcore_ranking are enabled even when preferred core is
not supported on the platform.
Similarly there are common freq_attrs between the amd-pstate and the
amd-pstate-epp drivers (eg: amd_pstate_max_freq,
amd_pstate_lowest_nonlinear_freq, etc.) but are duplicated in two
different freq_attr structs.
Unify all the attributes in a single place and associate each of them
with a visibility function that determines whether the attribute
should be visible based on the underlying platform support and the
current amd_pstate mode.
Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
Signed-off-by: Gautham R. Shenoy <gautham.shenoy@amd.com>
---
drivers/cpufreq/amd-pstate.c | 124 ++++++++++++++++++++++++++---------
1 file changed, 93 insertions(+), 31 deletions(-)
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
index 24cdeffbcd40..4de2037a414c 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -1220,12 +1220,87 @@ static ssize_t show_energy_performance_preference(
return sysfs_emit(buf, "%s\n", energy_perf_strings[preference]);
}
+cpufreq_freq_attr_ro(amd_pstate_max_freq);
+cpufreq_freq_attr_ro(amd_pstate_lowest_nonlinear_freq);
+
+cpufreq_freq_attr_ro(amd_pstate_highest_perf);
+cpufreq_freq_attr_ro(amd_pstate_prefcore_ranking);
+cpufreq_freq_attr_ro(amd_pstate_hw_prefcore);
+cpufreq_freq_attr_rw(energy_performance_preference);
+cpufreq_freq_attr_ro(energy_performance_available_preferences);
+
+struct freq_attr_visibility {
+ struct freq_attr *attr;
+ bool (*visibility_fn)(void);
+};
+
+/* For attributes which are always visible */
+static bool always_visible(void)
+{
+ return true;
+}
+
+/* Determines whether prefcore related attributes should be visible */
+static bool prefcore_visibility(void)
+{
+ return amd_pstate_prefcore;
+}
+
+/* Determines whether energy performance preference should be visible */
+static bool epp_visibility(void)
+{
+ return cppc_state == AMD_PSTATE_ACTIVE;
+}
+
+static struct freq_attr_visibility amd_pstate_attr_visibility[] = {
+ {&amd_pstate_max_freq, always_visible},
+ {&amd_pstate_lowest_nonlinear_freq, always_visible},
+ {&amd_pstate_highest_perf, always_visible},
+ {&amd_pstate_prefcore_ranking, prefcore_visibility},
+ {&amd_pstate_hw_prefcore, prefcore_visibility},
+ {&energy_performance_preference, epp_visibility},
+ {&energy_performance_available_preferences, epp_visibility},
+};
+
+static struct freq_attr **get_freq_attrs(void)
+{
+ bool attr_visible[ARRAY_SIZE(amd_pstate_attr_visibility)];
+ struct freq_attr **attrs;
+ int i, j, count;
+
+ for (i = 0, count = 0; i < ARRAY_SIZE(amd_pstate_attr_visibility); i++) {
+ struct freq_attr_visibility *v = &amd_pstate_attr_visibility[i];
+
+ attr_visible[i] = v->visibility_fn();
+ if (attr_visible[i])
+ count++;
+ }
+
+ /* amd_pstate_{max_freq, lowest_nonlinear_freq, highest_perf} should always be visible */
+ BUG_ON(!count);
+
+ attrs = kcalloc(count + 1, sizeof(struct freq_attr *), GFP_KERNEL);
+ if (!attrs)
+ return ERR_PTR(-ENOMEM);
+
+ for (i = 0, j = 0; i < ARRAY_SIZE(amd_pstate_attr_visibility); i++) {
+ if (!attr_visible[i])
+ continue;
+
+ attrs[j++] = amd_pstate_attr_visibility[i].attr;
+ }
+
+ return attrs;
+}
+
static void amd_pstate_driver_cleanup(void)
{
if (amd_pstate_prefcore)
sched_clear_itmt_support();
cppc_state = AMD_PSTATE_DISABLE;
+ kfree(current_pstate_driver->attr);
+ current_pstate_driver->attr = NULL;
current_pstate_driver = NULL;
}
@@ -1250,6 +1325,7 @@ static int amd_pstate_set_driver(int mode_idx)
static int amd_pstate_register_driver(int mode)
{
+ struct freq_attr **attr = NULL;
int ret;
ret = amd_pstate_set_driver(mode);
@@ -1258,6 +1334,22 @@ static int amd_pstate_register_driver(int mode)
cppc_state = mode;
+ /*
+ * Note: It is important to compute the attrs _after_
+ * re-initializing the cppc_state. Some attributes become
+ * visible only when cppc_state is AMD_PSTATE_ACTIVE.
+ */
+ attr = get_freq_attrs();
+ if (IS_ERR(attr)) {
+ ret = (int) PTR_ERR(attr);
+ pr_err("Couldn't compute freq_attrs for current mode %s [%d]\n",
+ amd_pstate_get_mode_string(cppc_state), ret);
+ amd_pstate_driver_cleanup();
+ return ret;
+ }
+
+ current_pstate_driver->attr = attr;
+
/* at least one CPU supports CPB */
current_pstate_driver->boost_enabled = cpu_feature_enabled(X86_FEATURE_CPB);
@@ -1399,37 +1491,9 @@ static ssize_t prefcore_show(struct device *dev,
return sysfs_emit(buf, "%s\n", str_enabled_disabled(amd_pstate_prefcore));
}
-cpufreq_freq_attr_ro(amd_pstate_max_freq);
-cpufreq_freq_attr_ro(amd_pstate_lowest_nonlinear_freq);
-
-cpufreq_freq_attr_ro(amd_pstate_highest_perf);
-cpufreq_freq_attr_ro(amd_pstate_prefcore_ranking);
-cpufreq_freq_attr_ro(amd_pstate_hw_prefcore);
-cpufreq_freq_attr_rw(energy_performance_preference);
-cpufreq_freq_attr_ro(energy_performance_available_preferences);
static DEVICE_ATTR_RW(status);
static DEVICE_ATTR_RO(prefcore);
-static struct freq_attr *amd_pstate_attr[] = {
- &amd_pstate_max_freq,
- &amd_pstate_lowest_nonlinear_freq,
- &amd_pstate_highest_perf,
- &amd_pstate_prefcore_ranking,
- &amd_pstate_hw_prefcore,
- NULL,
-};
-
-static struct freq_attr *amd_pstate_epp_attr[] = {
- &amd_pstate_max_freq,
- &amd_pstate_lowest_nonlinear_freq,
- &amd_pstate_highest_perf,
- &amd_pstate_prefcore_ranking,
- &amd_pstate_hw_prefcore,
- &energy_performance_preference,
- &energy_performance_available_preferences,
- NULL,
-};
-
static struct attribute *pstate_global_attributes[] = {
&dev_attr_status.attr,
&dev_attr_prefcore.attr,
@@ -1696,7 +1760,6 @@ static struct cpufreq_driver amd_pstate_driver = {
.set_boost = amd_pstate_set_boost,
.update_limits = amd_pstate_update_limits,
.name = "amd-pstate",
- .attr = amd_pstate_attr,
};
static struct cpufreq_driver amd_pstate_epp_driver = {
@@ -1712,7 +1775,6 @@ static struct cpufreq_driver amd_pstate_epp_driver = {
.update_limits = amd_pstate_update_limits,
.set_boost = amd_pstate_set_boost,
.name = "amd-pstate-epp",
- .attr = amd_pstate_epp_attr,
};
/*
@@ -1858,7 +1920,7 @@ static int __init amd_pstate_init(void)
return ret;
global_attr_free:
- cpufreq_unregister_driver(current_pstate_driver);
+ amd_pstate_unregister_driver(0);
return ret;
}
device_initcall(amd_pstate_init);
--
2.34.1
^ permalink raw reply related
* [PATCH v3 02/12] amd-pstate: Update cppc_req_cached in fast_switch case
From: Gautham R. Shenoy @ 2026-03-20 14:43 UTC (permalink / raw)
To: Mario Limonciello, Rafael J . Wysocki, Viresh Kumar,
K Prateek Nayak
Cc: linux-kernel, linux-pm, Gautham R. Shenoy, Mario Limonciello
In-Reply-To: <20260320144321.18543-1-gautham.shenoy@amd.com>
The function msr_update_perf() does not cache the new value that is
written to MSR_AMD_CPPC_REQ into the variable cpudata->cppc_req_cached
when the update is happening from the fast path.
Fix that by caching the value everytime the MSR_AMD_CPPC_REQ gets
updated.
This issue was discovered by Claude Opus 4.6 with the aid of Chris
Mason's AI review-prompts
(https://github.com/masoncl/review-prompts/tree/main/kernel).
Assisted-by: Claude:claude-opus-4.6 review-prompts/linux
Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
Fixes: fff395796917 ("cpufreq/amd-pstate: Always write EPP value when updating perf")
Signed-off-by: Gautham R. Shenoy <gautham.shenoy@amd.com>
---
drivers/cpufreq/amd-pstate.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
index d57969c72c9d..24cdeffbcd40 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -261,7 +261,6 @@ static int msr_update_perf(struct cpufreq_policy *policy, u8 min_perf,
if (fast_switch) {
wrmsrq(MSR_AMD_CPPC_REQ, value);
- return 0;
} else {
int ret = wrmsrq_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, value);
--
2.34.1
^ permalink raw reply related
* [PATCH v3 01/12] amd-pstate: Fix memory leak in amd_pstate_epp_cpu_init()
From: Gautham R. Shenoy @ 2026-03-20 14:43 UTC (permalink / raw)
To: Mario Limonciello, Rafael J . Wysocki, Viresh Kumar,
K Prateek Nayak
Cc: linux-kernel, linux-pm, Gautham R. Shenoy, Mario Limonciello
In-Reply-To: <20260320144321.18543-1-gautham.shenoy@amd.com>
On failure to set the epp, the function amd_pstate_epp_cpu_init()
returns with an error code without freeing the cpudata object that was
allocated at the beginning of the function.
Ensure that the cpudata object is freed before returning from the
function.
This memory leak was discovered by Claude Opus 4.6 with the aid of
Chris Mason's AI review-prompts
(https://github.com/masoncl/review-prompts/tree/main/kernel).
Assisted-by: Claude:claude-opus-4.6 review-prompts/linux
Fixes: f9a378ff6443 ("cpufreq/amd-pstate: Set different default EPP policy for Epyc and Ryzen")
Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
Signed-off-by: Gautham R. Shenoy <gautham.shenoy@amd.com>
---
drivers/cpufreq/amd-pstate.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
index 5aa9fcd80cf5..d57969c72c9d 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -1533,7 +1533,7 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
ret = amd_pstate_set_epp(policy, cpudata->epp_default);
if (ret)
- return ret;
+ goto free_cpudata1;
current_pstate_driver->adjust_perf = NULL;
--
2.34.1
^ permalink raw reply related
* [PATCH v3 00/12] amd-pstate: Introduce AMD CPPC Performance Priority
From: Gautham R. Shenoy @ 2026-03-20 14:43 UTC (permalink / raw)
To: Mario Limonciello, Rafael J . Wysocki, Viresh Kumar,
K Prateek Nayak
Cc: linux-kernel, linux-pm, Gautham R. Shenoy
Hello,
This is the v3 of the patchset to add support to the amd-pstate driver
for a new feature named "CPPC Performance Priority" that will be
available on some of the future AMD processors.
Details of the feature can be found in the AMD Publication titled
"AMD64 Collaborative Processor Performance Control (CPPC) Performance
Priority" (https://docs.amd.com/v/u/en-US/69206_1.10_AMD64_CPPC_PUB)
v2-->v3 changes:
* Picked up the Reviewed-by: tags from Mario except for Patches 5 and
6 which have major changes (see below)
* Patch 3: Fixed the subtle bug in amd_pstate_driver_cleanup() by cleaning
setting current_pstate_driver->attr to NULL [Claude Opus 4.6 +
review-prompts]
* Patch 5: Added bios_floor_perf field to struct amd_cpudata to cache
boot-time floor_perf value [New]
* Patch 5: Moved policy->driver_data = cpudata assignment earlier in
amd_pstate_cpu_init() (before amd_pstate_cppc_enable()) so that
policy->driver_data is valid when amd_pstate_init_floor_perf() is
called inside amd_pstate_cppc_enable() [Bug discovered while
running amd-pstate-ut tests]
* Patch 5: Added policy->driver_data = NULL in error paths of both
amd_pstate_cpu_init() and amd_pstate_epp_cpu_init() to clean up on
failure. [Code-Hardening]
* Patch 5: Restores bios_floor_perf via amd_pstate_set_floor_perf() in both
amd_pstate_cpu_exit() and amd_pstate_epp_cpu_exit() [New]
* Patch 6: Added input validation in store_amd_pstate_floor_freq():
rejects frequencies outside [cpuinfo_min_freq, scaling_max_freq]
with -EINVAL. [Code Hardening]
* Patch 6: Removed stray blank line between
show_amd_pstate_floor_freq() and
show_amd_pstate_floor_count(). [Mario]
* Patch 6: Reset the floor_perf to bios_floor_perf in the suspend,
offline, and exit paths, and restore the value to the cached
user-request floor_freq on the resume and online paths mirroring
how bios_min_perf is handled for MSR_AMD_CPPC_REQ [New]
* Patch 8: Add the capability to run a single test from amd_pstate_ut [New]
* Patch 9: New unit test to validate the driver->attrs [Mario]
* Patch 10 and 11: Split the Documentation fixes for
amd_pstate_hw_prefcore and amd_pstate_prefcore_ranking into two
different patches [Mario]
v1 --> v2 Changes:
* Picked up the Reviewed-by: tags from Boris and Mario for a couple of patches.
* Defined AMD_CPPC_FLOOR_PERF_CNT_MASK via GENMASK_ULL() instead of
GENMASK() to fix the build errors reported by the kernel test robot
(https://lore.kernel.org/lkml/202603070431.ykswVnpp-lkp@intel.com/)
* Moved the code from amd_pstate_cache_cppc_req2() into
amd_pstate_init_floor_perf() since there are no other callers of
amd_pstate_cache_cppc_req2().
* Cached the user requested amd_pstate_floor_freq into
cpudata->floor_freq [Prateek] and return the same when the user
reads the syfs file.
Description:
This feature allows userspace to specify different floor performance
levels for different CPUs. The platform firmware takes these different
floor performance levels into consideration while throttling the CPUs
under power/thermal constraints.
The presence of this feature is advertised through bit 16 of EDX
register for CPUID leaf 0x80000007. The number of distinct floor
performance levels supported on the platform will be advertised
through the bits 32:39 of the MSR_AMD_CPPC_CAP1. Bits 0:7 of a new MSR
MSR_AMD_CPPC_REQ2 (0xc00102b5) will be used to specify the desired
floor performance level for that CPU.
Key changes made by this patchset:
* Fix a memory leak bug and a control-flow bug.
* Plumb in proper visibility controls for the freq_attr attributes
so that only relevant attributes can be made visible depending on
the underlying platform and the current amd-pstate driver mode.
* Add support for the new CPUID bits, the new MSR and parsing bits
32:39 of MSR_AMD_CPPC_CAP1.
* Set the default value for MSR_AMD_CPPC_REQ2[0:7] (Floor perf) to
CPPC.nominal_perf when the value at boot-time is lower than
CPPC.lowest_perf
* Add sysfs support for floor_freq and floor_count
* Add a new unit-test in amd-pstate-ut to validate the driver
freq_attrs.
* Introduce a tracepoint trace_amd_pstate_cppc_req2 for tracking
the updates to MSR_AMD_CPPC_REQ2.
* Add documentation for amd_pstate_floor_{freq,count}
Gautham R. Shenoy (12):
amd-pstate: Fix memory leak in amd_pstate_epp_cpu_init()
amd-pstate: Update cppc_req_cached in fast_switch case
amd-pstate: Make certain freq_attrs conditionally visible
x86/cpufeatures: Add AMD CPPC Performance Priority feature.
amd-pstate: Add support for CPPC_REQ2 and FLOOR_PERF
amd-pstate: Add sysfs support for floor_freq and floor_count
amd-pstate: Introduce a tracepoint trace_amd_pstate_cppc_req2()
amd-pstate-ut: Add ability to run a single testcase
amd-pstate-ut: Add a testcase to validate the visibility of driver attributes
Documentation/amd-pstate: List amd_pstate_hw_prefcore sysfs file
Documentation/amd-pstate: List amd_pstate_prefcore_ranking sysfs file
Documentation/amd-pstate: Add documentation for amd_pstate_floor_{freq,count}
Documentation/admin-guide/pm/amd-pstate.rst | 42 ++-
arch/x86/include/asm/cpufeatures.h | 2 +-
arch/x86/include/asm/msr-index.h | 5 +
arch/x86/kernel/cpu/scattered.c | 1 +
drivers/cpufreq/amd-pstate-trace.h | 35 +++
drivers/cpufreq/amd-pstate-ut.c | 150 +++++++++-
drivers/cpufreq/amd-pstate.c | 312 +++++++++++++++++---
drivers/cpufreq/amd-pstate.h | 12 +
tools/arch/x86/include/asm/cpufeatures.h | 2 +-
9 files changed, 511 insertions(+), 50 deletions(-)
--
2.34.1
^ permalink raw reply
* Re: [PATCH 14/15] sched/cputime: Handle idle irqtime gracefully
From: Frederic Weisbecker @ 2026-03-20 14:32 UTC (permalink / raw)
To: Shrikanth Hegde
Cc: LKML, Christophe Leroy (CS GROUP), Rafael J. Wysocki,
Alexander Gordeev, Anna-Maria Behnsen, Ben Segall, Boqun Feng,
Christian Borntraeger, Dietmar Eggemann, Heiko Carstens,
Ingo Molnar, Jan Kiszka, Joel Fernandes, Juri Lelli,
Kieran Bingham, Madhavan Srinivasan, Mel Gorman, Michael Ellerman,
Neeraj Upadhyay, Nicholas Piggin, Paul E . McKenney,
Peter Zijlstra, Steven Rostedt, Sven Schnelle, Thomas Gleixner,
Uladzislau Rezki, Valentin Schneider, Vasily Gorbik,
Vincent Guittot, Viresh Kumar, Xin Zhao, linux-pm, linux-s390,
linuxppc-dev
In-Reply-To: <415e925a-e9f0-40ad-9f53-263dd34dd2a9@linux.ibm.com>
Le Tue, Mar 03, 2026 at 04:41:18PM +0530, Shrikanth Hegde a écrit :
> Hi Frederic,
>
> On 2/6/26 7:52 PM, Frederic Weisbecker wrote:
> > The dyntick-idle cputime accounting always assumes that IRQ time
> > accounting is enabled and consequently stops elapsing the idle time
> > during dyntick-idle IRQs.
> >
> > This doesn't mix up well with disabled IRQ time accounting because then
> > idle IRQs become a cputime blind-spot. Also this feature is disabled
> > on most configurations and the overhead of pausing dyntick-idle
> > accounting while in idle IRQs could then be avoided.
> >
> > Fix the situation with conditionally pausing dyntick-idle accounting
> > during idle IRQs only if neither native vtime (which does IRQ time
> > accounting) nor generic IRQ time accounting are enabled.
> >
> > Also make sure that the accumulated IRQ time is not accidentally
> > substracted from later accounting.
> >
> > Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
> > ---
> > kernel/sched/cputime.c | 24 +++++++++++++++++++++---
> > kernel/sched/sched.h | 1 +
> > 2 files changed, 22 insertions(+), 3 deletions(-)
> >
> > diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c
> > index d588a4a50e57..92fa2f037b6e 100644
> > --- a/kernel/sched/cputime.c
> > +++ b/kernel/sched/cputime.c
> > @@ -46,7 +46,8 @@ static void irqtime_account_delta(struct irqtime *irqtime, u64 delta,
> > u64_stats_update_begin(&irqtime->sync);
> > cpustat[idx] += delta;
> > irqtime->total += delta;
> > - irqtime->tick_delta += delta;
> > + if (!irqtime->idle_dyntick)
> > + irqtime->tick_delta += delta;
>
> Wouldn't kcpustat_idle_dyntick achieve the same thing?
Yes indeed.
>
> > u64_stats_update_end(&irqtime->sync);
> > }
> > @@ -81,6 +82,16 @@ void irqtime_account_irq(struct task_struct *curr, unsigned int offset)
> > irqtime_account_delta(irqtime, delta, CPUTIME_SOFTIRQ);
> > }
> > +static inline void irqtime_dyntick_start(void)
> > +{
> > + __this_cpu_write(cpu_irqtime.idle_dyntick, true);
> > +}
> > +
> > +static inline void irqtime_dyntick_stop(void)
> > +{
> > + __this_cpu_write(cpu_irqtime.idle_dyntick, false);
> > +}
> > +
> > static u64 irqtime_tick_accounted(u64 maxtime)
> > {
> > struct irqtime *irqtime = this_cpu_ptr(&cpu_irqtime);
> > @@ -94,6 +105,9 @@ static u64 irqtime_tick_accounted(u64 maxtime)
> > #else /* !CONFIG_IRQ_TIME_ACCOUNTING: */
> > +static inline void irqtime_dyntick_start(void) { }
> > +static inline void irqtime_dyntick_stop(void) { }
> > +
> > static u64 irqtime_tick_accounted(u64 dummy)
> > {
> > return 0;
> > @@ -444,6 +458,7 @@ void kcpustat_dyntick_stop(u64 now)
> > WARN_ON_ONCE(!kc->idle_dyntick);
> > kcpustat_idle_stop(kc, now);
> > kc->idle_dyntick = false;
> > + irqtime_dyntick_stop();
> > vtime_dyntick_stop();
> > steal_account_process_time(ULONG_MAX);
> > }
> > @@ -455,6 +470,7 @@ void kcpustat_dyntick_start(u64 now)
> > if (!vtime_generic_enabled_this_cpu()) {
> > vtime_dyntick_start();
> > + irqtime_dyntick_start();
> > kc->idle_dyntick = true;
> > kcpustat_idle_start(kc, now);
> > }
> > @@ -464,7 +480,8 @@ void kcpustat_irq_enter(u64 now)
> > {
> > struct kernel_cpustat *kc = kcpustat_this_cpu;
> > - if (!vtime_generic_enabled_this_cpu())
> > + if (!vtime_generic_enabled_this_cpu() &&
> > + (irqtime_enabled() || vtime_accounting_enabled_this_cpu()))
> > kcpustat_idle_stop(kc, now);
> > }
> Scenario: context_tracking is not enabled(since nohz_full or isolcpus not specified) and
> irqtime/native is not enabled. ( config is CONFIG_VIRT_CPU_ACCOUNTING_GEN + IRQ_TIME=n)
>
>
> cpu goes into tickless mode. Gets irqs, but kcpustat_irq_enter/exit is nop.
> Then the time it spent in irq is still accounted for idle time, during
> kcpustat_dyntick_stop?
Right! As is the case for IRQs firing in system and user time. Basically this
just consolidate the IRQ time accounting behaviour in CONFIG_VIRT_CPU_ACCOUNTING_GEN=n
> Who is going to account the irq time in this case?
Nothing, it's part of idle time.
We could also decide to account the idle IRQ time as system time. I guess it's a
matter of which semantic we want to give. Though that would be more overhead.
Thanks.
--
Frederic Weisbecker
SUSE Labs
^ permalink raw reply
* Re: [PATCH v3 0/1] writeback: don't block sync for filesystems with no data integrity guarantees
From: Christian Brauner @ 2026-03-20 13:19 UTC (permalink / raw)
To: Joanne Koong
Cc: Christian Brauner, linux-fsdevel, jack, miklos, david,
therealgraysky, linux-pm
In-Reply-To: <20260320005145.2483161-1-joannelkoong@gmail.com>
On Thu, 19 Mar 2026 17:51:44 -0700, Joanne Koong wrote:
> Changelog
> ---------
> v2: https://lore.kernel.org/linux-fsdevel/20260319194540.3463371-1-joannelkoong@gmail.com/
> v2 -> v3:
> * Move SB_I_NO_DATA_INTEGRITY check to sync_inodes_sb() instead of
> sync_inodes_one_sb() (David)
> * Move comment block (David)
>
> [...]
Applied to the vfs.fixes branch of the vfs/vfs.git tree.
Patches in the vfs.fixes branch should appear in linux-next soon.
Please report any outstanding bugs that were missed during review in a
new review to the original patch series allowing us to drop it.
It's encouraged to provide Acked-bys and Reviewed-bys even though the
patch has now been applied. If possible patch trailers will be updated.
Note that commit hashes shown below are subject to change due to rebase,
trailer updates or similar. If in doubt, please check the listed branch.
tree: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git
branch: vfs.fixes
[1/1] writeback: don't block sync for filesystems with no data integrity guarantees
https://git.kernel.org/vfs/vfs/c/76f9377cd2ab
^ permalink raw reply
* Re: [RFC PATCH 1/2] thermal/cpufreq_cooling: remove unused cpu_idx in get_load()
From: Lukasz Luba @ 2026-03-20 12:32 UTC (permalink / raw)
To: Xuewen Yan
Cc: rui.zhang, rafael, linux-pm, viresh.kumar, amit.kachhap,
daniel.lezcano, linux-kernel, ke.wang, di.shen, jeson.gao,
xuewen.yan94
In-Reply-To: <20260320113148.7308-1-xuewen.yan@unisoc.com>
Hi Xuewen,
On 3/20/26 11:31, Xuewen Yan wrote:
> From: Di Shen <di.shen@unisoc.com>
>
> The cpu_idx variable in the get_load function is now
> unused and can be safely removed.
>
> No code logic is affected.
>
> Signed-off-by: Di Shen <di.shen@unisoc.com>
> ---
> drivers/thermal/cpufreq_cooling.c | 13 +++++--------
> 1 file changed, 5 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/thermal/cpufreq_cooling.c b/drivers/thermal/cpufreq_cooling.c
> index 32bf5ab44f4a..d030dbeb2973 100644
> --- a/drivers/thermal/cpufreq_cooling.c
> +++ b/drivers/thermal/cpufreq_cooling.c
> @@ -151,26 +151,23 @@ static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_cdev,
> * get_load() - get load for a cpu
> * @cpufreq_cdev: struct cpufreq_cooling_device for the cpu
> * @cpu: cpu number
> - * @cpu_idx: index of the cpu in time_in_idle array
> *
> * Return: The average load of cpu @cpu in percentage since this
> * function was last called.
> */
> #ifdef CONFIG_SMP
> -static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu,
> - int cpu_idx)
> +static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu)
> {
> unsigned long util = sched_cpu_util(cpu);
>
> return (util * 100) / arch_scale_cpu_capacity(cpu);
> }
> #else /* !CONFIG_SMP */
> -static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu,
> - int cpu_idx)
> +static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu)
> {
> u32 load;
> u64 now, now_idle, delta_time, delta_idle;
> - struct time_in_idle *idle_time = &cpufreq_cdev->idle_time[cpu_idx];
> + struct time_in_idle *idle_time = &cpufreq_cdev->idle_time[cpu];
This is a bug. We allocate 'num_cpus' size of array based on
number of CPU in the cpumask for a given cpufreq policy.
If there are 4 cpus in the CPU cluster but CPUs have ids:
CPU4-7 then accessing it with this change would explode.
Please re-design this patch set slightly and I will have a look
on the 2nd version (and particularly the part in current patch 2/2).
Regards,
Lukasz
^ permalink raw reply
* Re: [PATCH V2] cpufreq: conservative: Reset requested_freq on limits change
From: Rafael J. Wysocki @ 2026-03-20 11:51 UTC (permalink / raw)
To: Zhongqiu Han, Viresh Kumar
Cc: linux-pm, Vincent Guittot, Sumit Semwal, Lifeng Zheng,
linux-kernel
In-Reply-To: <4c75f644-2c06-48b1-a72b-1b84be7ba4ab@oss.qualcomm.com>
On Fri, Mar 20, 2026 at 11:02 AM Zhongqiu Han
<zhongqiu.han@oss.qualcomm.com> wrote:
>
> On 3/20/2026 5:38 PM, Viresh Kumar wrote:
> > A recently reported issue highlighted that the cached requested_freq
> > is not guaranteed to stay in sync with policy->cur. If the platform
> > changes the actual CPU frequency after the governor sets one (e.g.
> > due to platform-specific frequency scaling) and a re-sync occurs
> > later, policy->cur may diverge from requested_freq.
> >
> > This can lead to incorrect behavior in the conservative governor.
> > For example, the governor may assume the CPU is already running at
> > the maximum frequency and skip further increases even though there
> > is still headroom.
> >
> > Avoid this by resetting the cached requested_freq to policy->cur on
> > detecting a change in policy limits.
> >
>
> Reviewed-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
Applied as 7.0-rc material, thanks!
> > Reported-by: Lifeng Zheng <zhenglifeng1@huawei.com>
> > Tested-by: Lifeng Zheng <zhenglifeng1@huawei.com>
> > Link: https://lore.kernel.org/all/20260210115458.3493646-1-zhenglifeng1@huawei.com/
> > Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
> > ---
> > [v2]
> > - Completely different design to solve the problem.
> >
> > drivers/cpufreq/cpufreq_conservative.c | 12 ++++++++++++
> > drivers/cpufreq/cpufreq_governor.c | 3 +++
> > drivers/cpufreq/cpufreq_governor.h | 1 +
> > 3 files changed, 16 insertions(+)
> >
> > diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
> > index e0e847764511..df01d33993d8 100644
> > --- a/drivers/cpufreq/cpufreq_conservative.c
> > +++ b/drivers/cpufreq/cpufreq_conservative.c
> > @@ -313,6 +313,17 @@ static void cs_start(struct cpufreq_policy *policy)
> > dbs_info->requested_freq = policy->cur;
> > }
> >
> > +static void cs_limits(struct cpufreq_policy *policy)
> > +{
> > + struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy->governor_data);
> > +
> > + /*
> > + * The limits have changed, so may have the current frequency. Reset
> > + * requested_freq to avoid any unintended outcomes due to the mismatch.
> > + */
> > + dbs_info->requested_freq = policy->cur;
> > +}
> > +
> > static struct dbs_governor cs_governor = {
> > .gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("conservative"),
> > .kobj_type = { .default_groups = cs_groups },
> > @@ -322,6 +333,7 @@ static struct dbs_governor cs_governor = {
> > .init = cs_init,
> > .exit = cs_exit,
> > .start = cs_start,
> > + .limits = cs_limits,
> > };
> >
> > #define CPU_FREQ_GOV_CONSERVATIVE (cs_governor.gov)
> > diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
> > index 36eb7aee4bcd..acf101878733 100644
> > --- a/drivers/cpufreq/cpufreq_governor.c
> > +++ b/drivers/cpufreq/cpufreq_governor.c
> > @@ -563,6 +563,7 @@ EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_stop);
> >
> > void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy)
> > {
> > + struct dbs_governor *gov = dbs_governor_of(policy);
> > struct policy_dbs_info *policy_dbs;
> >
> > /* Protect gov->gdbs_data against cpufreq_dbs_governor_exit() */
> > @@ -574,6 +575,8 @@ void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy)
> > mutex_lock(&policy_dbs->update_mutex);
> > cpufreq_policy_apply_limits(policy);
> > gov_update_sample_delay(policy_dbs, 0);
> > + if (gov->limits)
> > + gov->limits(policy);
> > mutex_unlock(&policy_dbs->update_mutex);
> >
> > out:
> > diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h
> > index 168c23fd7fca..1462d59277bd 100644
> > --- a/drivers/cpufreq/cpufreq_governor.h
> > +++ b/drivers/cpufreq/cpufreq_governor.h
> > @@ -138,6 +138,7 @@ struct dbs_governor {
> > int (*init)(struct dbs_data *dbs_data);
> > void (*exit)(struct dbs_data *dbs_data);
> > void (*start)(struct cpufreq_policy *policy);
> > + void (*limits)(struct cpufreq_policy *policy);
> > };
> >
> > static inline struct dbs_governor *dbs_governor_of(struct cpufreq_policy *policy)
>
>
> --
> Thx and BRs,
> Zhongqiu Han
>
^ permalink raw reply
* Re: [PATCH] cpufreq: Don't skip cpufreq_frequency_table_cpuinfo()
From: Rafael J. Wysocki @ 2026-03-20 11:48 UTC (permalink / raw)
To: Viresh Kumar
Cc: Rafael J. Wysocki, Zihuan Zhang, linux-pm, Vincent Guittot,
Sumit Semwal, Pierre Gondois, Lifeng Zheng, Rafael J. Wysocki,
linux-kernel
In-Reply-To: <65ba5c45749267c82e8a87af3dc788b37a0b3f48.1773998611.git.viresh.kumar@linaro.org>
On Fri, Mar 20, 2026 at 10:24 AM Viresh Kumar <viresh.kumar@linaro.org> wrote:
>
> The commit 6db0f533d320 ("cpufreq: preserve freq_table_sorted across
> suspend/hibernate") unintentionally made a change where
> cpufreq_frequency_table_cpuinfo() isn't getting called anymore for old
> policies getting re-initialized.
>
> This leads to potentially invalid values of policy->max and
> policy->cpuinfo_max_freq.
>
> Fix the issue by reverting the original commit and adding the condition
> for just the sorting function.
>
> Fixes: 6db0f533d320 ("cpufreq: preserve freq_table_sorted across suspend/hibernate")
> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
> ---
> drivers/cpufreq/cpufreq.c | 9 +++------
> drivers/cpufreq/freq_table.c | 4 ++++
> 2 files changed, 7 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> index 277884d91913..1f794524a1d9 100644
> --- a/drivers/cpufreq/cpufreq.c
> +++ b/drivers/cpufreq/cpufreq.c
> @@ -1427,12 +1427,9 @@ static int cpufreq_policy_online(struct cpufreq_policy *policy,
> * If there is a problem with its frequency table, take it
> * offline and drop it.
> */
> - if (policy->freq_table_sorted != CPUFREQ_TABLE_SORTED_ASCENDING &&
> - policy->freq_table_sorted != CPUFREQ_TABLE_SORTED_DESCENDING) {
> - ret = cpufreq_table_validate_and_sort(policy);
> - if (ret)
> - goto out_offline_policy;
> - }
> + ret = cpufreq_table_validate_and_sort(policy);
> + if (ret)
> + goto out_offline_policy;
>
> /* related_cpus should at least include policy->cpus. */
> cpumask_copy(policy->related_cpus, policy->cpus);
> diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
> index 7f251daf03ce..5b364d8da4f9 100644
> --- a/drivers/cpufreq/freq_table.c
> +++ b/drivers/cpufreq/freq_table.c
> @@ -360,6 +360,10 @@ int cpufreq_table_validate_and_sort(struct cpufreq_policy *policy)
> if (policy_has_boost_freq(policy))
> policy->boost_supported = true;
>
> + if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING ||
> + policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_DESCENDING)
> + return 0;
> +
> return set_freq_table_sorted(policy);
> }
>
> --
Applied as 7.0-rc material, thanks!
^ permalink raw reply
* [RFC PATCH 2/2] thermal/cpufreq_cooling: Use idle_time to get cpu_load when scx_enabled
From: Xuewen Yan @ 2026-03-20 11:31 UTC (permalink / raw)
To: daniel.lezcano, amit.kachhap, viresh.kumar, lukasz.luba, rafael
Cc: rui.zhang, linux-pm, linux-kernel, ke.wang, di.shen, jeson.gao,
xuewen.yan94
In-Reply-To: <20260320113148.7308-1-xuewen.yan@unisoc.com>
From: Di Shen <di.shen@unisoc.com>
Recently, while enabling sched-ext debugging, we observed abnormal behavior
in our thermal power_allocator’s temperature control.
Through debugging, we found that the CPU util was too low, causing
the CPU frequency to remain unrestricted.
This issue stems from the fact that in the sched_cpu_util() function,
when scx is enabled, cpu_util_cfs becomes zero. As a result,
the thermal subsystem perceives an extremely low CPU utilization,
which degrades the effectiveness of the power_allocator’s control.
However, the scx_cpuperf_target() reflects the targeted performance,
not the utilisation. We couldn't use it.
Until a perfect solution is found, using idle_time to get the cpu load
might be a better approach.
Co-developed-by: Xuewen Yan <xuewen.yan@unisoc.com>
Signed-off-by: Xuewen Yan <xuewen.yan@unisoc.com>
Signed-off-by: Di Shen <di.shen@unisoc.com>
---
Previous discussion:
https://lore.kernel.org/all/5a5d565b-33ac-4d5c-b0dd-1353324a6117@arm.com/
---
drivers/thermal/cpufreq_cooling.c | 54 ++++++++++++++++++++-----------
1 file changed, 35 insertions(+), 19 deletions(-)
diff --git a/drivers/thermal/cpufreq_cooling.c b/drivers/thermal/cpufreq_cooling.c
index d030dbeb2973..e8fa70a95d00 100644
--- a/drivers/thermal/cpufreq_cooling.c
+++ b/drivers/thermal/cpufreq_cooling.c
@@ -24,6 +24,9 @@
#include <linux/units.h>
#include "thermal_trace.h"
+#ifdef CONFIG_SCHED_CLASS_EXT
+#include "../../kernel/sched/sched.h"
+#endif
/*
* Cooling state <-> CPUFreq frequency
@@ -72,7 +75,7 @@ struct cpufreq_cooling_device {
struct em_perf_domain *em;
struct cpufreq_policy *policy;
struct thermal_cooling_device_ops cooling_ops;
-#ifndef CONFIG_SMP
+#if !defined(CONFIG_SMP) || defined(CONFIG_SCHED_CLASS_EXT)
struct time_in_idle *idle_time;
#endif
struct freq_qos_request qos_req;
@@ -147,23 +150,9 @@ static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_cdev,
return freq;
}
-/**
- * get_load() - get load for a cpu
- * @cpufreq_cdev: struct cpufreq_cooling_device for the cpu
- * @cpu: cpu number
- *
- * Return: The average load of cpu @cpu in percentage since this
- * function was last called.
- */
-#ifdef CONFIG_SMP
-static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu)
-{
- unsigned long util = sched_cpu_util(cpu);
-
- return (util * 100) / arch_scale_cpu_capacity(cpu);
-}
-#else /* !CONFIG_SMP */
-static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu)
+#if !defined(CONFIG_SMP) || defined(CONFIG_SCHED_CLASS_EXT)
+static u32 get_load_from_idle_time(struct cpufreq_cooling_device *cpufreq_cdev,
+ int cpu)
{
u32 load;
u64 now, now_idle, delta_time, delta_idle;
@@ -183,8 +172,35 @@ static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu)
return load;
}
-#endif /* CONFIG_SMP */
+#endif /* !defined(CONFIG_SMP) || defined(CONFIG_SCHED_CLASS_EXT) */
+/**
+ * get_load() - get load for a cpu
+ * @cpufreq_cdev: struct cpufreq_cooling_device for the cpu
+ * @cpu: cpu number
+ *
+ * Return: The average load of cpu @cpu in percentage since this
+ * function was last called.
+ */
+#ifndef CONFIG_SMP
+static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu,
+ int cpu_idx)
+{
+ return get_load_from_idle_time(cpufreq_cdev, cpu, cpu_idx);
+}
+#else /* CONFIG_SMP */
+static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu)
+{
+ unsigned long util;
+
+#ifdef CONFIG_SCHED_CLASS_EXT
+ if (scx_enabled())
+ return get_load_from_idle_time(cpufreq_cdev, cpu);
+#endif
+ util = sched_cpu_util(cpu);
+ return (util * 100) / arch_scale_cpu_capacity(cpu);
+}
+#endif /* !CONFIG_SMP */
/**
* get_dynamic_power() - calculate the dynamic power
* @cpufreq_cdev: &cpufreq_cooling_device for this cdev
--
2.25.1
^ permalink raw reply related
* [RFC PATCH 1/2] thermal/cpufreq_cooling: remove unused cpu_idx in get_load()
From: Xuewen Yan @ 2026-03-20 11:31 UTC (permalink / raw)
To: daniel.lezcano, amit.kachhap, viresh.kumar, lukasz.luba, rafael
Cc: rui.zhang, linux-pm, linux-kernel, ke.wang, di.shen, jeson.gao,
xuewen.yan94
From: Di Shen <di.shen@unisoc.com>
The cpu_idx variable in the get_load function is now
unused and can be safely removed.
No code logic is affected.
Signed-off-by: Di Shen <di.shen@unisoc.com>
---
drivers/thermal/cpufreq_cooling.c | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/drivers/thermal/cpufreq_cooling.c b/drivers/thermal/cpufreq_cooling.c
index 32bf5ab44f4a..d030dbeb2973 100644
--- a/drivers/thermal/cpufreq_cooling.c
+++ b/drivers/thermal/cpufreq_cooling.c
@@ -151,26 +151,23 @@ static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_cdev,
* get_load() - get load for a cpu
* @cpufreq_cdev: struct cpufreq_cooling_device for the cpu
* @cpu: cpu number
- * @cpu_idx: index of the cpu in time_in_idle array
*
* Return: The average load of cpu @cpu in percentage since this
* function was last called.
*/
#ifdef CONFIG_SMP
-static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu,
- int cpu_idx)
+static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu)
{
unsigned long util = sched_cpu_util(cpu);
return (util * 100) / arch_scale_cpu_capacity(cpu);
}
#else /* !CONFIG_SMP */
-static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu,
- int cpu_idx)
+static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu)
{
u32 load;
u64 now, now_idle, delta_time, delta_idle;
- struct time_in_idle *idle_time = &cpufreq_cdev->idle_time[cpu_idx];
+ struct time_in_idle *idle_time = &cpufreq_cdev->idle_time[cpu];
now_idle = get_cpu_idle_time(cpu, &now, 0);
delta_idle = now_idle - idle_time->time;
@@ -231,7 +228,7 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev,
u32 *power)
{
unsigned long freq;
- int i = 0, cpu;
+ int cpu;
u32 total_load = 0;
struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
struct cpufreq_policy *policy = cpufreq_cdev->policy;
@@ -242,7 +239,7 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev,
u32 load;
if (cpu_online(cpu))
- load = get_load(cpufreq_cdev, cpu, i);
+ load = get_load(cpufreq_cdev, cpu);
else
load = 0;
--
2.25.1
^ permalink raw reply related
* Re: [PATCH 6/6] platform/x86/intel/pmc: Add Nova Lake support to intel_pmc_core driver
From: Ilpo Järvinen @ 2026-03-20 11:08 UTC (permalink / raw)
To: Xi Pardee
Cc: irenic.rajneesh, david.e.box, platform-driver-x86, LKML, linux-pm
In-Reply-To: <20260302223214.484585-7-xi.pardee@linux.intel.com>
On Mon, 2 Mar 2026, Xi Pardee wrote:
> Add Nova Lake support in intel_pmc_core driver
>
> Signed-off-by: Xi Pardee <xi.pardee@linux.intel.com>
> ---
> drivers/platform/x86/intel/pmc/Makefile | 2 +-
> drivers/platform/x86/intel/pmc/core.c | 2 +
> drivers/platform/x86/intel/pmc/core.h | 31 +
> drivers/platform/x86/intel/pmc/nvl.c | 1537 +++++++++++++++++++++++
> drivers/platform/x86/intel/pmc/ptl.c | 2 +-
> 5 files changed, 1572 insertions(+), 2 deletions(-)
> create mode 100644 drivers/platform/x86/intel/pmc/nvl.c
>
> diff --git a/drivers/platform/x86/intel/pmc/Makefile b/drivers/platform/x86/intel/pmc/Makefile
> index bb960c8721d77..53e4a60dcf3cc 100644
> --- a/drivers/platform/x86/intel/pmc/Makefile
> +++ b/drivers/platform/x86/intel/pmc/Makefile
> @@ -4,7 +4,7 @@
> #
>
> intel_pmc_core-y := core.o spt.o cnp.o icl.o \
> - tgl.o adl.o mtl.o arl.o lnl.o ptl.o wcl.o
> + tgl.o adl.o mtl.o arl.o lnl.o ptl.o wcl.o nvl.o
Perhaps split to three lines as this starts to grow a bit long.
> obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o
> intel_pmc_core_pltdrv-y := pltdrv.o
> obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core_pltdrv.o
> diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c
> index 85fff5e3abe0d..81e1f55bb7916 100644
> --- a/drivers/platform/x86/intel/pmc/core.c
> +++ b/drivers/platform/x86/intel/pmc/core.c
> @@ -1859,6 +1859,8 @@ static const struct x86_cpu_id intel_pmc_core_ids[] = {
> X86_MATCH_VFM(INTEL_LUNARLAKE_M, &lnl_pmc_dev),
> X86_MATCH_VFM(INTEL_PANTHERLAKE_L, &ptl_pmc_dev),
> X86_MATCH_VFM(INTEL_WILDCATLAKE_L, &wcl_pmc_dev),
> + X86_MATCH_VFM(INTEL_NOVALAKE, &nvl_s_pmc_dev),
> + X86_MATCH_VFM(INTEL_NOVALAKE_L, &nvl_h_pmc_dev),
> {}
> };
>
> diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h
> index c4984e44f7b80..ccfde1dc10d30 100644
> --- a/drivers/platform/x86/intel/pmc/core.h
> +++ b/drivers/platform/x86/intel/pmc/core.h
> @@ -307,6 +307,29 @@ enum ppfear_regs {
> #define WCL_NUM_S0IX_BLOCKER 94
> #define WCL_BLK_REQ_OFFSET 50
>
> +/* Nova Lake */
> +#define NVL_PCDH_PPFEAR_NUM_ENTRIES 13
> +#define NVL_PCDH_PMC_MMIO_REG_LEN 0x363C
> +#define NVL_PCDS_PMC_MMIO_REG_LEN 0x3118
> +#define NVL_PCHS_PMC_MMIO_REG_LEN 0x30D8
> +#define NVL_LPM_PRI_OFFSET 0x17A4
> +#define NVL_LPM_EN_OFFSET 0x17A0
> +#define NVL_LPM_RESIDENCY_OFFSET 0x17A8
> +#define NVL_LPM_LIVE_STATUS_OFFSET 0x1760
> +#define NVL_LPM_NUM_MAPS 15
> +#define NVL_PCDH_NUM_S0IX_BLOCKER 107
> +#define NVL_PCDS_NUM_S0IX_BLOCKER 71
> +#define NVL_PCHS_NUM_S0IX_BLOCKER 54
> +#define NVL_PCDS_PMC_LTR_RESERVED 0x1BAC
> +#define NVL_PCDH_BLK_REQ_OFFSET 53
> +#define NVL_PCDS_BLK_REQ_OFFSET 18
> +#define NVL_PCHS_BLK_REQ_OFFSET 46
> +#define NVL_PMT_PC_GUID 0x13000101
> +#define NVL_PMT_DMU_GUID 0x1A000101
It would be nice to progress towards consistent capitalization of hex
letters. This patch isn't even consistent within itself. My preference is
lowercase as it avoids the LONG CAPS BLOCK effect that is pretty imposing.
> +#define NVL_LTR_BLK_OFFSET 64
> +#define NVL_PKGC_BLK_OFFSET 4
> +#define NVL_PMT_DMU_DIE_C6_OFFSET 25
> +
> /* SSRAM PMC Device ID */
> /* LNL */
> #define PMC_DEVID_LNL_SOCM 0xa87f
> @@ -329,6 +352,11 @@ enum ppfear_regs {
> #define PMC_DEVID_MTL_IOEP 0x7ecf
> #define PMC_DEVID_MTL_IOEM 0x7ebf
>
> +/* NVL */
> +#define PMC_DEVID_NVL_PCDH 0xd37e
> +#define PMC_DEVID_NVL_PCDS 0xd47e
> +#define PMC_DEVID_NVL_PCHS 0x6e27
> +
> extern const char *pmc_lpm_modes[];
>
> struct pmc_bit_map {
> @@ -556,6 +584,7 @@ extern const struct pmc_reg_map mtl_ioep_reg_map;
> extern const struct pmc_bit_map ptl_pcdp_clocksource_status_map[];
> extern const struct pmc_bit_map ptl_pcdp_vnn_req_status_3_map[];
> extern const struct pmc_bit_map ptl_pcdp_signal_status_map[];
> +extern const struct pmc_bit_map ptl_pcdp_ltr_show_map[];
>
> void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev);
> int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore);
> @@ -579,6 +608,8 @@ extern struct pmc_dev_info arl_h_pmc_dev;
> extern struct pmc_dev_info lnl_pmc_dev;
> extern struct pmc_dev_info ptl_pmc_dev;
> extern struct pmc_dev_info wcl_pmc_dev;
> +extern struct pmc_dev_info nvl_s_pmc_dev;
> +extern struct pmc_dev_info nvl_h_pmc_dev;
>
> void cnl_suspend(struct pmc_dev *pmcdev);
> int cnl_resume(struct pmc_dev *pmcdev);
> diff --git a/drivers/platform/x86/intel/pmc/nvl.c b/drivers/platform/x86/intel/pmc/nvl.c
> new file mode 100644
> index 0000000000000..ae338a4de2257
> --- /dev/null
> +++ b/drivers/platform/x86/intel/pmc/nvl.c
> @@ -0,0 +1,1537 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * This file contains platform specific structure definitions
> + * and init function used by Nova Lake PCH.
> + *
> + * Copyright (c) 2026, Intel Corporation.
> + */
> +
> +#include <linux/pci.h>
> +
> +#include "core.h"
> +
> +/* PMC SSRAM PMT Telemetry GUIDS */
> +#define PCDH_LPM_REQ_GUID 0x01093101
> +#define PCHS_LPM_REQ_GUID 0x01092101
> +#define PCDS_LPM_REQ_GUID 0x01091102
> +
> +/*
> + * Die Mapping to Product.
> + * Product PCDDie PCHDie
> + * NVL-H PCD-H None
> + * NVL-S PCD-S PCH-S
> + */
> +
> +static const struct pmc_bit_map nvl_pcdh_pfear_map[] = {
> + {"PMC_PGD0", BIT(0)},
> + {"FUSE_OSSE_PGD0", BIT(1)},
> + {"SPI_PGD0", BIT(2)},
> + {"XHCI_PGD0", BIT(3)},
> + {"SPA_PGD0", BIT(4)},
> + {"SPB_PGD0", BIT(5)},
> + {"MPFPW2_PGD0", BIT(6)},
> + {"GBE_PGD0", BIT(7)},
> +
> + {"SBR16B20_PGD0", BIT(0)},
> + {"DBG_SBR_PGD0", BIT(1)},
> + {"SBR16B7_PGD0", BIT(2)},
> + {"STRC_PGD0", BIT(3)},
> + {"SBR16B8_PGD0", BIT(4)},
> + {"D2D_DISP_PGD1", BIT(5)},
> + {"LPSS_PGD0", BIT(6)},
> + {"LPC_PGD0", BIT(7)},
> +
> + {"SMB_PGD0", BIT(0)},
> + {"ISH_PGD0", BIT(1)},
> + {"SBR16B2_PGD0", BIT(2)},
> + {"NPK_PGD0", BIT(3)},
> + {"D2D_NOC_PGD1", BIT(4)},
> + {"DBG_SBR16B_PGD0", BIT(5)},
> + {"FUSE_PGD0", BIT(6)},
> + {"SBR16B0_PGD0", BIT(7)},
> +
> + {"P2SB0_PGD0", BIT(0)},
> + {"OTG_PGD0", BIT(1)},
> + {"EXI_PGD0", BIT(2)},
> + {"CSE_PGD0", BIT(3)},
> + {"CSME_KVM_PGD0", BIT(4)},
> + {"CSME_PMT_PGD0", BIT(5)},
> + {"CSME_CLINK_PGD0", BIT(6)},
> + {"SBR16B21_PGD0", BIT(7)},
> +
> + {"CSME_USBR_PGD0", BIT(0)},
> + {"SBR16B22_PGD0", BIT(1)},
> + {"CSME_SMT1_PGD0", BIT(2)},
> + {"MPFPW1_PGD0", BIT(3)},
> + {"CSME_SMS2_PGD0", BIT(4)},
> + {"CSME_SMS_PGD0", BIT(5)},
> + {"CSME_RTC_PGD0", BIT(6)},
> + {"CSMEPSF_PGD0", BIT(7)},
> +
> + {"D2D_NOC_PGD0", BIT(0)},
> + {"ESE_PGD0", BIT(1)},
> + {"SBR16B6_PGD0", BIT(2)},
> + {"P2SB1_PGD0", BIT(3)},
> + {"SBR16B3_PGD0", BIT(4)},
> + {"OSSE_SMT1_PGD0", BIT(5)},
> + {"D2D_DISP_PGD0", BIT(6)},
> + {"SNPS_USB2_A_PGD0", BIT(7)},
> +
> + {"U3FPW1_PGD0", BIT(0)},
> + {"FIA_X_PGD0", BIT(1)},
> + {"PSF4_PGD0", BIT(2)},
> + {"CNVI_PGD0", BIT(3)},
> + {"UFSX2_PGD0", BIT(4)},
> + {"ENDBG_PGD0", BIT(5)},
> + {"DBC_PGD0", BIT(6)},
> + {"FIA_PG_PGD0", BIT(7)},
> +
> + {"D2D_IPU_PGD0", BIT(0)},
> + {"NPK_PGD1", BIT(1)},
> + {"FIACPCB_X_PGD0", BIT(2)},
> + {"SBR8B4_PGD0", BIT(3)},
> + {"DBG_PSF_PGD0", BIT(4)},
> + {"PSF6_PGD0", BIT(5)},
> + {"UFSPW1_PGD0", BIT(6)},
> + {"FIA_U_PGD0", BIT(7)},
> +
> + {"PSF8_PGD0", BIT(0)},
> + {"SBR16B9_PGD0", BIT(1)},
> + {"PSF0_PGD0", BIT(2)},
> + {"FIACPCB_U_PGD0", BIT(3)},
> + {"TAM_PGD0", BIT(4)},
> + {"D2D_NOC_PGD2", BIT(5)},
> + {"SBR8B2_PGD0", BIT(6)},
> + {"THC0_PGD0", BIT(7)},
> +
> + {"THC1_PGD0", BIT(0)},
> + {"PMC_PGD1", BIT(1)},
> + {"DISP_PGA1_PGD0", BIT(2)},
> + {"TCSS_PGD0", BIT(3)},
> + {"DISP_PGA_PGD0", BIT(4)},
> + {"SBR16B1_PGD0", BIT(5)},
> + {"SBRG_PGD0", BIT(6)},
> + {"PSF5_PGD0", BIT(7)},
> +
> + {"SBR8B3_PGD0", BIT(0)},
> + {"ACE_PGD0", BIT(1)},
> + {"ACE_PGD1", BIT(2)},
> + {"ACE_PGD2", BIT(3)},
> + {"ACE_PGD3", BIT(4)},
> + {"ACE_PGD4", BIT(5)},
> + {"ACE_PGD5", BIT(6)},
> + {"ACE_PGD6", BIT(7)},
> +
> + {"ACE_PGD7", BIT(0)},
> + {"ACE_PGD8", BIT(1)},
> + {"ACE_PGD9", BIT(2)},
> + {"ACE_PGD10", BIT(3)},
> + {"FIACPCB_PG_PGD0", BIT(4)},
> + {"SNPS_USB2_B_PGD0", BIT(5)},
> + {"OSSE_PGD0", BIT(6)},
> + {"SBR8B0_PGD0", BIT(7)},
> +
> + {"SBR16B4_PGD0", BIT(0)},
> + {"CSME_PTIO_PGD0", BIT(1)},
> + {}
> +};
> +
> +static const struct pmc_bit_map *ext_nvl_pcdh_pfear_map[] = {
> + nvl_pcdh_pfear_map,
> + NULL
> +};
> +
> +const struct pmc_bit_map nvl_pcdh_clocksource_status_map[] = {
> + {"AON2_OFF_STS", BIT(0), 1},
> + {"AON3_OFF_STS", BIT(1), 0},
> + {"AON4_OFF_STS", BIT(2), 1},
> + {"AON5_OFF_STS", BIT(3), 1},
> + {"AON1_OFF_STS", BIT(4), 0},
> + {"XTAL_LVM_OFF_STS", BIT(5), 0},
> + {"MPFPW1_0_PLL_OFF_STS", BIT(6), 1},
> + {"D2D_PLL_OFF_STS", BIT(7), 1},
> + {"USB3_PLL_OFF_STS", BIT(8), 1},
> + {"AON3_SPL_OFF_STS", BIT(9), 1},
> + {"MPFPW2_0_PLL_OFF_STS", BIT(12), 1},
> + {"XTAL_AGGR_OFF_STS", BIT(17), 1},
> + {"USB2_PLL_OFF_STS", BIT(18), 0},
> + {"DDI2_PLL_OFF_STS", BIT(19), 1},
> + {"SE_TCSS_PLL_OFF_STS", BIT(20), 1},
> + {"DDI_PLL_OFF_STS", BIT(21), 1},
> + {"FILTER_PLL_OFF_STS", BIT(22), 1},
> + {"ACE_PLL_OFF_STS", BIT(24), 0},
> + {"FABRIC_PLL_OFF_STS", BIT(25), 1},
> + {"SOC_PLL_OFF_STS", BIT(26), 1},
> + {"REF_PLL_OFF_STS", BIT(28), 1},
> + {"IMG_PLL_OFF_STS", BIT(29), 1},
> + {"GENLOCK_FILTER_PLL_OFF_STS", BIT(30), 1},
> + {"RTC_PLL_OFF_STS", BIT(31), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcdh_power_gating_status_0_map[] = {
> + {"PMC_PGD0_PG_STS", BIT(0), 0},
> + {"FUSE_OSSE_PGD0_PG_STS", BIT(1), 0},
> + {"ESPISPI_PGD0_PG_STS", BIT(2), 0},
> + {"XHCI_PGD0_PG_STS", BIT(3), 1},
> + {"SPA_PGD0_PG_STS", BIT(4), 1},
> + {"SPB_PGD0_PG_STS", BIT(5), 1},
> + {"MPFPW2_PGD0_PG_STS", BIT(6), 0},
> + {"GBE_PGD0_PG_STS", BIT(7), 1},
> + {"SBR16B20_PGD0_PG_STS", BIT(8), 0},
> + {"DBG_PGD0_PG_STS", BIT(9), 0},
> + {"SBR16B7_PGD0_PG_STS", BIT(10), 0},
> + {"STRC_PGD0_PG_STS", BIT(11), 0},
> + {"SBR16B8_PGD0_PG_STS", BIT(12), 0},
> + {"D2D_DISP_PGD1_PG_STS", BIT(13), 1},
> + {"LPSS_PGD0_PG_STS", BIT(14), 1},
> + {"LPC_PGD0_PG_STS", BIT(15), 0},
> + {"SMB_PGD0_PG_STS", BIT(16), 0},
> + {"ISH_PGD0_PG_STS", BIT(17), 0},
> + {"SBR16B2_PGD0_PG_STS", BIT(18), 0},
> + {"NPK_PGD0_PG_STS", BIT(19), 0},
> + {"D2D_NOC_PGD1_PG_STS", BIT(20), 1},
> + {"DBG_SBR16B_PGD0_PG_STS", BIT(21), 0},
> + {"FUSE_PGD0_PG_STS", BIT(22), 0},
> + {"SBR16B0_PGD0_PG_STS", BIT(23), 0},
> + {"P2SB0_PGD0_PG_STS", BIT(24), 1},
> + {"XDCI_PGD0_PG_STS", BIT(25), 1},
> + {"EXI_PGD0_PG_STS", BIT(26), 0},
> + {"CSE_PGD0_PG_STS", BIT(27), 1},
> + {"KVMCC_PGD0_PG_STS", BIT(28), 1},
> + {"PMT_PGD0_PG_STS", BIT(29), 1},
> + {"CLINK_PGD0_PG_STS", BIT(30), 1},
> + {"SBR16B21_PGD0_PG_STS", BIT(31), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcdh_power_gating_status_1_map[] = {
> + {"USBR0_PGD0_PG_STS", BIT(0), 1},
> + {"SBR16B22_PGD0_PG_STS", BIT(1), 0},
> + {"SMT1_PGD0_PG_STS", BIT(2), 1},
> + {"MPFPW1_PGD0_PG_STS", BIT(3), 0},
> + {"SMS2_PGD0_PG_STS", BIT(4), 1},
> + {"SMS1_PGD0_PG_STS", BIT(5), 1},
> + {"CSMERTC_PGD0_PG_STS", BIT(6), 0},
> + {"CSMEPSF_PGD0_PG_STS", BIT(7), 0},
> + {"D2D_NOC_PGD0_PG_STS", BIT(8), 0},
> + {"ESE_PGD0_PG_STS", BIT(9), 1},
> + {"SBR16B6_PGD0_PG_STS", BIT(10), 0},
> + {"P2SB1_PGD0_PG_STS", BIT(11), 1},
> + {"SBR16B3_PGD0_PG_STS", BIT(12), 0},
> + {"OSSE_SMT1_PGD0_PG_STS", BIT(13), 1},
> + {"D2D_DISP_PGD0_PG_STS", BIT(14), 1},
> + {"SNPA_USB2_A_PGD0_PG_STS", BIT(15), 0},
> + {"U3FPW1_PGD0_PG_STS", BIT(16), 0},
> + {"FIA_X_PGD0_PG_STS", BIT(17), 0},
> + {"PSF4_PGD0_PG_STS", BIT(18), 0},
> + {"CNVI_PGD0_PG_STS", BIT(19), 0},
> + {"UFSX2_PGD0_PG_STS", BIT(20), 1},
> + {"ENDBG_PGD0_PG_STS", BIT(21), 0},
> + {"DBC_PGD0_PG_STS", BIT(22), 0},
> + {"FIA_PG_PGD0_PG_STS", BIT(23), 0},
> + {"D2D_IPU_PGD0_PG_STS", BIT(24), 1},
> + {"NPK_PGD1_PG_STS", BIT(25), 0},
> + {"FIACPCB_X_PGD0_PG_STS", BIT(26), 0},
> + {"SBR8B4_PGD0_PG_STS", BIT(27), 0},
> + {"DBG_PSF_PGD0_PG_STS", BIT(28), 0},
> + {"PSF6_PGD0_PG_STS", BIT(29), 0},
> + {"UFSPW1_PGD0_PG_STS", BIT(30), 0},
> + {"FIA_U_PGD0_PG_STS", BIT(31), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcdh_power_gating_status_2_map[] = {
> + {"PSF8_PGD0_PG_STS", BIT(0), 0},
> + {"SBR16B9_PGD0_PG_STS", BIT(1), 0},
> + {"PSF0_PGD0_PG_STS", BIT(2), 0},
> + {"FIACPCB_U_PGD0_PG_STS", BIT(3), 0},
> + {"TAM_PGD0_PG_STS", BIT(4), 1},
> + {"D2D_NOC_PGD2_PG_STS", BIT(5), 1},
> + {"SBR8B2_PGD0_PG_STS", BIT(6), 0},
> + {"THC0_PGD0_PG_STS", BIT(7), 1},
> + {"THC1_PGD0_PG_STS", BIT(8), 1},
> + {"PMC_PGD1_PG_STS", BIT(9), 0},
> + {"DISP_PGA1_PGD0_PG_STS", BIT(10), 0},
> + {"TCSS_PGD0_PG_STS", BIT(11), 0},
> + {"DISP_PGA_PGD0_PG_STS", BIT(12), 0},
> + {"SBR16B1_PGD0_PG_STS", BIT(13), 0},
> + {"SBRG_PGD0_PG_STS", BIT(14), 0},
> + {"PSF5_PGD0_PG_STS", BIT(15), 0},
> + {"SBR8B3_PGD0_PG_STS", BIT(16), 0},
> + {"ACE_PGD0_PG_STS", BIT(17), 0},
> + {"ACE_PGD1_PG_STS", BIT(18), 0},
> + {"ACE_PGD2_PG_STS", BIT(19), 0},
> + {"ACE_PGD3_PG_STS", BIT(20), 0},
> + {"ACE_PGD4_PG_STS", BIT(21), 0},
> + {"ACE_PGD5_PG_STS", BIT(22), 0},
> + {"ACE_PGD6_PG_STS", BIT(23), 0},
> + {"ACE_PGD7_PG_STS", BIT(24), 0},
> + {"ACE_PGD8_PG_STS", BIT(25), 0},
> + {"ACE_PGD9_PG_STS", BIT(26), 0},
> + {"ACE_PGD10_PG_STS", BIT(27), 0},
> + {"FIACPCB_PG_PGD0_PG_STS", BIT(28), 0},
> + {"SNPS_USB2_B_PGD0_PG_STS", BIT(29), 0},
> + {"OSSE_PGD0_PG_STS", BIT(30), 1},
> + {"SBR8B0_PGD0_PG_STS", BIT(31), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcdh_power_gating_status_3_map[] = {
> + {"SBR16B4_PGD0_PG_STS", BIT(0), 0},
> + {"PTIO_PGD0_PG_STS", BIT(1), 1},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcdh_d3_status_0_map[] = {
> + {"LPSS_D3_STS", BIT(3), 1},
> + {"XDCI_D3_STS", BIT(4), 1},
> + {"XHCI_D3_STS", BIT(5), 1},
> + {"OSSE_D3_STS", BIT(6), 0},
> + {"SPA_D3_STS", BIT(12), 0},
> + {"SPB_D3_STS", BIT(13), 0},
> + {"ESPISPI_D3_STS", BIT(18), 0},
> + {"PSTH_D3_STS", BIT(21), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcdh_d3_status_1_map[] = {
> + {"OSSE_SMT1_D3_STS", BIT(0), 0},
> + {"GBE_D3_STS", BIT(19), 0},
> + {"ITSS_D3_STS", BIT(23), 0},
> + {"CNVI_D3_STS", BIT(27), 0},
> + {"UFSX2_D3_STS", BIT(28), 0},
> + {"ESE_D3_STS", BIT(29), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcdh_d3_status_2_map[] = {
> + {"CSMERTC_D3_STS", BIT(1), 0},
> + {"CSE_D3_STS", BIT(4), 0},
> + {"KVMCC_D3_STS", BIT(5), 0},
> + {"USBR0_D3_STS", BIT(6), 0},
> + {"ISH_D3_STS", BIT(7), 0},
> + {"SMT1_D3_STS", BIT(8), 0},
> + {"SMT2_D3_STS", BIT(9), 0},
> + {"SMT3_D3_STS", BIT(10), 0},
> + {"OSSE_SMT2_D3_STS", BIT(11), 0},
> + {"CLINK_D3_STS", BIT(14), 0},
> + {"PTIO_D3_STS", BIT(16), 0},
> + {"PMT_D3_STS", BIT(17), 0},
> + {"SMS1_D3_STS", BIT(18), 0},
> + {"SMS2_D3_STS", BIT(19), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcdh_d3_status_3_map[] = {
> + {"THC0_D3_STS", BIT(14), 1},
> + {"THC1_D3_STS", BIT(15), 1},
> + {"OSSE_SMT3_D3_STS", BIT(16), 0},
> + {"ACE_D3_STS", BIT(23), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcdh_vnn_req_status_0_map[] = {
> + {"LPSS_VNN_REQ_STS", BIT(3), 1},
> + {"OSSE_VNN_REQ_STS", BIT(6), 1},
> + {"ESPISPI_VNN_REQ_STS", BIT(18), 1},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcdh_vnn_req_status_1_map[] = {
> + {"OSSE_SMT1_VNN_REQ_STS", BIT(0), 1},
> + {"NPK_VNN_REQ_STS", BIT(4), 1},
> + {"DFXAGG_VNN_REQ_STS", BIT(8), 0},
> + {"EXI_VNN_REQ_STS", BIT(9), 1},
> + {"P2D_VNN_REQ_STS", BIT(18), 1},
> + {"GBE_VNN_REQ_STS", BIT(19), 1},
> + {"SMB_VNN_REQ_STS", BIT(25), 1},
> + {"LPC_VNN_REQ_STS", BIT(26), 0},
> + {"ESE_VNN_REQ_STS", BIT(29), 1},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcdh_vnn_req_status_2_map[] = {
> + {"CSMERTC_VNN_REQ_STS", BIT(1), 1},
> + {"CSE_VNN_REQ_STS", BIT(4), 1},
> + {"ISH_VNN_REQ_STS", BIT(7), 1},
> + {"SMT1_VNN_REQ_STS", BIT(8), 1},
> + {"CLINK_VNN_REQ_STS", BIT(14), 1},
> + {"SMS1_VNN_REQ_STS", BIT(18), 1},
> + {"SMS2_VNN_REQ_STS", BIT(19), 1},
> + {"GPIOCOM4_VNN_REQ_STS", BIT(20), 1},
> + {"GPIOCOM3_VNN_REQ_STS", BIT(21), 1},
> + {"DISP_SHIM_VNN_REQ_STS", BIT(22), 1},
> + {"GPIOCOM1_VNN_REQ_STS", BIT(23), 1},
> + {"GPIOCOM0_VNN_REQ_STS", BIT(24), 1},
> + {}
> +};
> +
> +const struct pmc_bit_map nvl_pcdh_vnn_req_status_3_map[] = {
> + {"DTS0_VNN_REQ_STS", BIT(7), 0},
> + {"GPIOCOM5_VNN_REQ_STS", BIT(11), 1},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcdh_vnn_misc_status_map[] = {
> + {"CPU_C10_REQ_STS", BIT(0), 0},
> + {"TS_OFF_REQ_STS", BIT(1), 0},
> + {"PNDE_MET_REQ_STS", BIT(2), 1},
> + {"PG5_PMA0_REQ_STS", BIT(3), 1},
> + {"FW_THROTTLE_ALLOWED_REQ_STS", BIT(4), 0},
> + {"VNN_SOC_REQ_STS", BIT(6), 1},
> + {"ISH_VNNAON_REQ_STS", BIT(7), 0},
> + {"D2D_NOC_CFI_QACTIVE_REQ_STS", BIT(8), 1},
> + {"D2D_NOC_GPSB_QACTIVE_REQ_STS", BIT(9), 1},
> + {"D2D_IPU_QACTIVE_REQ_STS", BIT(10), 1},
> + {"PLT_GREATER_REQ_STS", BIT(11), 1},
> + {"ALL_SBR_IDLE_REQ_STS", BIT(12), 0},
> + {"PMC_IDLE_FB_OCP_REQ_STS", BIT(13), 0},
> + {"PM_SYNC_STATES_REQ_STS", BIT(14), 0},
> + {"EA_REQ_STS", BIT(15), 0},
> + {"MPHY_CORE_OFF_REQ_STS", BIT(16), 0},
> + {"BRK_EV_EN_REQ_STS", BIT(17), 0},
> + {"AUTO_DEMO_EN_REQ_STS", BIT(18), 0},
> + {"ITSS_CLK_SRC_REQ_STS", BIT(19), 1},
> + {"ARC_IDLE_REQ_STS", BIT(21), 0},
> + {"PG5_PMA1_REQ_STS", BIT(22), 1},
> + {"FIA_DEEP_PM_REQ_STS", BIT(23), 0},
> + {"XDCI_ATTACHED_REQ_STS", BIT(24), 1},
> + {"ARC_INTERRUPT_WAKE_REQ_STS", BIT(25), 0},
> + {"D2D_DISP_DDI_QACTIVE_REQ_STS", BIT(26), 1},
> + {"PRE_WAKE0_REQ_STS", BIT(27), 1},
> + {"PRE_WAKE1_REQ_STS", BIT(28), 1},
> + {"PRE_WAKE2_REQ_STS", BIT(29), 1},
> + {"PG5_PMA2_GVNN", BIT(30), 1},
> + {"D2D_DISP_EDP_QACTIVE_REQ_STS", BIT(31), 1},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcdh_rsc_status_map[] = {
> + {"CORE", 0, 1},
> + {"Memory", 0, 1},
> + {"PRIM_D2D", 0, 1},
> + {"PSF0", 0, 1},
> + {"PSF4", 0, 1},
> + {"PSF6", 0, 1},
> + {"PSF8", 0, 1},
> + {"SB", 0, 1},
> + {}
> +};
> +
> +static const struct pmc_bit_map *nvl_pcdh_lpm_maps[] = {
> + nvl_pcdh_clocksource_status_map,
> + nvl_pcdh_power_gating_status_0_map,
> + nvl_pcdh_power_gating_status_1_map,
> + nvl_pcdh_power_gating_status_2_map,
> + nvl_pcdh_power_gating_status_3_map,
> + nvl_pcdh_d3_status_0_map,
> + nvl_pcdh_d3_status_1_map,
> + nvl_pcdh_d3_status_2_map,
> + nvl_pcdh_d3_status_3_map,
> + nvl_pcdh_vnn_req_status_0_map,
> + nvl_pcdh_vnn_req_status_1_map,
> + nvl_pcdh_vnn_req_status_2_map,
> + nvl_pcdh_vnn_req_status_3_map,
> + nvl_pcdh_vnn_misc_status_map,
> + ptl_pcdp_signal_status_map,
> + NULL
> +};
> +
> +static const struct pmc_bit_map *nvl_pcdh_blk_maps[] = {
> + nvl_pcdh_power_gating_status_0_map,
> + nvl_pcdh_power_gating_status_1_map,
> + nvl_pcdh_power_gating_status_2_map,
> + nvl_pcdh_power_gating_status_3_map,
> + nvl_pcdh_rsc_status_map,
> + nvl_pcdh_vnn_req_status_0_map,
> + nvl_pcdh_vnn_req_status_1_map,
> + nvl_pcdh_vnn_req_status_2_map,
> + nvl_pcdh_vnn_req_status_3_map,
> + nvl_pcdh_d3_status_0_map,
> + nvl_pcdh_d3_status_1_map,
> + nvl_pcdh_d3_status_2_map,
> + nvl_pcdh_d3_status_3_map,
> + nvl_pcdh_clocksource_status_map,
> + nvl_pcdh_vnn_misc_status_map,
> + ptl_pcdp_signal_status_map,
> + NULL
> +};
> +
> +static const struct pmc_bit_map nvl_pcds_pfear_map[] = {
> + {"PMC_PGD0", BIT(0)},
> + {"FUSE_OSSE_PGD0", BIT(1)},
> + {"SPI_PGD0", BIT(2)},
> + {"XHCI_PGD0", BIT(3)},
> + {"SPA_PGD0", BIT(4)},
> + {"SPB_PGD0", BIT(5)},
> + {"RSVD6", BIT(6)},
> + {"GBE_PGD0", BIT(7)},
> +
> + {"RSVD8", BIT(0)},
> + {"RSVD9", BIT(1)},
> + {"SBR16B7_PGD0", BIT(2)},
> + {"SBR16B21_PGD0", BIT(3)},
> + {"RSVD12", BIT(4)},
> + {"D2D_DISP_PGD1", BIT(5)},
> + {"LPSS_PGD0", BIT(6)},
> + {"LPC_PGD0", BIT(7)},
> +
> + {"SMB_PGD0", BIT(0)},
> + {"ISH_PGD0", BIT(1)},
> + {"SBR16B1_PGD0", BIT(2)},
> + {"NPK_PGD0", BIT(3)},
> + {"D2D_NOC_PGD1", BIT(4)},
> + {"DBG_SBR16B_PGD0", BIT(5)},
> + {"FUSE_PGD0", BIT(6)},
> + {"RSVD23", BIT(7)},
> +
> + {"P2SB0_PGD0", BIT(0)},
> + {"OTG_PGD0", BIT(1)},
> + {"EXI_PGD0", BIT(2)},
> + {"CSE_PGD0", BIT(3)},
> + {"CSME_KVM_PGD0", BIT(4)},
> + {"CSME_PMT_PGD0", BIT(5)},
> + {"CSME_CLINK_PGD0", BIT(6)},
> + {"CSME_PTIO_PGD0", BIT(7)},
> +
> + {"CSME_USBR_PGD0", BIT(0)},
> + {"SBR16B22_PGD0", BIT(1)},
> + {"CSME_SMT1_PGD0", BIT(2)},
> + {"P2SB1_PGD0", BIT(3)},
> + {"CSME_SMS2_PGD0", BIT(4)},
> + {"CSME_SMS_PGD0", BIT(5)},
> + {"CSME_RTC_PGD0", BIT(6)},
> + {"CSMEPSF_PGD0", BIT(7)},
> +
> + {"D2D_NOC_PGD0", BIT(0)},
> + {"RSVD41", BIT(1)},
> + {"RSVD42", BIT(2)},
> + {"RSVD43", BIT(3)},
> + {"SBR16B2_PGD0", BIT(4)},
> + {"OSSE_SMT1_PGD0", BIT(5)},
> + {"D2D_DISP_PGD0", BIT(6)},
> + {"RSVD47_PGD0", BIT(7)},
> +
> + {"RSVD48", BIT(0)},
> + {"DBG_PSF_PGD0", BIT(1)},
> + {"RSVD50", BIT(2)},
> + {"CNVI_PGD0", BIT(3)},
> + {"UFSX2_PGD0", BIT(4)},
> + {"ENDBG_PGD0", BIT(5)},
> + {"DBC_PGD0", BIT(6)},
> + {"SBR16B4_PGD0", BIT(7)},
> +
> + {"RSVD56", BIT(0)},
> + {"NPK_PGD1", BIT(1)},
> + {"RSVD58", BIT(2)},
> + {"SBR16B20_PGD0", BIT(3)},
> + {"RSVD60", BIT(4)},
> + {"SBR8B20_PGD0", BIT(5)},
> + {"RSVD62", BIT(6)},
> + {"FIA_U_PGD0", BIT(7)},
> +
> + {"PSF8_PGD0", BIT(0)},
> + {"RSVD65", BIT(1)},
> + {"RSVD66", BIT(2)},
> + {"FIACPCB_U_PGD0", BIT(3)},
> + {"TAM_PGD0", BIT(4)},
> + {"D2D_NOC_PGD2", BIT(5)},
> + {"SBR8B2_PGD0", BIT(6)},
> + {"THC0_PGD0", BIT(7)},
> +
> + {"THC1_PGD0", BIT(0)},
> + {"PMC_PGD1", BIT(1)},
> + {"SBR16B3_PGD0", BIT(2)},
> + {"TCSS_PGD0", BIT(3)},
> + {"DISP_PGA_PGD0", BIT(4)},
> + {"RSVD77", BIT(5)},
> + {"RSVD78", BIT(6)},
> + {"RSVD79", BIT(7)},
> +
> + {"SBRG_PGD0", BIT(0)},
> + {"RSVD81", BIT(1)},
> + {"SBR16B0_PGD0", BIT(2)},
> + {"SBR8B0_PGD0", BIT(3)},
> + {"PSF7_PGD0", BIT(4)},
> + {"RSVD85", BIT(5)},
> + {"RSVD86", BIT(6)},
> + {"RSVD87", BIT(7)},
> +
> + {"SBR16B6_PGD0", BIT(0)},
> + {"PSD0_PGD0", BIT(1)},
> + {"STRC_PGD0", BIT(2)},
> + {"RSVD91", BIT(3)},
> + {"DBG_SBR_PGD0", BIT(4)},
> + {"RSVD93", BIT(5)},
> + {"OSSE_PGD0", BIT(6)},
> + {"DISP_PGA1_PGD0", BIT(7)},
> + {}
> +};
> +
> +static const struct pmc_bit_map *ext_nvl_pcds_pfear_map[] = {
> + nvl_pcds_pfear_map,
> + NULL
> +};
> +
> +static const struct pmc_bit_map nvl_pcds_ltr_show_map[] = {
> + {"SOUTHPORT_A", CNP_PMC_LTR_SPA},
> + {"SOUTHPORT_B", CNP_PMC_LTR_SPB},
> + {"SATA", CNP_PMC_LTR_SATA},
> + {"GIGABIT_ETHERNET", CNP_PMC_LTR_GBE},
> + {"XHCI", CNP_PMC_LTR_XHCI},
> + {"SOUTHPORT_F", ADL_PMC_LTR_SPF},
> + {"ME", CNP_PMC_LTR_ME},
> + {"SATA1", CNP_PMC_LTR_EVA},
> + {"SOUTHPORT_C", CNP_PMC_LTR_SPC},
> + {"HD_AUDIO", CNP_PMC_LTR_AZ},
> + {"CNV", CNP_PMC_LTR_CNV},
> + {"LPSS", CNP_PMC_LTR_LPSS},
> + {"SOUTHPORT_D", CNP_PMC_LTR_SPD},
> + {"SOUTHPORT_E", CNP_PMC_LTR_SPE},
> + {"SATA2", PTL_PMC_LTR_SATA2},
> + {"ESPI", CNP_PMC_LTR_ESPI},
> + {"SCC", CNP_PMC_LTR_SCC},
> + {"ISH", CNP_PMC_LTR_ISH},
> + {"UFSX2", CNP_PMC_LTR_UFSX2},
> + {"EMMC", CNP_PMC_LTR_EMMC},
> + {"WIGIG", ICL_PMC_LTR_WIGIG},
> + {"THC0", TGL_PMC_LTR_THC0},
> + {"THC1", TGL_PMC_LTR_THC1},
> + {"SOUTHPORT_G", MTL_PMC_LTR_SPG},
> + {"RSVD", NVL_PCDS_PMC_LTR_RESERVED},
> + {"IOE_PMC", MTL_PMC_LTR_IOE_PMC},
> + {"DMI3", ARL_PMC_LTR_DMI3},
> + {"OSSE", LNL_PMC_LTR_OSSE},
> +
> + /* Below two cannot be used for LTR_IGNORE */
> + {"CURRENT_PLATFORM", PTL_PMC_LTR_CUR_PLT},
> + {"AGGREGATED_SYSTEM", PTL_PMC_LTR_CUR_ASLT},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcds_clocksource_status_map[] = {
> + {"AON2_OFF_STS", BIT(0), 1},
> + {"AON3_OFF_STS", BIT(1), 0},
> + {"AON4_OFF_STS", BIT(2), 1},
> + {"AON5_OFF_STS", BIT(3), 1},
> + {"AON1_OFF_STS", BIT(4), 0},
> + {"XTAL_LVM_OFF_STS", BIT(5), 0},
> + {"D2D_OFF_STS", BIT(8), 1},
> + {"AON3_SPL_OFF_STS", BIT(9), 1},
> + {"XTAL_AGGR_OFF_STS", BIT(17), 1},
> + {"BCLK_EXT_INJ_OFF_STS", BIT(18), 1},
> + {"DDI2_PLL_OFF_STS", BIT(19), 1},
> + {"SE_TCSS_PLL_OFF_STS", BIT(20), 1},
> + {"DDI_PLL_OFF_STS", BIT(21), 1},
> + {"FILTER_PLL_OFF_STS", BIT(22), 1},
> + {"PHY_OC_EXT_INJ_OFF_STS", BIT(23), 1},
> + {"ACE_PLL_OFF_STS", BIT(24), 0},
> + {"FABRIC_PLL_OFF_STS", BIT(25), 1},
> + {"SOC_PLL_OFF_STS", BIT(26), 1},
> + {"REF_PLL_OFF_STS", BIT(28), 1},
> + {"GENLOCK_FILTER_PLL_OFF_STS", BIT(30), 1},
> + {"RTC_PLL_OFF_STS", BIT(31), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcds_power_gating_status_0_map[] = {
> + {"PMC_PGD0_PG_STS", BIT(0), 0},
> + {"FUSE_OSSE_PGD0_PG_STS", BIT(1), 0},
> + {"ESPISPI_PGD0_PG_STS", BIT(2), 0},
> + {"XHCI_PGD0_PG_STS", BIT(3), 0},
> + {"SPA_PGD0_PG_STS", BIT(4), 0},
> + {"SPB_PGD0_PG_STS", BIT(5), 0},
> + {"RSVD_6", BIT(6), 0},
> + {"GBE_PGD0_PG_STS", BIT(7), 0},
> + {"RSVD_8", BIT(8), 0},
> + {"RSVD_9", BIT(9), 0},
> + {"SBR16B7_PGD0_PG_STS", BIT(10), 0},
> + {"SBR16B21_PGD0_PG_STS", BIT(11), 0},
> + {"RSVD_12", BIT(12), 0},
> + {"D2D_DISP_PGD1_PG_STS", BIT(13), 1},
> + {"LPSS_PGD0_PG_STS", BIT(14), 0},
> + {"LPC_PGD0_PG_STS", BIT(15), 0},
> + {"SMB_PGD0_PG_STS", BIT(16), 0},
> + {"ISH_PGD0_PG_STS", BIT(17), 0},
> + {"SBR16B1_PGD0_PG_STS", BIT(18), 0},
> + {"NPK_PGD0_PG_STS", BIT(19), 0},
> + {"D2D_NOC_PGD1_PG_STS", BIT(20), 1},
> + {"DBG_SBR16B_PGD0_PG_STS", BIT(21), 0},
> + {"FUSE_PGD0_PG_STS", BIT(22), 0},
> + {"RSVD_23", BIT(23), 0},
> + {"P2SB0_PGD0_PG_STS", BIT(24), 1},
> + {"XDCI_PGD0_PG_STS", BIT(25), 0},
> + {"EXI_PGD0_PG_STS", BIT(26), 0},
> + {"CSE_PGD0_PG_STS", BIT(27), 1},
> + {"KVMCC_PGD0_PG_STS", BIT(28), 0},
> + {"PMT_PGD0_PG_STS", BIT(29), 0},
> + {"CLINK_PGD0_PG_STS", BIT(30), 0},
> + {"PTIO_PGD0_PG_STS", BIT(31), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcds_power_gating_status_1_map[] = {
> + {"USBR0_PGD0_PG_STS", BIT(0), 0},
> + {"SBR16B22_PGD0_PG_STS", BIT(1), 0},
> + {"SMT1_PGD0_PG_STS", BIT(2), 0},
> + {"P2SB1_PGD0_PG_STS", BIT(3), 1},
> + {"SMS2_PGD0_PG_STS", BIT(4), 0},
> + {"SMS1_PGD0_PG_STS", BIT(5), 0},
> + {"CSMERTC_PGD0_PG_STS", BIT(6), 0},
> + {"CSMEPSF_PGD0_PG_STS", BIT(7), 0},
> + {"D2D_NOC_PGD0_PG_STS", BIT(8), 0},
> + {"RSVD_9", BIT(9), 0},
> + {"RSVD_10", BIT(10), 0},
> + {"RSVD_11", BIT(11), 0},
> + {"SBR16B2_PGD0_PG_STS", BIT(12), 0},
> + {"OSSE_SMT1_PGD0_PG_STS", BIT(13), 1},
> + {"D2D_DISP_PGD0_PG_STS", BIT(14), 1},
> + {"RSVD_15", BIT(15), 0},
> + {"RSVD_16", BIT(16), 0},
> + {"DBG_PSF_PGD0_PG_STS", BIT(17), 0},
> + {"RSVD_18", BIT(18), 0},
> + {"CNVI_PGD0_PG_STS", BIT(19), 0},
> + {"UFSX2_PGD0_PG_STS", BIT(20), 0},
> + {"ENDBG_PGD0_PG_STS", BIT(21), 0},
> + {"DBC_PGD0_PG_STS", BIT(22), 0},
> + {"SBR16B4_PGD0_PG_STS", BIT(23), 0},
> + {"RSVD_24", BIT(24), 0},
> + {"NPK_PGD1_PG_STS", BIT(25), 0},
> + {"RSVD_26", BIT(26), 0},
> + {"SBR16B20_PGD0_PG_STS", BIT(27), 0},
> + {"RSVD_28", BIT(28), 0},
> + {"SBR8B20_PGD0_PG_STS", BIT(29), 0},
> + {"RSVD_30", BIT(30), 0},
> + {"FIA_U_PGD0_PG_STS", BIT(31), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcds_power_gating_status_2_map[] = {
> + {"PSF8_PGD0_PG_STS", BIT(0), 0},
> + {"RSVD_1", BIT(1), 0},
> + {"RSVD_2", BIT(2), 0},
> + {"FIACPCB_U_PGD0_PG_STS", BIT(3), 0},
> + {"TAM_PGD0_PG_STS", BIT(4), 1},
> + {"D2D_NOC_PGD2_PG_STS", BIT(5), 1},
> + {"SBR8B2_PGD0_PG_STS", BIT(6), 0},
> + {"THC0_PGD0_PG_STS", BIT(7), 0},
> + {"THC1_PGD0_PG_STS", BIT(8), 0},
> + {"PMC_PGD1_PG_STS", BIT(9), 0},
> + {"SBR16B3_PGD0_PG_STS", BIT(10), 0},
> + {"TCSS_PGD0_PG_STS", BIT(11), 0},
> + {"DISP_PGA_PGD0_PG_STS", BIT(12), 0},
> + {"RSVD_13", BIT(13), 0},
> + {"RSVD_14", BIT(14), 0},
> + {"RSVD_15", BIT(15), 0},
> + {"SBRG_PGD0_PG_STS", BIT(16), 0},
> + {"RSVD_17", BIT(17), 0},
> + {"SBR16B0_PGD0_PG_STS", BIT(18), 0},
> + {"SBR8B0_PGD0_PG_STS", BIT(19), 0},
> + {"PSF7_PGD0_PG_STS", BIT(20), 0},
> + {"RSVD_21", BIT(21), 0},
> + {"RSVD_22", BIT(22), 0},
> + {"RSVD_23", BIT(23), 0},
> + {"SBR16B6_PGD0_PG_STS", BIT(24), 0},
> + {"PSF0_PGD0_PG_STS", BIT(25), 0},
> + {"STRC_PGD0_PG_STS", BIT(26), 0},
> + {"RSVD_27", BIT(27), 0},
> + {"DBG_SBR_PGD0_PG_STS", BIT(28), 0},
> + {"RSVD_29", BIT(29), 0},
> + {"OSSE_PGD0_PG_STS", BIT(30), 1},
> + {"DISP_PGA1_PGD0_PG_STS", BIT(31), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcds_d3_status_0_map[] = {
> + {"LPSS_D3_STS", BIT(3), 1},
> + {"XDCI_D3_STS", BIT(4), 1},
> + {"XHCI_D3_STS", BIT(5), 1},
> + {"SPA_D3_STS", BIT(12), 0},
> + {"SPB_D3_STS", BIT(13), 0},
> + {"ESPISPI_D3_STS", BIT(18), 0},
> + {"PSTH_D3_STS", BIT(21), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcds_d3_status_1_map[] = {
> + {"OSSE_D3_STS", BIT(14), 0},
> + {"GBE_D3_STS", BIT(19), 0},
> + {"ITSS_D3_STS", BIT(23), 0},
> + {"CNVI_D3_STS", BIT(27), 0},
> + {"UFSX2_D3_STS", BIT(28), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcds_d3_status_2_map[] = {
> + {"CSMERTC_D3_STS", BIT(1), 0},
> + {"CSE_D3_STS", BIT(4), 0},
> + {"KVMCC_D3_STS", BIT(5), 0},
> + {"USBR0_D3_STS", BIT(6), 0},
> + {"ISH_D3_STS", BIT(7), 0},
> + {"SMT1_D3_STS", BIT(8), 0},
> + {"SMT2_D3_STS", BIT(9), 0},
> + {"SMT3_D3_STS", BIT(10), 0},
> + {"OSSE_SMT1_D3_STS", BIT(12), 0},
> + {"CLINK_D3_STS", BIT(14), 0},
> + {"PTIO_D3_STS", BIT(16), 0},
> + {"PMT_D3_STS", BIT(17), 0},
> + {"SMS1_D3_STS", BIT(18), 0},
> + {"SMS2_D3_STS", BIT(19), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcds_d3_status_3_map[] = {
> + {"OSSE_SMT2_D3_STS", BIT(0), 0},
> + {"THC0_D3_STS", BIT(14), 1},
> + {"THC1_D3_STS", BIT(15), 1},
> + {"OSSE_SMT3_D3_STS", BIT(19), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcds_vnn_req_status_0_map[] = {
> + {"LPSS_VNN_REQ_STS", BIT(3), 0},
> + {"ESPISPI_VNN_REQ_STS", BIT(18), 1},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcds_vnn_req_status_1_map[] = {
> + {"NPK_VNN_REQ_STS", BIT(4), 1},
> + {"DFXAGG_VNN_REQ_STS", BIT(8), 0},
> + {"EXI_VNN_REQ_STS", BIT(9), 1},
> + {"OSSE_VNN_REQ_STS", BIT(14), 1},
> + {"P2D_VNN_REQ_STS", BIT(18), 1},
> + {"GBE_VNN_REQ_STS", BIT(19), 0},
> + {"SMB_VNN_REQ_STS", BIT(25), 1},
> + {"LPC_VNN_REQ_STS", BIT(26), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcds_vnn_req_status_2_map[] = {
> + {"CSMERTC_VNN_REQ_STS", BIT(1), 0},
> + {"CSE_VNN_REQ_STS", BIT(4), 1},
> + {"ISH_VNN_REQ_STS", BIT(7), 0},
> + {"SMT1_VNN_REQ_STS", BIT(8), 0},
> + {"OSSE_SMT1_VNN_REQ_STS", BIT(12), 1},
> + {"CLINK_VNN_REQ_STS", BIT(14), 0},
> + {"SMS1_VNN_REQ_STS", BIT(18), 0},
> + {"SMS2_VNN_REQ_STS", BIT(19), 0},
> + {"GPIOCOM4_VNN_REQ_STS", BIT(20), 0},
> + {"GPIOCOM3_VNN_REQ_STS", BIT(21), 1},
> + {"GPIOCOM1_VNN_REQ_STS", BIT(23), 1},
> + {"GPIOCOM0_VNN_REQ_STS", BIT(24), 1},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcds_vnn_req_status_3_map[] = {
> + {"DISP_SHIM_VNN_REQ_STS", BIT(4), 1},
> + {"DTS0_VNN_REQ_STS", BIT(7), 0},
> + {"GPIOCOM5_VNN_REQ_STS", BIT(11), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcds_vnn_misc_status_map[] = {
> + {"CPU_C10_REQ_STS", BIT(0), 0},
> + {"TS_OFF_REQ_STS", BIT(1), 0},
> + {"PNDE_MET_REQ_STS", BIT(2), 1},
> + {"PG5_PMA0_REQ_STS", BIT(3), 1},
> + {"FW_THROTTLE_ALLOWED_REQ_STS", BIT(4), 0},
> + {"VNN_SOC_REQ_STS", BIT(6), 1},
> + {"ISH_VNNAON_REQ_STS", BIT(7), 0},
> + {"D2D_NOC_CFI_QACTIVE_REQ_STS", BIT(8), 1},
> + {"D2D_NOC_GPSB_QACTIVE_REQ_STS", BIT(9), 1},
> + {"PLT_GREATER_REQ_STS", BIT(11), 1},
> + {"ALL_SBR_IDLE_REQ_STS", BIT(12), 0},
> + {"PMC_IDLE_FB_OCP_REQ_STS", BIT(13), 0},
> + {"PM_SYNC_STATES_REQ_STS", BIT(14), 0},
> + {"EA_REQ_STS", BIT(15), 0},
> + {"MPHY_CORE_OFF_REQ_STS", BIT(16), 0},
> + {"BRK_EV_EN_REQ_STS", BIT(17), 0},
> + {"AUTO_DEMO_EN_REQ_STS", BIT(18), 0},
> + {"ITSS_CLK_SRC_REQ_STS", BIT(19), 1},
> + {"ARC_IDLE_REQ_STS", BIT(21), 0},
> + {"PG5_PMA1_REQ_STS", BIT(22), 1},
> + {"DG5_PMA0_REQ_STS", BIT(23), 1},
> + {"ARC_INTERRUPT_WAKE_REQ_STS", BIT(25), 0},
> + {"D2D_DISP_DDI_QACTIVE_REQ_STS", BIT(26), 1},
> + {"PRE_WAKE0_REQ_STS", BIT(27), 1},
> + {"PRE_WAKE1_REQ_STS", BIT(28), 1},
> + {"PRE_WAKE2_REQ_STS", BIT(29), 1},
> + {"D2D_DISP_EDP_QACTIVE_REQ_STS", BIT(31), 1},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcds_rsc_status_map[] = {
> + {"CORE", 0, 1},
> + {"Memory", 0, 1},
> + {"PRIM_D2D", 0, 1},
> + {"PSF0", 0, 1},
> + {"SB", 0, 1},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pcds_signal_status_map[] = {
> + {"LSX_Wake0_STS", BIT(0), 0},
> + {"LSX_Wake1_STS", BIT(1), 0},
> + {"LSX_Wake2_STS", BIT(2), 0},
> + {"LSX_Wake3_STS", BIT(3), 0},
> + {"LSX_Wake4_STS", BIT(4), 0},
> + {"LSX_Wake5_STS", BIT(5), 0},
> + {"LSX_Wake6_STS", BIT(6), 0},
> + {"LSX_Wake7_STS", BIT(7), 0},
> + {"LPSS_Wake0_STS", BIT(8), 1},
> + {"LPSS_Wake1_STS", BIT(9), 1},
> + {"Int_Timer_SS_Wake0_STS", BIT(10), 1},
> + {"Int_Timer_SS_Wake1_STS", BIT(11), 1},
> + {"Int_Timer_SS_Wake2_STS", BIT(12), 1},
> + {"Int_Timer_SS_Wake3_STS", BIT(13), 1},
> + {"Int_Timer_SS_Wake4_STS", BIT(14), 1},
> + {"Int_Timer_SS_Wake5_STS", BIT(15), 1},
> + {}
> +};
> +
> +static const struct pmc_bit_map *nvl_pcds_lpm_maps[] = {
> + nvl_pcds_clocksource_status_map,
> + nvl_pcds_power_gating_status_0_map,
> + nvl_pcds_power_gating_status_1_map,
> + nvl_pcds_power_gating_status_2_map,
> + nvl_pcds_d3_status_0_map,
> + nvl_pcds_d3_status_1_map,
> + nvl_pcds_d3_status_2_map,
> + nvl_pcds_d3_status_3_map,
> + nvl_pcds_vnn_req_status_0_map,
> + nvl_pcds_vnn_req_status_1_map,
> + nvl_pcds_vnn_req_status_2_map,
> + nvl_pcds_vnn_req_status_3_map,
> + nvl_pcds_vnn_misc_status_map,
> + nvl_pcds_signal_status_map,
> + NULL
> +};
> +
> +static const struct pmc_bit_map *nvl_pcds_blk_maps[] = {
> + nvl_pcds_power_gating_status_0_map,
> + nvl_pcds_power_gating_status_1_map,
> + nvl_pcds_power_gating_status_2_map,
> + nvl_pcds_rsc_status_map,
> + nvl_pcds_vnn_req_status_0_map,
> + nvl_pcds_vnn_req_status_1_map,
> + nvl_pcds_vnn_req_status_2_map,
> + nvl_pcds_vnn_req_status_3_map,
> + nvl_pcds_d3_status_0_map,
> + nvl_pcds_d3_status_1_map,
> + nvl_pcds_d3_status_2_map,
> + nvl_pcds_d3_status_3_map,
> + nvl_pcds_clocksource_status_map,
> + nvl_pcds_vnn_misc_status_map,
> + nvl_pcds_signal_status_map,
> + NULL
> +};
> +
> +static const struct pmc_bit_map nvl_pchs_pfear_map[] = {
> + {"PMC_PGD0", BIT(0)},
> + {"FIA_D_PGD0", BIT(1)},
> + {"SPI_PGD0", BIT(2)},
> + {"XHCI_PGD0", BIT(3)},
> + {"SPA_PGD0", BIT(4)},
> + {"SPB_PGD0", BIT(5)},
> + {"MPFPW2_PGD0", BIT(6)},
> + {"GBE_PGD0", BIT(7)},
> +
> + {"RSVD8", BIT(0)},
> + {"PSF3_PGD0", BIT(1)},
> + {"SBR5_PGD0", BIT(2)},
> + {"SBR0_PGD0", BIT(3)},
> + {"RSVD12", BIT(4)},
> + {"D2D_DISP_PGD1", BIT(5)},
> + {"LPSS_PGD0", BIT(6)},
> + {"LPC_PGD0", BIT(7)},
> +
> + {"SMB_PGD0", BIT(0)},
> + {"ISH_PGD0", BIT(1)},
> + {"P2SB_PGD0", BIT(2)},
> + {"NPK_PGD0", BIT(3)},
> + {"D2D_NOC_PGD1", BIT(4)},
> + {"EAH_PGD0", BIT(5)},
> + {"FUSE_PGD0", BIT(6)},
> + {"SBR8_PGD0", BIT(7)},
> +
> + {"PSF7_PGD0", BIT(0)},
> + {"OTG_PGD0", BIT(1)},
> + {"EXI_PGD0", BIT(2)},
> + {"CSE_PGD0", BIT(3)},
> + {"CSME_KVM_PGD0", BIT(4)},
> + {"CSME_PMT_PGD0", BIT(5)},
> + {"CSME_CLINK_PGD0", BIT(6)},
> + {"CSME_PTIO_PGD0", BIT(7)},
> +
> + {"CSME_USBR_PGD0", BIT(0)},
> + {"SBR1_PGD0", BIT(1)},
> + {"CSME_SMT1_PGD0", BIT(2)},
> + {"MPFPW1_PGD0", BIT(3)},
> + {"CSME_SMS2_PGD0", BIT(4)},
> + {"CSME_SMS_PGD0", BIT(5)},
> + {"CSME_RTC_PGD0", BIT(6)},
> + {"CSMEPSF_PGD0", BIT(7)},
> +
> + {"D2D_NOC_PGD0", BIT(0)},
> + {"ESE_PGD0", BIT(1)},
> + {"SBR2_PGD0", BIT(2)},
> + {"SBR3_PGD0", BIT(3)},
> + {"SBR4_PGD0", BIT(4)},
> + {"RSVD45", BIT(5)},
> + {"D2D_DISP_PGD0", BIT(6)},
> + {"PSF1_PGD0", BIT(7)},
> +
> + {"U3FPW1_PGD0", BIT(0)},
> + {"DMI3FPW_PGD0", BIT(1)},
> + {"PSF4_PGD0", BIT(2)},
> + {"CNVI_PGD0", BIT(3)},
> + {"RSVD52", BIT(4)},
> + {"ENDBG_PGD0", BIT(5)},
> + {"DBC_PGD0", BIT(6)},
> + {"SMT4_PGD0", BIT(7)},
> +
> + {"RSVD56", BIT(0)},
> + {"NPK_PGD1", BIT(1)},
> + {"RSVD58", BIT(2)},
> + {"DMI3_PGD0", BIT(3)},
> + {"RSVD60", BIT(4)},
> + {"FIACPCB_D_PGD0", BIT(5)},
> + {"RSVD62", BIT(6)},
> + {"FIA_U_PGD0", BIT(7)},
> +
> + {"FIACPCB_PGS_PGD0", BIT(0)},
> + {"FIA_PGS_PGD0", BIT(1)},
> + {"RSVD66", BIT(2)},
> + {"FIACPCB_U_PGD0", BIT(3)},
> + {"TAM_PGD0", BIT(4)},
> + {"D2D_NOC_PGD2", BIT(5)},
> + {"PSF2_PGD0", BIT(6)},
> + {"THC0_PGD0", BIT(7)},
> +
> + {"THC1_PGD0", BIT(0)},
> + {"PMC_PGD1", BIT(1)},
> + {"SBR9_PGD0", BIT(2)},
> + {"U3FPW2_PGD0", BIT(3)},
> + {"RSVD76", BIT(4)},
> + {"DBG_PSF_PGD0", BIT(5)},
> + {"DBG_SBR_PGD0", BIT(6)},
> + {"SBR6_PGD0", BIT(7)},
> +
> + {"SPC_PGD0", BIT(0)},
> + {"ACE_PGD0", BIT(1)},
> + {"ACE_PGD1", BIT(2)},
> + {"ACE_PGD2", BIT(3)},
> + {"ACE_PGD3", BIT(4)},
> + {"ACE_PGD4", BIT(5)},
> + {"ACE_PGD5", BIT(6)},
> + {"ACE_PGD6", BIT(7)},
> +
> + {"ACE_PGD7", BIT(0)},
> + {"ACE_PGD8", BIT(1)},
> + {"ACE_PGD9", BIT(2)},
> + {"ACE_PGD10", BIT(3)},
> + {"U3FPW3_PGD0", BIT(4)},
> + {"SBR7_PGD0", BIT(5)},
> + {"OSSE_PGD0", BIT(6)},
> + {"ST_PGD0", BIT(7)},
> + {}
> +};
> +
> +static const struct pmc_bit_map *ext_nvl_pchs_pfear_map[] = {
> + nvl_pchs_pfear_map,
> + NULL
> +};
> +
> +static const struct pmc_bit_map nvl_pchs_clocksource_status_map[] = {
> + {"AON2_OFF_STS", BIT(0), 1},
> + {"AON3_OFF_STS", BIT(1), 0},
> + {"AON4_OFF_STS", BIT(2), 0},
> + {"AON2_SPL_OFF_STS", BIT(3), 0},
> + {"AONL_OFF_STS", BIT(4), 0},
> + {"XTAL_LVM_OFF_STS", BIT(5), 0},
> + {"AON5_OFF_STS", BIT(6), 0},
> + {"USB3_PLL_OFF_STS", BIT(8), 1},
> + {"MAIN_CRO_OFF_STS", BIT(11), 0},
> + {"MAIN_DIVIDER_OFF_STS", BIT(12), 1},
> + {"REF_PLL_NON_OC_OFF_STS", BIT(13), 1},
> + {"DMI_PLL_OFF_STS", BIT(14), 1},
> + {"PHY_EXT_INJ_OFF_STS", BIT(15), 1},
> + {"AON6_MCRO_OFF_STS", BIT(16), 0},
> + {"XTAL_AGGR_OFF_STS", BIT(17), 0},
> + {"USB2_PLL_OFF_STS", BIT(18), 1},
> + {"GBE_PLL_OFF_STS", BIT(21), 1},
> + {"SATA_PLL_OFF_STS", BIT(22), 1},
> + {"PCIE0_PLL_OFF_STS", BIT(23), 1},
> + {"PCIE1_PLL_OFF_STS", BIT(24), 1},
> + {"FABRIC_PLL_OFF_STS", BIT(25), 1},
> + {"PCIE2_PLL_OFF_STS", BIT(26), 1},
> + {"REF_PLL_OFF_STS", BIT(28), 1},
> + {"REF38P4_PLL_OFF_STS", BIT(31), 1},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pchs_power_gating_status_0_map[] = {
> + {"PMC_PGD0_PG_STS", BIT(0), 0},
> + {"FIA_D_PGD0_PG_STS", BIT(1), 0},
> + {"ESPISPI_PGD0_PG_STS", BIT(2), 0},
> + {"XHCI_PGD0_PG_STS", BIT(3), 0},
> + {"SPA_PGD0_PG_STS", BIT(4), 1},
> + {"SPB_PGD0_PG_STS", BIT(5), 1},
> + {"MPFPW2_PGD0_PG_STS", BIT(6), 0},
> + {"GBE_PGD0_PG_STS", BIT(7), 1},
> + {"RSVD_8", BIT(8), 0},
> + {"PSF3_PGD0_PG_STS", BIT(9), 0},
> + {"SBR5_PGD0_PG_STS", BIT(10), 0},
> + {"SBR0_PGD0_PG_STS", BIT(11), 0},
> + {"RSVD_12", BIT(12), 0},
> + {"D2D_DISP_PGD1_PG_STS", BIT(13), 0},
> + {"LPSS_PGD0_PG_STS", BIT(14), 1},
> + {"LPC_PGD0_PG_STS", BIT(15), 0},
> + {"SMB_PGD0_PG_STS", BIT(16), 0},
> + {"ISH_PGD0_PG_STS", BIT(17), 0},
> + {"P2S_PGD0_PG_STS", BIT(18), 0},
> + {"NPK_PGD0_PG_STS", BIT(19), 0},
> + {"D2D_NOC_PGD1_PG_STS", BIT(20), 0},
> + {"EAH_PGD0_PG_STS", BIT(21), 0},
> + {"FUSE_PGD0_PG_STS", BIT(22), 0},
> + {"SBR8_PGD0_PG_STS", BIT(23), 0},
> + {"PSF7_PGD0_PG_STS", BIT(24), 0},
> + {"XDCI_PGD0_PG_STS", BIT(25), 1},
> + {"EXI_PGD0_PG_STS", BIT(26), 0},
> + {"CSE_PGD0_PG_STS", BIT(27), 1},
> + {"KVMCC_PGD0_PG_STS", BIT(28), 1},
> + {"PMT_PGD0_PG_STS", BIT(29), 1},
> + {"CLINK_PGD0_PG_STS", BIT(30), 1},
> + {"PTIO_PGD0_PG_STS", BIT(31), 1},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pchs_power_gating_status_1_map[] = {
> + {"USBR0_PGD0_PG_STS", BIT(0), 1},
> + {"SBR1_PGD0_PG_STS", BIT(1), 0},
> + {"SMT1_PGD0_PG_STS", BIT(2), 1},
> + {"MPFPW1_PGD0_PG_STS", BIT(3), 0},
> + {"SMS2_PGD0_PG_STS", BIT(4), 1},
> + {"SMS1_PGD0_PG_STS", BIT(5), 1},
> + {"CSMERTC_PGD0_PG_STS", BIT(6), 0},
> + {"CSMEPSF_PGD0_PG_STS", BIT(7), 0},
> + {"D2D_NOC_PGD0_PG_STS", BIT(8), 0},
> + {"ESE_PGD0_PG_STS", BIT(9), 1},
> + {"SBR2_PGD0_PG_STS", BIT(10), 0},
> + {"SBR3_PGD0_PG_STS", BIT(11), 0},
> + {"SBR4_PGD0_PG_STS", BIT(12), 0},
> + {"RSVD_13", BIT(13), 0},
> + {"D2D_DISP_PGD0_PG_STS", BIT(14), 0},
> + {"PSF1_PGD0_PG_STS", BIT(15), 0},
> + {"U3FPW1_PGD0_PG_STS", BIT(16), 0},
> + {"DMI3FPW_PGD0_PG_STS", BIT(17), 0},
> + {"PSF4_PGD0_PG_STS", BIT(18), 0},
> + {"CNVI_PGD0_PG_STS", BIT(19), 0},
> + {"RSVD_20", BIT(20), 0},
> + {"ENDBG_PGD0_PG_STS", BIT(21), 0},
> + {"DBC_PGD0_PG_STS", BIT(22), 0},
> + {"SMT4_PGD0_PG_STS", BIT(23), 1},
> + {"RSVD_24", BIT(24), 0},
> + {"NPK_PGD1_PG_STS", BIT(25), 0},
> + {"RSVD_26", BIT(26), 0},
> + {"DMI3_PGD0_PG_STS", BIT(27), 1},
> + {"RSVD_28", BIT(28), 0},
> + {"FIACPCB_D_PGD0_PG_STS", BIT(29), 0},
> + {"RSVD_30", BIT(30), 0},
> + {"FIA_U_PGD0_PG_STS", BIT(31), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pchs_power_gating_status_2_map[] = {
> + {"FIACPCB_PGS_PGD0_PG_STS", BIT(0), 0},
> + {"FIA_PGS_PGD0_PG_STS", BIT(1), 0},
> + {"RSVD_2", BIT(2), 0},
> + {"FIACPCB_U_PGD0_PG_STS", BIT(3), 0},
> + {"TAM_PGD0_PG_STS", BIT(4), 0},
> + {"D2D_NOC_PGD2_PG_STS", BIT(5), 0},
> + {"PSF2_PGD0_PG_STS", BIT(6), 0},
> + {"THC0_PGD0_PG_STS", BIT(7), 1},
> + {"THC1_PGD0_PG_STS", BIT(8), 1},
> + {"PMC_PGD1_PG_STS", BIT(9), 0},
> + {"SBR9_PGA0_PGD0_PG_STS", BIT(10), 0},
> + {"U3FPW2_PGD0_PG_STS", BIT(11), 0},
> + {"RSVD_12", BIT(12), 0},
> + {"DBG_PSF_PGD0_PG_STS", BIT(13), 0},
> + {"DBG_SBR_PGD0_PG_STS", BIT(14), 0},
> + {"SBR6_PGD0_PG_STS", BIT(15), 0},
> + {"SPC_PGD0_PG_STS", BIT(16), 1},
> + {"ACE_PGD0_PG_STS", BIT(17), 0},
> + {"ACE_PGD1_PG_STS", BIT(18), 0},
> + {"ACE_PGD2_PG_STS", BIT(19), 0},
> + {"ACE_PGD3_PG_STS", BIT(20), 0},
> + {"ACE_PGD4_PG_STS", BIT(21), 0},
> + {"ACE_PGD5_PG_STS", BIT(22), 0},
> + {"ACE_PGD6_PG_STS", BIT(23), 0},
> + {"ACE_PGD7_PG_STS", BIT(24), 0},
> + {"ACE_PGD8_PG_STS", BIT(25), 0},
> + {"ACE_PGD9_PG_STS", BIT(26), 0},
> + {"ACE_PGD10_PG_STS", BIT(27), 0},
> + {"U3FPW3_PGD0_PG_STS", BIT(28), 0},
> + {"SBR7_PGD0_PG_STS", BIT(29), 0},
> + {"OSSE_PGD0_PG_STS", BIT(30), 0},
> + {"SATA_PGD0_PG_STS", BIT(31), 1},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pchs_d3_status_0_map[] = {
> + {"LPSS_D3_STS", BIT(3), 1},
> + {"XDCI_D3_STS", BIT(4), 1},
> + {"XHCI_D3_STS", BIT(5), 0},
> + {"SPA_D3_STS", BIT(12), 0},
> + {"SPB_D3_STS", BIT(13), 0},
> + {"SPC_D3_STS", BIT(14), 0},
> + {"ESPISPI_D3_STS", BIT(18), 0},
> + {"SATA_D3_STS", BIT(20), 1},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pchs_d3_status_1_map[] = {
> + {"OSSE_D3_STS", BIT(6), 0},
> + {"GBE_D3_STS", BIT(19), 0},
> + {"ITSS_D3_STS", BIT(23), 0},
> + {"P2S_D3_STS", BIT(24), 0},
> + {"CNVI_D3_STS", BIT(27), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pchs_d3_status_2_map[] = {
> + {"CSMERTC_D3_STS", BIT(1), 0},
> + {"CSE_D3_STS", BIT(4), 0},
> + {"KVMCC_D3_STS", BIT(5), 0},
> + {"USBR0_D3_STS", BIT(6), 0},
> + {"ISH_D3_STS", BIT(7), 0},
> + {"SMT1_D3_STS", BIT(8), 0},
> + {"SMT2_D3_STS", BIT(9), 0},
> + {"SMT3_D3_STS", BIT(10), 0},
> + {"SMT4_D3_STS", BIT(11), 0},
> + {"SMT5_D3_STS", BIT(12), 0},
> + {"SMT6_D3_STS", BIT(13), 0},
> + {"CLINK_D3_STS", BIT(14), 0},
> + {"PTIO_D3_STS", BIT(16), 0},
> + {"PMT_D3_STS", BIT(17), 0},
> + {"SMS1_D3_STS", BIT(18), 0},
> + {"SMS2_D3_STS", BIT(19), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pchs_d3_status_3_map[] = {
> + {"THC0_D3_STS", BIT(14), 0},
> + {"THC1_D3_STS", BIT(15), 0},
> + {"ACE_D3_STS", BIT(23), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pchs_vnn_req_status_1_map[] = {
> + {"NPK_VNN_REQ_STS", BIT(4), 0},
> + {"OSSE_VNN_REQ_STS", BIT(6), 0},
> + {"DFXAGG_VNN_REQ_STS", BIT(8), 0},
> + {"EXI_VNN_REQ_STS", BIT(9), 0},
> + {"GBE_VNN_REQ_STS", BIT(19), 0},
> + {"SMB_VNN_REQ_STS", BIT(25), 0},
> + {"LPC_VNN_REQ_STS", BIT(26), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pchs_vnn_req_status_2_map[] = {
> + {"CSMERTC_VNN_REQ_STS", BIT(1), 0},
> + {"CSE_VNN_REQ_STS", BIT(4), 0},
> + {"ISH_VNN_REQ_STS", BIT(7), 0},
> + {"SMT1_VNN_REQ_STS", BIT(8), 0},
> + {"SMT4_VNN_REQ_STS", BIT(11), 0},
> + {"CLINK_VNN_REQ_STS", BIT(14), 0},
> + {"SMS1_VNN_REQ_STS", BIT(18), 0},
> + {"SMS2_VNN_REQ_STS", BIT(19), 0},
> + {"GPIOCOM4_VNN_REQ_STS", BIT(20), 0},
> + {"GPIOCOM3_VNN_REQ_STS", BIT(21), 0},
> + {"GPIOCOM2_VNN_REQ_STS", BIT(22), 0},
> + {"GPIOCOM1_VNN_REQ_STS", BIT(23), 0},
> + {"GPIOCOM0_VNN_REQ_STS", BIT(24), 0},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pchs_vnn_misc_status_map[] = {
> + {"CPU_C10_REQ_STS", BIT(0), 0},
> + {"TS_OFF_REQ_STS", BIT(1), 0},
> + {"PNDE_MET_REQ_STS", BIT(2), 1},
> + {"PG5_PMA0_GVNN_REQ_STS", BIT(3), 1},
> + {"FW_THROTTLE_ALLOWED_REQ_STS", BIT(4), 0},
> + {"DMI_IN_L1_REQ_STS", BIT(6), 0},
> + {"ISH_VNNAON_REQ_STS", BIT(7), 0},
> + {"PLT_GREATER_REQ_STS", BIT(11), 1},
> + {"ALL_SBR_IDLE_REQ_STS", BIT(12), 0},
> + {"PMC_IDLE_FB_OCP_REQ_STS", BIT(13), 0},
> + {"PM_SYNC_STATES_REQ_STS", BIT(14), 0},
> + {"EA_REQ_STS", BIT(15), 0},
> + {"DMI_CLKREQ_B_REQ_STS", BIT(16), 0},
> + {"BRK_EV_EN_REQ_STS", BIT(17), 0},
> + {"AUTO_DEMO_EN_REQ_STS", BIT(18), 0},
> + {"ITSS_CLK_SRC_REQ_STS", BIT(19), 1},
> + {"ARC_IDLE_REQ_STS", BIT(21), 0},
> + {"PG5_PMA1_GVNN_REQ_STS", BIT(22), 1},
> + {"FIA_DEEP_PM_REQ_STS", BIT(23), 0},
> + {"XDCI_ATTACHED_REQ_STS", BIT(24), 0},
> + {"ARC_INTERRUPT_WAKE_REQ_STS", BIT(25), 0},
> + {"PRE_WAKE0_REQ_STS", BIT(27), 1},
> + {"PRE_WAKE1_REQ_STS", BIT(28), 1},
> + {"PRE_WAKE2_EN_REQ_STS", BIT(29), 0},
> + {"PG5_PMA2_GVNN_REQ_STS", BIT(30), 1},
> + {}
> +};
> +
> +static const struct pmc_bit_map nvl_pchs_rsc_status_map[] = {
> + {"Memory", 0, 1},
> + {"Memory_NS", 0, 1},
> + {"PSF1", 0, 1},
> + {"PSF2", 0, 1},
> + {"PSF3", 0, 1},
> + {"REF_PLL", 0, 1},
> + {"SB", 0, 1},
> + {}
> +};
> +
> +static const struct pmc_bit_map *nvl_pchs_lpm_maps[] = {
> + nvl_pchs_clocksource_status_map,
> + nvl_pchs_power_gating_status_0_map,
> + nvl_pchs_power_gating_status_1_map,
> + nvl_pchs_power_gating_status_2_map,
> + nvl_pchs_d3_status_0_map,
> + nvl_pchs_d3_status_1_map,
> + nvl_pchs_d3_status_2_map,
> + nvl_pchs_d3_status_3_map,
> + nvl_pcds_vnn_req_status_0_map,
> + nvl_pchs_vnn_req_status_1_map,
> + nvl_pchs_vnn_req_status_2_map,
> + nvl_pcdh_vnn_req_status_3_map,
> + nvl_pchs_vnn_misc_status_map,
> + ptl_pcdp_signal_status_map,
> + NULL
> +};
> +
> +static const struct pmc_bit_map *nvl_pchs_blk_maps[] = {
> + nvl_pchs_power_gating_status_0_map,
> + nvl_pchs_power_gating_status_1_map,
> + nvl_pchs_power_gating_status_2_map,
> + nvl_pchs_rsc_status_map,
> + nvl_pchs_d3_status_0_map,
> + nvl_pchs_clocksource_status_map,
> + nvl_pchs_vnn_misc_status_map,
> + NULL
> +};
> +
> +static const struct pmc_reg_map nvl_pcdh_reg_map = {
> + .pfear_sts = ext_nvl_pcdh_pfear_map,
> + .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
> + .slp_s0_res_counter_step = TGL_PMC_SLP_S0_RES_COUNTER_STEP,
> + .ltr_show_sts = ptl_pcdp_ltr_show_map,
> + .msr_sts = msr_map,
> + .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
> + .regmap_length = NVL_PCDH_PMC_MMIO_REG_LEN,
> + .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
> + .ppfear_buckets = NVL_PCDH_PPFEAR_NUM_ENTRIES,
> + .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
> + .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
> + .lpm_num_maps = NVL_LPM_NUM_MAPS,
> + .ltr_ignore_max = LNL_NUM_IP_IGN_ALLOWED,
> + .lpm_res_counter_step_x2 = TGL_PMC_LPM_RES_COUNTER_STEP_X2,
> + .etr3_offset = ETR3_OFFSET,
> + .lpm_sts_latch_en_offset = MTL_LPM_STATUS_LATCH_EN_OFFSET,
> + .lpm_priority_offset = NVL_LPM_PRI_OFFSET,
> + .lpm_en_offset = NVL_LPM_EN_OFFSET,
> + .lpm_residency_offset = NVL_LPM_RESIDENCY_OFFSET,
> + .lpm_sts = nvl_pcdh_lpm_maps,
> + .lpm_status_offset = MTL_LPM_STATUS_OFFSET,
> + .lpm_live_status_offset = NVL_LPM_LIVE_STATUS_OFFSET,
> + .s0ix_blocker_maps = nvl_pcdh_blk_maps,
> + .s0ix_blocker_offset = LNL_S0IX_BLOCKER_OFFSET,
> + .num_s0ix_blocker = NVL_PCDH_NUM_S0IX_BLOCKER,
> + .blocker_req_offset = NVL_PCDH_BLK_REQ_OFFSET,
> + .lpm_req_guid = PCDH_LPM_REQ_GUID,
> +};
> +
> +static const struct pmc_reg_map nvl_pcds_reg_map = {
> + .pfear_sts = ext_nvl_pcds_pfear_map,
> + .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
> + .slp_s0_res_counter_step = TGL_PMC_SLP_S0_RES_COUNTER_STEP,
> + .ltr_show_sts = nvl_pcds_ltr_show_map,
> + .msr_sts = msr_map,
> + .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
> + .regmap_length = NVL_PCDS_PMC_MMIO_REG_LEN,
> + .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
> + .ppfear_buckets = LNL_PPFEAR_NUM_ENTRIES,
> + .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
> + .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
> + .lpm_num_maps = PTL_LPM_NUM_MAPS,
> + .ltr_ignore_max = LNL_NUM_IP_IGN_ALLOWED,
> + .lpm_res_counter_step_x2 = TGL_PMC_LPM_RES_COUNTER_STEP_X2,
> + .etr3_offset = ETR3_OFFSET,
> + .lpm_sts_latch_en_offset = MTL_LPM_STATUS_LATCH_EN_OFFSET,
> + .lpm_priority_offset = MTL_LPM_PRI_OFFSET,
> + .lpm_en_offset = MTL_LPM_EN_OFFSET,
> + .lpm_residency_offset = MTL_LPM_RESIDENCY_OFFSET,
> + .lpm_sts = nvl_pcds_lpm_maps,
> + .lpm_status_offset = MTL_LPM_STATUS_OFFSET,
> + .lpm_live_status_offset = MTL_LPM_LIVE_STATUS_OFFSET,
> + .s0ix_blocker_maps = nvl_pcds_blk_maps,
> + .s0ix_blocker_offset = LNL_S0IX_BLOCKER_OFFSET,
> + .num_s0ix_blocker = NVL_PCDS_NUM_S0IX_BLOCKER,
> + .lpm_req_guid = PCDS_LPM_REQ_GUID,
> + .blocker_req_offset = NVL_PCDS_BLK_REQ_OFFSET,
> +};
> +
> +static const struct pmc_reg_map nvl_pchs_reg_map = {
> + .pfear_sts = ext_nvl_pchs_pfear_map,
> + .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
> + .slp_s0_res_counter_step = TGL_PMC_SLP_S0_RES_COUNTER_STEP,
> + .ltr_show_sts = ptl_pcdp_ltr_show_map,
> + .msr_sts = msr_map,
> + .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
> + .regmap_length = NVL_PCHS_PMC_MMIO_REG_LEN,
> + .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
> + .ppfear_buckets = LNL_PPFEAR_NUM_ENTRIES,
> + .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
> + .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
> + .lpm_num_maps = PTL_LPM_NUM_MAPS,
> + .ltr_ignore_max = LNL_NUM_IP_IGN_ALLOWED,
> + .lpm_res_counter_step_x2 = TGL_PMC_LPM_RES_COUNTER_STEP_X2,
> + .etr3_offset = ETR3_OFFSET,
> + .lpm_sts_latch_en_offset = MTL_LPM_STATUS_LATCH_EN_OFFSET,
> + .lpm_priority_offset = MTL_LPM_PRI_OFFSET,
> + .lpm_en_offset = MTL_LPM_EN_OFFSET,
> + .lpm_residency_offset = MTL_LPM_RESIDENCY_OFFSET,
> + .lpm_sts = nvl_pchs_lpm_maps,
> + .lpm_status_offset = MTL_LPM_STATUS_OFFSET,
> + .lpm_live_status_offset = MTL_LPM_LIVE_STATUS_OFFSET,
> + .s0ix_blocker_maps = nvl_pchs_blk_maps,
> + .s0ix_blocker_offset = LNL_S0IX_BLOCKER_OFFSET,
> + .num_s0ix_blocker = NVL_PCHS_NUM_S0IX_BLOCKER,
> + .blocker_req_offset = NVL_PCHS_BLK_REQ_OFFSET,
> + .lpm_req_guid = PCHS_LPM_REQ_GUID,
> +};
> +
> +static struct pmc_info nvl_pmc_info_list[] = {
> + {
> + .devid = PMC_DEVID_NVL_PCDH,
> + .map = &nvl_pcdh_reg_map,
> + },
> + {
> + .devid = PMC_DEVID_NVL_PCDS,
> + .map = &nvl_pcds_reg_map,
> + },
> + {
> + .devid = PMC_DEVID_NVL_PCHS,
> + .map = &nvl_pchs_reg_map,
> + },
> + {}
> +};
> +
> +const char *nvl_ltr_block_counter_arr[] = {
> + "PKGC_PREVENT_LTR_IADOMAIN",
> + "PKGC_PREVENT_LTR_GDIE",
> + "PKGC_PREVENT_LTR_PCH",
> + "PKGC_PREVENT_LTR_DISPLAY",
> + "PKGC_PREVENT_LTR_IPU",
> + NULL
> +};
> +
> +const char *nvl_pkgc_blocker_residency[] = {
> + "PKGC_BLOCK_RESIDENCY_INVALID",
> + "PKGC_BLOCK_RESIDENCY_MISC",
> + "PKGC_BLOCK_RESIDENCY_CDIE_MISC",
> + "PKGC_BLOCK_RESIDENCY_MEDIA_MISC",
> + "PKGC_BLOCK_RESIDENCY_GT_MISC",
> + "PKGC_BLOCK_RESIDENCY_HUBATOM_MISC",
> + "PKGC_BLOCK_RESIDENCY_IPU_BUSY",
> + "PKGC_BLOCK_RESIDENCY_IPU_LTR",
> + "PKGC_BLOCK_RESIDENCY_IPU_TIMER",
> + "PKGC_BLOCK_RESIDENCY_DISP_BUSY",
> + "PKGC_BLOCK_RESIDENCY_DISP_LTR",
> + "PKGC_BLOCK_RESIDENCY_DISP_TIMER",
> + "PKGC_BLOCK_RESIDENCY_VPU_BUSY",
> + "PKGC_BLOCK_RESIDENCY_VPU_TIMER",
> + "PKGC_BLOCK_RESIDENCY_PMC_BUSY",
> + "PKGC_BLOCK_RESIDENCY_PMC_LTR",
> + "PKGC_BLOCK_RESIDENCY_PMC_TIMER",
> + "PKGC_BLOCK_RESIDENCY_HUBATOM_ARAT",
> + "PKGC_BLOCK_RESIDENCY_CDIE0_ARAT",
> + "PKGC_BLOCK_RESIDENCY_CDIE1_ARAT",
> + "PKGC_BLOCK_RESIDENCY_GT_ARAT",
> + "PKGC_BLOCK_RESIDENCY_MEDIA_ARAT",
> + "PKGC_BLOCK_RESIDENCY_DEMOTION",
> + "PKGC_BLOCK_RESIDENCY_THERMALS",
> + "PKGC_BLOCK_RESIDENCY_SNCU",
> + "PKGC_BLOCK_RESIDENCY_SVTU",
> + "PKGC_BLOCK_RESIDENCY_IAA",
> + "PKGC_BLOCK_RESIDENCY_IOC",
> + NULL,
> +};
> +
> +static u8 nvl_pmc_list[] = {PMC_IDX_MAIN, PMC_IDX_PCH, PMC_IDX_MAX};
> +static u8 nvl_h_pmc_list[] = {PMC_IDX_MAIN, PMC_IDX_PCH, PMC_IDX_MAX};
> +
> +#define NVL_NPU_PCI_DEV 0xd71d
> +
> +/*
> + * Set power state of select devices that do not have drivers to D3
> + * so that they do not block Package C entry.
> + */
> +static void nvl_d3_fixup(void)
> +{
> + pmc_core_set_device_d3(NVL_NPU_PCI_DEV);
> +}
> +
> +static int nvl_resume(struct pmc_dev *pmcdev)
> +{
> + nvl_d3_fixup();
> + return cnl_resume(pmcdev);
> +}
> +
> +static int nvl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
> +{
> + nvl_d3_fixup();
> + return generic_core_init(pmcdev, pmc_dev_info);
> +}
> +
> +static u32 NVL_PMT_DMU_GUIDS[] = {NVL_PMT_DMU_GUID, 0x0};
Please use lowercase for the name. Uppercase is reserved for macros.
I seem to have missed the others got added with uppercase. The distinction
between macros & variables is important so lets try to not muddle waters
when it comes to that.
> +struct pmc_dev_info nvl_s_pmc_dev = {
> + .pmc_list = nvl_pmc_list,
> + .regmap_list = nvl_pmc_info_list,
> + .map = &nvl_pcds_reg_map,
> + .sub_req_show = &pmc_core_substate_blk_req_fops,
> + .suspend = cnl_suspend,
> + .resume = nvl_resume,
> + .init = nvl_core_init,
> + .sub_req = pmc_core_pmt_get_blk_sub_req,
> + .dmu_guids = NVL_PMT_DMU_GUIDS,
> + .pc_guid = NVL_PMT_PC_GUID,
> + .pkgc_ltr_blocker_offset = NVL_LTR_BLK_OFFSET,
> + .pkgc_ltr_blocker_counters = nvl_ltr_block_counter_arr,
> + .pkgc_blocker_offset = NVL_PKGC_BLK_OFFSET,
> + .pkgc_blocker_counters = nvl_pkgc_blocker_residency,
> + .ssram_hidden = false,
> + .die_c6_offset = NVL_PMT_DMU_DIE_C6_OFFSET,
> +};
> +
> +struct pmc_dev_info nvl_h_pmc_dev = {
> + .pmc_list = nvl_h_pmc_list,
> + .regmap_list = nvl_pmc_info_list,
> + .map = &nvl_pcdh_reg_map,
> + .sub_req_show = &pmc_core_substate_blk_req_fops,
> + .suspend = cnl_suspend,
> + .resume = nvl_resume,
> + .init = nvl_core_init,
> + .sub_req = pmc_core_pmt_get_blk_sub_req,
> + .dmu_guids = NVL_PMT_DMU_GUIDS,
> + .pc_guid = NVL_PMT_PC_GUID,
> + .pkgc_ltr_blocker_offset = NVL_LTR_BLK_OFFSET,
> + .pkgc_ltr_blocker_counters = nvl_ltr_block_counter_arr,
> + .pkgc_blocker_offset = NVL_PKGC_BLK_OFFSET,
> + .pkgc_blocker_counters = nvl_pkgc_blocker_residency,
> + .ssram_hidden = false,
> + .die_c6_offset = NVL_PMT_DMU_DIE_C6_OFFSET,
> +};
> diff --git a/drivers/platform/x86/intel/pmc/ptl.c b/drivers/platform/x86/intel/pmc/ptl.c
> index 538ca5ae2e9ec..d39ae842ddd57 100644
> --- a/drivers/platform/x86/intel/pmc/ptl.c
> +++ b/drivers/platform/x86/intel/pmc/ptl.c
> @@ -137,7 +137,7 @@ static const struct pmc_bit_map *ext_ptl_pcdp_pfear_map[] = {
> NULL
> };
>
> -static const struct pmc_bit_map ptl_pcdp_ltr_show_map[] = {
> +const struct pmc_bit_map ptl_pcdp_ltr_show_map[] = {
> {"SOUTHPORT_A", CNP_PMC_LTR_SPA},
> {"SOUTHPORT_B", CNP_PMC_LTR_SPB},
> {"SATA", CNP_PMC_LTR_SATA},
>
--
i.
^ permalink raw reply
* [GIT PULL] pmdomain fixes for v7.0-rc5
From: Ulf Hansson @ 2026-03-20 11:05 UTC (permalink / raw)
To: Linus, linux-pm, linux-kernel; +Cc: Ulf Hansson, linux-arm-kernel
Hi Linus,
Here's a pull-request with a couple of pmdomain fixes intended for v7.0-rc5.
Details about the highlights are as usual found in the signed tag.
Please pull this in!
Kind regards
Ulf Hansson
The following changes since commit 0fb59eaca18f1254ecdce34354eec3cb1b3b5e10:
pmdomain: rockchip: Fix PD_VCODEC for RK3588 (2026-03-04 11:22:36 +0100)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm.git tags/pmdomain-v7.0-rc1-2
for you to fetch changes up to b826d2c0b0ecb844c84431ba6b502e744f5d919a:
pmdomain: bcm: bcm2835-power: Increase ASB control timeout (2026-03-18 19:15:34 +0100)
----------------------------------------------------------------
pmdomain providers:
- bcm: Increase ASB control timeout for bcm2835
- mediatek: Fix power domain count
----------------------------------------------------------------
Adam Ford (1):
pmdomain: mediatek: Fix power domain count
Maíra Canal (1):
pmdomain: bcm: bcm2835-power: Increase ASB control timeout
drivers/pmdomain/bcm/bcm2835-power.c | 12 ++++--------
drivers/pmdomain/mediatek/mtk-pm-domains.c | 2 +-
2 files changed, 5 insertions(+), 9 deletions(-)
^ permalink raw reply
* Re: [RFC PATCH v6 4/4] cpufreq/freq_table: Allow decreasing cpuinfo.max_freq
From: Viresh Kumar @ 2026-03-20 10:58 UTC (permalink / raw)
To: Pierre Gondois
Cc: linux-kernel, Jie Zhan, Lifeng Zheng, Ionela Voinescu,
Sumit Gupta, Huang Rui, Gautham R. Shenoy, Mario Limonciello,
Perry Yuan, Rafael J. Wysocki, Srinivas Pandruvada, Len Brown,
Saravana Kannan, linux-pm
In-Reply-To: <20260317101753.2284763-5-pierre.gondois@arm.com>
On 17-03-26, 11:17, Pierre Gondois wrote:
> Drivers not using freq. tables update cpuinfo.max_freq in their
> .set_boost() callback. E.g. amd-pstate, cppc_cpufreq.
> Drivers relying on freq. tables and supporting boost frequencies
> rely on cpufreq_frequency_table_cpuinfo(). cpuinfo.max_freq is
> only updated if the new maximal value is higher than the previous
> one.
>
> Using the scmi-cpufreq driver which relies on freq. tables, enabling
> boost will permanently increases the cpuinfo.max_freq value.
> This patch allows to lower cpuinfo.max_freq.
>
> Note:
> commit 538b0188da46 ("cpufreq: ACPI: Set cpuinfo.max_freq directly
> if max boost is known")
Rafael needs to decide this part, since it may end up breaking acpi-cpufreq.
I am okay otherwise.
--
viresh
^ permalink raw reply
* Re: [PATCH 5/6] platform/x86/intel/pmc: Retrieve PMC info only for available PMCs
From: Ilpo Järvinen @ 2026-03-20 10:58 UTC (permalink / raw)
To: Xi Pardee
Cc: irenic.rajneesh, david.e.box, platform-driver-x86, LKML, linux-pm
In-Reply-To: <20260302223214.484585-6-xi.pardee@linux.intel.com>
On Mon, 2 Mar 2026, Xi Pardee wrote:
> Update the Intel PMC Core driver to fetch PMC information only for
> available PMCs. Previously, the driver attempted to retrieve PMC info
> even when the corresponding PMC was not present.
>
> This change aligns with recent updates to the Intel SSRAM Telemetry
> driver. Starting with NVL, the SSRAM Telemetry driver is probed for
> each individual SSRAM device. The prior implementation could not
> differentiate between an unavailable PMC and one that had not yet
> completed information retrieval. To resolve this, the PMC Core driver
> now skips obtaining PMC info for unavailable PMCs.
>
> Signed-off-by: Xi Pardee <xi.pardee@linux.intel.com>
> ---
> drivers/platform/x86/intel/pmc/arl.c | 5 +++++
> drivers/platform/x86/intel/pmc/core.c | 19 +++++++++++--------
> drivers/platform/x86/intel/pmc/core.h | 2 ++
> drivers/platform/x86/intel/pmc/lnl.c | 3 +++
> drivers/platform/x86/intel/pmc/mtl.c | 3 +++
> drivers/platform/x86/intel/pmc/ptl.c | 3 +++
> drivers/platform/x86/intel/pmc/wcl.c | 3 +++
> 7 files changed, 30 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/platform/x86/intel/pmc/arl.c b/drivers/platform/x86/intel/pmc/arl.c
> index 4d91ee010f6d0..34506542c94da 100644
> --- a/drivers/platform/x86/intel/pmc/arl.c
> +++ b/drivers/platform/x86/intel/pmc/arl.c
> @@ -672,6 +672,9 @@ static struct pmc_info arl_pmc_info_list[] = {
> {}
> };
>
> +static u8 arl_pmc_list[] = {PMC_IDX_MAIN, PMC_IDX_IOE, PMC_IDX_PCH, PMC_IDX_MAX};
> +static u8 arl_h_pmc_list[] = {PMC_IDX_MAIN, PMC_IDX_IOE, PMC_IDX_MAX};
This seems a bit dangerous approach if somebody forgets to add that
PMC_IDX_MAX. It would be better to do it with sizeof() for safety).
> +
> #define ARL_NPU_PCI_DEV 0xad1d
> #define ARL_GNA_PCI_DEV 0xae4c
> #define ARL_H_NPU_PCI_DEV 0x7d1d
> @@ -721,6 +724,7 @@ static int arl_h_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_
> static u32 ARL_PMT_DMU_GUIDS[] = {ARL_PMT_DMU_GUID, 0x0};
> struct pmc_dev_info arl_pmc_dev = {
> .dmu_guids = ARL_PMT_DMU_GUIDS,
> + .pmc_list = arl_pmc_list,
> .regmap_list = arl_pmc_info_list,
> .map = &arl_socs_reg_map,
> .sub_req_show = &pmc_core_substate_req_regs_fops,
> @@ -735,6 +739,7 @@ struct pmc_dev_info arl_pmc_dev = {
> static u32 ARL_H_PMT_DMU_GUIDS[] = {ARL_PMT_DMU_GUID, ARL_H_PMT_DMU_GUID, 0x0};
> struct pmc_dev_info arl_h_pmc_dev = {
> .dmu_guids = ARL_H_PMT_DMU_GUIDS,
> + .pmc_list = arl_h_pmc_list,
> .regmap_list = arl_pmc_info_list,
> .map = &mtl_socm_reg_map,
> .sub_req_show = &pmc_core_substate_req_regs_fops,
> diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c
> index 7bd0e1eaa32e2..85fff5e3abe0d 100644
> --- a/drivers/platform/x86/intel/pmc/core.c
> +++ b/drivers/platform/x86/intel/pmc/core.c
> @@ -1744,16 +1744,19 @@ static int pmc_core_pmc_add(struct pmc_dev *pmcdev, unsigned int pmc_idx)
> return 0;
> }
>
> -static int pmc_core_ssram_get_reg_base(struct pmc_dev *pmcdev)
> +static int pmc_core_ssram_get_reg_base(struct pmc_dev *pmcdev, u8 *pmc_list)
> {
> + unsigned int i;
> int ret;
>
> - ret = pmc_core_pmc_add(pmcdev, PMC_IDX_MAIN);
> - if (ret)
> - return ret;
> -
> - pmc_core_pmc_add(pmcdev, PMC_IDX_IOE);
> - pmc_core_pmc_add(pmcdev, PMC_IDX_PCH);
> + for (i = 0; pmc_list[i] != PMC_IDX_MAX; ++i) {
> + if (pmc_list[i] == PMC_IDX_MAIN) {
> + ret = pmc_core_pmc_add(pmcdev, pmc_list[i]);
> + if (ret)
> + return ret;
> + } else
> + pmc_core_pmc_add(pmcdev, pmc_list[i]);
Isn't this same as:
/* Non-MAIN PMCs are allowed to fail */
ret = pmc_core_pmc_add(pmcdev, pmc_list[i]);
if (ret && (pmc_list[i] == PMC_IDX_MAIN))
return ret;
> + }
>
> return 0;
> }
> @@ -1775,7 +1778,7 @@ int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
> ssram = pmc_dev_info->regmap_list != NULL;
> if (ssram) {
> pmcdev->regmap_list = pmc_dev_info->regmap_list;
> - ret = pmc_core_ssram_get_reg_base(pmcdev);
> + ret = pmc_core_ssram_get_reg_base(pmcdev, pmc_dev_info->pmc_list);
> /*
> * EAGAIN error code indicates Intel PMC SSRAM Telemetry driver
> * has not finished probe and PMC info is not available yet. Try
> diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h
> index f09791f866223..c4984e44f7b80 100644
> --- a/drivers/platform/x86/intel/pmc/core.h
> +++ b/drivers/platform/x86/intel/pmc/core.h
> @@ -501,6 +501,7 @@ enum pmc_index {
> * @pc_guid: GUID for telemetry region to read PKGC blocker info
> * @pkgc_ltr_blocker_offset: Offset to PKGC LTR blockers in telemetry region
> * @pkgc_blocker_offset:Offset to PKGC blocker in telemetry region
> + * @pmc_list: Index list of available PMC
> * @regmap_list: Pointer to a list of pmc_info structure that could be
> * available for the platform. When set, this field implies
> * SSRAM support.
> @@ -521,6 +522,7 @@ struct pmc_dev_info {
> u32 pc_guid;
> u32 pkgc_ltr_blocker_offset;
> u32 pkgc_blocker_offset;
> + u8 *pmc_list;
> struct pmc_info *regmap_list;
> const struct pmc_reg_map *map;
> const struct file_operations *sub_req_show;
> diff --git a/drivers/platform/x86/intel/pmc/lnl.c b/drivers/platform/x86/intel/pmc/lnl.c
> index 18f303af328e3..7b09b59e1326c 100644
> --- a/drivers/platform/x86/intel/pmc/lnl.c
> +++ b/drivers/platform/x86/intel/pmc/lnl.c
> @@ -544,6 +544,8 @@ static struct pmc_info lnl_pmc_info_list[] = {
> {}
> };
>
> +static u8 lnl_pmc_list[] = {PMC_IDX_MAIN, PMC_IDX_MAX};
> +
> #define LNL_NPU_PCI_DEV 0x643e
> #define LNL_IPU_PCI_DEV 0x645d
>
> @@ -571,6 +573,7 @@ static int lnl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_in
> }
>
> struct pmc_dev_info lnl_pmc_dev = {
> + .pmc_list = lnl_pmc_list,
> .regmap_list = lnl_pmc_info_list,
> .map = &lnl_socm_reg_map,
> .sub_req_show = &pmc_core_substate_req_regs_fops,
> diff --git a/drivers/platform/x86/intel/pmc/mtl.c b/drivers/platform/x86/intel/pmc/mtl.c
> index b724dd8c34dba..6438fca266392 100644
> --- a/drivers/platform/x86/intel/pmc/mtl.c
> +++ b/drivers/platform/x86/intel/pmc/mtl.c
> @@ -965,6 +965,8 @@ static struct pmc_info mtl_pmc_info_list[] = {
> {}
> };
>
> +static u8 mtl_pmc_list[] = {PMC_IDX_MAIN, PMC_IDX_IOE, PMC_IDX_MAX};
> +
> #define MTL_GNA_PCI_DEV 0x7e4c
> #define MTL_IPU_PCI_DEV 0x7d19
> #define MTL_VPU_PCI_DEV 0x7d1d
> @@ -995,6 +997,7 @@ static int mtl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_in
> static u32 MTL_PMT_DMU_GUIDS[] = {MTL_PMT_DMU_GUID, 0x0};
> struct pmc_dev_info mtl_pmc_dev = {
> .dmu_guids = MTL_PMT_DMU_GUIDS,
> + .pmc_list = mtl_pmc_list,
> .regmap_list = mtl_pmc_info_list,
> .map = &mtl_socm_reg_map,
> .sub_req_show = &pmc_core_substate_req_regs_fops,
> diff --git a/drivers/platform/x86/intel/pmc/ptl.c b/drivers/platform/x86/intel/pmc/ptl.c
> index 6c68772e738c8..538ca5ae2e9ec 100644
> --- a/drivers/platform/x86/intel/pmc/ptl.c
> +++ b/drivers/platform/x86/intel/pmc/ptl.c
> @@ -543,6 +543,8 @@ static struct pmc_info ptl_pmc_info_list[] = {
> {}
> };
>
> +static u8 ptl_pmc_list[] = {PMC_IDX_MAIN, PMC_IDX_MAX};
> +
> #define PTL_NPU_PCI_DEV 0xb03e
> #define PTL_IPU_PCI_DEV 0xb05d
>
> @@ -569,6 +571,7 @@ static int ptl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_in
> }
>
> struct pmc_dev_info ptl_pmc_dev = {
> + .pmc_list = ptl_pmc_list,
> .regmap_list = ptl_pmc_info_list,
> .map = &ptl_pcdp_reg_map,
> .sub_req_show = &pmc_core_substate_blk_req_fops,
> diff --git a/drivers/platform/x86/intel/pmc/wcl.c b/drivers/platform/x86/intel/pmc/wcl.c
> index b55069945e9e7..429f53f22a89f 100644
> --- a/drivers/platform/x86/intel/pmc/wcl.c
> +++ b/drivers/platform/x86/intel/pmc/wcl.c
> @@ -469,6 +469,8 @@ static struct pmc_info wcl_pmc_info_list[] = {
> {}
> };
>
> +static u8 wcl_pmc_list[] = {PMC_IDX_MAIN, PMC_IDX_MAX};
> +
> #define WCL_NPU_PCI_DEV 0xfd3e
>
> /*
> @@ -494,6 +496,7 @@ static int wcl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_in
>
> struct pmc_dev_info wcl_pmc_dev = {
> .regmap_list = wcl_pmc_info_list,
> + .pmc_list = wcl_pmc_list,
> .map = &wcl_pcdn_reg_map,
> .sub_req_show = &pmc_core_substate_blk_req_fops,
> .suspend = cnl_suspend,
>
--
i.
^ permalink raw reply
* Re: [PATCH] cpufreq: acpi-cpufreq: use DMI max speed when CPPC is unavailable
From: Rafael J. Wysocki @ 2026-03-20 10:58 UTC (permalink / raw)
To: Henry Tseng
Cc: Rafael J. Wysocki, Viresh Kumar, Len Brown, linux-pm, linux-acpi,
SW Chen, Kevin Ko
In-Reply-To: <20260320095648.3598007-1-henrytseng@qnap.com>
On Fri, Mar 20, 2026 at 10:57 AM Henry Tseng <henrytseng@qnap.com> wrote:
>
> On AMD Ryzen Embedded V1780B (Family 17h, Zen 1), the BIOS does not
> provide ACPI _CPC objects and the CPU does not support MSR-based CPPC
> (X86_FEATURE_CPPC). The _PSS table only lists nominal P-states
> (P0 = 3350 MHz), so when get_max_boost_ratio() fails at
> cppc_get_perf_caps(), cpuinfo_max_freq reports only the base frequency
> instead of the rated boost frequency (3600 MHz).
>
> dmesg:
> ACPI CPPC: No CPC descriptor for CPU:0
> acpi_cpufreq: CPU0: Unable to get performance capabilities (-19)
>
> cppc-cpufreq already has a DMI fallback (cppc_get_dmi_max_khz()) that
> reads the processor max speed from SMBIOS Type 4. Export it and reuse
> it in acpi-cpufreq as a last-resort source for the boost frequency.
>
> A sanity check ensures the DMI value is above the _PSS P0 frequency
> and within 2x of it; values outside that range are ignored and the
> existing arch_set_max_freq_ratio() path is taken instead. The 2x
> upper bound is based on a survey of the AMD Ryzen Embedded V1000
> series, where the highest boost-to-base ratio is 1.8x (V1404I:
> 2.0 GHz base / 3.6 GHz boost).
>
> Tested on AMD Ryzen Embedded V1780B with v7.0-rc4:
>
> Before: cpuinfo_max_freq = 3350000 (base only)
> After: cpuinfo_max_freq = 3600000 (includes boost)
>
> Link: https://www.amd.com/en/products/embedded/ryzen/ryzen-v1000-series.html#specifications
> Signed-off-by: Henry Tseng <henrytseng@qnap.com>
> ---
> drivers/acpi/cppc_acpi.c | 3 ++-
> drivers/cpufreq/acpi-cpufreq.c | 21 ++++++++++++++++-----
> include/acpi/cppc_acpi.h | 1 +
> 3 files changed, 19 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
> index f0e513e9ed5d..f53de414acf2 100644
> --- a/drivers/acpi/cppc_acpi.c
> +++ b/drivers/acpi/cppc_acpi.c
> @@ -1944,7 +1944,7 @@ static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private)
> }
>
> /* Look up the max frequency in DMI */
> -static u64 cppc_get_dmi_max_khz(void)
> +u64 cppc_get_dmi_max_khz(void)
> {
> u16 mhz = 0;
>
> @@ -1958,6 +1958,7 @@ static u64 cppc_get_dmi_max_khz(void)
>
> return KHZ_PER_MHZ * mhz;
> }
> +EXPORT_SYMBOL_GPL(cppc_get_dmi_max_khz);
>
> /*
> * If CPPC lowest_freq and nominal_freq registers are exposed then we can
> diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
> index e7eff6c2f092..9b4638ad27ba 100644
> --- a/drivers/cpufreq/acpi-cpufreq.c
> +++ b/drivers/cpufreq/acpi-cpufreq.c
> @@ -849,13 +849,24 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
>
> policy->cpuinfo.max_freq = freq * max_boost_ratio >> SCHED_CAPACITY_SHIFT;
> } else {
> +#ifdef CONFIG_ACPI_CPPC_LIB
> + unsigned int freq = freq_table[0].frequency;
> + u64 max_speed = cppc_get_dmi_max_khz();
> /*
> - * If the maximum "boost" frequency is unknown, ask the arch
> - * scale-invariance code to use the "nominal" performance for
> - * CPU utilization scaling so as to prevent the schedutil
> - * governor from selecting inadequate CPU frequencies.
> + * Use DMI "Max Speed" if it looks plausible: must be
> + * above _PSS P0 frequency and within 2x of it.
> */
> - arch_set_max_freq_ratio(true);
> + if (max_speed > freq && max_speed < freq * 2)
> + policy->cpuinfo.max_freq = max_speed;
> + else
> +#endif
> + /*
> + * If the maximum "boost" frequency is unknown, ask the arch
> + * scale-invariance code to use the "nominal" performance for
> + * CPU utilization scaling so as to prevent the schedutil
> + * governor from selecting inadequate CPU frequencies.
> + */
> + arch_set_max_freq_ratio(true);
Please move the code in the else {} block into a separate function.
Then you'll be able to return early after updating cpuinfo.max_freq.
> }
>
> policy->freq_table = freq_table;
> diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
> index 4d644f03098e..e6c5ef3173c5 100644
> --- a/include/acpi/cppc_acpi.h
> +++ b/include/acpi/cppc_acpi.h
> @@ -156,6 +156,7 @@ extern int cppc_set_enable(int cpu, bool enable);
> extern int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps);
> extern bool cppc_perf_ctrs_in_pcc_cpu(unsigned int cpu);
> extern bool cppc_perf_ctrs_in_pcc(void);
> +extern u64 cppc_get_dmi_max_khz(void);
> extern unsigned int cppc_perf_to_khz(struct cppc_perf_caps *caps, unsigned int perf);
> extern unsigned int cppc_khz_to_perf(struct cppc_perf_caps *caps, unsigned int freq);
> extern bool acpi_cpc_valid(void);
> --
> 2.43.0
>
^ permalink raw reply
* Re: [PATCH 4/6] platform/x86/intel/pmc: Add support for variable DMU offsets
From: Ilpo Järvinen @ 2026-03-20 10:50 UTC (permalink / raw)
To: Xi Pardee
Cc: irenic.rajneesh, david.e.box, platform-driver-x86, LKML, linux-pm
In-Reply-To: <20260302223214.484585-5-xi.pardee@linux.intel.com>
On Mon, 2 Mar 2026, Xi Pardee wrote:
> Add support for handling different DMU Die C6 offsets across platforms.
> The previous implementation assumed a uniform DMU Die C6 offset for all
> platforms, which is no longer valid.
>
> Signed-off-by: Xi Pardee <xi.pardee@linux.intel.com>
> ---
> drivers/platform/x86/intel/pmc/arl.c | 2 ++
> drivers/platform/x86/intel/pmc/core.c | 2 +-
> drivers/platform/x86/intel/pmc/core.h | 2 ++
> drivers/platform/x86/intel/pmc/mtl.c | 1 +
> 4 files changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/platform/x86/intel/pmc/arl.c b/drivers/platform/x86/intel/pmc/arl.c
> index 95372a0807acf..4d91ee010f6d0 100644
> --- a/drivers/platform/x86/intel/pmc/arl.c
> +++ b/drivers/platform/x86/intel/pmc/arl.c
> @@ -729,6 +729,7 @@ struct pmc_dev_info arl_pmc_dev = {
> .init = arl_core_init,
> .sub_req = pmc_core_pmt_get_lpm_req,
> .ssram_hidden = true,
> + .die_c6_offset = MTL_PMT_DMU_DIE_C6_OFFSET,
> };
>
> static u32 ARL_H_PMT_DMU_GUIDS[] = {ARL_PMT_DMU_GUID, ARL_H_PMT_DMU_GUID, 0x0};
> @@ -742,4 +743,5 @@ struct pmc_dev_info arl_h_pmc_dev = {
> .init = arl_h_core_init,
> .sub_req = pmc_core_pmt_get_lpm_req,
> .ssram_hidden = true,
> + .die_c6_offset = MTL_PMT_DMU_DIE_C6_OFFSET,
> };
> diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c
> index 7670970c995b9..7bd0e1eaa32e2 100644
> --- a/drivers/platform/x86/intel/pmc/core.c
> +++ b/drivers/platform/x86/intel/pmc/core.c
> @@ -1387,7 +1387,7 @@ void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_de
> }
>
> pmcdev->punit_ep = ep;
> - pmcdev->die_c6_offset = MTL_PMT_DMU_DIE_C6_OFFSET;
> + pmcdev->die_c6_offset = pmc_dev_info->die_c6_offset;
> }
>
> if (pmc_dev_info->pc_guid) {
> diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h
> index 31fe71b01120b..f09791f866223 100644
> --- a/drivers/platform/x86/intel/pmc/core.h
> +++ b/drivers/platform/x86/intel/pmc/core.h
> @@ -514,6 +514,7 @@ enum pmc_index {
> * @init: Function to perform platform specific init action
> * @sub_req: Function to achieve low power mode substate requirements
> * @ssram_hidden: Flag to indicate whether SSRAM is hidden
> + * @die_c6_offseyt: Telemetry offset to read Die C6 residency
Typo (-t)
> */
> struct pmc_dev_info {
> u32 *dmu_guids;
> @@ -530,6 +531,7 @@ struct pmc_dev_info {
> int (*init)(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info);
> int (*sub_req)(struct pmc_dev *pmcdev, struct pmc *pmc, struct telem_endpoint *ep);
> bool ssram_hidden;
> + u32 die_c6_offset;
> };
>
> extern const struct pmc_bit_map msr_map[];
> diff --git a/drivers/platform/x86/intel/pmc/mtl.c b/drivers/platform/x86/intel/pmc/mtl.c
> index 193ebbe584023..b724dd8c34dba 100644
> --- a/drivers/platform/x86/intel/pmc/mtl.c
> +++ b/drivers/platform/x86/intel/pmc/mtl.c
> @@ -1003,4 +1003,5 @@ struct pmc_dev_info mtl_pmc_dev = {
> .init = mtl_core_init,
> .sub_req = pmc_core_pmt_get_lpm_req,
> .ssram_hidden = true,
> + .die_c6_offset = MTL_PMT_DMU_DIE_C6_OFFSET,
> };
>
--
i.
^ permalink raw reply
* Re: [PATCH 3/6] platform/x86/intel/pmc: Use PCI DID for PMC SSRAM device discovery
From: Ilpo Järvinen @ 2026-03-20 10:45 UTC (permalink / raw)
To: Xi Pardee
Cc: irenic.rajneesh, david.e.box, platform-driver-x86, LKML, linux-pm
In-Reply-To: <20260302223214.484585-4-xi.pardee@linux.intel.com>
On Mon, 2 Mar 2026, Xi Pardee wrote:
> Update the PMC SSRAM discovery process to identify the device using its
> PCI Device ID rather than relying on a fixed PCI bus location. The
> enumeration of integrated devices on the PCI bus is no longer guaranteed
> to be consistent across CPUs.
>
> On earlier platforms, the IOE and PCH SSRAM devices were hidden from the
> BIOS, and the SOC SSRAM device is associated to telemetry regions from all
> available SSRAM devices. Starting with Nova Lake, the IOE and PCH SSRAM
> devices register their telemetry regions independently, meaning each
> telemetry region is now linked to its corresponding SSRAM device. A new
> ssram_hidden attribute has been added to the pmc_dev_info structure to
> reflect this distinction.
>
> Signed-off-by: David E. Box <david.e.box@linux.intel.com>
> Signed-off-by: Xi Pardee <xi.pardee@linux.intel.com>
> ---
> drivers/platform/x86/intel/pmc/arl.c | 4 ++--
> drivers/platform/x86/intel/pmc/core.c | 16 ++++++++++++----
> drivers/platform/x86/intel/pmc/core.h | 6 ++++--
> drivers/platform/x86/intel/pmc/lnl.c | 2 +-
> drivers/platform/x86/intel/pmc/mtl.c | 2 +-
> drivers/platform/x86/intel/pmc/ptl.c | 2 +-
> drivers/platform/x86/intel/pmc/wcl.c | 2 +-
> 7 files changed, 22 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/platform/x86/intel/pmc/arl.c b/drivers/platform/x86/intel/pmc/arl.c
> index eb23bc68340ab..95372a0807acf 100644
> --- a/drivers/platform/x86/intel/pmc/arl.c
> +++ b/drivers/platform/x86/intel/pmc/arl.c
> @@ -720,7 +720,6 @@ static int arl_h_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_
>
> static u32 ARL_PMT_DMU_GUIDS[] = {ARL_PMT_DMU_GUID, 0x0};
> struct pmc_dev_info arl_pmc_dev = {
> - .pci_func = 0,
> .dmu_guids = ARL_PMT_DMU_GUIDS,
> .regmap_list = arl_pmc_info_list,
> .map = &arl_socs_reg_map,
> @@ -729,11 +728,11 @@ struct pmc_dev_info arl_pmc_dev = {
> .resume = arl_resume,
> .init = arl_core_init,
> .sub_req = pmc_core_pmt_get_lpm_req,
> + .ssram_hidden = true,
> };
>
> static u32 ARL_H_PMT_DMU_GUIDS[] = {ARL_PMT_DMU_GUID, ARL_H_PMT_DMU_GUID, 0x0};
> struct pmc_dev_info arl_h_pmc_dev = {
> - .pci_func = 2,
> .dmu_guids = ARL_H_PMT_DMU_GUIDS,
> .regmap_list = arl_pmc_info_list,
> .map = &mtl_socm_reg_map,
> @@ -742,4 +741,5 @@ struct pmc_dev_info arl_h_pmc_dev = {
> .resume = arl_h_resume,
> .init = arl_h_core_init,
> .sub_req = pmc_core_pmt_get_lpm_req,
> + .ssram_hidden = true,
> };
> diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c
> index e5b48a68cf495..7670970c995b9 100644
> --- a/drivers/platform/x86/intel/pmc/core.c
> +++ b/drivers/platform/x86/intel/pmc/core.c
> @@ -1660,12 +1660,10 @@ static int pmc_core_get_telem_info(struct pmc_dev *pmcdev, struct pmc_dev_info *
> unsigned int pmc_idx;
> int ret;
>
> - pcidev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(20, pmc_dev_info->pci_func));
> - if (!pcidev)
> - return -ENODEV;
> -
> for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) {
> + struct pci_dev *pcidev __free(pci_dev_put) = NULL;
Please don't use = NULL; pattern with __free() because it's dangerous in
some cases, please see the long comment in cleanup.h for details why.
Place the declaration where you do the assignment.
> struct pmc *pmc;
> + u16 devid;
>
> pmc = pmcdev->pmcs[pmc_idx];
> if (!pmc)
> @@ -1674,6 +1672,15 @@ static int pmc_core_get_telem_info(struct pmc_dev *pmcdev, struct pmc_dev_info *
> if (!pmc->map->lpm_req_guid)
> return -ENXIO;
>
> + if (pmc_dev_info->ssram_hidden)
> + devid = pmcdev->pmcs[PMC_IDX_MAIN]->devid;
> + else
> + devid = pmc->devid;
> +
> + pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, devid, NULL);
> + if (!pcidev)
> + return -ENODEV;
> +
> ep = pmt_telem_find_and_register_endpoint(pcidev, pmc->map->lpm_req_guid, 0);
> if (IS_ERR(ep)) {
> dev_dbg(&pmcdev->pdev->dev, "couldn't get telem endpoint %pe", ep);
> @@ -1724,6 +1731,7 @@ static int pmc_core_pmc_add(struct pmc_dev *pmcdev, unsigned int pmc_idx)
>
> pmc->map = map;
> pmc->base_addr = pmc_ssram_telemetry.base_addr;
> + pmc->devid = pmc_ssram_telemetry.devid;
> pmc->regbase = ioremap(pmc->base_addr, pmc->map->regmap_length);
>
> if (!pmc->regbase) {
> diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h
> index 829b1dee3f636..31fe71b01120b 100644
> --- a/drivers/platform/x86/intel/pmc/core.h
> +++ b/drivers/platform/x86/intel/pmc/core.h
> @@ -425,6 +425,7 @@ struct pmc_info {
> * @ltr_ign: Holds LTR ignore data while suspended
> * @num_lpm_modes: Count of enabled modes
> * @lpm_en_modes: Array of enabled modes from lowest to highest priority
> + * @devid: Device ID of the SSRAM device
> *
> * pmc contains info about one power management controller device.
> */
> @@ -436,6 +437,7 @@ struct pmc {
> u32 ltr_ign;
> u8 num_lpm_modes;
> u8 lpm_en_modes[LPM_MAX_NUM_MODES];
> + u16 devid;
> };
>
> /**
> @@ -495,7 +497,6 @@ enum pmc_index {
>
> /**
> * struct pmc_dev_info - Structure to keep PMC device info
> - * @pci_func: Function number of the primary PMC
> * @dmu_guids: List of Die Management Unit GUID
> * @pc_guid: GUID for telemetry region to read PKGC blocker info
> * @pkgc_ltr_blocker_offset: Offset to PKGC LTR blockers in telemetry region
> @@ -512,9 +513,9 @@ enum pmc_index {
> * @resume: Function to perform platform specific resume
> * @init: Function to perform platform specific init action
> * @sub_req: Function to achieve low power mode substate requirements
> + * @ssram_hidden: Flag to indicate whether SSRAM is hidden
I'd elaborate this as some of the SSRAM devices are hidden in this case.
IMO, the "Flag to indicate whether" is pretty pointless, the C type
information pretty much indicates it's a flag.
> */
> struct pmc_dev_info {
> - u8 pci_func;
> u32 *dmu_guids;
> u32 pc_guid;
> u32 pkgc_ltr_blocker_offset;
> @@ -528,6 +529,7 @@ struct pmc_dev_info {
> int (*resume)(struct pmc_dev *pmcdev);
> int (*init)(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info);
> int (*sub_req)(struct pmc_dev *pmcdev, struct pmc *pmc, struct telem_endpoint *ep);
> + bool ssram_hidden;
> };
>
> extern const struct pmc_bit_map msr_map[];
> diff --git a/drivers/platform/x86/intel/pmc/lnl.c b/drivers/platform/x86/intel/pmc/lnl.c
> index 1cd81ee54dcf8..18f303af328e3 100644
> --- a/drivers/platform/x86/intel/pmc/lnl.c
> +++ b/drivers/platform/x86/intel/pmc/lnl.c
> @@ -571,7 +571,6 @@ static int lnl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_in
> }
>
> struct pmc_dev_info lnl_pmc_dev = {
> - .pci_func = 2,
> .regmap_list = lnl_pmc_info_list,
> .map = &lnl_socm_reg_map,
> .sub_req_show = &pmc_core_substate_req_regs_fops,
> @@ -579,4 +578,5 @@ struct pmc_dev_info lnl_pmc_dev = {
> .resume = lnl_resume,
> .init = lnl_core_init,
> .sub_req = pmc_core_pmt_get_lpm_req,
> + .ssram_hidden = true,
> };
> diff --git a/drivers/platform/x86/intel/pmc/mtl.c b/drivers/platform/x86/intel/pmc/mtl.c
> index 57508cbf9cd42..193ebbe584023 100644
> --- a/drivers/platform/x86/intel/pmc/mtl.c
> +++ b/drivers/platform/x86/intel/pmc/mtl.c
> @@ -994,7 +994,6 @@ static int mtl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_in
>
> static u32 MTL_PMT_DMU_GUIDS[] = {MTL_PMT_DMU_GUID, 0x0};
> struct pmc_dev_info mtl_pmc_dev = {
> - .pci_func = 2,
> .dmu_guids = MTL_PMT_DMU_GUIDS,
> .regmap_list = mtl_pmc_info_list,
> .map = &mtl_socm_reg_map,
> @@ -1003,4 +1002,5 @@ struct pmc_dev_info mtl_pmc_dev = {
> .resume = mtl_resume,
> .init = mtl_core_init,
> .sub_req = pmc_core_pmt_get_lpm_req,
> + .ssram_hidden = true,
> };
> diff --git a/drivers/platform/x86/intel/pmc/ptl.c b/drivers/platform/x86/intel/pmc/ptl.c
> index 1f48e2bbc699f..6c68772e738c8 100644
> --- a/drivers/platform/x86/intel/pmc/ptl.c
> +++ b/drivers/platform/x86/intel/pmc/ptl.c
> @@ -569,7 +569,6 @@ static int ptl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_in
> }
>
> struct pmc_dev_info ptl_pmc_dev = {
> - .pci_func = 2,
> .regmap_list = ptl_pmc_info_list,
> .map = &ptl_pcdp_reg_map,
> .sub_req_show = &pmc_core_substate_blk_req_fops,
> @@ -577,4 +576,5 @@ struct pmc_dev_info ptl_pmc_dev = {
> .resume = ptl_resume,
> .init = ptl_core_init,
> .sub_req = pmc_core_pmt_get_blk_sub_req,
> + .ssram_hidden = true,
> };
> diff --git a/drivers/platform/x86/intel/pmc/wcl.c b/drivers/platform/x86/intel/pmc/wcl.c
> index a45707e6364f2..b55069945e9e7 100644
> --- a/drivers/platform/x86/intel/pmc/wcl.c
> +++ b/drivers/platform/x86/intel/pmc/wcl.c
> @@ -493,7 +493,6 @@ static int wcl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_in
> }
>
> struct pmc_dev_info wcl_pmc_dev = {
> - .pci_func = 2,
> .regmap_list = wcl_pmc_info_list,
> .map = &wcl_pcdn_reg_map,
> .sub_req_show = &pmc_core_substate_blk_req_fops,
> @@ -501,4 +500,5 @@ struct pmc_dev_info wcl_pmc_dev = {
> .resume = wcl_resume,
> .init = wcl_core_init,
> .sub_req = pmc_core_pmt_get_blk_sub_req,
> + .ssram_hidden = true,
> };
>
--
i.
^ permalink raw reply
* Re: [PATCH 2/6] platform/x86/intel/pmc: Enable Pkgc blocking residency counter
From: Ilpo Järvinen @ 2026-03-20 10:27 UTC (permalink / raw)
To: Xi Pardee
Cc: irenic.rajneesh, david.e.box, platform-driver-x86, LKML, linux-pm
In-Reply-To: <20260302223214.484585-3-xi.pardee@linux.intel.com>
[-- Attachment #1: Type: text/plain, Size: 5133 bytes --]
On Mon, 2 Mar 2026, Xi Pardee wrote:
> Enable the Package C-state blocking counter in the PMT telemetry
> region. This counter reports the number of 10 µs intervals during
> which a Package C-state 10.2/3 entry was blocked for the specified
> reasons.
>
> Signed-off-by: Xi Pardee <xi.pardee@linux.intel.com>
> ---
> drivers/platform/x86/intel/pmc/core.c | 27 +++++++++++++++++++++++++++
> drivers/platform/x86/intel/pmc/core.h | 8 ++++++++
> 2 files changed, 35 insertions(+)
>
> diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c
> index bf95a1f2ba428..e5b48a68cf495 100644
> --- a/drivers/platform/x86/intel/pmc/core.c
> +++ b/drivers/platform/x86/intel/pmc/core.c
> @@ -1093,6 +1093,28 @@ static int pmc_core_pkgc_ltr_blocker_show(struct seq_file *s, void *unused)
> }
> DEFINE_SHOW_ATTRIBUTE(pmc_core_pkgc_ltr_blocker);
>
> +static int pmc_core_pkgc_blocker_residency_show(struct seq_file *s, void *unused)
> +{
> + struct pmc_dev *pmcdev = s->private;
> + const char **pkgc_blocker_counters;
> + u32 counter, offset;
> + unsigned int i;
> + int ret;
> +
> + offset = pmcdev->pkgc_blocker_offset;
> + pkgc_blocker_counters = pmcdev->pkgc_blocker_counters;
> + for (i = 0; pkgc_blocker_counters[i]; i++, offset++) {
> + ret = pmt_telem_read32(pmcdev->pc_ep, offset,
> + &counter, 1);
> + if (ret)
> + return ret;
> + seq_printf(s, "%-30s %-30u\n", pkgc_blocker_counters[i], counter);
> + }
> +
> + return 0;
I wonder if it would be create a common helper as this looks practically
the same as pmc_core_pkgc_ltr_blocker_show() added in the previous patch?
> +}
> +DEFINE_SHOW_ATTRIBUTE(pmc_core_pkgc_blocker_residency);
> +
> static int pmc_core_lpm_latch_mode_show(struct seq_file *s, void *unused)
> {
> struct pmc_dev *pmcdev = s->private;
> @@ -1380,6 +1402,8 @@ void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_de
> pmcdev->pc_ep = ep;
> pmcdev->pkgc_ltr_blocker_counters = pmc_dev_info->pkgc_ltr_blocker_counters;
> pmcdev->pkgc_ltr_blocker_offset = pmc_dev_info->pkgc_ltr_blocker_offset;
> + pmcdev->pkgc_blocker_counters = pmc_dev_info->pkgc_blocker_counters;
> + pmcdev->pkgc_blocker_offset = pmc_dev_info->pkgc_blocker_offset;
> }
>
> release_dev:
> @@ -1512,6 +1536,9 @@ static void pmc_core_dbgfs_register(struct pmc_dev *pmcdev, struct pmc_dev_info
> debugfs_create_file("pkgc_ltr_blocker_show", 0444,
> pmcdev->dbgfs_dir, pmcdev,
> &pmc_core_pkgc_ltr_blocker_fops);
> + debugfs_create_file("pkgc_blocker_residency_show", 0444,
> + pmcdev->dbgfs_dir, pmcdev,
> + &pmc_core_pkgc_blocker_residency_fops);
> }
>
> }
> diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h
> index a20aab73c1409..829b1dee3f636 100644
> --- a/drivers/platform/x86/intel/pmc/core.h
> +++ b/drivers/platform/x86/intel/pmc/core.h
> @@ -455,6 +455,8 @@ struct pmc {
> *
> * @pkgc_ltr_blocker_counters: Array of PKGC LTR blocker counters
> * @pkgc_ltr_blocker_offset: Offset to PKGC LTR blockers in telemetry region
> + * @pkgc_blocker_counters: Array of PKGC blocker counters
> + * @pkgc_blocker_offset: Offset to PKGC blocker in telemetry region
> *
> * pmc_dev contains info about power management controller device.
> */
> @@ -480,6 +482,8 @@ struct pmc_dev {
>
> const char **pkgc_ltr_blocker_counters;
> u32 pkgc_ltr_blocker_offset;
> + const char **pkgc_blocker_counters;
> + u32 pkgc_blocker_offset;
> };
>
> enum pmc_index {
> @@ -495,6 +499,7 @@ enum pmc_index {
> * @dmu_guids: List of Die Management Unit GUID
> * @pc_guid: GUID for telemetry region to read PKGC blocker info
> * @pkgc_ltr_blocker_offset: Offset to PKGC LTR blockers in telemetry region
> + * @pkgc_blocker_offset:Offset to PKGC blocker in telemetry region
> * @regmap_list: Pointer to a list of pmc_info structure that could be
> * available for the platform. When set, this field implies
> * SSRAM support.
> @@ -502,6 +507,7 @@ enum pmc_index {
> * specific attributes of the primary PMC
> * @sub_req_show: File operations to show substate requirements
> * @pkgc_ltr_blocker_counters: Array of PKGC LTR blocker counters
> + * @pkgc_blocker_counters: Array of PKGC blocker counters
> * @suspend: Function to perform platform specific suspend
> * @resume: Function to perform platform specific resume
> * @init: Function to perform platform specific init action
> @@ -512,10 +518,12 @@ struct pmc_dev_info {
> u32 *dmu_guids;
> u32 pc_guid;
> u32 pkgc_ltr_blocker_offset;
> + u32 pkgc_blocker_offset;
> struct pmc_info *regmap_list;
> const struct pmc_reg_map *map;
> const struct file_operations *sub_req_show;
> const char **pkgc_ltr_blocker_counters;
> + const char **pkgc_blocker_counters;
> void (*suspend)(struct pmc_dev *pmcdev);
> int (*resume)(struct pmc_dev *pmcdev);
> int (*init)(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info);
>
--
i.
^ permalink raw reply
* Re: [PATCH 1/6] platform/x86/intel/pmc: Enable PkgC LTR blocking counter
From: Ilpo Järvinen @ 2026-03-20 10:25 UTC (permalink / raw)
To: Xi Pardee
Cc: irenic.rajneesh, david.e.box, platform-driver-x86, LKML, linux-pm
In-Reply-To: <20260302223214.484585-2-xi.pardee@linux.intel.com>
On Mon, 2 Mar 2026, Xi Pardee wrote:
> Enable the Package C-state LTR blocking counter in the PMT telemetry
> region. This counter records how many times any Package C-state entry
> is blocked for the specified reasons.
>
> Signed-off-by: Xi Pardee <xi.pardee@linux.intel.com>
> ---
> drivers/platform/x86/intel/pmc/core.c | 77 ++++++++++++++++++++++-----
> drivers/platform/x86/intel/pmc/core.h | 15 +++++-
> 2 files changed, 79 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c
> index 02b303418d185..bf95a1f2ba428 100644
> --- a/drivers/platform/x86/intel/pmc/core.c
> +++ b/drivers/platform/x86/intel/pmc/core.c
> @@ -1071,6 +1071,28 @@ static int pmc_core_die_c6_us_show(struct seq_file *s, void *unused)
> }
> DEFINE_SHOW_ATTRIBUTE(pmc_core_die_c6_us);
>
> +static int pmc_core_pkgc_ltr_blocker_show(struct seq_file *s, void *unused)
> +{
> + struct pmc_dev *pmcdev = s->private;
> + const char **pkgc_ltr_blocker_counters;
> + u32 counter, offset;
> + unsigned int i;
> + int ret;
> +
> + offset = pmcdev->pkgc_ltr_blocker_offset;
> + pkgc_ltr_blocker_counters = pmcdev->pkgc_ltr_blocker_counters;
> + for (i = 0; pkgc_ltr_blocker_counters[i]; i++, offset++) {
> + ret = pmt_telem_read32(pmcdev->pc_ep, offset,
> + &counter, 1);
Fits easily to one line. Though, I'm not sure if offset variable improves
things, more like it makes this more complex than it need to be. To me it
would look more straightforward to do just:
ret = pmt_telem_read32(pmcdev->pc_ep,
pmcdev->pkgc_ltr_blocker_offset + i,
...);
> + if (ret)
> + return ret;
> + seq_printf(s, "%-30s %-30u\n", pkgc_ltr_blocker_counters[i], counter);
> + }
> +
> + return 0;
> +}
> +DEFINE_SHOW_ATTRIBUTE(pmc_core_pkgc_ltr_blocker);
> +
> static int pmc_core_lpm_latch_mode_show(struct seq_file *s, void *unused)
> {
> struct pmc_dev *pmcdev = s->private;
> @@ -1322,7 +1344,7 @@ static struct telem_endpoint *pmc_core_register_endpoint(struct pci_dev *pcidev,
> return ERR_PTR(-ENODEV);
> }
>
> -void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 *guids)
> +void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
> {
> struct telem_endpoint *ep;
> struct pci_dev *pcidev;
> @@ -1333,17 +1355,35 @@ void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 *guids)
> return;
> }
>
> - ep = pmc_core_register_endpoint(pcidev, guids);
> - pci_dev_put(pcidev);
> - if (IS_ERR(ep)) {
> - dev_err(&pmcdev->pdev->dev,
> - "pmc_core: couldn't get DMU telem endpoint %ld",
> - PTR_ERR(ep));
> - return;
> + if (pmc_dev_info->dmu_guids) {
> + ep = pmc_core_register_endpoint(pcidev, pmc_dev_info->dmu_guids);
> + if (IS_ERR(ep)) {
> + dev_err(&pmcdev->pdev->dev,
> + "pmc_core: couldn't get DMU telem endpoint %ld",
> + PTR_ERR(ep));
> + goto release_dev;
> + }
> +
> + pmcdev->punit_ep = ep;
> + pmcdev->die_c6_offset = MTL_PMT_DMU_DIE_C6_OFFSET;
> + }
> +
> + if (pmc_dev_info->pc_guid) {
> + ep = pmt_telem_find_and_register_endpoint(pcidev, pmc_dev_info->pc_guid, 0);
> + if (IS_ERR(ep)) {
> + dev_err(&pmcdev->pdev->dev,
> + "pmc_core: couldn't get Package C-state telem endpoint %ld",
> + PTR_ERR(ep));
> + goto release_dev;
> + }
> +
> + pmcdev->pc_ep = ep;
> + pmcdev->pkgc_ltr_blocker_counters = pmc_dev_info->pkgc_ltr_blocker_counters;
> + pmcdev->pkgc_ltr_blocker_offset = pmc_dev_info->pkgc_ltr_blocker_offset;
> }
>
> - pmcdev->punit_ep = ep;
> - pmcdev->die_c6_offset = MTL_PMT_DMU_DIE_C6_OFFSET;
> +release_dev:
> + pci_dev_put(pcidev);
Use __free(pci_dev_put) instead of complicating the code flow.
Please remember to place the variable declaration at the place of
assignment (no = NULL; assignments with __free()). You may want to do the
__free() conversion in own patch preceeding this.
--
i.
> }
>
> void pmc_core_set_device_d3(unsigned int device)
> @@ -1467,6 +1507,13 @@ static void pmc_core_dbgfs_register(struct pmc_dev *pmcdev, struct pmc_dev_info
> pmcdev->dbgfs_dir, pmcdev,
> &pmc_core_die_c6_us_fops);
> }
> +
> + if (pmcdev->pc_ep) {
> + debugfs_create_file("pkgc_ltr_blocker_show", 0444,
> + pmcdev->dbgfs_dir, pmcdev,
> + &pmc_core_pkgc_ltr_blocker_fops);
> + }
> +
> }
>
> /*
> @@ -1717,8 +1764,8 @@ int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
> }
>
> pmc_core_get_low_power_modes(pmcdev);
> - if (pmc_dev_info->dmu_guids)
> - pmc_core_punit_pmt_init(pmcdev, pmc_dev_info->dmu_guids);
> + if (pmc_dev_info->dmu_guids || pmc_dev_info->pc_guid)
> + pmc_core_punit_pmt_init(pmcdev, pmc_dev_info);
>
> if (ssram) {
> ret = pmc_core_get_telem_info(pmcdev, pmc_dev_info);
> @@ -1739,6 +1786,9 @@ int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
> if (pmcdev->punit_ep)
> pmt_telem_unregister_endpoint(pmcdev->punit_ep);
>
> + if (pmcdev->pc_ep)
> + pmt_telem_unregister_endpoint(pmcdev->pc_ep);
> +
> return ret;
> }
>
> @@ -1835,6 +1885,9 @@ static void pmc_core_clean_structure(struct platform_device *pdev)
> if (pmcdev->punit_ep)
> pmt_telem_unregister_endpoint(pmcdev->punit_ep);
>
> + if (pmcdev->pc_ep)
> + pmt_telem_unregister_endpoint(pmcdev->pc_ep);
> +
> platform_set_drvdata(pdev, NULL);
> }
>
> diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h
> index 118c8740ad3aa..a20aab73c1409 100644
> --- a/drivers/platform/x86/intel/pmc/core.h
> +++ b/drivers/platform/x86/intel/pmc/core.h
> @@ -453,6 +453,9 @@ struct pmc {
> * @suspend: Function to perform platform specific suspend
> * @resume: Function to perform platform specific resume
> *
> + * @pkgc_ltr_blocker_counters: Array of PKGC LTR blocker counters
> + * @pkgc_ltr_blocker_offset: Offset to PKGC LTR blockers in telemetry region
> + *
> * pmc_dev contains info about power management controller device.
> */
> struct pmc_dev {
> @@ -471,8 +474,12 @@ struct pmc_dev {
> u8 num_of_pkgc;
>
> u32 die_c6_offset;
> + struct telem_endpoint *pc_ep;
> struct telem_endpoint *punit_ep;
> struct pmc_info *regmap_list;
> +
> + const char **pkgc_ltr_blocker_counters;
> + u32 pkgc_ltr_blocker_offset;
> };
>
> enum pmc_index {
> @@ -486,12 +493,15 @@ enum pmc_index {
> * struct pmc_dev_info - Structure to keep PMC device info
> * @pci_func: Function number of the primary PMC
> * @dmu_guids: List of Die Management Unit GUID
> + * @pc_guid: GUID for telemetry region to read PKGC blocker info
> + * @pkgc_ltr_blocker_offset: Offset to PKGC LTR blockers in telemetry region
> * @regmap_list: Pointer to a list of pmc_info structure that could be
> * available for the platform. When set, this field implies
> * SSRAM support.
> * @map: Pointer to a pmc_reg_map struct that contains platform
> * specific attributes of the primary PMC
> * @sub_req_show: File operations to show substate requirements
> + * @pkgc_ltr_blocker_counters: Array of PKGC LTR blocker counters
> * @suspend: Function to perform platform specific suspend
> * @resume: Function to perform platform specific resume
> * @init: Function to perform platform specific init action
> @@ -500,9 +510,12 @@ enum pmc_index {
> struct pmc_dev_info {
> u8 pci_func;
> u32 *dmu_guids;
> + u32 pc_guid;
> + u32 pkgc_ltr_blocker_offset;
> struct pmc_info *regmap_list;
> const struct pmc_reg_map *map;
> const struct file_operations *sub_req_show;
> + const char **pkgc_ltr_blocker_counters;
> void (*suspend)(struct pmc_dev *pmcdev);
> int (*resume)(struct pmc_dev *pmcdev);
> int (*init)(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info);
> @@ -535,7 +548,7 @@ int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore);
>
> int pmc_core_resume_common(struct pmc_dev *pmcdev);
> int get_primary_reg_base(struct pmc *pmc);
> -void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 *guids);
> +void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info);
> void pmc_core_set_device_d3(unsigned int device);
>
> int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info);
>
^ permalink raw reply
* Re: [PATCH v3 1/1] writeback: don't block sync for filesystems with no data integrity guarantees
From: Jan Kara @ 2026-03-20 10:16 UTC (permalink / raw)
To: Joanne Koong
Cc: brauner, linux-fsdevel, jack, miklos, david, therealgraysky,
linux-pm, stable
In-Reply-To: <20260320005145.2483161-2-joannelkoong@gmail.com>
On Thu 19-03-26 17:51:45, Joanne Koong wrote:
> Add a SB_I_NO_DATA_INTEGRITY superblock flag for filesystems that cannot
> guarantee data persistence on sync (eg fuse). For superblocks with this
> flag set, sync kicks off writeback of dirty inodes but does not wait
> for the flusher threads to complete the writeback.
>
> This replaces the per-inode AS_NO_DATA_INTEGRITY mapping flag added in
> commit f9a49aa302a0 ("fs/writeback: skip AS_NO_DATA_INTEGRITY mappings
> in wait_sb_inodes()"). The flag belongs at the superblock level because
> data integrity is a filesystem-wide property, not a per-inode one.
> Having this flag at the superblock level also allows us to skip having
> to iterate every dirty inode in wait_sb_inodes() only to skip each inode
> individually.
>
> Prior to this commit, mappings with no data integrity guarantees skipped
> waiting on writeback completion but still waited on the flusher threads
> to finish initiating the writeback. Waiting on the flusher threads is
> unnecessary. This commit kicks off writeback but does not wait on the
> flusher threads. This change properly addresses a recent report [1] for
> a suspend-to-RAM hang seen on fuse-overlayfs that was caused by waiting
> on the flusher threads to finish:
>
> Workqueue: pm_fs_sync pm_fs_sync_work_fn
> Call Trace:
> <TASK>
> __schedule+0x457/0x1720
> schedule+0x27/0xd0
> wb_wait_for_completion+0x97/0xe0
> sync_inodes_sb+0xf8/0x2e0
> __iterate_supers+0xdc/0x160
> ksys_sync+0x43/0xb0
> pm_fs_sync_work_fn+0x17/0xa0
> process_one_work+0x193/0x350
> worker_thread+0x1a1/0x310
> kthread+0xfc/0x240
> ret_from_fork+0x243/0x280
> ret_from_fork_asm+0x1a/0x30
> </TASK>
>
> On fuse this is problematic because there are paths that may cause the
> flusher thread to block (eg if systemd freezes the user session cgroups
> first, which freezes the fuse daemon, before invoking the kernel
> suspend. The kernel suspend triggers ->write_node() which on fuse issues
> a synchronous setattr request, which cannot be processed since the
> daemon is frozen. Or if the daemon is buggy and cannot properly complete
> writeback, initiating writeback on a dirty folio already under writeback
> leads to writeback_get_folio() -> folio_prepare_writeback() ->
> unconditional wait on writeback to finish, which will cause a hang).
> This commit restores fuse to its prior behavior before tmp folios were
> removed, where sync was essentially a no-op.
>
> [1] https://lore.kernel.org/linux-fsdevel/CAJnrk1a-asuvfrbKXbEwwDSctvemF+6zfhdnuzO65Pt8HsFSRw@mail.gmail.com/T/#m632c4648e9cafc4239299887109ebd880ac6c5c1
>
> Fixes: 0c58a97f919c ("fuse: remove tmp folio for writebacks and internal rb tree")
> Reported-by: John <therealgraysky@proton.me>
> Cc: <stable@vger.kernel.org>
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Looks good to me. Feel free to add:
Reviewed-by: Jan Kara <jack@suse.cz>
I'd just slightly expand the added comment like:
> @@ -2916,6 +2911,17 @@ void sync_inodes_sb(struct super_block *sb)
> */
> if (bdi == &noop_backing_dev_info)
> return;
> +
> + /*
> + * If the superblock has SB_I_NO_DATA_INTEGRITY set, there's no need to
> + * wait for the writeout to complete, as the filesystem cannot guarantee
> + * data persistence on sync. Just kick off writeback and return.
For filesystems such as FUSE it is important that IO submission is done
completely asynchronously as e.g. on system suspend or with broken FUSE
server, the IO submission might hang.
Honza
> + */
> + if (sb->s_iflags & SB_I_NO_DATA_INTEGRITY) {
> + wakeup_flusher_threads_bdi(bdi, WB_REASON_SYNC);
> + return;
> + }
> +
> WARN_ON(!rwsem_is_locked(&sb->s_umount));
>
> /* protect against inode wb switch, see inode_switch_wbs_work_fn() */
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index a9c836d7f586..f6240f24b814 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -3202,10 +3202,8 @@ void fuse_init_file_inode(struct inode *inode, unsigned int flags)
>
> inode->i_fop = &fuse_file_operations;
> inode->i_data.a_ops = &fuse_file_aops;
> - if (fc->writeback_cache) {
> + if (fc->writeback_cache)
> mapping_set_writeback_may_deadlock_on_reclaim(&inode->i_data);
> - mapping_set_no_data_integrity(&inode->i_data);
> - }
>
> INIT_LIST_HEAD(&fi->write_files);
> INIT_LIST_HEAD(&fi->queued_writes);
> diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
> index e57b8af06be9..c795abe47a4f 100644
> --- a/fs/fuse/inode.c
> +++ b/fs/fuse/inode.c
> @@ -1709,6 +1709,7 @@ static void fuse_sb_defaults(struct super_block *sb)
> sb->s_export_op = &fuse_export_operations;
> sb->s_iflags |= SB_I_IMA_UNVERIFIABLE_SIGNATURE;
> sb->s_iflags |= SB_I_NOIDMAP;
> + sb->s_iflags |= SB_I_NO_DATA_INTEGRITY;
> if (sb->s_user_ns != &init_user_ns)
> sb->s_iflags |= SB_I_UNTRUSTED_MOUNTER;
> sb->s_flags &= ~(SB_NOSEC | SB_I_VERSION);
> diff --git a/include/linux/fs/super_types.h b/include/linux/fs/super_types.h
> index fa7638b81246..383050e7fdf5 100644
> --- a/include/linux/fs/super_types.h
> +++ b/include/linux/fs/super_types.h
> @@ -338,5 +338,6 @@ struct super_block {
> #define SB_I_NOUMASK 0x00001000 /* VFS does not apply umask */
> #define SB_I_NOIDMAP 0x00002000 /* No idmapped mounts on this superblock */
> #define SB_I_ALLOW_HSM 0x00004000 /* Allow HSM events on this superblock */
> +#define SB_I_NO_DATA_INTEGRITY 0x00008000 /* fs cannot guarantee data persistence on sync */
>
> #endif /* _LINUX_FS_SUPER_TYPES_H */
> diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
> index ec442af3f886..31a848485ad9 100644
> --- a/include/linux/pagemap.h
> +++ b/include/linux/pagemap.h
> @@ -210,7 +210,6 @@ enum mapping_flags {
> AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM = 9,
> AS_KERNEL_FILE = 10, /* mapping for a fake kernel file that shouldn't
> account usage to user cgroups */
> - AS_NO_DATA_INTEGRITY = 11, /* no data integrity guarantees */
> /* Bits 16-25 are used for FOLIO_ORDER */
> AS_FOLIO_ORDER_BITS = 5,
> AS_FOLIO_ORDER_MIN = 16,
> @@ -346,16 +345,6 @@ static inline bool mapping_writeback_may_deadlock_on_reclaim(const struct addres
> return test_bit(AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM, &mapping->flags);
> }
>
> -static inline void mapping_set_no_data_integrity(struct address_space *mapping)
> -{
> - set_bit(AS_NO_DATA_INTEGRITY, &mapping->flags);
> -}
> -
> -static inline bool mapping_no_data_integrity(const struct address_space *mapping)
> -{
> - return test_bit(AS_NO_DATA_INTEGRITY, &mapping->flags);
> -}
> -
> static inline gfp_t mapping_gfp_mask(const struct address_space *mapping)
> {
> return mapping->gfp_mask;
> --
> 2.52.0
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply
* Re: [PATCH 9/9] pmdomain: renesas: rmobile-sysc: Drop GENPD_FLAG_NO_STAY_ON
From: Ulf Hansson @ 2026-03-20 10:13 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Saravana Kannan, Rafael J . Wysocki, Greg Kroah-Hartman, linux-pm,
Kevin Hilman, Stephen Boyd, Marek Szyprowski, Bjorn Andersson,
Abel Vesa, Peng Fan, Tomi Valkeinen, Maulik Shah, Konrad Dybcio,
Thierry Reding, Jonathan Hunter, Dmitry Baryshkov,
linux-arm-kernel, linux-kernel
In-Reply-To: <CAMuHMdUK+xePxZc-OXRfDmvQ1v4q5d=HQ9c9aNqUg7gPAMxUAA@mail.gmail.com>
On Fri, 20 Mar 2026 at 10:37, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>
> Hi Ulf,
>
> Thanks for your patch!
>
> On Tue, 3 Mar 2026 at 14:23, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> > Due to the new fine grained sync_state support for onecell genpd provider
> > drivers, we should no longer need use the legacy behaviour. Therefore,
> > let's drop GENPD_FLAG_NO_STAY_ON.
> >
> > Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
>
> Rmobile-sysc is not a onecell provider, and thus never needed this flag.
I see, thanks for clarifying. I will update the commit message to
reflect this properly.
> Regardless:
> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
>
Thanks!
Kind regards
Uffe
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox