aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Tian <kevin.tian@intel.com>2011-08-22 10:14:14 +0100
committerKevin Tian <kevin.tian@intel.com>2011-08-22 10:14:14 +0100
commit90a3c688f30c92cc943c2ac3307933eb9b4c5c52 (patch)
treed4c49ce5206cabb59b877572bc38a9f3ed3fe750
parente8685728a2aa87c2b236908ff5276338af353179 (diff)
downloadxen-90a3c688f30c92cc943c2ac3307933eb9b4c5c52.tar.gz
xen-90a3c688f30c92cc943c2ac3307933eb9b4c5c52.tar.bz2
xen-90a3c688f30c92cc943c2ac3307933eb9b4c5c52.zip
cpuidle: initialize default Cstate information
C0/C1 should be always available when cpuidle is enabled in Xen. When there's case that Dom0 doesn't register ACPI Cstate information, e.g. due to BIOS issue or acpi processor module is not installed, this patch provides basic C0/C1 information available to xenpm tool. Signed-off-by: Kevin Tian <kevin.tian@intel.com> xen-unstable changeset: 23662:2faba14bac13 xen-unstable date: Fri Jul 08 08:32:37 2011 +0100
-rw-r--r--xen/arch/x86/acpi/cpu_idle.c170
-rw-r--r--xen/arch/x86/smpboot.c1
2 files changed, 114 insertions, 57 deletions
diff --git a/xen/arch/x86/acpi/cpu_idle.c b/xen/arch/x86/acpi/cpu_idle.c
index b1001bcac0..deaf4e3f32 100644
--- a/xen/arch/x86/acpi/cpu_idle.c
+++ b/xen/arch/x86/acpi/cpu_idle.c
@@ -52,6 +52,8 @@
#include <public/sysctl.h>
#include <acpi/cpufreq/cpufreq.h>
#include <asm/apic.h>
+#include <xen/notifier.h>
+#include <xen/cpu.h>
/*#define DEBUG_PM_CX*/
@@ -598,23 +600,51 @@ default_halt:
halt();
}
-static int init_cx_pminfo(struct acpi_processor_power *acpi_power)
+static int cpuidle_init_cpu(int cpu)
{
- int i;
-
- memset(acpi_power, 0, sizeof(*acpi_power));
-
- for ( i = 0; i < ACPI_PROCESSOR_MAX_POWER; i++ )
- acpi_power->states[i].idx = i;
+ struct acpi_processor_power *acpi_power;
- acpi_power->states[ACPI_STATE_C1].type = ACPI_STATE_C1;
- acpi_power->states[ACPI_STATE_C1].entry_method = ACPI_CSTATE_EM_HALT;
+ acpi_power = processor_powers[cpu];
+ if ( !acpi_power )
+ {
+ int i;
+ acpi_power = xmalloc(struct acpi_processor_power);
+ if ( !acpi_power )
+ return -ENOMEM;
+ memset(acpi_power, 0, sizeof(*acpi_power));
- acpi_power->states[ACPI_STATE_C0].valid = 1;
- acpi_power->states[ACPI_STATE_C1].valid = 1;
+ for ( i = 0; i < ACPI_PROCESSOR_MAX_POWER; i++ )
+ acpi_power->states[i].idx = i;
+
+ acpi_power->states[ACPI_STATE_C1].type = ACPI_STATE_C1;
+ acpi_power->states[ACPI_STATE_C1].entry_method = ACPI_CSTATE_EM_HALT;
+
+ acpi_power->states[ACPI_STATE_C0].valid = 1;
+ acpi_power->states[ACPI_STATE_C1].valid = 1;
+
+ acpi_power->count = 2;
+ acpi_power->safe_state = &acpi_power->states[ACPI_STATE_C1];
+ acpi_power->cpu = cpu;
+ processor_powers[cpu] = acpi_power;
+ }
- acpi_power->count = 2;
- acpi_power->safe_state = &acpi_power->states[ACPI_STATE_C1];
+ if ( cpu == 0 )
+ {
+ if ( boot_cpu_has(X86_FEATURE_NONSTOP_TSC) )
+ {
+ get_tick = get_stime_tick;
+ ticks_elapsed = stime_ticks_elapsed;
+ tick_to_ns = stime_tick_to_ns;
+ ns_to_tick = ns_to_stime_tick;
+ }
+ else
+ {
+ get_tick = get_acpi_pm_tick;
+ ticks_elapsed = acpi_pm_ticks_elapsed;
+ tick_to_ns = acpi_pm_tick_to_ns;
+ ns_to_tick = ns_to_acpi_pm_tick;
+ }
+ }
return 0;
}
@@ -943,7 +973,7 @@ long set_cx_pminfo(uint32_t cpu, struct xen_processor_power *power)
XEN_GUEST_HANDLE(xen_processor_cx_t) states;
xen_processor_cx_t xen_cx;
struct acpi_processor_power *acpi_power;
- int cpu_id, i;
+ int cpu_id, i, ret;
if ( unlikely(!guest_handle_okay(power->states, power->count)) )
return -EFAULT;
@@ -955,46 +985,19 @@ long set_cx_pminfo(uint32_t cpu, struct xen_processor_power *power)
if ( cpu_id == -1 )
{
printk(XENLOG_ERR "no cpu_id for acpi_id %d\n", cpu);
- return -EFAULT;
- }
-
- if ( cpu_id == 0 )
- {
- if ( boot_cpu_has(X86_FEATURE_NONSTOP_TSC) )
- {
- get_tick = get_stime_tick;
- ticks_elapsed = stime_ticks_elapsed;
- tick_to_ns = stime_tick_to_ns;
- ns_to_tick = ns_to_stime_tick;
- }
- else
- {
- get_tick = get_acpi_pm_tick;
- ticks_elapsed = acpi_pm_ticks_elapsed;
- tick_to_ns = acpi_pm_tick_to_ns;
- ns_to_tick = ns_to_acpi_pm_tick;
- }
- }
-
- acpi_power = processor_powers[cpu_id];
- if ( !acpi_power )
- {
- acpi_power = xmalloc(struct acpi_processor_power);
- if ( !acpi_power )
- return -ENOMEM;
- memset(acpi_power, 0, sizeof(*acpi_power));
- processor_powers[cpu_id] = acpi_power;
+ return -EINVAL;
}
- init_cx_pminfo(acpi_power);
+ ret = cpuidle_init_cpu(cpu_id);
+ if ( ret < 0 )
+ return ret;
- acpi_power->cpu = cpu_id;
+ acpi_power = processor_powers[cpu_id];
acpi_power->flags.bm_check = power->flags.bm_check;
acpi_power->flags.bm_control = power->flags.bm_control;
acpi_power->flags.has_cst = power->flags.has_cst;
states = power->states;
-
for ( i = 0; i < power->count; i++ )
{
if ( unlikely(copy_from_guest_offset(&xen_cx, states, i, 1)) )
@@ -1009,19 +1012,17 @@ long set_cx_pminfo(uint32_t cpu, struct xen_processor_power *power)
/* FIXME: C-state dependency is not supported by far */
- /*print_acpi_power(cpu_id, acpi_power);*/
-
- if ( cpu_id == 0 && pm_idle_save == NULL )
- {
- pm_idle_save = pm_idle;
- pm_idle = acpi_processor_idle;
- }
-
if ( cpu_id == 0 )
{
+ if ( pm_idle_save == NULL )
+ {
+ pm_idle_save = pm_idle;
+ pm_idle = acpi_processor_idle;
+ }
+
dead_idle = acpi_dead_idle;
}
-
+
return 0;
}
@@ -1032,7 +1033,7 @@ uint32_t pmstat_get_cx_nr(uint32_t cpuid)
int pmstat_get_cx_stat(uint32_t cpuid, struct pm_cx_stat *stat)
{
- const struct acpi_processor_power *power = processor_powers[cpuid];
+ struct acpi_processor_power *power = processor_powers[cpuid];
uint64_t usage, res, idle_usage = 0, idle_res = 0;
int i;
struct hw_residencies hw_res = {0};
@@ -1049,6 +1050,30 @@ int pmstat_get_cx_stat(uint32_t cpuid, struct pm_cx_stat *stat)
stat->nr = power->count;
stat->idle_time = get_cpu_idle_time(cpuid);
+ /* mimic the stat when detail info hasn't been registered by dom0 */
+ if ( pm_idle_save == NULL )
+ {
+ /* C1 */
+ usage = 1;
+ res = stat->idle_time;
+ if ( copy_to_guest_offset(stat->triggers, 1, &usage, 1) ||
+ copy_to_guest_offset(stat->residencies, 1, &res, 1) )
+ return -EFAULT;
+
+ /* C0 */
+ res = NOW() - res;
+ if ( copy_to_guest_offset(stat->triggers, 0, &usage, 1) ||
+ copy_to_guest_offset(stat->residencies, 0, &res, 1) )
+ return -EFAULT;
+
+ stat->pc3 = 0;
+ stat->pc6 = 0;
+ stat->pc7 = 0;
+ stat->cc3 = 0;
+ stat->cc6 = 0;
+ return 0;
+ }
+
for ( i = power->count - 1; i >= 0; i-- )
{
if ( i != 0 )
@@ -1103,3 +1128,36 @@ bool_t cpuidle_using_deep_cstate(void)
{
return xen_cpuidle && max_cstate > (local_apic_timer_c2_ok ? 2 : 1);
}
+
+static int cpu_callback(
+ struct notifier_block *nfb, unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+
+ /* Only hook on CPU_ONLINE because a dead cpu may utilize the info to
+ * to enter deep C-state */
+ switch ( action )
+ {
+ case CPU_ONLINE:
+ (void)cpuidle_init_cpu(cpu);
+ break;
+ default:
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block cpu_nfb = {
+ .notifier_call = cpu_callback
+};
+
+static int __init cpuidle_presmp_init(void)
+{
+ void *cpu = (void *)(long)smp_processor_id();
+ cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
+ register_cpu_notifier(&cpu_nfb);
+ return 0;
+}
+presmp_initcall(cpuidle_presmp_init);
+
diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c
index 73539c64ed..7da84a061a 100644
--- a/xen/arch/x86/smpboot.c
+++ b/xen/arch/x86/smpboot.c
@@ -45,7 +45,6 @@
#include <mach_apic.h>
#include <mach_wakecpu.h>
#include <smpboot_hooks.h>
-#include <acpi/cpufreq/processor_perf.h>
#define setup_trampoline() (bootsym_phys(trampoline_realmode_entry))