All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 2] Add user PM control interface
@ 2008-12-10  8:46 Liu, Jinsong
  2008-12-10  9:08 ` Jan Beulich
  0 siblings, 1 reply; 7+ messages in thread
From: Liu, Jinsong @ 2008-12-10  8:46 UTC (permalink / raw)
  To: xen-devel@lists.xensource.com; +Cc: Keir Fraser

[-- Attachment #1: Type: text/plain, Size: 1111 bytes --]

Add user PM control interface

This patch provide user PM control interface.
Now it only implements cpufreq related interface.

User can use libxc to get cpufreq parameters:
1. common parameter independent on cpufreq governor
    affected_cpus;
    scaling_available_frequencies;
    scaling_available_governors;
    scaling_driver;
    cpuinfo_cur_freq;
    cpuinfo_max_freq;
    cpuinfo_min_freq;
    scaling_max_freq;
    scaling_min_freq;
    scaling_governor
2. parameters depend on specific governor:
    userspace governor: scaling_setspeed;
    ondemand governor:  sampling_rate_max;
                        sampling_rate_min;
                        sampling_rate;
                        up_threshold;

User can also set cpufreq control parameters:
1. common control parameters:
    scaling_governor;
    scaling_max_freq;
    scaling_min_freq;
2. control parameters depend on specific governor:
    userspace governor: scaling_setspeed;
    ondemand governor:  sampling_rate;
                        up_threshold;

Signed-off-by: Liu, Jinsong <jinsong.liu@intel.com>

[-- Attachment #2: px-2-control-interface.patch --]
[-- Type: application/octet-stream, Size: 26419 bytes --]

Add user PM control interface

This patch provide user PM control interface.
Now it only implements cpufreq related interface.

User can use libxc to get cpufreq parameters:
1. common parameter independent on cpufreq governor
    affected_cpus;
    scaling_available_frequencies;
    scaling_available_governors;
    scaling_driver;
    cpuinfo_cur_freq;
    cpuinfo_max_freq;
    cpuinfo_min_freq;
    scaling_max_freq;
    scaling_min_freq;
    scaling_governor
2. parameters depend on specific governor:
    userspace governor: scaling_setspeed;
    ondemand governor:  sampling_rate_max;
                        sampling_rate_min;
                        sampling_rate;
                        up_threshold;

User can also set cpufreq control parameters:
1. common control parameters:
    scaling_governor;
    scaling_max_freq;
    scaling_min_freq;
2. control parameters depend on specific governor:
    userspace governor: scaling_setspeed;
    ondemand governor:  sampling_rate;
                        up_threshold;

Signed-off-by: Liu, Jinsong <jinsong.liu@intel.com>

diff -r 483fce3f5183 tools/libxc/xc_pm.c
--- a/tools/libxc/xc_pm.c	Wed Dec 10 11:28:50 2008 +0800
+++ b/tools/libxc/xc_pm.c	Wed Dec 10 16:16:53 2008 +0800
@@ -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, in
 
     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);
+}
diff -r 483fce3f5183 tools/libxc/xenctrl.h
--- a/tools/libxc/xenctrl.h	Wed Dec 10 11:28:50 2008 +0800
+++ b/tools/libxc/xenctrl.h	Wed Dec 10 16:16:53 2008 +0800
@@ -1161,4 +1161,46 @@ int xc_pm_reset_cxstat(int xc_handle, in
 
 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 */
diff -r 483fce3f5183 xen/arch/ia64/xen/cpufreq/cpufreq.c
--- a/xen/arch/ia64/xen/cpufreq/cpufreq.c	Wed Dec 10 11:28:50 2008 +0800
+++ b/xen/arch/ia64/xen/cpufreq/cpufreq.c	Wed Dec 10 16:16:53 2008 +0800
@@ -275,6 +275,7 @@ acpi_cpufreq_cpu_exit (struct cpufreq_po
 }
 
 static struct cpufreq_driver acpi_cpufreq_driver = {
+	.name       = "acpi-cpufreq",
 	.verify     = acpi_cpufreq_verify,
 	.target     = acpi_cpufreq_target,
 	.get        = acpi_cpufreq_get,
diff -r 483fce3f5183 xen/arch/x86/acpi/cpufreq/cpufreq.c
--- a/xen/arch/x86/acpi/cpufreq/cpufreq.c	Wed Dec 10 11:28:50 2008 +0800
+++ b/xen/arch/x86/acpi/cpufreq/cpufreq.c	Wed Dec 10 16:16:53 2008 +0800
@@ -549,6 +549,7 @@ static int acpi_cpufreq_cpu_exit(struct 
 }
 
 static struct cpufreq_driver acpi_cpufreq_driver = {
+    .name   = "acpi-cpufreq",
     .verify = acpi_cpufreq_verify,
     .target = acpi_cpufreq_target,
     .init   = acpi_cpufreq_cpu_init,
diff -r 483fce3f5183 xen/common/sysctl.c
--- a/xen/common/sysctl.c	Wed Dec 10 11:28:50 2008 +0800
+++ b/xen/common/sysctl.c	Wed Dec 10 16:16:53 2008 +0800
@@ -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_sysc
     }
     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;
diff -r 483fce3f5183 xen/drivers/acpi/pmstat.c
--- a/xen/drivers/acpi/pmstat.c	Wed Dec 10 11:28:50 2008 +0800
+++ b/xen/drivers/acpi/pmstat.c	Wed Dec 10 16:16:53 2008 +0800
@@ -47,6 +47,11 @@ extern int pmstat_get_cx_stat(uint32_t c
 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
 
     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;
+}
diff -r 483fce3f5183 xen/drivers/cpufreq/cpufreq.c
--- a/xen/drivers/cpufreq/cpufreq.c	Wed Dec 10 11:28:50 2008 +0800
+++ b/xen/drivers/cpufreq/cpufreq.c	Wed Dec 10 16:16:53 2008 +0800
@@ -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;
 
diff -r 483fce3f5183 xen/drivers/cpufreq/cpufreq_ondemand.c
--- a/xen/drivers/cpufreq/cpufreq_ondemand.c	Wed Dec 10 11:28:50 2008 +0800
+++ b/xen/drivers/cpufreq/cpufreq_ondemand.c	Wed Dec 10 16:16:53 2008 +0800
@@ -51,11 +51,49 @@ 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)
 {
@@ -214,7 +252,7 @@ int cpufreq_governor_dbs(struct cpufreq_
          * 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;
 
diff -r 483fce3f5183 xen/include/acpi/cpufreq/cpufreq.h
--- a/xen/include/acpi/cpufreq/cpufreq.h	Wed Dec 10 11:28:50 2008 +0800
+++ b/xen/include/acpi/cpufreq/cpufreq.h	Wed Dec 10 16:16:53 2008 +0800
@@ -16,8 +16,6 @@
 #include <xen/cpumask.h>
 
 #include "processor_perf.h"
-
-#define CPUFREQ_NAME_LEN 16
 
 struct cpufreq_governor;
 
@@ -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
 #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);
diff -r 483fce3f5183 xen/include/public/sysctl.h
--- a/xen/include/public/sysctl.h	Wed Dec 10 11:28:50 2008 +0800
+++ b/xen/include/public/sysctl.h	Wed Dec 10 16:16:53 2008 +0800
@@ -273,6 +273,91 @@ typedef struct xen_sysctl_cpu_hotplug xe
 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;
 };

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2] Add user PM control interface
  2008-12-10  8:46 [PATCH 2] Add user PM control interface Liu, Jinsong
@ 2008-12-10  9:08 ` Jan Beulich
  2008-12-10 10:04   ` Keir Fraser
  0 siblings, 1 reply; 7+ messages in thread
From: Jan Beulich @ 2008-12-10  9:08 UTC (permalink / raw)
  To: Jinsong Liu; +Cc: xen-devel@lists.xensource.com, Keir Fraser

Was this coordinated with whoever maintains general power management
tools on the Linux side? It would seem to me that adding this stuff to the
sysctl interface is nice only from a pure Xen perspective. With the general
rule of the kernel not supposed to use domctl and sysctl interfaces, it
would mean that these tools have to use a completely distinct code path
to handle the Xen case, whereas when this information was readily
accessible to the Dom0 kernel, it could mimic the standard sysfs interface
for the tools to use (with just the change that they need to be prepared
to find more CPUs there than the kernel reports it is running on).

Jan

>>> "Liu, Jinsong" <jinsong.liu@intel.com> 10.12.08 09:46 >>>
Add user PM control interface

This patch provide user PM control interface.
Now it only implements cpufreq related interface.

User can use libxc to get cpufreq parameters:
1. common parameter independent on cpufreq governor
    affected_cpus;
    scaling_available_frequencies;
    scaling_available_governors;
    scaling_driver;
    cpuinfo_cur_freq;
    cpuinfo_max_freq;
    cpuinfo_min_freq;
    scaling_max_freq;
    scaling_min_freq;
    scaling_governor
2. parameters depend on specific governor:
    userspace governor: scaling_setspeed;
    ondemand governor:  sampling_rate_max;
                        sampling_rate_min;
                        sampling_rate;
                        up_threshold;

User can also set cpufreq control parameters:
1. common control parameters:
    scaling_governor;
    scaling_max_freq;
    scaling_min_freq;
2. control parameters depend on specific governor:
    userspace governor: scaling_setspeed;
    ondemand governor:  sampling_rate;
                        up_threshold;

Signed-off-by: Liu, Jinsong <jinsong.liu@intel.com>

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2] Add user PM control interface
  2008-12-10  9:08 ` Jan Beulich
@ 2008-12-10 10:04   ` Keir Fraser
  2008-12-10 10:06     ` Keir Fraser
  2008-12-10 10:32     ` Keir Fraser
  0 siblings, 2 replies; 7+ messages in thread
From: Keir Fraser @ 2008-12-10 10:04 UTC (permalink / raw)
  To: Jan Beulich, Jinsong Liu; +Cc: xen-devel@lists.xensource.com

The only reason for dom0 kernel not to use domctl/sysctl is that the
structures may be subject to change. So if you do, then the dom0 kernel in
that case becomes part of the 'matched set' with Xen itself and the tools.
As a distributor of 'whole system' software, you may not actually care about
this limitation (since you can track dependencies and easily cause all
packages to be upgraded)?

Adding some domctl/sysctl usage in the Linux kernel would actually be fine
by me, except that I do think it should be conditional on a Kconfig option
that makes the above additional constraint very clear to the user.

And actually, I don't think we've broken sysctl/domctl compatibility, or
changed their ABI version numbers, at all recently.

Personally I don't really care about support of the usual Linux pm tools,
since I suspect they will suffer from not taking into account whole system
activity rather than merely dom0 activity. But perhaps we have an acceptable
middle ground here?

 -- Keir

On 10/12/2008 09:08, "Jan Beulich" <jbeulich@novell.com> wrote:

> Was this coordinated with whoever maintains general power management
> tools on the Linux side? It would seem to me that adding this stuff to the
> sysctl interface is nice only from a pure Xen perspective. With the general
> rule of the kernel not supposed to use domctl and sysctl interfaces, it
> would mean that these tools have to use a completely distinct code path
> to handle the Xen case, whereas when this information was readily
> accessible to the Dom0 kernel, it could mimic the standard sysfs interface
> for the tools to use (with just the change that they need to be prepared
> to find more CPUs there than the kernel reports it is running on).
> 
> Jan
> 
>>>> "Liu, Jinsong" <jinsong.liu@intel.com> 10.12.08 09:46 >>>
> Add user PM control interface
> 
> This patch provide user PM control interface.
> Now it only implements cpufreq related interface.
> 
> User can use libxc to get cpufreq parameters:
> 1. common parameter independent on cpufreq governor
>     affected_cpus;
>     scaling_available_frequencies;
>     scaling_available_governors;
>     scaling_driver;
>     cpuinfo_cur_freq;
>     cpuinfo_max_freq;
>     cpuinfo_min_freq;
>     scaling_max_freq;
>     scaling_min_freq;
>     scaling_governor
> 2. parameters depend on specific governor:
>     userspace governor: scaling_setspeed;
>     ondemand governor:  sampling_rate_max;
>                         sampling_rate_min;
>                         sampling_rate;
>                         up_threshold;
> 
> User can also set cpufreq control parameters:
> 1. common control parameters:
>     scaling_governor;
>     scaling_max_freq;
>     scaling_min_freq;
> 2. control parameters depend on specific governor:
>     userspace governor: scaling_setspeed;
>     ondemand governor:  sampling_rate;
>                         up_threshold;
> 
> Signed-off-by: Liu, Jinsong <jinsong.liu@intel.com>
> 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2] Add user PM control interface
  2008-12-10 10:04   ` Keir Fraser
@ 2008-12-10 10:06     ` Keir Fraser
  2008-12-10 10:32     ` Keir Fraser
  1 sibling, 0 replies; 7+ messages in thread
From: Keir Fraser @ 2008-12-10 10:06 UTC (permalink / raw)
  To: Jan Beulich, Jinsong Liu; +Cc: xen-devel@lists.xensource.com

On 10/12/2008 10:04, "Keir Fraser" <keir.fraser@eu.citrix.com> wrote:

> Adding some domctl/sysctl usage in the Linux kernel would actually be fine
> by me, except that I do think it should be conditional on a Kconfig option
> that makes the above additional constraint very clear to the user.

Oh, another thing would be that, since this at least initially would be used
only for passthrough of info to userspace, the kernel could gracefully
disable this feature if not executed on a compatible Xen version.

 -- Keir

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2] Add user PM control interface
  2008-12-10 10:04   ` Keir Fraser
  2008-12-10 10:06     ` Keir Fraser
@ 2008-12-10 10:32     ` Keir Fraser
  2008-12-10 10:41       ` Jan Beulich
  1 sibling, 1 reply; 7+ messages in thread
From: Keir Fraser @ 2008-12-10 10:32 UTC (permalink / raw)
  To: Keir Fraser, Jan Beulich, Jinsong Liu; +Cc: xen-devel@lists.xensource.com

On 10/12/2008 10:04, "Keir Fraser" <keir.fraser@eu.citrix.com> wrote:

> The only reason for dom0 kernel not to use domctl/sysctl is that the
> structures may be subject to change. So if you do, then the dom0 kernel in
> that case becomes part of the 'matched set' with Xen itself and the tools.
> As a distributor of 'whole system' software, you may not actually care about
> this limitation (since you can track dependencies and easily cause all
> packages to be upgraded)?
> 
> Adding some domctl/sysctl usage in the Linux kernel would actually be fine
> by me, except that I do think it should be conditional on a Kconfig option
> that makes the above additional constraint very clear to the user.
> 
> And actually, I don't think we've broken sysctl/domctl compatibility, or
> changed their ABI version numbers, at all recently.

Thinking some more, this doesn't work well unless we start guaranteeing
source compatibility at least... Perhaps it's time now to make stronger
guarantees about the domctl and sysctl interfaces.

Really in this case it depends: is support for Linux pm tools going to be
practically useful, especially in the general cases such as #dom0-cpus !=
#physical-cpus? It does seem a bit dubious to me.

 -- Keir

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2] Add user PM control interface
  2008-12-10 10:32     ` Keir Fraser
@ 2008-12-10 10:41       ` Jan Beulich
  2008-12-10 13:08         ` Tian, Kevin
  0 siblings, 1 reply; 7+ messages in thread
From: Jan Beulich @ 2008-12-10 10:41 UTC (permalink / raw)
  To: Keir Fraser, Jinsong Liu; +Cc: xen-devel@lists.xensource.com

>>> Keir Fraser <keir.fraser@eu.citrix.com> 10.12.08 11:32 >>>
>Really in this case it depends: is support for Linux pm tools going to be
>practically useful, especially in the general cases such as #dom0-cpus !=
>#physical-cpus? It does seem a bit dubious to me.

I'm not certain either, which is why I asked whether this was sync-ed with
the maintainers of these tools.

Jan

^ permalink raw reply	[flat|nested] 7+ messages in thread

* RE: [PATCH 2] Add user PM control interface
  2008-12-10 10:41       ` Jan Beulich
@ 2008-12-10 13:08         ` Tian, Kevin
  0 siblings, 0 replies; 7+ messages in thread
From: Tian, Kevin @ 2008-12-10 13:08 UTC (permalink / raw)
  To: 'Jan Beulich', Keir Fraser, Liu, Jinsong
  Cc: xen-devel@lists.xensource.com

>From: Jan Beulich
>Sent: Wednesday, December 10, 2008 6:41 PM
>
>>>> Keir Fraser <keir.fraser@eu.citrix.com> 10.12.08 11:32 >>>
>>Really in this case it depends: is support for Linux pm tools 
>going to be
>>practically useful, especially in the general cases such as 
>#dom0-cpus !=
>>#physical-cpus? It does seem a bit dubious to me.
>
>I'm not certain either, which is why I asked whether this was 
>sync-ed with
>the maintainers of these tools.
>

I don't think supporting linux pm tools an easy work, or even
a sane stuff:

First, dom0 doesn't have global view to whole system. For example,
PowerTOP relies on /proc/interrupts to count for break event
summary. Then you need tweak that interface to include irqs
owned by Xen and other domains, and update its status when
it's opened for read. More important is, I don't think every device
owned by xen/domU can find a placeholder within dom0's 
namespace, considering current per-domain pirq, or in future 
maybe per-cpu local vector allocation. Even that's viable, finally
it'd be still preferred to have some virtualization aware concept
e.g. to report a more informative result like which domains 
contribute how many break events instead of a raw information.

Then, It's a mess to mix cpu nodes between those available
to dom0 and other nodes which are only placeholder to carry
physical cpu attribute. Especially for those combining both
purposes, for example, some attributes under cpu0 node is 
for dom0's vcpu0 and others for physical cpu0. You have to
disable existing linux stuff in case contending for same attribute, and
those lines may be not a single module and then you need
add condition check into those common files. Also it's possible
for user request failed to reach xen specific driver, due to some
higher level check on vcpu existence. 

IOW, I'm inclined to think in future virtualization specific pm tool
would be more useful, which acquire hypervisor pm stats directly
and then can show a more informative picture to user. That said,
I'd like to see current domctl/sysctl approach as the base for
subsequent pm area development. Xenpm is the only user on
those interface by far, which can be a good example for more 
advanced pm tools since we already provide equivalent control
knobs as linux side. People can try to support linux pm tools by
tweaking dom0 kernel, but current approach is the base anyway.

Thanks,
Kevin

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2008-12-10 13:08 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-12-10  8:46 [PATCH 2] Add user PM control interface Liu, Jinsong
2008-12-10  9:08 ` Jan Beulich
2008-12-10 10:04   ` Keir Fraser
2008-12-10 10:06     ` Keir Fraser
2008-12-10 10:32     ` Keir Fraser
2008-12-10 10:41       ` Jan Beulich
2008-12-10 13:08         ` Tian, Kevin

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.