aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/libxc/xc_pm.c68
-rw-r--r--tools/libxc/xenctrl.h13
-rw-r--r--xen/arch/x86/acpi/cpu_idle.c39
-rw-r--r--xen/arch/x86/acpi/pmstat.c25
-rw-r--r--xen/include/public/sysctl.h23
5 files changed, 163 insertions, 5 deletions
diff --git a/tools/libxc/xc_pm.c b/tools/libxc/xc_pm.c
index 0378cbd521..2737cbe312 100644
--- a/tools/libxc/xc_pm.c
+++ b/tools/libxc/xc_pm.c
@@ -99,3 +99,71 @@ int xc_pm_reset_pxstat(int xc_handle, int cpuid)
return xc_sysctl(xc_handle, &sysctl);
}
+
+int xc_pm_get_max_cx(int xc_handle, int cpuid, int *max_cx)
+{
+ DECLARE_SYSCTL;
+ int ret = 0;
+
+ sysctl.cmd = XEN_SYSCTL_get_pmstat;
+ sysctl.u.get_pmstat.type = PMSTAT_get_max_cx;
+ sysctl.u.get_pmstat.cpuid = cpuid;
+ if ( (ret = xc_sysctl(xc_handle, &sysctl)) != 0 )
+ return ret;
+
+ *max_cx = sysctl.u.get_pmstat.u.getcx.nr;
+ return ret;
+}
+
+int xc_pm_get_cxstat(int xc_handle, int cpuid, struct xc_cx_stat *cxpt)
+{
+ DECLARE_SYSCTL;
+ int max_cx, ret;
+
+ if( !cxpt || !(cxpt->triggers) || !(cxpt->residencies) )
+ return -EINVAL;
+
+ if ( (ret = xc_pm_get_max_cx(xc_handle, cpuid, &max_cx)) )
+ goto unlock_0;
+
+ if ( (ret = lock_pages(cxpt, sizeof(struct xc_cx_stat))) )
+ goto unlock_0;
+ if ( (ret = lock_pages(cxpt->triggers, max_cx * sizeof(uint64_t))) )
+ goto unlock_1;
+ if ( (ret = lock_pages(cxpt->residencies, max_cx * sizeof(uint64_t))) )
+ goto unlock_2;
+
+ sysctl.cmd = XEN_SYSCTL_get_pmstat;
+ sysctl.u.get_pmstat.type = PMSTAT_get_cxstat;
+ sysctl.u.get_pmstat.cpuid = cpuid;
+ set_xen_guest_handle(sysctl.u.get_pmstat.u.getcx.triggers, cxpt->triggers);
+ set_xen_guest_handle(sysctl.u.get_pmstat.u.getcx.residencies,
+ cxpt->residencies);
+
+ if ( (ret = xc_sysctl(xc_handle, &sysctl)) )
+ goto unlock_3;
+
+ cxpt->nr = sysctl.u.get_pmstat.u.getcx.nr;
+ cxpt->last = sysctl.u.get_pmstat.u.getcx.last;
+ cxpt->idle_time = sysctl.u.get_pmstat.u.getcx.idle_time;
+
+unlock_3:
+ unlock_pages(cxpt->residencies, max_cx * sizeof(uint64_t));
+unlock_2:
+ unlock_pages(cxpt->triggers, max_cx * sizeof(uint64_t));
+unlock_1:
+ unlock_pages(cxpt, sizeof(struct xc_cx_stat));
+unlock_0:
+ return ret;
+}
+
+int xc_pm_reset_cxstat(int xc_handle, int cpuid)
+{
+ DECLARE_SYSCTL;
+
+ sysctl.cmd = XEN_SYSCTL_get_pmstat;
+ sysctl.u.get_pmstat.type = PMSTAT_reset_cxstat;
+ sysctl.u.get_pmstat.cpuid = cpuid;
+
+ return xc_sysctl(xc_handle, &sysctl);
+}
diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h
index 130a05e19d..1e03025ca6 100644
--- a/tools/libxc/xenctrl.h
+++ b/tools/libxc/xenctrl.h
@@ -1053,4 +1053,17 @@ 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);
+struct xc_cx_stat {
+ uint32_t nr; /* entry nr in triggers & residencies, including C0 */
+ uint32_t last; /* last Cx state */
+ uint64_t idle_time; /* idle time from boot */
+ uint64_t *triggers; /* Cx trigger counts */
+ uint64_t *residencies; /* Cx residencies */
+};
+typedef struct xc_cx_stat xc_cx_stat_t;
+
+int xc_pm_get_max_cx(int xc_handle, int cpuid, int *max_cx);
+int xc_pm_get_cxstat(int xc_handle, int cpuid, struct xc_cx_stat *cxpt);
+int xc_pm_reset_cxstat(int xc_handle, int cpuid);
+
#endif /* XENCTRL_H */
diff --git a/xen/arch/x86/acpi/cpu_idle.c b/xen/arch/x86/acpi/cpu_idle.c
index f7d615fb42..0d471d9a7d 100644
--- a/xen/arch/x86/acpi/cpu_idle.c
+++ b/xen/arch/x86/acpi/cpu_idle.c
@@ -44,6 +44,7 @@
#include <asm/hpet.h>
#include <asm/processor.h>
#include <public/platform.h>
+#include <public/sysctl.h>
#define DEBUG_PM_CX
@@ -940,3 +941,41 @@ long set_cx_pminfo(uint32_t cpu, struct xen_processor_power *power)
return 0;
}
+
+uint32_t pmstat_get_cx_nr(uint32_t cpuid)
+{
+ return processor_powers[cpuid].count;
+}
+
+int pmstat_get_cx_stat(uint32_t cpuid, struct pm_cx_stat *stat)
+{
+ struct acpi_processor_power *power = &processor_powers[cpuid];
+ struct vcpu *v = idle_vcpu[cpuid];
+ uint64_t usage;
+ int i;
+
+ stat->last = (power->state) ? power->state->type : 0;
+ stat->nr = processor_powers[cpuid].count;
+ stat->idle_time = v->runstate.time[RUNSTATE_running];
+ if ( v->is_running )
+ stat->idle_time += NOW() - v->runstate.state_entry_time;
+
+ for ( i = 0; i < power->count; i++ )
+ {
+ usage = power->states[i].usage;
+ if ( copy_to_guest_offset(stat->triggers, i, &usage, 1) )
+ return -EFAULT;
+ }
+ for ( i = 0; i < power->count; i++ )
+ if ( copy_to_guest_offset(stat->residencies, i,
+ &power->states[i].time, 1) )
+ return -EFAULT;
+
+ return 0;
+}
+
+int pmstat_reset_cx_stat(uint32_t cpuid)
+{
+ return 0;
+}
+
diff --git a/xen/arch/x86/acpi/pmstat.c b/xen/arch/x86/acpi/pmstat.c
index a18a78e69f..9aa5a4750a 100644
--- a/xen/arch/x86/acpi/pmstat.c
+++ b/xen/arch/x86/acpi/pmstat.c
@@ -42,6 +42,10 @@
struct pm_px px_statistic_data[NR_CPUS];
+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);
+
int do_get_pm_info(struct xen_sysctl_get_pmstat *op)
{
int ret = 0;
@@ -50,7 +54,7 @@ int do_get_pm_info(struct xen_sysctl_get_pmstat *op)
/* 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 )
+ if ( !pmpt->perf.init && (op->type & PMSTAT_CATEGORY_MASK) == PMSTAT_PX )
return -EINVAL;
if ( !cpu_online(op->cpuid) )
@@ -100,6 +104,25 @@ int do_get_pm_info(struct xen_sysctl_get_pmstat *op)
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;
diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h
index 0a2c55b7cf..76998c946f 100644
--- a/xen/include/public/sysctl.h
+++ b/xen/include/public/sysctl.h
@@ -233,15 +233,30 @@ struct pm_px_stat {
typedef struct pm_px_stat pm_px_stat_t;
DEFINE_XEN_GUEST_HANDLE(pm_px_stat_t);
+struct pm_cx_stat {
+ uint32_t nr; /* entry nr in triggers & residencies, including C0 */
+ uint32_t last; /* last Cx state */
+ uint64_aligned_t idle_time; /* idle time from boot */
+ XEN_GUEST_HANDLE_64(uint64) triggers; /* Cx trigger counts */
+ XEN_GUEST_HANDLE_64(uint64) residencies; /* Cx residencies */
+};
+
struct xen_sysctl_get_pmstat {
-#define PMSTAT_get_max_px 0x11
-#define PMSTAT_get_pxstat 0x12
-#define PMSTAT_reset_pxstat 0x13
+#define PMSTAT_CATEGORY_MASK 0xf0
+#define PMSTAT_PX 0x10
+#define PMSTAT_CX 0x20
+#define PMSTAT_get_max_px (PMSTAT_PX | 0x1)
+#define PMSTAT_get_pxstat (PMSTAT_PX | 0x2)
+#define PMSTAT_reset_pxstat (PMSTAT_PX | 0x3)
+#define PMSTAT_get_max_cx (PMSTAT_CX | 0x1)
+#define PMSTAT_get_cxstat (PMSTAT_CX | 0x2)
+#define PMSTAT_reset_cxstat (PMSTAT_CX | 0x3)
uint32_t type;
uint32_t cpuid;
union {
struct pm_px_stat getpx;
- /* other struct for cx, tx, etc */
+ struct pm_cx_stat getcx;
+ /* other struct for tx, etc */
} u;
};
typedef struct xen_sysctl_get_pmstat xen_sysctl_get_pmstat_t;