Cpufreq S3 suspend/resume logic Based on cpufreq init logic reconstruct, this patch implement cpufreq S3 suspend/resume logic. When suspend to S3, it stop cpufreq dbs governor; When resume from S3, firstly it sync cpu state and freq at the 1st dbs timer; from 2nd dbs timer on, cpufreq dbs governor control cpu px transfer according to its workload algorithm. Px statistic is also handled S3 suspend/reusme accordingly. Signed-off-by: Liu Jinsong diff -r 3cad3a1a14c5 xen/arch/x86/acpi/cpufreq/cpufreq.c --- a/xen/arch/x86/acpi/cpufreq/cpufreq.c Sat Jun 21 15:46:41 2008 +0800 +++ b/xen/arch/x86/acpi/cpufreq/cpufreq.c Sat Jun 21 15:50:16 2008 +0800 @@ -64,7 +64,6 @@ struct acpi_cpufreq_data { struct processor_performance *acpi_data; struct cpufreq_frequency_table *freq_table; unsigned int max_freq; - unsigned int resume; unsigned int cpu_feature; }; @@ -332,14 +331,16 @@ static int acpi_cpufreq_target(struct cp next_perf_state = data->freq_table[next_state].index; if (perf->state == next_perf_state) { - if (unlikely(data->resume)) { - printk("xen_pminfo: @acpi_cpufreq_target, " - "Called after resume, resetting to P%d\n", + if (unlikely(policy->resume)) { + printk(KERN_INFO "Called after resume, resetting to P%d\n", next_perf_state); - data->resume = 0; + policy->resume = 0; } - else + else { + printk(KERN_INFO "Already at target state (P%d)\n", + next_perf_state); return 0; + } } switch (data->cpu_feature) { @@ -535,7 +536,7 @@ acpi_cpufreq_cpu_init(struct cpufreq_pol * the first call to ->target() should result in us actually * writing something to the appropriate registers. */ - data->resume = 1; + policy->resume = 1; return result; diff -r 3cad3a1a14c5 xen/arch/x86/acpi/cpufreq/cpufreq_ondemand.c --- a/xen/arch/x86/acpi/cpufreq/cpufreq_ondemand.c Sat Jun 21 15:46:41 2008 +0800 +++ b/xen/arch/x86/acpi/cpufreq/cpufreq_ondemand.c Sat Jun 21 15:50:16 2008 +0800 @@ -79,6 +79,12 @@ static void dbs_check_cpu(struct cpu_dbs return; policy = this_dbs_info->cur_policy; + + if (unlikely(policy->resume)) { + __cpufreq_driver_target(policy, policy->max,CPUFREQ_RELATION_H); + return; + } + cur_ns = NOW(); total_ns = cur_ns - this_dbs_info->prev_cpu_wall; this_dbs_info->prev_cpu_wall = NOW(); @@ -217,8 +223,7 @@ int cpufreq_governor_dbs(struct cpufreq_ break; case CPUFREQ_GOV_STOP: - if (this_dbs_info->enable) - dbs_timer_exit(this_dbs_info); + dbs_timer_exit(this_dbs_info); dbs_enable--; break; @@ -233,5 +238,4 @@ int cpufreq_governor_dbs(struct cpufreq_ break; } return 0; -} - +} diff -r 3cad3a1a14c5 xen/arch/x86/acpi/cpufreq/utility.c --- a/xen/arch/x86/acpi/cpufreq/utility.c Sat Jun 21 15:46:41 2008 +0800 +++ b/xen/arch/x86/acpi/cpufreq/utility.c Sat Jun 21 15:50:16 2008 +0800 @@ -36,6 +36,33 @@ struct cpufreq_driver *cpufreq_driver; /********************************************************************* * Px STATISTIC INFO * *********************************************************************/ + +void px_statistic_suspend(void) +{ + int cpu; + uint64_t now; + + now = NOW(); + + for_each_online_cpu(cpu) { + struct pm_px *pxpt = &px_statistic_data[cpu]; + pxpt->u.pt[pxpt->u.cur].residency += + now - pxpt->prev_state_wall; + } +} + +void px_statistic_resume(void) +{ + int cpu; + uint64_t now; + + now = NOW(); + + for_each_online_cpu(cpu) { + struct pm_px *pxpt = &px_statistic_data[cpu]; + pxpt->prev_state_wall = now; + } +} void px_statistic_update(cpumask_t cpumask, uint8_t from, uint8_t to) { @@ -242,3 +269,62 @@ int __cpufreq_driver_getavg(struct cpufr return ret; } + + +/********************************************************************* + * CPUFREQ SUSPEND/RESUME * + *********************************************************************/ + +void cpufreq_suspend(void) +{ + int cpu; + + /* 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 */ + for_each_online_cpu(cpu) { + struct processor_performance *perf = &processor_pminfo[cpu].perf; + + if (!perf->init) + return; + } + + cpufreq_dom_dbs(CPUFREQ_GOV_STOP); + + cpufreq_dom_exit(); + + px_statistic_suspend(); +} + +int cpufreq_resume(void) +{ + int cpu, ret = 0; + + /* 1. 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 */ + /* 2. set state and resume flag to sync cpu to right state and freq */ + for_each_online_cpu(cpu) { + struct processor_performance *perf = &processor_pminfo[cpu].perf; + struct cpufreq_policy *policy = &xen_px_policy[cpu]; + + if (!perf->init) + goto err; + perf->state = 0; + policy->resume = 1; + } + + px_statistic_resume(); + + ret = cpufreq_dom_init(); + if (ret) + goto err; + + ret = cpufreq_dom_dbs(CPUFREQ_GOV_START); + if (ret) + goto err; + + return ret; + +err: + cpufreq_dom_exit(); + return ret; +} diff -r 3cad3a1a14c5 xen/arch/x86/acpi/power.c --- a/xen/arch/x86/acpi/power.c Sat Jun 21 15:46:41 2008 +0800 +++ b/xen/arch/x86/acpi/power.c Sat Jun 21 15:52:46 2008 +0800 @@ -27,6 +27,8 @@ #include #include +#include + static char opt_acpi_sleep[20]; string_param("acpi_sleep", opt_acpi_sleep); @@ -125,6 +127,8 @@ static int enter_state(u32 state) printk(XENLOG_INFO "Preparing system for ACPI S%d state.", state); freeze_domains(); + + cpufreq_suspend(); disable_nonboot_cpus(); if ( num_online_cpus() != 1 ) @@ -181,6 +185,7 @@ static int enter_state(u32 state) enable_cpu: enable_nonboot_cpus(); + cpufreq_resume(); thaw_domains(); spin_unlock(&pm_lock); return error; diff -r 3cad3a1a14c5 xen/include/acpi/cpufreq/cpufreq.h --- a/xen/include/acpi/cpufreq/cpufreq.h Sat Jun 21 15:46:41 2008 +0800 +++ b/xen/include/acpi/cpufreq/cpufreq.h Sat Jun 21 15:50:16 2008 +0800 @@ -36,7 +36,10 @@ struct cpufreq_policy { unsigned int max; /* in kHz */ unsigned int cur; /* in kHz, only needed if cpufreq * governors are used */ + unsigned int resume; /* flag for cpufreq 1st run + * S3 wakeup, hotplug cpu, etc */ }; +extern struct cpufreq_policy xen_px_policy[NR_CPUS]; #define CPUFREQ_SHARED_TYPE_NONE (0) /* None */ #define CPUFREQ_SHARED_TYPE_HW (1) /* HW does needed coordination */ diff -r 3cad3a1a14c5 xen/include/acpi/cpufreq/processor_perf.h --- a/xen/include/acpi/cpufreq/processor_perf.h Sat Jun 21 15:46:41 2008 +0800 +++ b/xen/include/acpi/cpufreq/processor_perf.h Sat Jun 21 15:50:16 2008 +0800 @@ -10,6 +10,13 @@ void px_statistic_update(cpumask_t, uint void px_statistic_update(cpumask_t, uint8_t, uint8_t); int px_statistic_init(int); void px_statistic_reset(int); +void px_statistic_suspend(void); +void px_statistic_resume(void); +void cpufreq_dom_exit(void); +int cpufreq_dom_init(void); +int cpufreq_dom_dbs(unsigned int); +void cpufreq_suspend(void); +int cpufreq_resume(void); struct processor_performance { uint32_t state;