Skip to content

Commit

Permalink
cpufreq/amd-pstate: Always write EPP value when updating perf
Browse files Browse the repository at this point in the history
For MSR systems the EPP value is in the same register as perf targets
and so divding them into two separate MSR writes is wasteful.

In msr_update_perf(), update both EPP and perf values in one write to
MSR_AMD_CPPC_REQ, and cache them if successful.

To accomplish this plumb the EPP value into the update_perf call and
modify all its callers to check the return value.

As this unifies calls, ensure that the MSR write is necessary before
flushing a write out. Also drop the comparison from the passive flow
tracing.

Reviewed-by: Gautham R. Shenoy <gautham.shenoy@amd.com>
Link: https://lore.kernel.org/r/20241209185248.16301-13-mario.limonciello@amd.com
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
  • Loading branch information
Mario Limonciello committed Dec 11, 2024
1 parent b3781f3 commit fff3957
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 59 deletions.
7 changes: 1 addition & 6 deletions drivers/cpufreq/amd-pstate-trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ TRACE_EVENT(amd_pstate_perf,
u64 aperf,
u64 tsc,
unsigned int cpu_id,
bool changed,
bool fast_switch
),

Expand All @@ -44,7 +43,6 @@ TRACE_EVENT(amd_pstate_perf,
aperf,
tsc,
cpu_id,
changed,
fast_switch
),

Expand All @@ -57,7 +55,6 @@ TRACE_EVENT(amd_pstate_perf,
__field(unsigned long long, aperf)
__field(unsigned long long, tsc)
__field(unsigned int, cpu_id)
__field(bool, changed)
__field(bool, fast_switch)
),

Expand All @@ -70,11 +67,10 @@ TRACE_EVENT(amd_pstate_perf,
__entry->aperf = aperf;
__entry->tsc = tsc;
__entry->cpu_id = cpu_id;
__entry->changed = changed;
__entry->fast_switch = fast_switch;
),

TP_printk("amd_min_perf=%lu amd_des_perf=%lu amd_max_perf=%lu freq=%llu mperf=%llu aperf=%llu tsc=%llu cpu_id=%u changed=%s fast_switch=%s",
TP_printk("amd_min_perf=%lu amd_des_perf=%lu amd_max_perf=%lu freq=%llu mperf=%llu aperf=%llu tsc=%llu cpu_id=%u fast_switch=%s",
(unsigned long)__entry->min_perf,
(unsigned long)__entry->target_perf,
(unsigned long)__entry->capacity,
Expand All @@ -83,7 +79,6 @@ TRACE_EVENT(amd_pstate_perf,
(unsigned long long)__entry->aperf,
(unsigned long long)__entry->tsc,
(unsigned int)__entry->cpu_id,
(__entry->changed) ? "true" : "false",
(__entry->fast_switch) ? "true" : "false"
)
);
Expand Down
108 changes: 55 additions & 53 deletions drivers/cpufreq/amd-pstate.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,25 +222,47 @@ static s16 shmem_get_epp(struct amd_cpudata *cpudata)
}

static int msr_update_perf(struct amd_cpudata *cpudata, u32 min_perf,
u32 des_perf, u32 max_perf, bool fast_switch)
u32 des_perf, u32 max_perf, u32 epp, bool fast_switch)
{
u64 value, prev;

value = prev = READ_ONCE(cpudata->cppc_req_cached);

value &= ~(AMD_CPPC_MAX_PERF_MASK | AMD_CPPC_MIN_PERF_MASK |
AMD_CPPC_DES_PERF_MASK | AMD_CPPC_EPP_PERF_MASK);
value |= FIELD_PREP(AMD_CPPC_MAX_PERF_MASK, max_perf);
value |= FIELD_PREP(AMD_CPPC_DES_PERF_MASK, des_perf);
value |= FIELD_PREP(AMD_CPPC_MIN_PERF_MASK, min_perf);
value |= FIELD_PREP(AMD_CPPC_EPP_PERF_MASK, epp);

if (value == prev)
return 0;

if (fast_switch) {
wrmsrl(MSR_AMD_CPPC_REQ, READ_ONCE(cpudata->cppc_req_cached));
wrmsrl(MSR_AMD_CPPC_REQ, value);
return 0;
} else {
int ret = wrmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, value);

if (ret)
return ret;
}

return wrmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ,
READ_ONCE(cpudata->cppc_req_cached));
WRITE_ONCE(cpudata->cppc_req_cached, value);
WRITE_ONCE(cpudata->epp_cached, epp);

return 0;
}

DEFINE_STATIC_CALL(amd_pstate_update_perf, msr_update_perf);

static inline int amd_pstate_update_perf(struct amd_cpudata *cpudata,
u32 min_perf, u32 des_perf,
u32 max_perf, bool fast_switch)
u32 max_perf, u32 epp,
bool fast_switch)
{
return static_call(amd_pstate_update_perf)(cpudata, min_perf, des_perf,
max_perf, fast_switch);
max_perf, epp, fast_switch);
}

static int msr_set_epp(struct amd_cpudata *cpudata, u32 epp)
Expand All @@ -261,6 +283,7 @@ static int msr_set_epp(struct amd_cpudata *cpudata, u32 epp)
return ret;
}

/* update both so that msr_update_perf() can effectively check */
WRITE_ONCE(cpudata->epp_cached, epp);
WRITE_ONCE(cpudata->cppc_req_cached, value);

Expand Down Expand Up @@ -459,12 +482,18 @@ static inline int amd_pstate_init_perf(struct amd_cpudata *cpudata)
return static_call(amd_pstate_init_perf)(cpudata);
}

static int shmem_update_perf(struct amd_cpudata *cpudata,
u32 min_perf, u32 des_perf,
u32 max_perf, bool fast_switch)
static int shmem_update_perf(struct amd_cpudata *cpudata, u32 min_perf,
u32 des_perf, u32 max_perf, u32 epp, bool fast_switch)
{
struct cppc_perf_ctrls perf_ctrls;

if (cppc_state == AMD_PSTATE_ACTIVE) {
int ret = shmem_set_epp(cpudata, epp);

if (ret)
return ret;
}

perf_ctrls.max_perf = max_perf;
perf_ctrls.min_perf = min_perf;
perf_ctrls.desired_perf = des_perf;
Expand Down Expand Up @@ -510,9 +539,7 @@ static void amd_pstate_update(struct amd_cpudata *cpudata, u32 min_perf,
{
unsigned long max_freq;
struct cpufreq_policy *policy = cpufreq_cpu_get(cpudata->cpu);
u64 prev = READ_ONCE(cpudata->cppc_req_cached);
u32 nominal_perf = READ_ONCE(cpudata->nominal_perf);
u64 value = prev;

des_perf = clamp_t(unsigned long, des_perf, min_perf, max_perf);

Expand All @@ -528,27 +555,14 @@ static void amd_pstate_update(struct amd_cpudata *cpudata, u32 min_perf,
if (!cpudata->boost_supported)
max_perf = min_t(unsigned long, nominal_perf, max_perf);

value &= ~(AMD_CPPC_MAX_PERF_MASK | AMD_CPPC_MIN_PERF_MASK |
AMD_CPPC_DES_PERF_MASK);
value |= FIELD_PREP(AMD_CPPC_MAX_PERF_MASK, max_perf);
value |= FIELD_PREP(AMD_CPPC_DES_PERF_MASK, des_perf);
value |= FIELD_PREP(AMD_CPPC_MIN_PERF_MASK, min_perf);

if (trace_amd_pstate_perf_enabled() && amd_pstate_sample(cpudata)) {
trace_amd_pstate_perf(min_perf, des_perf, max_perf, cpudata->freq,
cpudata->cur.mperf, cpudata->cur.aperf, cpudata->cur.tsc,
cpudata->cpu, (value != prev), fast_switch);
cpudata->cpu, fast_switch);
}

if (value == prev)
goto cpufreq_policy_put;
amd_pstate_update_perf(cpudata, min_perf, des_perf, max_perf, 0, fast_switch);

WRITE_ONCE(cpudata->cppc_req_cached, value);

amd_pstate_update_perf(cpudata, min_perf, des_perf,
max_perf, fast_switch);

cpufreq_policy_put:
cpufreq_cpu_put(policy);
}

Expand Down Expand Up @@ -1544,36 +1558,24 @@ static void amd_pstate_epp_cpu_exit(struct cpufreq_policy *policy)
static int amd_pstate_epp_update_limit(struct cpufreq_policy *policy)
{
struct amd_cpudata *cpudata = policy->driver_data;
u64 value;
u32 epp;

amd_pstate_update_min_max_limit(policy);

value = READ_ONCE(cpudata->cppc_req_cached);

value &= ~(AMD_CPPC_MAX_PERF_MASK | AMD_CPPC_MIN_PERF_MASK |
AMD_CPPC_DES_PERF_MASK | AMD_CPPC_EPP_PERF_MASK);
value |= FIELD_PREP(AMD_CPPC_MAX_PERF_MASK, cpudata->max_limit_perf);
value |= FIELD_PREP(AMD_CPPC_DES_PERF_MASK, 0);
value |= FIELD_PREP(AMD_CPPC_MIN_PERF_MASK, cpudata->min_limit_perf);

if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE)
WRITE_ONCE(cpudata->epp_cached, 0);
value |= FIELD_PREP(AMD_CPPC_EPP_PERF_MASK, cpudata->epp_cached);

WRITE_ONCE(cpudata->cppc_req_cached, value);
epp = 0;
else
epp = READ_ONCE(cpudata->epp_cached);

if (trace_amd_pstate_epp_perf_enabled()) {
trace_amd_pstate_epp_perf(cpudata->cpu, cpudata->highest_perf,
cpudata->epp_cached,
trace_amd_pstate_epp_perf(cpudata->cpu, cpudata->highest_perf, epp,
cpudata->min_limit_perf,
cpudata->max_limit_perf,
policy->boost_enabled);
}

amd_pstate_update_perf(cpudata, cpudata->min_limit_perf, 0U,
cpudata->max_limit_perf, false);

return amd_pstate_set_epp(cpudata, READ_ONCE(cpudata->epp_cached));
return amd_pstate_update_perf(cpudata, cpudata->min_limit_perf, 0U,
cpudata->max_limit_perf, epp, false);
}

static int amd_pstate_epp_set_policy(struct cpufreq_policy *policy)
Expand Down Expand Up @@ -1602,7 +1604,7 @@ static int amd_pstate_epp_set_policy(struct cpufreq_policy *policy)
return 0;
}

static void amd_pstate_epp_reenable(struct amd_cpudata *cpudata)
static int amd_pstate_epp_reenable(struct amd_cpudata *cpudata)
{
u64 max_perf;
int ret;
Expand All @@ -1620,17 +1622,19 @@ static void amd_pstate_epp_reenable(struct amd_cpudata *cpudata)
max_perf, cpudata->boost_state);
}

amd_pstate_update_perf(cpudata, 0, 0, max_perf, false);
amd_pstate_set_epp(cpudata, cpudata->epp_cached);
return amd_pstate_update_perf(cpudata, 0, 0, max_perf, cpudata->epp_cached, false);
}

static int amd_pstate_epp_cpu_online(struct cpufreq_policy *policy)
{
struct amd_cpudata *cpudata = policy->driver_data;
int ret;

pr_debug("AMD CPU Core %d going online\n", cpudata->cpu);

amd_pstate_epp_reenable(cpudata);
ret = amd_pstate_epp_reenable(cpudata);
if (ret)
return ret;
cpudata->suspended = false;

return 0;
Expand All @@ -1654,10 +1658,8 @@ static int amd_pstate_epp_cpu_offline(struct cpufreq_policy *policy)
min_perf, min_perf, policy->boost_enabled);
}

amd_pstate_update_perf(cpudata, min_perf, 0, min_perf, false);
amd_pstate_set_epp(cpudata, AMD_CPPC_EPP_BALANCE_POWERSAVE);

return 0;
return amd_pstate_update_perf(cpudata, min_perf, 0, min_perf,
AMD_CPPC_EPP_BALANCE_POWERSAVE, false);
}

static int amd_pstate_epp_suspend(struct cpufreq_policy *policy)
Expand Down

0 comments on commit fff3957

Please sign in to comment.