[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [RFC PATCH 03/31] pmstat: move pmstat.c file to the xen/drivers/pm/stat.c location



On Thu, 9 Nov 2017, Oleksandr Tyshchenko wrote:
> From: Oleksandr Dmytryshyn <oleksandr.dmytryshyn@xxxxxxxxxxxxxxx>
> 
> Cpufreq driver should be more generalizable (not ACPI-specific).
> Thus this file should be placed to more convenient location.
> 
> This is a rebased version of the original patch:
> https://lists.xen.org/archives/html/xen-devel/2014-11/msg00935.html
> 
> Signed-off-by: Oleksandr Dmytryshyn <oleksandr.dmytryshyn@xxxxxxxxxxxxxxx>
> Signed-off-by: Oleksandr Tyshchenko <oleksandr_tyshchenko@xxxxxxxx>
> CC: Jan Beulich <jbeulich@xxxxxxxx>
> CC: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
> CC: Stefano Stabellini <sstabellini@xxxxxxxxxx>
> CC: Julien Grall <julien.grall@xxxxxxxxxx>

Reviewed-by: Stefano Stabellini <sstabellini@xxxxxxxxxx>


> ---
>  MAINTAINERS               |   1 +
>  xen/arch/x86/Kconfig      |   1 +
>  xen/common/sysctl.c       |   2 +-
>  xen/drivers/Kconfig       |   2 +
>  xen/drivers/Makefile      |   1 +
>  xen/drivers/acpi/Makefile |   1 -
>  xen/drivers/acpi/pmstat.c | 526 
> ----------------------------------------------
>  xen/drivers/pm/Kconfig    |   3 +
>  xen/drivers/pm/Makefile   |   1 +
>  xen/drivers/pm/stat.c     | 526 
> ++++++++++++++++++++++++++++++++++++++++++++++
>  10 files changed, 536 insertions(+), 528 deletions(-)
>  delete mode 100644 xen/drivers/acpi/pmstat.c
>  create mode 100644 xen/drivers/pm/Kconfig
>  create mode 100644 xen/drivers/pm/Makefile
>  create mode 100644 xen/drivers/pm/stat.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 9794a81..87ade6f 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -294,6 +294,7 @@ F:        xen/arch/x86/acpi/
>  X:   xen/arch/x86/acpi/boot.c
>  X:   xen/arch/x86/acpi/lib.c
>  F:   xen/drivers/cpufreq/
> +F:   xen/drivers/pm/
>  F:   xen/include/xen/cpufreq.h
>  F:   xen/include/xen/processor_perf.h
>  
> diff --git a/xen/arch/x86/Kconfig b/xen/arch/x86/Kconfig
> index 30c2769..86c8eca 100644
> --- a/xen/arch/x86/Kconfig
> +++ b/xen/arch/x86/Kconfig
> @@ -23,6 +23,7 @@ config X86
>       select HAS_PDX
>       select NUMA
>       select VGA
> +     select HAS_PM
>  
>  config ARCH_DEFCONFIG
>       string
> diff --git a/xen/common/sysctl.c b/xen/common/sysctl.c
> index a6882d1..ac96347 100644
> --- a/xen/common/sysctl.c
> +++ b/xen/common/sysctl.c
> @@ -171,7 +171,7 @@ long do_sysctl(XEN_GUEST_HANDLE_PARAM(xen_sysctl_t) 
> u_sysctl)
>          op->u.availheap.avail_bytes <<= PAGE_SHIFT;
>          break;
>  
> -#if defined (CONFIG_ACPI) && defined (CONFIG_HAS_CPUFREQ)
> +#if defined (CONFIG_HAS_PM) && defined (CONFIG_HAS_CPUFREQ)
>      case XEN_SYSCTL_get_pmstat:
>          ret = do_get_pm_info(&op->u.get_pmstat);
>          break;
> diff --git a/xen/drivers/Kconfig b/xen/drivers/Kconfig
> index bc3a54f..ddaec11 100644
> --- a/xen/drivers/Kconfig
> +++ b/xen/drivers/Kconfig
> @@ -12,4 +12,6 @@ source "drivers/pci/Kconfig"
>  
>  source "drivers/video/Kconfig"
>  
> +source "drivers/pm/Kconfig"
> +
>  endmenu
> diff --git a/xen/drivers/Makefile b/xen/drivers/Makefile
> index 1939180..dd0b496 100644
> --- a/xen/drivers/Makefile
> +++ b/xen/drivers/Makefile
> @@ -4,3 +4,4 @@ subdir-$(CONFIG_HAS_PCI) += pci
>  subdir-$(CONFIG_HAS_PASSTHROUGH) += passthrough
>  subdir-$(CONFIG_ACPI) += acpi
>  subdir-$(CONFIG_VIDEO) += video
> +subdir-$(CONFIG_HAS_PM) += pm
> diff --git a/xen/drivers/acpi/Makefile b/xen/drivers/acpi/Makefile
> index 444b11d..6f6470a 100644
> --- a/xen/drivers/acpi/Makefile
> +++ b/xen/drivers/acpi/Makefile
> @@ -5,7 +5,6 @@ subdir-$(CONFIG_X86) += apei
>  obj-bin-y += tables.init.o
>  obj-$(CONFIG_NUMA) += numa.o
>  obj-y += osl.o
> -obj-$(CONFIG_HAS_CPUFREQ) += pmstat.o
>  
>  obj-$(CONFIG_X86) += hwregs.o
>  obj-$(CONFIG_X86) += reboot.o
> diff --git a/xen/drivers/acpi/pmstat.c b/xen/drivers/acpi/pmstat.c
> deleted file mode 100644
> index 2dbde1c..0000000
> --- a/xen/drivers/acpi/pmstat.c
> +++ /dev/null
> @@ -1,526 +0,0 @@
> -/*****************************************************************************
> -#  pmstat.c - Power Management statistic information (Px/Cx/Tx, etc.)
> -#
> -#  Copyright (c) 2008, Liu Jinsong <jinsong.liu@xxxxxxxxx>
> -#
> -# This program is free software; you can redistribute it and/or modify it 
> -# under the terms of the GNU General Public License as published by the Free 
> -# Software Foundation; either version 2 of the License, or (at your option) 
> -# any later version.
> -#
> -# This program is distributed in the hope that it will be useful, but 
> WITHOUT 
> -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
> -# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
> -# more details.
> -#
> -# You should have received a copy of the GNU General Public License along 
> with
> -# this program; If not, see <http://www.gnu.org/licenses/>.
> -#
> -# The full GNU General Public License is included in this distribution in the
> -# file called LICENSE.
> -#
> -*****************************************************************************/
> -
> -#include <xen/lib.h>
> -#include <xen/errno.h>
> -#include <xen/sched.h>
> -#include <xen/event.h>
> -#include <xen/irq.h>
> -#include <xen/iocap.h>
> -#include <xen/compat.h>
> -#include <xen/guest_access.h>
> -#include <asm/current.h>
> -#include <public/xen.h>
> -#include <xen/cpumask.h>
> -#include <asm/processor.h>
> -#include <xen/percpu.h>
> -#include <xen/domain.h>
> -#include <xen/acpi.h>
> -
> -#include <public/sysctl.h>
> -#include <xen/cpufreq.h>
> -#include <xen/pmstat.h>
> -
> -DEFINE_PER_CPU_READ_MOSTLY(struct pm_px *, cpufreq_statistic_data);
> -
> -/*
> - * Get PM statistic info
> - */
> -int do_get_pm_info(struct xen_sysctl_get_pmstat *op)
> -{
> -    int ret = 0;
> -    const struct processor_pminfo *pmpt;
> -
> -    if ( !op || (op->cpuid >= nr_cpu_ids) || !cpu_online(op->cpuid) )
> -        return -EINVAL;
> -    pmpt = processor_pminfo[op->cpuid];
> -
> -    switch ( op->type & PMSTAT_CATEGORY_MASK )
> -    {
> -    case PMSTAT_CX:
> -        if ( !(xen_processor_pmbits & XEN_PROCESSOR_PM_CX) )
> -            return -ENODEV;
> -        break;
> -    case PMSTAT_PX:
> -        if ( !(xen_processor_pmbits & XEN_PROCESSOR_PM_PX) )
> -            return -ENODEV;
> -        if ( !cpufreq_driver )
> -            return -ENODEV;
> -        if ( !pmpt || !(pmpt->perf.init & XEN_PX_INIT) )
> -            return -EINVAL;
> -        break;
> -    default:
> -        return -ENODEV;
> -    }
> -
> -    switch ( op->type )
> -    {
> -    case PMSTAT_get_max_px:
> -    {
> -        op->u.getpx.total = pmpt->perf.state_count;
> -        break;
> -    }
> -
> -    case PMSTAT_get_pxstat:
> -    {
> -        uint32_t ct;
> -        struct pm_px *pxpt;
> -        spinlock_t *cpufreq_statistic_lock = 
> -                   &per_cpu(cpufreq_statistic_lock, op->cpuid);
> -
> -        spin_lock(cpufreq_statistic_lock);
> -
> -        pxpt = per_cpu(cpufreq_statistic_data, op->cpuid);
> -        if ( !pxpt || !pxpt->u.pt || !pxpt->u.trans_pt )
> -        {
> -            spin_unlock(cpufreq_statistic_lock);
> -            return -ENODATA;
> -        }
> -
> -        pxpt->u.usable = pmpt->perf.state_count - pmpt->perf.platform_limit;
> -
> -        cpufreq_residency_update(op->cpuid, pxpt->u.cur);
> -
> -        ct = pmpt->perf.state_count;
> -        if ( copy_to_guest(op->u.getpx.trans_pt, pxpt->u.trans_pt, ct*ct) )
> -        {
> -            spin_unlock(cpufreq_statistic_lock);
> -            ret = -EFAULT;
> -            break;
> -        }
> -
> -        if ( copy_to_guest(op->u.getpx.pt, pxpt->u.pt, ct) )
> -        {
> -            spin_unlock(cpufreq_statistic_lock);
> -            ret = -EFAULT;
> -            break;
> -        }
> -
> -        op->u.getpx.total = pxpt->u.total;
> -        op->u.getpx.usable = pxpt->u.usable;
> -        op->u.getpx.last = pxpt->u.last;
> -        op->u.getpx.cur = pxpt->u.cur;
> -
> -        spin_unlock(cpufreq_statistic_lock);
> -
> -        break;
> -    }
> -
> -    case PMSTAT_reset_pxstat:
> -    {
> -        cpufreq_statistic_reset(op->cpuid);
> -        break;
> -    }
> -
> -    case PMSTAT_get_max_cx:
> -    {
> -        op->u.getcx.nr = pmstat_get_cx_nr(op->cpuid);
> -        ret = 0;
> -        break;
> -    }
> -
> -    case PMSTAT_get_cxstat:
> -    {
> -        ret = pmstat_get_cx_stat(op->cpuid, &op->u.getcx);
> -        break;
> -    }
> -
> -    case PMSTAT_reset_cxstat:
> -    {
> -        ret = pmstat_reset_cx_stat(op->cpuid);
> -        break;
> -    }
> -
> -    default:
> -        printk("not defined sub-hypercall @ do_get_pm_info\n");
> -        ret = -ENOSYS;
> -        break;
> -    }
> -
> -    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;
> -
> -    pmpt = processor_pminfo[op->cpuid];
> -    policy = per_cpu(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->u.get_para.cpu_num  != cpumask_weight(policy->cpus)) ||
> -         (op->u.get_para.freq_num != pmpt->perf.state_count)    ||
> -         (op->u.get_para.gov_num  != gov_num) )
> -    {
> -        op->u.get_para.cpu_num =  cpumask_weight(policy->cpus);
> -        op->u.get_para.freq_num = pmpt->perf.state_count;
> -        op->u.get_para.gov_num  = gov_num;
> -        return -EAGAIN;
> -    }
> -
> -    if ( !(affected_cpus = xzalloc_array(uint32_t, op->u.get_para.cpu_num)) )
> -        return -ENOMEM;
> -    for_each_cpu(cpu, policy->cpus)
> -        affected_cpus[j++] = cpu;
> -    ret = copy_to_guest(op->u.get_para.affected_cpus,
> -                       affected_cpus, op->u.get_para.cpu_num);
> -    xfree(affected_cpus);
> -    if ( ret )
> -        return ret;
> -
> -    if ( !(scaling_available_frequencies =
> -           xzalloc_array(uint32_t, op->u.get_para.freq_num)) )
> -        return -ENOMEM;
> -    for ( i = 0; i < op->u.get_para.freq_num; i++ )
> -        scaling_available_frequencies[i] =
> -                        pmpt->perf.states[i].core_frequency * 1000;
> -    ret = copy_to_guest(op->u.get_para.scaling_available_frequencies,
> -                   scaling_available_frequencies, op->u.get_para.freq_num);
> -    xfree(scaling_available_frequencies);
> -    if ( ret )
> -        return ret;
> -
> -    if ( !(scaling_available_governors =
> -           xzalloc_array(char, gov_num * CPUFREQ_NAME_LEN)) )
> -        return -ENOMEM;
> -    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->u.get_para.scaling_available_governors,
> -                scaling_available_governors, gov_num * CPUFREQ_NAME_LEN);
> -    xfree(scaling_available_governors);
> -    if ( ret )
> -        return ret;
> -
> -    op->u.get_para.cpuinfo_cur_freq =
> -        cpufreq_driver->get ? cpufreq_driver->get(op->cpuid) : policy->cur;
> -    op->u.get_para.cpuinfo_max_freq = policy->cpuinfo.max_freq;
> -    op->u.get_para.cpuinfo_min_freq = policy->cpuinfo.min_freq;
> -    op->u.get_para.scaling_cur_freq = policy->cur;
> -    op->u.get_para.scaling_max_freq = policy->max;
> -    op->u.get_para.scaling_min_freq = policy->min;
> -
> -    if ( cpufreq_driver->name[0] )
> -        strlcpy(op->u.get_para.scaling_driver, 
> -            cpufreq_driver->name, CPUFREQ_NAME_LEN);
> -    else
> -        strlcpy(op->u.get_para.scaling_driver, "Unknown", CPUFREQ_NAME_LEN);
> -
> -    if ( policy->governor->name[0] )
> -        strlcpy(op->u.get_para.scaling_governor, 
> -            policy->governor->name, CPUFREQ_NAME_LEN);
> -    else
> -        strlcpy(op->u.get_para.scaling_governor, "Unknown", 
> CPUFREQ_NAME_LEN);
> -
> -    /* governor specific para */
> -    if ( !strnicmp(op->u.get_para.scaling_governor, 
> -                   "userspace", CPUFREQ_NAME_LEN) )
> -    {
> -        op->u.get_para.u.userspace.scaling_setspeed = policy->cur;
> -    }
> -
> -    if ( !strnicmp(op->u.get_para.scaling_governor, 
> -                   "ondemand", CPUFREQ_NAME_LEN) )
> -    {
> -        ret = get_cpufreq_ondemand_para(
> -            &op->u.get_para.u.ondemand.sampling_rate_max,
> -            &op->u.get_para.u.ondemand.sampling_rate_min,
> -            &op->u.get_para.u.ondemand.sampling_rate,
> -            &op->u.get_para.u.ondemand.up_threshold);
> -    }
> -    op->u.get_para.turbo_enabled = cpufreq_get_turbo_status(op->cpuid);
> -
> -    return ret;
> -}
> -
> -static int set_cpufreq_gov(struct xen_sysctl_pm_op *op)
> -{
> -    struct cpufreq_policy new_policy, *old_policy;
> -
> -    old_policy = per_cpu(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->u.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;
> -
> -    policy = per_cpu(cpufreq_cpu_policy, op->cpuid);
> -
> -    if ( !policy || !policy->governor )
> -        return -EINVAL;
> -
> -    switch(op->u.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->u.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->u.set_para.ctrl_value;
> -        ret = __cpufreq_set_policy(policy, &new_policy);
> -
> -        break;
> -    }
> -
> -    case SCALING_SETSPEED:
> -    {
> -        unsigned int freq =op->u.set_para.ctrl_value;
> -
> -        if ( !strnicmp(policy->governor->name,
> -                       "userspace", CPUFREQ_NAME_LEN) )
> -            ret = write_userspace_scaling_setspeed(op->cpuid, freq);
> -        else
> -            ret = -EINVAL;
> -
> -        break;
> -    }
> -
> -    case SAMPLING_RATE:
> -    {
> -        unsigned int sampling_rate = op->u.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->u.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 || op->cpuid >= nr_cpu_ids || !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;
> -    }
> -
> -    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;
> -    }
> -
> -    case GET_CPUFREQ_AVGFREQ:
> -    {
> -        op->u.get_avgfreq = cpufreq_driver_getavg(op->cpuid, USR_GETAVG);
> -        break;
> -    }
> -
> -    case XEN_SYSCTL_pm_op_set_sched_opt_smt:
> -    {
> -        uint32_t saved_value;
> -
> -        saved_value = sched_smt_power_savings;
> -        sched_smt_power_savings = !!op->u.set_sched_opt_smt;
> -        op->u.set_sched_opt_smt = saved_value;
> -
> -        break;
> -    }
> -
> -    case XEN_SYSCTL_pm_op_set_vcpu_migration_delay:
> -    {
> -        set_vcpu_migration_delay(op->u.set_vcpu_migration_delay);
> -        break;
> -    }
> -
> -    case XEN_SYSCTL_pm_op_get_vcpu_migration_delay:
> -    {
> -        op->u.get_vcpu_migration_delay = get_vcpu_migration_delay();
> -        break;
> -    }
> -
> -    case XEN_SYSCTL_pm_op_get_max_cstate:
> -    {
> -        op->u.get_max_cstate = acpi_get_cstate_limit();
> -        break;
> -    }
> -
> -    case XEN_SYSCTL_pm_op_set_max_cstate:
> -    {
> -        acpi_set_cstate_limit(op->u.set_max_cstate);
> -        break;
> -    }
> -
> -    case XEN_SYSCTL_pm_op_enable_turbo:
> -    {
> -        ret = cpufreq_update_turbo(op->cpuid, CPUFREQ_TURBO_ENABLED);
> -        break;
> -    }
> -
> -    case XEN_SYSCTL_pm_op_disable_turbo:
> -    {
> -        ret = cpufreq_update_turbo(op->cpuid, CPUFREQ_TURBO_DISABLED);
> -        break;
> -    }
> -
> -    default:
> -        printk("not defined sub-hypercall @ do_pm_op\n");
> -        ret = -ENOSYS;
> -        break;
> -    }
> -
> -    return ret;
> -}
> -
> -int acpi_set_pdc_bits(u32 acpi_id, XEN_GUEST_HANDLE_PARAM(uint32) pdc)
> -{
> -    u32 bits[3];
> -    int ret;
> -
> -    if ( copy_from_guest(bits, pdc, 2) )
> -        ret = -EFAULT;
> -    else if ( bits[0] != ACPI_PDC_REVISION_ID || !bits[1] )
> -        ret = -EINVAL;
> -    else if ( copy_from_guest_offset(bits + 2, pdc, 2, 1) )
> -        ret = -EFAULT;
> -    else
> -    {
> -        u32 mask = 0;
> -
> -        if ( xen_processor_pmbits & XEN_PROCESSOR_PM_CX )
> -            mask |= ACPI_PDC_C_MASK | ACPI_PDC_SMP_C1PT;
> -        if ( xen_processor_pmbits & XEN_PROCESSOR_PM_PX )
> -            mask |= ACPI_PDC_P_MASK | ACPI_PDC_SMP_C1PT;
> -        if ( xen_processor_pmbits & XEN_PROCESSOR_PM_TX )
> -            mask |= ACPI_PDC_T_MASK | ACPI_PDC_SMP_C1PT;
> -        bits[2] &= (ACPI_PDC_C_MASK | ACPI_PDC_P_MASK | ACPI_PDC_T_MASK |
> -                    ACPI_PDC_SMP_C1PT) & ~mask;
> -        ret = arch_acpi_set_pdc_bits(acpi_id, bits, mask);
> -    }
> -    if ( !ret && __copy_to_guest_offset(pdc, 2, bits + 2, 1) )
> -        ret = -EFAULT;
> -
> -    return ret;
> -}
> diff --git a/xen/drivers/pm/Kconfig b/xen/drivers/pm/Kconfig
> new file mode 100644
> index 0000000..6d4fda1
> --- /dev/null
> +++ b/xen/drivers/pm/Kconfig
> @@ -0,0 +1,3 @@
> +
> +config HAS_PM
> +     bool
> diff --git a/xen/drivers/pm/Makefile b/xen/drivers/pm/Makefile
> new file mode 100644
> index 0000000..2073683
> --- /dev/null
> +++ b/xen/drivers/pm/Makefile
> @@ -0,0 +1 @@
> +obj-y += stat.o
> diff --git a/xen/drivers/pm/stat.c b/xen/drivers/pm/stat.c
> new file mode 100644
> index 0000000..2dbde1c
> --- /dev/null
> +++ b/xen/drivers/pm/stat.c
> @@ -0,0 +1,526 @@
> +/*****************************************************************************
> +#  pmstat.c - Power Management statistic information (Px/Cx/Tx, etc.)
> +#
> +#  Copyright (c) 2008, Liu Jinsong <jinsong.liu@xxxxxxxxx>
> +#
> +# This program is free software; you can redistribute it and/or modify it 
> +# under the terms of the GNU General Public License as published by the Free 
> +# Software Foundation; either version 2 of the License, or (at your option) 
> +# any later version.
> +#
> +# This program is distributed in the hope that it will be useful, but 
> WITHOUT 
> +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
> +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
> +# more details.
> +#
> +# You should have received a copy of the GNU General Public License along 
> with
> +# this program; If not, see <http://www.gnu.org/licenses/>.
> +#
> +# The full GNU General Public License is included in this distribution in the
> +# file called LICENSE.
> +#
> +*****************************************************************************/
> +
> +#include <xen/lib.h>
> +#include <xen/errno.h>
> +#include <xen/sched.h>
> +#include <xen/event.h>
> +#include <xen/irq.h>
> +#include <xen/iocap.h>
> +#include <xen/compat.h>
> +#include <xen/guest_access.h>
> +#include <asm/current.h>
> +#include <public/xen.h>
> +#include <xen/cpumask.h>
> +#include <asm/processor.h>
> +#include <xen/percpu.h>
> +#include <xen/domain.h>
> +#include <xen/acpi.h>
> +
> +#include <public/sysctl.h>
> +#include <xen/cpufreq.h>
> +#include <xen/pmstat.h>
> +
> +DEFINE_PER_CPU_READ_MOSTLY(struct pm_px *, cpufreq_statistic_data);
> +
> +/*
> + * Get PM statistic info
> + */
> +int do_get_pm_info(struct xen_sysctl_get_pmstat *op)
> +{
> +    int ret = 0;
> +    const struct processor_pminfo *pmpt;
> +
> +    if ( !op || (op->cpuid >= nr_cpu_ids) || !cpu_online(op->cpuid) )
> +        return -EINVAL;
> +    pmpt = processor_pminfo[op->cpuid];
> +
> +    switch ( op->type & PMSTAT_CATEGORY_MASK )
> +    {
> +    case PMSTAT_CX:
> +        if ( !(xen_processor_pmbits & XEN_PROCESSOR_PM_CX) )
> +            return -ENODEV;
> +        break;
> +    case PMSTAT_PX:
> +        if ( !(xen_processor_pmbits & XEN_PROCESSOR_PM_PX) )
> +            return -ENODEV;
> +        if ( !cpufreq_driver )
> +            return -ENODEV;
> +        if ( !pmpt || !(pmpt->perf.init & XEN_PX_INIT) )
> +            return -EINVAL;
> +        break;
> +    default:
> +        return -ENODEV;
> +    }
> +
> +    switch ( op->type )
> +    {
> +    case PMSTAT_get_max_px:
> +    {
> +        op->u.getpx.total = pmpt->perf.state_count;
> +        break;
> +    }
> +
> +    case PMSTAT_get_pxstat:
> +    {
> +        uint32_t ct;
> +        struct pm_px *pxpt;
> +        spinlock_t *cpufreq_statistic_lock = 
> +                   &per_cpu(cpufreq_statistic_lock, op->cpuid);
> +
> +        spin_lock(cpufreq_statistic_lock);
> +
> +        pxpt = per_cpu(cpufreq_statistic_data, op->cpuid);
> +        if ( !pxpt || !pxpt->u.pt || !pxpt->u.trans_pt )
> +        {
> +            spin_unlock(cpufreq_statistic_lock);
> +            return -ENODATA;
> +        }
> +
> +        pxpt->u.usable = pmpt->perf.state_count - pmpt->perf.platform_limit;
> +
> +        cpufreq_residency_update(op->cpuid, pxpt->u.cur);
> +
> +        ct = pmpt->perf.state_count;
> +        if ( copy_to_guest(op->u.getpx.trans_pt, pxpt->u.trans_pt, ct*ct) )
> +        {
> +            spin_unlock(cpufreq_statistic_lock);
> +            ret = -EFAULT;
> +            break;
> +        }
> +
> +        if ( copy_to_guest(op->u.getpx.pt, pxpt->u.pt, ct) )
> +        {
> +            spin_unlock(cpufreq_statistic_lock);
> +            ret = -EFAULT;
> +            break;
> +        }
> +
> +        op->u.getpx.total = pxpt->u.total;
> +        op->u.getpx.usable = pxpt->u.usable;
> +        op->u.getpx.last = pxpt->u.last;
> +        op->u.getpx.cur = pxpt->u.cur;
> +
> +        spin_unlock(cpufreq_statistic_lock);
> +
> +        break;
> +    }
> +
> +    case PMSTAT_reset_pxstat:
> +    {
> +        cpufreq_statistic_reset(op->cpuid);
> +        break;
> +    }
> +
> +    case PMSTAT_get_max_cx:
> +    {
> +        op->u.getcx.nr = pmstat_get_cx_nr(op->cpuid);
> +        ret = 0;
> +        break;
> +    }
> +
> +    case PMSTAT_get_cxstat:
> +    {
> +        ret = pmstat_get_cx_stat(op->cpuid, &op->u.getcx);
> +        break;
> +    }
> +
> +    case PMSTAT_reset_cxstat:
> +    {
> +        ret = pmstat_reset_cx_stat(op->cpuid);
> +        break;
> +    }
> +
> +    default:
> +        printk("not defined sub-hypercall @ do_get_pm_info\n");
> +        ret = -ENOSYS;
> +        break;
> +    }
> +
> +    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;
> +
> +    pmpt = processor_pminfo[op->cpuid];
> +    policy = per_cpu(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->u.get_para.cpu_num  != cpumask_weight(policy->cpus)) ||
> +         (op->u.get_para.freq_num != pmpt->perf.state_count)    ||
> +         (op->u.get_para.gov_num  != gov_num) )
> +    {
> +        op->u.get_para.cpu_num =  cpumask_weight(policy->cpus);
> +        op->u.get_para.freq_num = pmpt->perf.state_count;
> +        op->u.get_para.gov_num  = gov_num;
> +        return -EAGAIN;
> +    }
> +
> +    if ( !(affected_cpus = xzalloc_array(uint32_t, op->u.get_para.cpu_num)) )
> +        return -ENOMEM;
> +    for_each_cpu(cpu, policy->cpus)
> +        affected_cpus[j++] = cpu;
> +    ret = copy_to_guest(op->u.get_para.affected_cpus,
> +                       affected_cpus, op->u.get_para.cpu_num);
> +    xfree(affected_cpus);
> +    if ( ret )
> +        return ret;
> +
> +    if ( !(scaling_available_frequencies =
> +           xzalloc_array(uint32_t, op->u.get_para.freq_num)) )
> +        return -ENOMEM;
> +    for ( i = 0; i < op->u.get_para.freq_num; i++ )
> +        scaling_available_frequencies[i] =
> +                        pmpt->perf.states[i].core_frequency * 1000;
> +    ret = copy_to_guest(op->u.get_para.scaling_available_frequencies,
> +                   scaling_available_frequencies, op->u.get_para.freq_num);
> +    xfree(scaling_available_frequencies);
> +    if ( ret )
> +        return ret;
> +
> +    if ( !(scaling_available_governors =
> +           xzalloc_array(char, gov_num * CPUFREQ_NAME_LEN)) )
> +        return -ENOMEM;
> +    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->u.get_para.scaling_available_governors,
> +                scaling_available_governors, gov_num * CPUFREQ_NAME_LEN);
> +    xfree(scaling_available_governors);
> +    if ( ret )
> +        return ret;
> +
> +    op->u.get_para.cpuinfo_cur_freq =
> +        cpufreq_driver->get ? cpufreq_driver->get(op->cpuid) : policy->cur;
> +    op->u.get_para.cpuinfo_max_freq = policy->cpuinfo.max_freq;
> +    op->u.get_para.cpuinfo_min_freq = policy->cpuinfo.min_freq;
> +    op->u.get_para.scaling_cur_freq = policy->cur;
> +    op->u.get_para.scaling_max_freq = policy->max;
> +    op->u.get_para.scaling_min_freq = policy->min;
> +
> +    if ( cpufreq_driver->name[0] )
> +        strlcpy(op->u.get_para.scaling_driver, 
> +            cpufreq_driver->name, CPUFREQ_NAME_LEN);
> +    else
> +        strlcpy(op->u.get_para.scaling_driver, "Unknown", CPUFREQ_NAME_LEN);
> +
> +    if ( policy->governor->name[0] )
> +        strlcpy(op->u.get_para.scaling_governor, 
> +            policy->governor->name, CPUFREQ_NAME_LEN);
> +    else
> +        strlcpy(op->u.get_para.scaling_governor, "Unknown", 
> CPUFREQ_NAME_LEN);
> +
> +    /* governor specific para */
> +    if ( !strnicmp(op->u.get_para.scaling_governor, 
> +                   "userspace", CPUFREQ_NAME_LEN) )
> +    {
> +        op->u.get_para.u.userspace.scaling_setspeed = policy->cur;
> +    }
> +
> +    if ( !strnicmp(op->u.get_para.scaling_governor, 
> +                   "ondemand", CPUFREQ_NAME_LEN) )
> +    {
> +        ret = get_cpufreq_ondemand_para(
> +            &op->u.get_para.u.ondemand.sampling_rate_max,
> +            &op->u.get_para.u.ondemand.sampling_rate_min,
> +            &op->u.get_para.u.ondemand.sampling_rate,
> +            &op->u.get_para.u.ondemand.up_threshold);
> +    }
> +    op->u.get_para.turbo_enabled = cpufreq_get_turbo_status(op->cpuid);
> +
> +    return ret;
> +}
> +
> +static int set_cpufreq_gov(struct xen_sysctl_pm_op *op)
> +{
> +    struct cpufreq_policy new_policy, *old_policy;
> +
> +    old_policy = per_cpu(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->u.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;
> +
> +    policy = per_cpu(cpufreq_cpu_policy, op->cpuid);
> +
> +    if ( !policy || !policy->governor )
> +        return -EINVAL;
> +
> +    switch(op->u.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->u.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->u.set_para.ctrl_value;
> +        ret = __cpufreq_set_policy(policy, &new_policy);
> +
> +        break;
> +    }
> +
> +    case SCALING_SETSPEED:
> +    {
> +        unsigned int freq =op->u.set_para.ctrl_value;
> +
> +        if ( !strnicmp(policy->governor->name,
> +                       "userspace", CPUFREQ_NAME_LEN) )
> +            ret = write_userspace_scaling_setspeed(op->cpuid, freq);
> +        else
> +            ret = -EINVAL;
> +
> +        break;
> +    }
> +
> +    case SAMPLING_RATE:
> +    {
> +        unsigned int sampling_rate = op->u.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->u.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 || op->cpuid >= nr_cpu_ids || !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;
> +    }
> +
> +    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;
> +    }
> +
> +    case GET_CPUFREQ_AVGFREQ:
> +    {
> +        op->u.get_avgfreq = cpufreq_driver_getavg(op->cpuid, USR_GETAVG);
> +        break;
> +    }
> +
> +    case XEN_SYSCTL_pm_op_set_sched_opt_smt:
> +    {
> +        uint32_t saved_value;
> +
> +        saved_value = sched_smt_power_savings;
> +        sched_smt_power_savings = !!op->u.set_sched_opt_smt;
> +        op->u.set_sched_opt_smt = saved_value;
> +
> +        break;
> +    }
> +
> +    case XEN_SYSCTL_pm_op_set_vcpu_migration_delay:
> +    {
> +        set_vcpu_migration_delay(op->u.set_vcpu_migration_delay);
> +        break;
> +    }
> +
> +    case XEN_SYSCTL_pm_op_get_vcpu_migration_delay:
> +    {
> +        op->u.get_vcpu_migration_delay = get_vcpu_migration_delay();
> +        break;
> +    }
> +
> +    case XEN_SYSCTL_pm_op_get_max_cstate:
> +    {
> +        op->u.get_max_cstate = acpi_get_cstate_limit();
> +        break;
> +    }
> +
> +    case XEN_SYSCTL_pm_op_set_max_cstate:
> +    {
> +        acpi_set_cstate_limit(op->u.set_max_cstate);
> +        break;
> +    }
> +
> +    case XEN_SYSCTL_pm_op_enable_turbo:
> +    {
> +        ret = cpufreq_update_turbo(op->cpuid, CPUFREQ_TURBO_ENABLED);
> +        break;
> +    }
> +
> +    case XEN_SYSCTL_pm_op_disable_turbo:
> +    {
> +        ret = cpufreq_update_turbo(op->cpuid, CPUFREQ_TURBO_DISABLED);
> +        break;
> +    }
> +
> +    default:
> +        printk("not defined sub-hypercall @ do_pm_op\n");
> +        ret = -ENOSYS;
> +        break;
> +    }
> +
> +    return ret;
> +}
> +
> +int acpi_set_pdc_bits(u32 acpi_id, XEN_GUEST_HANDLE_PARAM(uint32) pdc)
> +{
> +    u32 bits[3];
> +    int ret;
> +
> +    if ( copy_from_guest(bits, pdc, 2) )
> +        ret = -EFAULT;
> +    else if ( bits[0] != ACPI_PDC_REVISION_ID || !bits[1] )
> +        ret = -EINVAL;
> +    else if ( copy_from_guest_offset(bits + 2, pdc, 2, 1) )
> +        ret = -EFAULT;
> +    else
> +    {
> +        u32 mask = 0;
> +
> +        if ( xen_processor_pmbits & XEN_PROCESSOR_PM_CX )
> +            mask |= ACPI_PDC_C_MASK | ACPI_PDC_SMP_C1PT;
> +        if ( xen_processor_pmbits & XEN_PROCESSOR_PM_PX )
> +            mask |= ACPI_PDC_P_MASK | ACPI_PDC_SMP_C1PT;
> +        if ( xen_processor_pmbits & XEN_PROCESSOR_PM_TX )
> +            mask |= ACPI_PDC_T_MASK | ACPI_PDC_SMP_C1PT;
> +        bits[2] &= (ACPI_PDC_C_MASK | ACPI_PDC_P_MASK | ACPI_PDC_T_MASK |
> +                    ACPI_PDC_SMP_C1PT) & ~mask;
> +        ret = arch_acpi_set_pdc_bits(acpi_id, bits, mask);
> +    }
> +    if ( !ret && __copy_to_guest_offset(pdc, 2, bits + 2, 1) )
> +        ret = -EFAULT;
> +
> +    return ret;
> +}
> -- 
> 2.7.4
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.