@@ -57,6 +57,8 @@ struct amd_pstate_drv_data
} req;
};
int err;
+ /* EPP feature related attributes */
+ unsigned int policy;
uint32_t max_freq;
uint32_t min_freq;
@@ -67,6 +69,8 @@ static DEFINE_PER_CPU_READ_MOSTLY(struct amd_pstate_drv_data *, amd_pstate_drv_d
uint16_t __read_mostly dmi_max_speed_mhz;
+static bool __ro_after_init epp_mode;
+
static bool __init amd_pstate_handle_option(const char *s, const char *end)
{
int ret;
@@ -223,14 +227,29 @@ static void amd_pstate_write_request_msrs(void *info)
}
static int cf_check amd_pstate_write_request(int cpu, uint8_t min_perf,
- uint8_t des_perf, uint8_t max_perf)
+ uint8_t des_perf, uint8_t max_perf,
+ int epp)
{
struct amd_pstate_drv_data *data = per_cpu(amd_pstate_drv_data, cpu);
- uint64_t prev = data->amd_req;
+ uint64_t prev = data->amd_req, val;
data->req.min_perf = min_perf;
data->req.max_perf = max_perf;
- data->req.des_perf = des_perf;
+ if ( !epp_mode )
+ data->req.des_perf = des_perf;
+ else
+ {
+ data->req.des_perf = 0;
+ /* Get pre-defined BIOS value */
+ if ( epp < 0 )
+ {
+ if ( rdmsr_safe(MSR_AMD_CPPC_REQ, val) )
+ return -EINVAL;
+ data->req.epp = (val >> 24) & 0xFF;
+ }
+ else
+ data->req.epp = epp;
+ }
if ( prev == data->amd_req )
return 0;
@@ -257,7 +276,7 @@ static int cf_check amd_pstate_cpufreq_target(struct cpufreq_policy *policy,
min_perf = data->hw.lowest_nonlinear_perf;
des_perf = amd_pstate_khz_to_perf(data, target_freq);
- return amd_pstate_write_request(policy->cpu, min_perf, des_perf, max_perf);
+ return amd_pstate_write_request(policy->cpu, min_perf, des_perf, max_perf, -1);
}
static void cf_check amd_pstate_init_msrs(void *info)
@@ -354,7 +373,7 @@ static void amd_pstate_boost_init(struct cpufreq_policy *policy, struct amd_psta
policy->turbo = CPUFREQ_TURBO_ENABLED;
}
-static int cf_check amd_pstate_cpufreq_cpu_init(struct cpufreq_policy *policy)
+static int amd_pstate_cpufreq_init_perf(struct cpufreq_policy *policy)
{
unsigned int cpu = policy->cpu;
struct amd_pstate_drv_data *data;
@@ -379,10 +398,23 @@ static int cf_check amd_pstate_cpufreq_cpu_init(struct cpufreq_policy *policy)
return -ENODEV;
}
- amd_pstate_boost_init(policy, data);
return 0;
}
+static int cf_check amd_pstate_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+ int ret = 0;
+ struct amd_pstate_drv_data *data;
+
+ ret = amd_pstate_cpufreq_init_perf(policy);
+ if ( ret )
+ return ret;
+
+ data = per_cpu(amd_pstate_drv_data, policy->cpu);
+ amd_pstate_boost_init(policy, data);
+ return ret;
+}
+
static int cf_check amd_pstate_cpufreq_cpu_exit(struct cpufreq_policy *policy)
{
struct amd_pstate_drv_data *data = per_cpu(amd_pstate_drv_data, policy->cpu);
@@ -393,6 +425,70 @@ static int cf_check amd_pstate_cpufreq_cpu_exit(struct cpufreq_policy *policy)
return 0;
}
+static void amd_perf_ctl_reset(void *data)
+{
+ wrmsr_safe(MSR_K8_PSTATE_CTRL, 0);
+}
+
+static int cf_check amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
+{
+ int ret = 0;
+ struct amd_pstate_drv_data *data;
+
+ /*
+ * Resetting P-State Control register will put the CPU in P0 frequency,
+ * which is ideal for initialization process.
+ */
+ on_selected_cpus(cpumask_of(policy->cpu), amd_perf_ctl_reset, NULL, 1);
+
+ ret = amd_pstate_cpufreq_init_perf(policy);
+ if ( ret )
+ return ret;
+
+ data = per_cpu(amd_pstate_drv_data, policy->cpu);
+
+ policy->policy = cpufreq_parse_policy(policy->governor);
+
+ amd_pstate_boost_init(policy, data);
+
+ amd_pstate_verbose("CPU %u initialized with amd-pstate active mode\n", policy->cpu);
+
+ return 0;
+}
+
+static int cf_check amd_pstate_epp_update_limit(struct cpufreq_policy *policy)
+{
+ struct amd_pstate_drv_data *data = per_cpu(amd_pstate_drv_data, policy->cpu);
+ uint8_t max_perf, min_perf, des_perf;
+ int epp = -1;
+
+ /* Initial min/max values for CPPC Performance Controls Register */
+ max_perf = data->hw.highest_perf;
+ min_perf = data->hw.lowest_perf;
+
+ if ( data->policy == CPUFREQ_POLICY_PERFORMANCE )
+ min_perf = max_perf;
+
+ /* CPPC EPP feature require to set zero to the desire perf bit */
+ des_perf = 0;
+
+ if ( data->policy == CPUFREQ_POLICY_PERFORMANCE )
+ /* Force the epp value to be zero for performance policy */
+ epp = CPPC_ENERGY_PERF_MAX_PERFORMANCE;
+ else if ( data->policy == CPUFREQ_POLICY_POWERSAVE )
+ /* Force the epp value to be 0xff for powersave policy */
+ epp = CPPC_ENERGY_PERF_MAX_POWERSAVE;
+
+ return amd_pstate_write_request(policy->cpu, min_perf, des_perf, max_perf, epp);
+}
+
+static int cf_check amd_pstate_epp_set_policy(struct cpufreq_policy *policy)
+{
+ amd_pstate_verbose("Set new policy for CPU %u\n", policy->cpu);
+
+ return amd_pstate_epp_update_limit(policy);
+}
+
static const struct cpufreq_driver __initconstrel amd_pstate_cpufreq_driver =
{
.name = XEN_AMD_PSTATE_DRIVER_NAME,
@@ -402,6 +498,15 @@ static const struct cpufreq_driver __initconstrel amd_pstate_cpufreq_driver =
.exit = amd_pstate_cpufreq_cpu_exit,
};
+static const struct cpufreq_driver __initconstrel amd_pstate_epp_driver =
+{
+ .name = XEN_AMD_PSTATE_EPP_DRIVER_NAME,
+ .verify = amd_pstate_cpufreq_verify,
+ .setpolicy = amd_pstate_epp_set_policy,
+ .init = amd_pstate_epp_cpu_init,
+ .exit = amd_pstate_cpufreq_cpu_exit,
+};
+
int __init amd_pstate_register_driver(void)
{
if ( !cpu_has_cppc )
@@ -409,4 +514,9 @@ int __init amd_pstate_register_driver(void)
if ( !opt_cpufreq_active )
return cpufreq_register_driver(&amd_pstate_cpufreq_driver);
+ else
+ {
+ epp_mode = true;
+ return cpufreq_register_driver(&amd_pstate_epp_driver);
+ }
}
@@ -21,10 +21,6 @@ static bool __ro_after_init feature_hdc;
static bool __ro_after_init opt_cpufreq_hdc = true;
-#define HWP_ENERGY_PERF_MAX_PERFORMANCE 0
-#define HWP_ENERGY_PERF_BALANCE 0x80
-#define HWP_ENERGY_PERF_MAX_POWERSAVE 0xff
-
union hwp_request
{
struct
@@ -597,7 +593,7 @@ int set_hwp_para(struct cpufreq_policy *policy,
data->minimum = data->hw.lowest;
data->maximum = data->hw.lowest;
data->activity_window = 0;
- data->energy_perf = HWP_ENERGY_PERF_MAX_POWERSAVE;
+ data->energy_perf = CPPC_ENERGY_PERF_MAX_POWERSAVE;
data->desired = 0;
break;
@@ -605,7 +601,7 @@ int set_hwp_para(struct cpufreq_policy *policy,
data->minimum = data->hw.highest;
data->maximum = data->hw.highest;
data->activity_window = 0;
- data->energy_perf = HWP_ENERGY_PERF_MAX_PERFORMANCE;
+ data->energy_perf = CPPC_ENERGY_PERF_MAX_PERFORMANCE;
data->desired = 0;
break;
@@ -613,7 +609,7 @@ int set_hwp_para(struct cpufreq_policy *policy,
data->minimum = data->hw.lowest;
data->maximum = data->hw.highest;
data->activity_window = 0;
- data->energy_perf = HWP_ENERGY_PERF_BALANCE;
+ data->energy_perf = CPPC_ENERGY_PERF_BALANCE;
data->desired = 0;
break;
@@ -83,6 +83,7 @@ struct cpufreq_policy {
int8_t turbo; /* tristate flag: 0 for unsupported
* -1 for disable, 1 for enabled
* See CPUFREQ_TURBO_* below for defines */
+ unsigned int policy;
};
DECLARE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_policy);
@@ -264,6 +265,10 @@ void cpufreq_dbs_timer_resume(void);
void intel_feature_detect(struct cpufreq_policy *policy);
+#define CPPC_ENERGY_PERF_MAX_PERFORMANCE 0
+#define CPPC_ENERGY_PERF_BALANCE 0x80
+#define CPPC_ENERGY_PERF_MAX_POWERSAVE 0xff
+
int hwp_cmdline_parse(const char *s, const char *e);
int hwp_register_driver(void);
#ifdef CONFIG_INTEL
@@ -425,7 +425,7 @@ struct xen_set_cppc_para {
#define XEN_HWP_DRIVER_NAME "hwp"
#define XEN_AMD_PSTATE_DRIVER_NAME "amd-pstate"
-
+#define XEN_AMD_PSTATE_EPP_DRIVER_NAME "amd-pstate-epp"
/*
* cpufreq para name of this structure named
* same as sysfs file name of native linux
amd-pstate has 2 operation modes: autonomous (active) mode, non-autonomous (passive) mode. In active mode, platform ignores the requestd done in the Desired Performance Target register and takes into account only the values set to the minimum, maximum and energy performance preference(EPP) registers. The EPP is used in the CCLK DPM controller to drive the frequency that a core is going to operate during short periods of activity. The SOC EPP targets are configured on a scale from 0 to 255 where 0 represents maximum performance and 255 represents maximum efficiency. This commit implements one new AMD CPU frequency driver `amd-pstate-epp` for active mode. Signed-off-by: Penny Zheng <Penny.Zheng@amd.com> --- xen/arch/x86/acpi/cpufreq/amd-pstate.c | 122 +++++++++++++++++++++++-- xen/arch/x86/acpi/cpufreq/hwp.c | 10 +- xen/include/acpi/cpufreq/cpufreq.h | 5 + xen/include/public/sysctl.h | 2 +- 4 files changed, 125 insertions(+), 14 deletions(-)