lkml.org 
[lkml]   [2023]   [Sep]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    SubjectRe: [PATCH V7 3/7] cpufreq: amd-pstate: Enable amd-pstate preferred core supporting.
    On Mon, Sep 18, 2023 at 04:14:03PM +0800, Meng, Li (Jassmine) wrote:
    > amd-pstate driver utilizes the functions and data structures
    > provided by the ITMT architecture to enable the scheduler to
    > favor scheduling on cores which can be get a higher frequency
    > with lower voltage. We call it amd-pstate preferrred core.
    >
    > Here sched_set_itmt_core_prio() is called to set priorities and
    > sched_set_itmt_support() is called to enable ITMT feature.
    > amd-pstate driver uses the highest performance value to indicate
    > the priority of CPU. The higher value has a higher priority.
    >
    > The initial core rankings are set up by amd-pstate when the
    > system boots.
    >
    > Add device attribute for hardware preferred core. It will check
    > if the processor and power firmware support preferred core
    > feature.
    >
    > Add device attribute for preferred core. Only when hardware
    > supports preferred core and user set `enabled` in early parameter,
    > it can be set to enabled.
    >
    > Add one new early parameter `disable` to allow user to disable
    > the preferred core.
    >
    > Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
    > Co-developed-by: Perry Yuan <Perry.Yuan@amd.com>
    > Signed-off-by: Perry Yuan <Perry.Yuan@amd.com>
    > Signed-off-by: Meng Li <li.meng@amd.com>
    > ---
    > drivers/cpufreq/amd-pstate.c | 163 +++++++++++++++++++++++++++++++----
    > 1 file changed, 147 insertions(+), 16 deletions(-)
    >
    > diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
    > index 9a1e194d5cf8..050e23594057 100644
    > --- a/drivers/cpufreq/amd-pstate.c
    > +++ b/drivers/cpufreq/amd-pstate.c
    > @@ -37,6 +37,7 @@
    > #include <linux/uaccess.h>
    > #include <linux/static_call.h>
    > #include <linux/amd-pstate.h>
    > +#include <linux/topology.h>
    >
    > #include <acpi/processor.h>
    > #include <acpi/cppc_acpi.h>
    > @@ -49,6 +50,8 @@
    >
    > #define AMD_PSTATE_TRANSITION_LATENCY 20000
    > #define AMD_PSTATE_TRANSITION_DELAY 1000
    > +#define AMD_PSTATE_PREFCORE_THRESHOLD 166
    > +#define AMD_PSTATE_MAX_CPPC_PERF 255
    >
    > /*
    > * TODO: We need more time to fine tune processors with shared memory solution
    > @@ -65,6 +68,12 @@ static struct cpufreq_driver amd_pstate_epp_driver;
    > static int cppc_state = AMD_PSTATE_UNDEFINED;
    > static bool cppc_enabled;
    >
    > +/*HW preferred Core featue is supported*/
    > +static bool hw_prefcore = true;
    > +
    > +/*Preferred Core featue is supported*/
    > +static bool prefcore = true;
    > +
    > /*
    > * AMD Energy Preference Performance (EPP)
    > * The EPP is used in the CCLK DPM controller to drive
    > @@ -290,23 +299,21 @@ static inline int amd_pstate_enable(bool enable)
    > static int pstate_init_perf(struct amd_cpudata *cpudata)
    > {
    > u64 cap1;
    > - u32 highest_perf;
    >
    > int ret = rdmsrl_safe_on_cpu(cpudata->cpu, MSR_AMD_CPPC_CAP1,
    > &cap1);
    > if (ret)
    > return ret;
    >
    > - /*
    > - * TODO: Introduce AMD specific power feature.
    > - *
    > - * CPPC entry doesn't indicate the highest performance in some ASICs.
    > + /* For platforms that do not support the preferred core feature, the
    > + * highest_pef may be configured with 166 or 255, to avoid max frequency
    > + * calculated wrongly. we take the AMD_CPPC_HIGHEST_PERF(cap1) value as
    > + * the default max perf.
    > */
    > - highest_perf = amd_get_highest_perf();
    > - if (highest_perf > AMD_CPPC_HIGHEST_PERF(cap1))
    > - highest_perf = AMD_CPPC_HIGHEST_PERF(cap1);
    > -
    > - WRITE_ONCE(cpudata->highest_perf, highest_perf);
    > + if (hw_prefcore)
    > + WRITE_ONCE(cpudata->highest_perf, AMD_PSTATE_PREFCORE_THRESHOLD);
    > + else
    > + WRITE_ONCE(cpudata->highest_perf, AMD_CPPC_HIGHEST_PERF(cap1));
    >
    > WRITE_ONCE(cpudata->nominal_perf, AMD_CPPC_NOMINAL_PERF(cap1));
    > WRITE_ONCE(cpudata->lowest_nonlinear_perf, AMD_CPPC_LOWNONLIN_PERF(cap1));
    > @@ -318,17 +325,15 @@ static int pstate_init_perf(struct amd_cpudata *cpudata)
    > static int cppc_init_perf(struct amd_cpudata *cpudata)
    > {
    > struct cppc_perf_caps cppc_perf;
    > - u32 highest_perf;
    >
    > int ret = cppc_get_perf_caps(cpudata->cpu, &cppc_perf);
    > if (ret)
    > return ret;
    >
    > - highest_perf = amd_get_highest_perf();
    > - if (highest_perf > cppc_perf.highest_perf)
    > - highest_perf = cppc_perf.highest_perf;
    > -
    > - WRITE_ONCE(cpudata->highest_perf, highest_perf);
    > + if (hw_prefcore)
    > + WRITE_ONCE(cpudata->highest_perf, AMD_PSTATE_PREFCORE_THRESHOLD);
    > + else
    > + WRITE_ONCE(cpudata->highest_perf, cppc_perf.highest_perf);
    >
    > WRITE_ONCE(cpudata->nominal_perf, cppc_perf.nominal_perf);
    > WRITE_ONCE(cpudata->lowest_nonlinear_perf,
    > @@ -676,6 +681,90 @@ static void amd_perf_ctl_reset(unsigned int cpu)
    > wrmsrl_on_cpu(cpu, MSR_AMD_PERF_CTL, 0);
    > }
    >
    > +/*
    > + * Set amd-pstate preferred core enable can't be done directly from cpufreq callbacks
    > + * due to locking, so queue the work for later.
    > + */
    > +static void amd_pstste_sched_prefcore_workfn(struct work_struct *work)
    > +{
    > + sched_set_itmt_support();
    > +}
    > +static DECLARE_WORK(sched_prefcore_work, amd_pstste_sched_prefcore_workfn);
    > +
    > +/*
    > + * Get the highest performance register value.
    > + * @cpu: CPU from which to get highest performance.
    > + * @highest_perf: Return address.
    > + *
    > + * Return: 0 for success, -EIO otherwise.
    > + */
    > +static int amd_pstate_get_highest_perf(int cpu, u32 *highest_perf)
    > +{
    > + int ret;
    > + u64 cppc_highest_perf;
    > +
    > + if (boot_cpu_has(X86_FEATURE_CPPC)) {
    > + u64 cap1;
    > +
    > + ret = rdmsrl_safe_on_cpu(cpu, MSR_AMD_CPPC_CAP1, &cap1);
    > + if (ret)
    > + return ret;
    > + WRITE_ONCE(*highest_perf, AMD_CPPC_HIGHEST_PERF(cap1));
    > + } else {
    > + ret = cppc_get_highest_perf(cpu, &cppc_highest_perf);
    > + *highest_perf = (u32)(cppc_highest_perf & 0xFFFF);
    > + }
    > +
    > + return (ret);
    > +}
    > +
    > +static void amd_pstate_init_prefcore(unsigned int cpu)
    > +{
    > + int ret;
    > + u32 highest_perf;
    > + static u32 max_highest_perf = 0, min_highest_perf = U32_MAX;
    > +
    > + if (!prefcore)
    > + return;
    > +
    > + ret = amd_pstate_get_highest_perf(cpu, &highest_perf);
    > + if (ret)
    > + return;
    > +
    > + /*
    > + * The priorities can be set regardless of whether or not
    > + * sched_set_itmt_support(true) has been called and it is valid to
    > + * update them at any time after it has been called.
    > + */
    > + sched_set_itmt_core_prio(highest_perf, cpu);
    > +
    > + /* check if CPPC preferred core feature is enabled*/
    > + if (highest_perf == AMD_PSTATE_MAX_CPPC_PERF) {
    > + pr_debug("AMD CPPC preferred core is unsupported!\n");
    > + hw_prefcore = false;
    > + prefcore = false;

    The problem that I commented in below version is still there. The
    amd_pstate_init_prefcore() will be called in amd_pstate_cpu_init() which
    will be initialized on each cpu. So the hw_perfcore/prefcore will be
    overwrited at last cpu initialization.

    https://lore.kernel.org/linux-pm/ZPiEM+gusure7vKy@amd.com/

    Thanks,
    Ray

    > + return;
    > + }
    > +
    > + if (max_highest_perf <= min_highest_perf) {
    > + if (highest_perf > max_highest_perf)
    > + max_highest_perf = highest_perf;
    > +
    > + if (highest_perf < min_highest_perf)
    > + min_highest_perf = highest_perf;
    > +
    > + if (max_highest_perf > min_highest_perf) {
    > + /*
    > + * This code can be run during CPU online under the
    > + * CPU hotplug locks, so sched_set_itmt_support()
    > + * cannot be called from here. Queue up a work item
    > + * to invoke it.
    > + */
    > + schedule_work(&sched_prefcore_work);
    > + }
    > + }
    > +}
    > +
    > static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
    > {
    > int min_freq, max_freq, nominal_freq, lowest_nonlinear_freq, ret;
    > @@ -697,6 +786,8 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
    >
    > cpudata->cpu = policy->cpu;
    >
    > + amd_pstate_init_prefcore(policy->cpu);
    > +
    > ret = amd_pstate_init_perf(cpudata);
    > if (ret)
    > goto free_cpudata1;
    > @@ -763,6 +854,22 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
    > return ret;
    > }
    >
    > +static int amd_pstate_cpu_online(struct cpufreq_policy *policy)
    > +{
    > + struct amd_cpudata *cpudata = policy->driver_data;
    > +
    > + pr_debug("CPU %d going online\n", cpudata->cpu);
    > +
    > + amd_pstate_init_prefcore(cpudata->cpu);
    > +
    > + return 0;
    > +}
    > +
    > +static int amd_pstate_cpu_offline(struct cpufreq_policy *policy)
    > +{
    > + return 0;
    > +}
    > +
    > static int amd_pstate_cpu_exit(struct cpufreq_policy *policy)
    > {
    > struct amd_cpudata *cpudata = policy->driver_data;
    > @@ -1037,6 +1144,12 @@ static ssize_t status_store(struct device *a, struct device_attribute *b,
    > return ret < 0 ? ret : count;
    > }
    >
    > +static ssize_t prefcore_show(struct device *dev,
    > + struct device_attribute *attr, char *buf)
    > +{
    > + return sysfs_emit(buf, "%s\n", prefcore ? "enabled" : "disabled");
    > +}
    > +
    > cpufreq_freq_attr_ro(amd_pstate_max_freq);
    > cpufreq_freq_attr_ro(amd_pstate_lowest_nonlinear_freq);
    >
    > @@ -1044,6 +1157,7 @@ cpufreq_freq_attr_ro(amd_pstate_highest_perf);
    > 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,
    > @@ -1063,6 +1177,7 @@ static struct freq_attr *amd_pstate_epp_attr[] = {
    >
    > static struct attribute *pstate_global_attributes[] = {
    > &dev_attr_status.attr,
    > + &dev_attr_prefcore.attr,
    > NULL
    > };
    >
    > @@ -1114,6 +1229,8 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
    > cpudata->cpu = policy->cpu;
    > cpudata->epp_policy = 0;
    >
    > + amd_pstate_init_prefcore(policy->cpu);
    > +
    > ret = amd_pstate_init_perf(cpudata);
    > if (ret)
    > goto free_cpudata1;
    > @@ -1285,6 +1402,8 @@ static int amd_pstate_epp_cpu_online(struct cpufreq_policy *policy)
    >
    > pr_debug("AMD CPU Core %d going online\n", cpudata->cpu);
    >
    > + amd_pstate_init_prefcore(cpudata->cpu);
    > +
    > if (cppc_state == AMD_PSTATE_ACTIVE) {
    > amd_pstate_epp_reenable(cpudata);
    > cpudata->suspended = false;
    > @@ -1389,6 +1508,8 @@ static struct cpufreq_driver amd_pstate_driver = {
    > .fast_switch = amd_pstate_fast_switch,
    > .init = amd_pstate_cpu_init,
    > .exit = amd_pstate_cpu_exit,
    > + .offline = amd_pstate_cpu_offline,
    > + .online = amd_pstate_cpu_online,
    > .suspend = amd_pstate_cpu_suspend,
    > .resume = amd_pstate_cpu_resume,
    > .set_boost = amd_pstate_set_boost,
    > @@ -1527,7 +1648,17 @@ static int __init amd_pstate_param(char *str)
    >
    > return amd_pstate_set_driver(mode_idx);
    > }
    > +
    > +static int __init amd_prefcore_param(char *str)
    > +{
    > + if (!strcmp(str, "disable"))
    > + prefcore = false;
    > +
    > + return 0;
    > +}
    > +
    > early_param("amd_pstate", amd_pstate_param);
    > +early_param("amd_prefcore", amd_prefcore_param);
    >
    > MODULE_AUTHOR("Huang Rui <ray.huang@amd.com>");
    > MODULE_DESCRIPTION("AMD Processor P-state Frequency Driver");
    > --
    > 2.34.1
    >

    \
     
     \ /
      Last update: 2023-09-20 04:46    [W:7.671 / U:0.128 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site