mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
Add user PM control interface
Signed-off-by: Liu, Jinsong <jinsong.liu@intel.com>
This commit is contained in:
1 parent
630b671347
commit
7542c4ff00
10 files changed
+646
-6
No files matched your search
@@ -23,8 +23,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <curses.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "xc_private.h"
|
||||
|
||||
/*
|
||||
* Get PM statistic info
|
||||
*/
|
||||
int xc_pm_get_max_px(int xc_handle, int cpuid, int *max_px)
|
||||
{
|
||||
DECLARE_SYSCTL;
|
||||
@@ -168,3 +175,136 @@ int xc_pm_reset_cxstat(int xc_handle, int cpuid)
|
||||
|
||||
return xc_sysctl(xc_handle, &sysctl);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 1. Get PM parameter
|
||||
* 2. Provide user PM control
|
||||
*/
|
||||
int xc_get_cpufreq_para(int xc_handle, int cpuid,
|
||||
struct xc_get_cpufreq_para *user_para)
|
||||
{
|
||||
DECLARE_SYSCTL;
|
||||
int ret = 0;
|
||||
struct xen_get_cpufreq_para *sys_para = &sysctl.u.pm_op.get_para;
|
||||
bool has_num = user_para->cpu_num &&
|
||||
user_para->freq_num &&
|
||||
user_para->gov_num;
|
||||
|
||||
if ( (xc_handle < 0) || !user_para )
|
||||
return -EINVAL;
|
||||
|
||||
if ( has_num )
|
||||
{
|
||||
if ( (!user_para->affected_cpus) ||
|
||||
(!user_para->scaling_available_frequencies) ||
|
||||
(!user_para->scaling_available_governors) )
|
||||
return -EINVAL;
|
||||
|
||||
if ( (ret = lock_pages(user_para->affected_cpus,
|
||||
user_para->cpu_num * sizeof(uint32_t))) )
|
||||
goto unlock_1;
|
||||
if ( (ret = lock_pages(user_para->scaling_available_frequencies,
|
||||
user_para->freq_num * sizeof(uint32_t))) )
|
||||
goto unlock_2;
|
||||
if ( (ret = lock_pages(user_para->scaling_available_governors,
|
||||
user_para->gov_num * CPUFREQ_NAME_LEN * sizeof(char))) )
|
||||
goto unlock_3;
|
||||
|
||||
set_xen_guest_handle(sys_para->affected_cpus,
|
||||
user_para->affected_cpus);
|
||||
set_xen_guest_handle(sys_para->scaling_available_frequencies,
|
||||
user_para->scaling_available_frequencies);
|
||||
set_xen_guest_handle(sys_para->scaling_available_governors,
|
||||
user_para->scaling_available_governors);
|
||||
}
|
||||
|
||||
sysctl.cmd = XEN_SYSCTL_pm_op;
|
||||
sysctl.u.pm_op.cmd = GET_CPUFREQ_PARA;
|
||||
sysctl.u.pm_op.cpuid = cpuid;
|
||||
sys_para->cpu_num = user_para->cpu_num;
|
||||
sys_para->freq_num = user_para->freq_num;
|
||||
sys_para->gov_num = user_para->gov_num;
|
||||
|
||||
ret = xc_sysctl(xc_handle, &sysctl);
|
||||
if ( ret )
|
||||
{
|
||||
if ( errno == EAGAIN )
|
||||
{
|
||||
user_para->cpu_num = sys_para->cpu_num;
|
||||
user_para->freq_num = sys_para->freq_num;
|
||||
user_para->gov_num = sys_para->gov_num;
|
||||
ret = -errno;
|
||||
}
|
||||
|
||||
if ( has_num )
|
||||
goto unlock_4;
|
||||
goto unlock_1;
|
||||
}
|
||||
else
|
||||
{
|
||||
user_para->cpuinfo_cur_freq = sys_para->cpuinfo_cur_freq;
|
||||
user_para->cpuinfo_max_freq = sys_para->cpuinfo_max_freq;
|
||||
user_para->cpuinfo_min_freq = sys_para->cpuinfo_min_freq;
|
||||
user_para->scaling_cur_freq = sys_para->scaling_cur_freq;
|
||||
user_para->scaling_max_freq = sys_para->scaling_max_freq;
|
||||
user_para->scaling_min_freq = sys_para->scaling_min_freq;
|
||||
|
||||
memcpy(user_para->scaling_driver,
|
||||
sys_para->scaling_driver, CPUFREQ_NAME_LEN);
|
||||
memcpy(user_para->scaling_governor,
|
||||
sys_para->scaling_governor, CPUFREQ_NAME_LEN);
|
||||
|
||||
/* copy to user_para no matter what cpufreq governor */
|
||||
BUILD_BUG_ON(sizeof(((struct xc_get_cpufreq_para *)0)->u) !=
|
||||
sizeof(((struct xen_get_cpufreq_para *)0)->u));
|
||||
|
||||
memcpy(&user_para->u, &sys_para->u, sizeof(sys_para->u));
|
||||
}
|
||||
|
||||
unlock_4:
|
||||
unlock_pages(user_para->scaling_available_governors,
|
||||
user_para->gov_num * CPUFREQ_NAME_LEN * sizeof(char));
|
||||
unlock_3:
|
||||
unlock_pages(user_para->scaling_available_frequencies,
|
||||
user_para->freq_num * sizeof(uint32_t));
|
||||
unlock_2:
|
||||
unlock_pages(user_para->affected_cpus,
|
||||
user_para->cpu_num * sizeof(uint32_t));
|
||||
unlock_1:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xc_set_cpufreq_gov(int xc_handle, int cpuid, char *govname)
|
||||
{
|
||||
DECLARE_SYSCTL;
|
||||
char *scaling_governor = sysctl.u.pm_op.set_gov.scaling_governor;
|
||||
|
||||
if ( (xc_handle < 0) || (!govname) )
|
||||
return -EINVAL;
|
||||
|
||||
sysctl.cmd = XEN_SYSCTL_pm_op;
|
||||
sysctl.u.pm_op.cmd = SET_CPUFREQ_GOV;
|
||||
sysctl.u.pm_op.cpuid = cpuid;
|
||||
strncpy(scaling_governor, govname, CPUFREQ_NAME_LEN);
|
||||
scaling_governor[CPUFREQ_NAME_LEN] = '\0';
|
||||
|
||||
return xc_sysctl(xc_handle, &sysctl);
|
||||
}
|
||||
|
||||
int xc_set_cpufreq_para(int xc_handle, int cpuid,
|
||||
int ctrl_type, int ctrl_value)
|
||||
{
|
||||
DECLARE_SYSCTL;
|
||||
|
||||
if ( xc_handle < 0 )
|
||||
return -EINVAL;
|
||||
|
||||
sysctl.cmd = XEN_SYSCTL_pm_op;
|
||||
sysctl.u.pm_op.cmd = SET_CPUFREQ_PARA;
|
||||
sysctl.u.pm_op.cpuid = cpuid;
|
||||
sysctl.u.pm_op.set_para.ctrl_type = ctrl_type;
|
||||
sysctl.u.pm_op.set_para.ctrl_value = ctrl_value;
|
||||
|
||||
return xc_sysctl(xc_handle, &sysctl);
|
||||
}
|
||||
@@ -1161,4 +1161,46 @@ int xc_pm_reset_cxstat(int xc_handle, int cpuid);
|
||||
|
||||
int xc_cpu_online(int xc_handle, int cpu);
|
||||
int xc_cpu_offline(int xc_handle, int cpu);
|
||||
|
||||
/*
|
||||
* cpufreq para name of this structure named
|
||||
* same as sysfs file name of native linux
|
||||
*/
|
||||
typedef xen_userspace_t xc_userspace_t;
|
||||
typedef xen_ondemand_t xc_ondemand_t;
|
||||
|
||||
struct xc_get_cpufreq_para {
|
||||
/* IN/OUT variable */
|
||||
uint32_t cpu_num;
|
||||
uint32_t freq_num;
|
||||
uint32_t gov_num;
|
||||
|
||||
/* for all governors */
|
||||
/* OUT variable */
|
||||
uint32_t *affected_cpus;
|
||||
uint32_t *scaling_available_frequencies;
|
||||
char *scaling_available_governors;
|
||||
char scaling_driver[CPUFREQ_NAME_LEN];
|
||||
|
||||
uint32_t cpuinfo_cur_freq;
|
||||
uint32_t cpuinfo_max_freq;
|
||||
uint32_t cpuinfo_min_freq;
|
||||
uint32_t scaling_cur_freq;
|
||||
|
||||
char scaling_governor[CPUFREQ_NAME_LEN];
|
||||
uint32_t scaling_max_freq;
|
||||
uint32_t scaling_min_freq;
|
||||
|
||||
/* for specific governor */
|
||||
union {
|
||||
xc_userspace_t userspace;
|
||||
xc_ondemand_t ondemand;
|
||||
} u;
|
||||
};
|
||||
|
||||
int xc_get_cpufreq_para(int xc_handle, int cpuid,
|
||||
struct xc_get_cpufreq_para *user_para);
|
||||
int xc_set_cpufreq_gov(int xc_handle, int cpuid, char *govname);
|
||||
int xc_set_cpufreq_para(int xc_handle, int cpuid,
|
||||
int ctrl_type, int ctrl_value);
|
||||
#endif /* XENCTRL_H */
|
||||
@@ -275,6 +275,7 @@ acpi_cpufreq_cpu_exit (struct cpufreq_policy *policy)
|
||||
}
|
||||
|
||||
static struct cpufreq_driver acpi_cpufreq_driver = {
|
||||
.name = "acpi-cpufreq",
|
||||
.verify = acpi_cpufreq_verify,
|
||||
.target = acpi_cpufreq_target,
|
||||
.get = acpi_cpufreq_get,
|
||||
|
||||
@@ -549,6 +549,7 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
|
||||
}
|
||||
|
||||
static struct cpufreq_driver acpi_cpufreq_driver = {
|
||||
.name = "acpi-cpufreq",
|
||||
.verify = acpi_cpufreq_verify,
|
||||
.target = acpi_cpufreq_target,
|
||||
.init = acpi_cpufreq_cpu_init,
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <xsm/xsm.h>
|
||||
|
||||
extern int do_get_pm_info(struct xen_sysctl_get_pmstat *op);
|
||||
extern int do_pm_op(struct xen_sysctl_pm_op *op);
|
||||
|
||||
extern long arch_do_sysctl(
|
||||
struct xen_sysctl *op, XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl);
|
||||
@@ -224,6 +225,21 @@ long do_sysctl(XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl)
|
||||
}
|
||||
break;
|
||||
|
||||
case XEN_SYSCTL_pm_op:
|
||||
{
|
||||
ret = do_pm_op(&op->u.pm_op);
|
||||
if ( ret && (ret != -EAGAIN) )
|
||||
break;
|
||||
|
||||
if ( op->u.pm_op.cmd == GET_CPUFREQ_PARA )
|
||||
if ( copy_to_guest(u_sysctl, op, 1) )
|
||||
{
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = arch_do_sysctl(op, u_sysctl);
|
||||
break;
|
||||
|
||||
@@ -47,6 +47,11 @@ extern uint32_t pmstat_get_cx_nr(uint32_t cpuid);
|
||||
extern int pmstat_get_cx_stat(uint32_t cpuid, struct pm_cx_stat *stat);
|
||||
extern int pmstat_reset_cx_stat(uint32_t cpuid);
|
||||
|
||||
extern struct list_head cpufreq_governor_list;
|
||||
|
||||
/*
|
||||
* Get PM statistic info
|
||||
*/
|
||||
int do_get_pm_info(struct xen_sysctl_get_pmstat *op)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -156,3 +161,304 @@ int do_get_pm_info(struct xen_sysctl_get_pmstat *op)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* 1. Get PM parameter
|
||||
* 2. Provide user PM control
|
||||
*/
|
||||
static int read_scaling_available_governors(char *scaling_available_governors,
|
||||
unsigned int size)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
struct cpufreq_governor *t;
|
||||
|
||||
if ( !scaling_available_governors )
|
||||
return -EINVAL;
|
||||
|
||||
list_for_each_entry(t, &cpufreq_governor_list, governor_list)
|
||||
{
|
||||
i += scnprintf(&scaling_available_governors[i],
|
||||
CPUFREQ_NAME_LEN, "%s ", t->name);
|
||||
if ( i > size )
|
||||
return -EINVAL;
|
||||
}
|
||||
scaling_available_governors[i-1] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_cpufreq_para(struct xen_sysctl_pm_op *op)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
const struct processor_pminfo *pmpt;
|
||||
struct cpufreq_policy *policy;
|
||||
uint32_t gov_num = 0;
|
||||
uint32_t *affected_cpus;
|
||||
uint32_t *scaling_available_frequencies;
|
||||
char *scaling_available_governors;
|
||||
struct list_head *pos;
|
||||
uint32_t cpu, i, j = 0;
|
||||
|
||||
if ( !op || !cpu_online(op->cpuid) )
|
||||
return -EINVAL;
|
||||
pmpt = processor_pminfo[op->cpuid];
|
||||
policy = cpufreq_cpu_policy[op->cpuid];
|
||||
|
||||
if ( !pmpt || !pmpt->perf.states ||
|
||||
!policy || !policy->governor )
|
||||
return -EINVAL;
|
||||
|
||||
list_for_each(pos, &cpufreq_governor_list)
|
||||
gov_num++;
|
||||
|
||||
if ( (op->get_para.cpu_num != cpus_weight(policy->cpus)) ||
|
||||
(op->get_para.freq_num != pmpt->perf.state_count) ||
|
||||
(op->get_para.gov_num != gov_num) )
|
||||
{
|
||||
op->get_para.cpu_num = cpus_weight(policy->cpus);
|
||||
op->get_para.freq_num = pmpt->perf.state_count;
|
||||
op->get_para.gov_num = gov_num;
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if ( !(affected_cpus = xmalloc_array(uint32_t, op->get_para.cpu_num)) )
|
||||
return -ENOMEM;
|
||||
memset(affected_cpus, 0, op->get_para.cpu_num * sizeof(uint32_t));
|
||||
for_each_cpu_mask(cpu, policy->cpus)
|
||||
affected_cpus[j++] = cpu;
|
||||
ret = copy_to_guest(op->get_para.affected_cpus,
|
||||
affected_cpus, op->get_para.cpu_num);
|
||||
xfree(affected_cpus);
|
||||
if ( ret )
|
||||
return ret;
|
||||
|
||||
if ( !(scaling_available_frequencies =
|
||||
xmalloc_array(uint32_t, op->get_para.freq_num)) )
|
||||
return -ENOMEM;
|
||||
memset(scaling_available_frequencies, 0,
|
||||
op->get_para.freq_num * sizeof(uint32_t));
|
||||
for ( i = 0; i < op->get_para.freq_num; i++ )
|
||||
scaling_available_frequencies[i] =
|
||||
pmpt->perf.states[i].core_frequency * 1000;
|
||||
ret = copy_to_guest(op->get_para.scaling_available_frequencies,
|
||||
scaling_available_frequencies, op->get_para.freq_num);
|
||||
xfree(scaling_available_frequencies);
|
||||
if ( ret )
|
||||
return ret;
|
||||
|
||||
if ( !(scaling_available_governors =
|
||||
xmalloc_array(char, gov_num * CPUFREQ_NAME_LEN)) )
|
||||
return -ENOMEM;
|
||||
memset(scaling_available_governors, 0,
|
||||
gov_num * CPUFREQ_NAME_LEN * sizeof(char));
|
||||
if ( (ret = read_scaling_available_governors(scaling_available_governors,
|
||||
gov_num * CPUFREQ_NAME_LEN * sizeof(char))) )
|
||||
{
|
||||
xfree(scaling_available_governors);
|
||||
return ret;
|
||||
}
|
||||
ret = copy_to_guest(op->get_para.scaling_available_governors,
|
||||
scaling_available_governors, gov_num * CPUFREQ_NAME_LEN);
|
||||
xfree(scaling_available_governors);
|
||||
if ( ret )
|
||||
return ret;
|
||||
|
||||
op->get_para.cpuinfo_cur_freq =
|
||||
cpufreq_driver->get ? cpufreq_driver->get(op->cpuid) : policy->cur;
|
||||
op->get_para.cpuinfo_max_freq = policy->cpuinfo.max_freq;
|
||||
op->get_para.cpuinfo_min_freq = policy->cpuinfo.min_freq;
|
||||
op->get_para.scaling_cur_freq = policy->cur;
|
||||
op->get_para.scaling_max_freq = policy->max;
|
||||
op->get_para.scaling_min_freq = policy->min;
|
||||
|
||||
if ( cpufreq_driver->name )
|
||||
strlcpy(op->get_para.scaling_driver,
|
||||
cpufreq_driver->name, CPUFREQ_NAME_LEN);
|
||||
else
|
||||
strlcpy(op->get_para.scaling_driver, "Unknown", CPUFREQ_NAME_LEN);
|
||||
|
||||
if ( policy->governor->name )
|
||||
strlcpy(op->get_para.scaling_governor,
|
||||
policy->governor->name, CPUFREQ_NAME_LEN);
|
||||
else
|
||||
strlcpy(op->get_para.scaling_governor, "Unknown", CPUFREQ_NAME_LEN);
|
||||
|
||||
/* governor specific para */
|
||||
if ( !strnicmp(op->get_para.scaling_governor,
|
||||
"userspace", CPUFREQ_NAME_LEN) )
|
||||
{
|
||||
op->get_para.u.userspace.scaling_setspeed = policy->cur;
|
||||
}
|
||||
|
||||
if ( !strnicmp(op->get_para.scaling_governor,
|
||||
"ondemand", CPUFREQ_NAME_LEN) )
|
||||
{
|
||||
ret = get_cpufreq_ondemand_para(
|
||||
&op->get_para.u.ondemand.sampling_rate_max,
|
||||
&op->get_para.u.ondemand.sampling_rate_min,
|
||||
&op->get_para.u.ondemand.sampling_rate,
|
||||
&op->get_para.u.ondemand.up_threshold);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_cpufreq_gov(struct xen_sysctl_pm_op *op)
|
||||
{
|
||||
struct cpufreq_policy new_policy, *old_policy;
|
||||
|
||||
if ( !op || !cpu_online(op->cpuid) )
|
||||
return -EINVAL;
|
||||
|
||||
old_policy = cpufreq_cpu_policy[op->cpuid];
|
||||
if ( !old_policy )
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(&new_policy, old_policy, sizeof(struct cpufreq_policy));
|
||||
|
||||
new_policy.governor = __find_governor(op->set_gov.scaling_governor);
|
||||
if (new_policy.governor == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return __cpufreq_set_policy(old_policy, &new_policy);
|
||||
}
|
||||
|
||||
static int set_cpufreq_para(struct xen_sysctl_pm_op *op)
|
||||
{
|
||||
int ret = 0;
|
||||
struct cpufreq_policy *policy;
|
||||
|
||||
if ( !op || !cpu_online(op->cpuid) )
|
||||
return -EINVAL;
|
||||
policy = cpufreq_cpu_policy[op->cpuid];
|
||||
|
||||
if ( !policy || !policy->governor )
|
||||
return -EINVAL;
|
||||
|
||||
switch(op->set_para.ctrl_type)
|
||||
{
|
||||
case SCALING_MAX_FREQ:
|
||||
{
|
||||
struct cpufreq_policy new_policy;
|
||||
|
||||
memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
|
||||
new_policy.max = op->set_para.ctrl_value;
|
||||
ret = __cpufreq_set_policy(policy, &new_policy);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SCALING_MIN_FREQ:
|
||||
{
|
||||
struct cpufreq_policy new_policy;
|
||||
|
||||
memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
|
||||
new_policy.min = op->set_para.ctrl_value;
|
||||
ret = __cpufreq_set_policy(policy, &new_policy);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SCALING_SETSPEED:
|
||||
{
|
||||
unsigned int freq =op->set_para.ctrl_value;
|
||||
|
||||
if ( !strnicmp(policy->governor->name,
|
||||
"userspace", CPUFREQ_NAME_LEN) )
|
||||
{
|
||||
if ( freq < policy->min )
|
||||
freq = policy->min;
|
||||
if ( freq > policy->max )
|
||||
freq = policy->max;
|
||||
|
||||
ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L);
|
||||
}
|
||||
else
|
||||
ret = -EINVAL;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SAMPLING_RATE:
|
||||
{
|
||||
unsigned int sampling_rate = op->set_para.ctrl_value;
|
||||
|
||||
if ( !strnicmp(policy->governor->name,
|
||||
"ondemand", CPUFREQ_NAME_LEN) )
|
||||
ret = write_ondemand_sampling_rate(sampling_rate);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case UP_THRESHOLD:
|
||||
{
|
||||
unsigned int up_threshold = op->set_para.ctrl_value;
|
||||
|
||||
if ( !strnicmp(policy->governor->name,
|
||||
"ondemand", CPUFREQ_NAME_LEN) )
|
||||
ret = write_ondemand_up_threshold(up_threshold);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int do_pm_op(struct xen_sysctl_pm_op *op)
|
||||
{
|
||||
int ret = 0;
|
||||
const struct processor_pminfo *pmpt;
|
||||
|
||||
if ( !op || !cpu_online(op->cpuid) )
|
||||
return -EINVAL;
|
||||
pmpt = processor_pminfo[op->cpuid];
|
||||
|
||||
switch ( op->cmd & PM_PARA_CATEGORY_MASK )
|
||||
{
|
||||
case CPUFREQ_PARA:
|
||||
if ( !(xen_processor_pmbits & XEN_PROCESSOR_PM_PX) )
|
||||
return -ENODEV;
|
||||
if ( !pmpt || !(pmpt->perf.init & XEN_PX_INIT) )
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
switch ( op->cmd )
|
||||
{
|
||||
case GET_CPUFREQ_PARA:
|
||||
{
|
||||
ret = get_cpufreq_para(op);
|
||||
break;
|
||||
}
|
||||
|
||||
case SET_CPUFREQ_GOV:
|
||||
{
|
||||
ret = set_cpufreq_gov(op);
|
||||
break;
|
||||
}
|
||||
|
||||
case SET_CPUFREQ_PARA:
|
||||
{
|
||||
ret = set_cpufreq_para(op);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
printk("not defined sub-hypercall @ do_pm_op\n");
|
||||
ret = -ENOSYS;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -53,9 +53,9 @@ struct cpufreq_dom {
|
||||
};
|
||||
static LIST_HEAD(cpufreq_dom_list_head);
|
||||
|
||||
static LIST_HEAD(cpufreq_governor_list);
|
||||
LIST_HEAD(cpufreq_governor_list);
|
||||
|
||||
static struct cpufreq_governor *__find_governor(const char *governor)
|
||||
struct cpufreq_governor *__find_governor(const char *governor)
|
||||
{
|
||||
struct cpufreq_governor *t;
|
||||
|
||||
|
||||
@@ -51,12 +51,50 @@ static struct dbs_tuners {
|
||||
unsigned int up_threshold;
|
||||
unsigned int powersave_bias;
|
||||
} dbs_tuners_ins = {
|
||||
.sampling_rate = 0,
|
||||
.up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
|
||||
.powersave_bias = 0,
|
||||
};
|
||||
|
||||
static struct timer dbs_timer[NR_CPUS];
|
||||
|
||||
int write_ondemand_sampling_rate(unsigned int sampling_rate)
|
||||
{
|
||||
if ( (sampling_rate > MAX_SAMPLING_RATE / MICROSECS(1)) ||
|
||||
(sampling_rate < MIN_SAMPLING_RATE / MICROSECS(1)) )
|
||||
return -EINVAL;
|
||||
|
||||
dbs_tuners_ins.sampling_rate = sampling_rate * MICROSECS(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_ondemand_up_threshold(unsigned int up_threshold)
|
||||
{
|
||||
if ( (up_threshold > MAX_FREQUENCY_UP_THRESHOLD) ||
|
||||
(up_threshold < MIN_FREQUENCY_UP_THRESHOLD) )
|
||||
return -EINVAL;
|
||||
|
||||
dbs_tuners_ins.up_threshold = up_threshold;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_cpufreq_ondemand_para(uint32_t *sampling_rate_max,
|
||||
uint32_t *sampling_rate_min,
|
||||
uint32_t *sampling_rate,
|
||||
uint32_t *up_threshold)
|
||||
{
|
||||
if (!sampling_rate_max || !sampling_rate_min ||
|
||||
!sampling_rate || !up_threshold)
|
||||
return -EINVAL;
|
||||
|
||||
*sampling_rate_max = MAX_SAMPLING_RATE/MICROSECS(1);
|
||||
*sampling_rate_min = MIN_SAMPLING_RATE/MICROSECS(1);
|
||||
*sampling_rate = dbs_tuners_ins.sampling_rate / MICROSECS(1);
|
||||
*up_threshold = dbs_tuners_ins.up_threshold;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t get_cpu_idle_time(unsigned int cpu)
|
||||
{
|
||||
uint64_t idle_ns;
|
||||
@@ -214,7 +252,7 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, unsigned int event)
|
||||
* Start the timerschedule work, when this governor
|
||||
* is used for first time
|
||||
*/
|
||||
if (dbs_enable == 1) {
|
||||
if ((dbs_enable == 1) && !dbs_tuners_ins.sampling_rate) {
|
||||
def_sampling_rate = policy->cpuinfo.transition_latency *
|
||||
DEF_SAMPLING_RATE_LATENCY_MULTIPLIER;
|
||||
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
|
||||
#include "processor_perf.h"
|
||||
|
||||
#define CPUFREQ_NAME_LEN 16
|
||||
|
||||
struct cpufreq_governor;
|
||||
|
||||
struct acpi_cpufreq_data {
|
||||
@@ -88,9 +86,14 @@ struct cpufreq_governor {
|
||||
};
|
||||
|
||||
extern struct cpufreq_governor cpufreq_gov_dbs;
|
||||
extern struct cpufreq_governor cpufreq_gov_userspace;
|
||||
extern struct cpufreq_governor cpufreq_gov_performance;
|
||||
extern struct cpufreq_governor cpufreq_gov_powersave;
|
||||
|
||||
extern int cpufreq_register_governor(struct cpufreq_governor *governor);
|
||||
extern int cpufreq_unregister_governor(struct cpufreq_governor *governor);
|
||||
#define CPUFREQ_DEFAULT_GOVERNOR &cpufreq_gov_dbs
|
||||
extern struct cpufreq_governor *__find_governor(const char *governor);
|
||||
#define CPUFREQ_DEFAULT_GOVERNOR &cpufreq_gov_performance
|
||||
|
||||
/* pass a target to the cpufreq driver */
|
||||
extern int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
||||
@@ -113,6 +116,7 @@ __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event)
|
||||
#define CPUFREQ_RELATION_H 1 /* highest frequency below or at target */
|
||||
|
||||
struct cpufreq_driver {
|
||||
char name[CPUFREQ_NAME_LEN];
|
||||
int (*init)(struct cpufreq_policy *policy);
|
||||
int (*verify)(struct cpufreq_policy *policy);
|
||||
int (*target)(struct cpufreq_policy *policy,
|
||||
@@ -210,3 +214,9 @@ struct cpu_dbs_info_s {
|
||||
};
|
||||
|
||||
int cpufreq_governor_dbs(struct cpufreq_policy *policy, unsigned int event);
|
||||
int get_cpufreq_ondemand_para(uint32_t *sampling_rate_max,
|
||||
uint32_t *sampling_rate_min,
|
||||
uint32_t *sampling_rate,
|
||||
uint32_t *up_threshold);
|
||||
int write_ondemand_sampling_rate(unsigned int sampling_rate);
|
||||
int write_ondemand_up_threshold(unsigned int up_threshold);
|
||||
@@ -273,6 +273,91 @@ struct xen_sysctl_cpu_hotplug {
|
||||
typedef struct xen_sysctl_cpu_hotplug xen_sysctl_cpu_hotplug_t;
|
||||
DEFINE_XEN_GUEST_HANDLE(xen_sysctl_cpu_hotplug_t);
|
||||
|
||||
/*
|
||||
* Get/set xen power management, include
|
||||
* 1. cpufreq governors and related parameters
|
||||
*/
|
||||
#define XEN_SYSCTL_pm_op 12
|
||||
struct xen_userspace {
|
||||
uint32_t scaling_setspeed;
|
||||
};
|
||||
typedef struct xen_userspace xen_userspace_t;
|
||||
|
||||
struct xen_ondemand {
|
||||
uint32_t sampling_rate_max;
|
||||
uint32_t sampling_rate_min;
|
||||
|
||||
uint32_t sampling_rate;
|
||||
uint32_t up_threshold;
|
||||
};
|
||||
typedef struct xen_ondemand xen_ondemand_t;
|
||||
|
||||
/*
|
||||
* cpufreq para name of this structure named
|
||||
* same as sysfs file name of native linux
|
||||
*/
|
||||
#define CPUFREQ_NAME_LEN 16
|
||||
struct xen_get_cpufreq_para {
|
||||
/* IN/OUT variable */
|
||||
uint32_t cpu_num;
|
||||
uint32_t freq_num;
|
||||
uint32_t gov_num;
|
||||
|
||||
/* for all governors */
|
||||
/* OUT variable */
|
||||
XEN_GUEST_HANDLE_64(uint32) affected_cpus;
|
||||
XEN_GUEST_HANDLE_64(uint32) scaling_available_frequencies;
|
||||
XEN_GUEST_HANDLE_64(char) scaling_available_governors;
|
||||
char scaling_driver[CPUFREQ_NAME_LEN];
|
||||
|
||||
uint32_t cpuinfo_cur_freq;
|
||||
uint32_t cpuinfo_max_freq;
|
||||
uint32_t cpuinfo_min_freq;
|
||||
uint32_t scaling_cur_freq;
|
||||
|
||||
char scaling_governor[CPUFREQ_NAME_LEN];
|
||||
uint32_t scaling_max_freq;
|
||||
uint32_t scaling_min_freq;
|
||||
|
||||
/* for specific governor */
|
||||
union {
|
||||
struct xen_userspace userspace;
|
||||
struct xen_ondemand ondemand;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct xen_set_cpufreq_gov {
|
||||
char scaling_governor[CPUFREQ_NAME_LEN];
|
||||
};
|
||||
|
||||
struct xen_set_cpufreq_para {
|
||||
#define SCALING_MAX_FREQ 1
|
||||
#define SCALING_MIN_FREQ 2
|
||||
#define SCALING_SETSPEED 3
|
||||
#define SAMPLING_RATE 4
|
||||
#define UP_THRESHOLD 5
|
||||
|
||||
uint32_t ctrl_type;
|
||||
uint32_t ctrl_value;
|
||||
};
|
||||
|
||||
struct xen_sysctl_pm_op {
|
||||
#define PM_PARA_CATEGORY_MASK 0xf0
|
||||
#define CPUFREQ_PARA 0x10
|
||||
|
||||
/* cpufreq command type */
|
||||
#define GET_CPUFREQ_PARA (CPUFREQ_PARA | 0x01)
|
||||
#define SET_CPUFREQ_GOV (CPUFREQ_PARA | 0x02)
|
||||
#define SET_CPUFREQ_PARA (CPUFREQ_PARA | 0x03)
|
||||
|
||||
uint32_t cmd;
|
||||
uint32_t cpuid;
|
||||
union {
|
||||
struct xen_get_cpufreq_para get_para;
|
||||
struct xen_set_cpufreq_gov set_gov;
|
||||
struct xen_set_cpufreq_para set_para;
|
||||
};
|
||||
};
|
||||
|
||||
struct xen_sysctl {
|
||||
uint32_t cmd;
|
||||
@@ -289,6 +374,7 @@ struct xen_sysctl {
|
||||
struct xen_sysctl_availheap availheap;
|
||||
struct xen_sysctl_get_pmstat get_pmstat;
|
||||
struct xen_sysctl_cpu_hotplug cpu_hotplug;
|
||||
struct xen_sysctl_pm_op pm_op;
|
||||
uint8_t pad[128];
|
||||
} u;
|
||||
};
|
||||
|
||||