CTRL_SRCS-y += xc_sedf.c
CTRL_SRCS-y += xc_csched.c
CTRL_SRCS-y += xc_tbuf.c
+CTRL_SRCS-y += xc_pm.c
ifneq ($(stubdom),y)
CTRL_SRCS-y += xc_resume.c
endif
--- /dev/null
+/******************************************************************************
+ * xc_pm.c - Libxc API for Xen Power Management (Px/Cx/Tx, etc.) statistic
+ *
+ * Copyright (c) 2008, Liu Jinsong <jinsong.liu@intel.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "xc_private.h"
+
+int xc_pm_get_max_px(int xc_handle, int cpuid, int *max_px)
+{
+ DECLARE_SYSCTL;
+ int ret;
+
+ sysctl.cmd = XEN_SYSCTL_get_pmstat;
+ sysctl.u.get_pmstat.type = PMSTAT_get_max_px;
+ sysctl.u.get_pmstat.cpuid = cpuid;
+ ret = xc_sysctl(xc_handle, &sysctl);
+ if ( ret )
+ return ret;
+
+ *max_px = sysctl.u.get_pmstat.u.getpx.total;
+ return ret;
+}
+
+int xc_pm_get_pxstat(int xc_handle, int cpuid, struct xc_px_stat *pxpt)
+{
+ DECLARE_SYSCTL;
+ int max_px, ret;
+
+ if ( !pxpt || !(pxpt->trans_pt) || !(pxpt->pt) )
+ return -EINVAL;
+
+ if ( (ret = xc_pm_get_max_px(xc_handle, cpuid, &max_px)) != 0)
+ return ret;
+
+ if ( (ret = lock_pages(pxpt->trans_pt,
+ max_px * max_px * sizeof(uint64_t))) != 0 )
+ return ret;
+
+ if ( (ret = lock_pages(pxpt->pt,
+ max_px * sizeof(struct xc_px_val))) != 0 )
+ {
+ unlock_pages(pxpt->trans_pt, max_px * max_px * sizeof(uint64_t));
+ return ret;
+ }
+
+ sysctl.cmd = XEN_SYSCTL_get_pmstat;
+ sysctl.u.get_pmstat.type = PMSTAT_get_pxstat;
+ sysctl.u.get_pmstat.cpuid = cpuid;
+ set_xen_guest_handle(sysctl.u.get_pmstat.u.getpx.trans_pt, pxpt->trans_pt);
+ set_xen_guest_handle(sysctl.u.get_pmstat.u.getpx.pt,
+ (pm_px_val_t *)pxpt->pt);
+
+ ret = xc_sysctl(xc_handle, &sysctl);
+ if ( ret )
+ {
+ unlock_pages(pxpt->trans_pt, max_px * max_px * sizeof(uint64_t));
+ unlock_pages(pxpt->pt, max_px * sizeof(struct xc_px_val));
+ return ret;
+ }
+
+ pxpt->total = sysctl.u.get_pmstat.u.getpx.total;
+ pxpt->usable = sysctl.u.get_pmstat.u.getpx.usable;
+ pxpt->last = sysctl.u.get_pmstat.u.getpx.last;
+ pxpt->cur = sysctl.u.get_pmstat.u.getpx.cur;
+
+ unlock_pages(pxpt->trans_pt, max_px * max_px * sizeof(uint64_t));
+ unlock_pages(pxpt->pt, max_px * sizeof(struct xc_px_val));
+
+ return ret;
+}
+
+int xc_pm_reset_pxstat(int xc_handle, int cpuid)
+{
+ DECLARE_SYSCTL;
+
+ sysctl.cmd = XEN_SYSCTL_get_pmstat;
+ sysctl.u.get_pmstat.type = PMSTAT_reset_pxstat;
+ sysctl.u.get_pmstat.cpuid = cpuid;
+
+ return xc_sysctl(xc_handle, &sysctl);
+}
char **strs);
#endif
+struct xc_px_val {
+ uint64_t freq; /* Px core frequency */
+ uint64_t residency; /* Px residency time */
+ uint64_t count; /* Px transition count */
+};
+
+struct xc_px_stat {
+ uint8_t total; /* total Px states */
+ uint8_t usable; /* usable Px states */
+ uint8_t last; /* last Px state */
+ uint8_t cur; /* current Px state */
+ uint64_t *trans_pt; /* Px transition table */
+ struct xc_px_val *pt;
+};
+
+int xc_pm_get_max_px(int xc_handle, int cpuid, int *max_px);
+int xc_pm_get_pxstat(int xc_handle, int cpuid, struct xc_px_stat *pxpt);
+int xc_pm_reset_pxstat(int xc_handle, int cpuid);
+
#endif /* XENCTRL_H */
obj-y += boot.o
obj-y += power.o suspend.o wakeup_prot.o cpu_idle.o
+obj-y += pmstat.o
if (!check_freqs(cmd.mask, freqs.new, data))
return -EAGAIN;
+ px_statistic_update(cmd.mask, perf->state, next_perf_state);
+
perf->state = next_perf_state;
policy->cur = freqs.new;
for_each_online_cpu(i) {
xen_px_policy[i].cpu = i;
+ ret = px_statistic_init(i);
+ if (ret)
+ goto out;
+
ret = acpi_cpufreq_cpu_init(&xen_px_policy[i]);
if (ret)
- goto cpufreq_init_out;
+ goto out;
}
/* setup ondemand cpufreq */
i = first_cpu(pt[dom]);
ret = cpufreq_governor_dbs(&xen_px_policy[i], CPUFREQ_GOV_START);
if (ret)
- goto cpufreq_init_out;
+ goto out;
}
-cpufreq_init_out:
+out:
xfree(pt);
return ret;
struct cpufreq_driver *cpufreq_driver;
+/*********************************************************************
+ * Px STATISTIC INFO *
+ *********************************************************************/
+
+void px_statistic_update(cpumask_t cpumask, uint8_t from, uint8_t to)
+{
+ uint32_t i;
+ uint64_t now;
+
+ now = NOW();
+
+ for_each_cpu_mask(i, cpumask) {
+ struct pm_px *pxpt = &px_statistic_data[i];
+ uint32_t statnum = processor_pminfo[i].perf.state_count;
+
+ pxpt->u.last = from;
+ pxpt->u.cur = to;
+ pxpt->u.pt[to].count++;
+ pxpt->u.pt[from].residency += now - pxpt->prev_state_wall;
+
+ (*(pxpt->u.trans_pt + from*statnum + to))++;
+
+ pxpt->prev_state_wall = now;
+ }
+}
+
+int px_statistic_init(int cpuid)
+{
+ uint32_t i, count;
+ struct pm_px *pxpt = &px_statistic_data[cpuid];
+ struct processor_pminfo *pmpt = &processor_pminfo[cpuid];
+
+ count = pmpt->perf.state_count;
+
+ pxpt->u.trans_pt = xmalloc_array(uint64_t, count * count);
+ if (!pxpt->u.trans_pt)
+ return -ENOMEM;
+
+ pxpt->u.pt = xmalloc_array(struct pm_px_val, count);
+ if (!pxpt->u.pt) {
+ xfree(pxpt->u.trans_pt);
+ return -ENOMEM;
+ }
+
+ memset(pxpt->u.trans_pt, 0, count * count * (sizeof(uint64_t)));
+ memset(pxpt->u.pt, 0, count * (sizeof(struct pm_px_val)));
+
+ pxpt->u.total = pmpt->perf.state_count;
+ pxpt->u.usable = pmpt->perf.state_count - pmpt->perf.ppc;
+
+ for (i=0; i < pmpt->perf.state_count; i++)
+ pxpt->u.pt[i].freq = pmpt->perf.states[i].core_frequency;
+
+ pxpt->prev_state_wall = NOW();
+
+ return 0;
+}
+
+void px_statistic_reset(int cpuid)
+{
+ uint32_t i, j, count;
+ struct pm_px *pxpt = &px_statistic_data[cpuid];
+
+ count = processor_pminfo[cpuid].perf.state_count;
+
+ for (i=0; i < count; i++) {
+ pxpt->u.pt[i].residency = 0;
+ pxpt->u.pt[i].count = 0;
+
+ for (j=0; j < count; j++)
+ *(pxpt->u.trans_pt + i*count + j) = 0;
+ }
+
+ pxpt->prev_state_wall = NOW();
+}
+
+
/*********************************************************************
* FREQUENCY TABLE HELPERS *
*********************************************************************/
--- /dev/null
+/*****************************************************************************
+# pmstat.c - Power Management statistic information (Px/Cx/Tx, etc.)
+#
+# Copyright (c) 2008, Liu Jinsong <jinsong.liu@intel.com>
+#
+# 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, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The full GNU General Public License is included in this distribution in the
+# file called LICENSE.
+#
+*****************************************************************************/
+
+#include <xen/config.h>
+#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 <public/sysctl.h>
+#include <acpi/cpufreq/cpufreq.h>
+
+struct pm_px px_statistic_data[NR_CPUS];
+
+int do_get_pm_info(struct xen_sysctl_get_pmstat *op)
+{
+ int ret = 0;
+ struct pm_px *pxpt = &px_statistic_data[op->cpuid];
+ struct processor_pminfo *pmpt = &processor_pminfo[op->cpuid];
+
+ /* to protect the case when Px was controlled by dom0-kernel */
+ /* or when CPU_FREQ not set in which case ACPI Px objects not parsed */
+ if ( !pmpt->perf.init )
+ return -EINVAL;
+
+ if ( !cpu_online(op->cpuid) )
+ return -EINVAL;
+
+ switch( op->type )
+ {
+ case PMSTAT_get_max_px:
+ {
+ op->u.getpx.total = pmpt->perf.state_count;
+ break;
+ }
+
+ case PMSTAT_get_pxstat:
+ {
+ uint64_t now, ct;
+
+ now = NOW();
+ pxpt->u.usable = pmpt->perf.state_count - pmpt->perf.ppc;
+ pxpt->u.pt[pxpt->u.cur].residency += now - pxpt->prev_state_wall;
+ pxpt->prev_state_wall = now;
+
+ ct = pmpt->perf.state_count;
+ if ( copy_to_guest(op->u.getpx.trans_pt, pxpt->u.trans_pt, ct*ct) )
+ {
+ ret = -EFAULT;
+ break;
+ }
+
+ if ( copy_to_guest(op->u.getpx.pt, pxpt->u.pt, ct) )
+ {
+ 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;
+
+ break;
+ }
+
+ case PMSTAT_reset_pxstat:
+ {
+ px_statistic_reset(op->cpuid);
+ break;
+ }
+
+ default:
+ printk("not defined sub-hypercall @ do_get_pm_info\n");
+ ret = -ENOSYS;
+ break;
+ }
+
+ return ret;
+}
if ( xenpxpt->flags == ( XEN_PX_PCT | XEN_PX_PSS |
XEN_PX_PSD | XEN_PX_PPC ) )
+ {
+ pxpt->init =1;
cpu_count++;
+ }
if ( cpu_count == num_online_cpus() )
ret = acpi_cpufreq_init();
break;
#include <xen/nodemask.h>
#include <xsm/xsm.h>
+extern int do_get_pm_info(struct xen_sysctl_get_pmstat *op);
+
extern long arch_do_sysctl(
struct xen_sysctl *op, XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl);
}
break;
+ case XEN_SYSCTL_get_pmstat:
+ {
+ ret = do_get_pm_info(&op->u.get_pmstat);
+ if ( ret )
+ break;
+
+ if ( copy_to_guest(u_sysctl, op, 1) )
+ {
+ ret = -EFAULT;
+ break;
+ }
+ }
+ break;
+
default:
ret = arch_do_sysctl(op, u_sysctl);
break;
#define __XEN_PROCESSOR_PM_H__
#include <public/platform.h>
+#include <public/sysctl.h>
int get_cpu_id(u8);
int acpi_cpufreq_init(void);
+void px_statistic_update(cpumask_t, uint8_t, uint8_t);
+int px_statistic_init(int);
+void px_statistic_reset(int);
struct processor_performance {
uint32_t state;
struct xen_psd_package domain_info;
cpumask_t shared_cpu_map;
uint32_t shared_type;
+
+ uint32_t init;
};
struct processor_pminfo {
uint32_t acpi_id;
uint32_t id;
- uint32_t flag;
struct processor_performance perf;
};
extern struct processor_pminfo processor_pminfo[NR_CPUS];
+struct px_stat {
+ uint8_t total; /* total Px states */
+ uint8_t usable; /* usable Px states */
+ uint8_t last; /* last Px state */
+ uint8_t cur; /* current Px state */
+ uint64_t *trans_pt; /* Px transition table */
+ pm_px_val_t *pt;
+};
+
+struct pm_px {
+ struct px_stat u;
+ uint64_t prev_state_wall;
+};
+
+extern struct pm_px px_statistic_data[NR_CPUS];
+
#endif /* __XEN_PROCESSOR_PM_H__ */
};
typedef struct xen_sysctl_availheap xen_sysctl_availheap_t;
DEFINE_XEN_GUEST_HANDLE(xen_sysctl_availheap_t);
-
+
+#define XEN_SYSCTL_get_pmstat 10
+struct pm_px_val {
+ uint64_aligned_t freq; /* Px core frequency */
+ uint64_aligned_t residency; /* Px residency time */
+ uint64_aligned_t count; /* Px transition count */
+};
+typedef struct pm_px_val pm_px_val_t;
+DEFINE_XEN_GUEST_HANDLE(pm_px_val_t);
+
+struct pm_px_stat {
+ uint8_t total; /* total Px states */
+ uint8_t usable; /* usable Px states */
+ uint8_t last; /* last Px state */
+ uint8_t cur; /* current Px state */
+ XEN_GUEST_HANDLE_64(uint64) trans_pt; /* Px transition table */
+ XEN_GUEST_HANDLE_64(pm_px_val_t) pt;
+};
+typedef struct pm_px_stat pm_px_stat_t;
+DEFINE_XEN_GUEST_HANDLE(pm_px_stat_t);
+
+struct xen_sysctl_get_pmstat {
+#define PMSTAT_get_max_px 0x11
+#define PMSTAT_get_pxstat 0x12
+#define PMSTAT_reset_pxstat 0x13
+ uint32_t type;
+ uint32_t cpuid;
+ union {
+ struct pm_px_stat getpx;
+ /* other struct for cx, tx, etc */
+ } u;
+};
+typedef struct xen_sysctl_get_pmstat xen_sysctl_get_pmstat_t;
+DEFINE_XEN_GUEST_HANDLE(xen_sysctl_get_pmstat_t);
+
struct xen_sysctl {
uint32_t cmd;
uint32_t interface_version; /* XEN_SYSCTL_INTERFACE_VERSION */
struct xen_sysctl_debug_keys debug_keys;
struct xen_sysctl_getcpuinfo getcpuinfo;
struct xen_sysctl_availheap availheap;
+ struct xen_sysctl_get_pmstat get_pmstat;
uint8_t pad[128];
} u;
};