[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] x86: Add cpufreq logic to S3 suspend/resume
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1214579807 -3600 # Node ID baaea9f0db5eb153de5bb89e09f084a98e28ae99 # Parent 2ac9155a85c110dd25c963c8fa625c476556b474 x86: Add cpufreq logic to S3 suspend/resume When suspend to S3, stop the cpufreq dbs governor. When resume from S3, firstly 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. Signed-off-by: Liu Jinsong <jinsong.liu@xxxxxxxxx> --- xen/arch/x86/acpi/cpufreq/cpufreq.c | 139 +++++++++++++++++---------- xen/arch/x86/acpi/cpufreq/cpufreq_ondemand.c | 12 +- xen/arch/x86/acpi/cpufreq/utility.c | 86 ++++++++++++++++ xen/arch/x86/acpi/power.c | 5 xen/include/acpi/cpufreq/cpufreq.h | 3 xen/include/acpi/cpufreq/processor_perf.h | 7 + 6 files changed, 201 insertions(+), 51 deletions(-) diff -r 2ac9155a85c1 -r baaea9f0db5e xen/arch/x86/acpi/cpufreq/cpufreq.c --- a/xen/arch/x86/acpi/cpufreq/cpufreq.c Fri Jun 27 16:12:14 2008 +0100 +++ b/xen/arch/x86/acpi/cpufreq/cpufreq.c Fri Jun 27 16:16:47 2008 +0100 @@ -47,6 +47,10 @@ struct processor_pminfo processor_pminfo struct processor_pminfo processor_pminfo[NR_CPUS]; struct cpufreq_policy xen_px_policy[NR_CPUS]; +static cpumask_t *cpufreq_dom_pt; +static cpumask_t cpufreq_dom_mask; +static unsigned int cpufreq_dom_max; + enum { UNDEFINED_CAPABLE = 0, SYSTEM_INTEL_MSR_CAPABLE, @@ -60,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; }; @@ -328,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) { @@ -531,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; @@ -549,61 +554,101 @@ static struct cpufreq_driver acpi_cpufre .init = acpi_cpufreq_cpu_init, }; -int acpi_cpufreq_init(void) -{ - unsigned int i, ret = 0; - unsigned int dom, max_dom = 0; - cpumask_t *pt, dom_mask; - - cpus_clear(dom_mask); +void cpufreq_dom_exit(void) +{ + cpufreq_dom_max = 0; + cpus_clear(cpufreq_dom_mask); + if (cpufreq_dom_pt) + xfree(cpufreq_dom_pt); +} + +int cpufreq_dom_init(void) +{ + unsigned int i; + + cpufreq_dom_max = 0; + cpus_clear(cpufreq_dom_mask); for_each_online_cpu(i) { - cpu_set(processor_pminfo[i].perf.domain_info.domain, dom_mask); - if (max_dom < processor_pminfo[i].perf.domain_info.domain) - max_dom = processor_pminfo[i].perf.domain_info.domain; - } - max_dom++; - - pt = xmalloc_array(cpumask_t, max_dom); - if (!pt) + cpu_set(processor_pminfo[i].perf.domain_info.domain, cpufreq_dom_mask); + if (cpufreq_dom_max < processor_pminfo[i].perf.domain_info.domain) + cpufreq_dom_max = processor_pminfo[i].perf.domain_info.domain; + } + cpufreq_dom_max++; + + cpufreq_dom_pt = xmalloc_array(cpumask_t, cpufreq_dom_max); + if (!cpufreq_dom_pt) return -ENOMEM; - memset(pt, 0, max_dom * sizeof(cpumask_t)); - - /* get cpumask of each psd domain */ + memset(cpufreq_dom_pt, 0, cpufreq_dom_max * sizeof(cpumask_t)); + for_each_online_cpu(i) - cpu_set(i, pt[processor_pminfo[i].perf.domain_info.domain]); + cpu_set(i, cpufreq_dom_pt[processor_pminfo[i].perf.domain_info.domain]); for_each_online_cpu(i) - processor_pminfo[i].perf.shared_cpu_map = - pt[processor_pminfo[i].perf.domain_info.domain]; - - cpufreq_driver = &acpi_cpufreq_driver; - - /* setup cpufreq infrastructure */ + processor_pminfo[i].perf.shared_cpu_map = + cpufreq_dom_pt[processor_pminfo[i].perf.domain_info.domain]; + + return 0; +} + +static int cpufreq_cpu_init(void) +{ + int i, ret = 0; + for_each_online_cpu(i) { xen_px_policy[i].cpu = i; ret = px_statistic_init(i); if (ret) - goto out; + return ret; ret = acpi_cpufreq_cpu_init(&xen_px_policy[i]); if (ret) - goto out; - } - - /* setup ondemand cpufreq */ - for (dom=0; dom<max_dom; dom++) { - if (!cpu_isset(dom, dom_mask)) + return ret; + } + return ret; +} + +int cpufreq_dom_dbs(unsigned int event) +{ + int cpu, dom, ret = 0; + + for (dom=0; dom<cpufreq_dom_max; dom++) { + if (!cpu_isset(dom, cpufreq_dom_mask)) continue; - i = first_cpu(pt[dom]); - ret = cpufreq_governor_dbs(&xen_px_policy[i], CPUFREQ_GOV_START); + cpu = first_cpu(cpufreq_dom_pt[dom]); + ret = cpufreq_governor_dbs(&xen_px_policy[cpu], event); if (ret) - goto out; - } - -out: - xfree(pt); - + return ret; + } return ret; } + +int acpi_cpufreq_init(void) +{ + int ret = 0; + + /* setup cpumask of psd dom and shared cpu map of cpu */ + ret = cpufreq_dom_init(); + if (ret) + goto err; + + /* setup cpufreq driver */ + cpufreq_driver = &acpi_cpufreq_driver; + + /* setup cpufreq infrastructure */ + ret = cpufreq_cpu_init(); + if (ret) + goto err; + + /* setup cpufreq dbs according to dom coordiation */ + ret = cpufreq_dom_dbs(CPUFREQ_GOV_START); + if (ret) + goto err; + + return ret; + +err: + cpufreq_dom_exit(); + return ret; +} diff -r 2ac9155a85c1 -r baaea9f0db5e xen/arch/x86/acpi/cpufreq/cpufreq_ondemand.c --- a/xen/arch/x86/acpi/cpufreq/cpufreq_ondemand.c Fri Jun 27 16:12:14 2008 +0100 +++ b/xen/arch/x86/acpi/cpufreq/cpufreq_ondemand.c Fri Jun 27 16:16:47 2008 +0100 @@ -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 2ac9155a85c1 -r baaea9f0db5e xen/arch/x86/acpi/cpufreq/utility.c --- a/xen/arch/x86/acpi/cpufreq/utility.c Fri Jun 27 16:12:14 2008 +0100 +++ b/xen/arch/x86/acpi/cpufreq/utility.c Fri Jun 27 16:16:47 2008 +0100 @@ -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 2ac9155a85c1 -r baaea9f0db5e xen/arch/x86/acpi/power.c --- a/xen/arch/x86/acpi/power.c Fri Jun 27 16:12:14 2008 +0100 +++ b/xen/arch/x86/acpi/power.c Fri Jun 27 16:16:47 2008 +0100 @@ -27,6 +27,8 @@ #include <public/platform.h> #include <asm/tboot.h> +#include <acpi/cpufreq/cpufreq.h> + 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 2ac9155a85c1 -r baaea9f0db5e xen/include/acpi/cpufreq/cpufreq.h --- a/xen/include/acpi/cpufreq/cpufreq.h Fri Jun 27 16:12:14 2008 +0100 +++ b/xen/include/acpi/cpufreq/cpufreq.h Fri Jun 27 16:16:47 2008 +0100 @@ -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 2ac9155a85c1 -r baaea9f0db5e xen/include/acpi/cpufreq/processor_perf.h --- a/xen/include/acpi/cpufreq/processor_perf.h Fri Jun 27 16:12:14 2008 +0100 +++ b/xen/include/acpi/cpufreq/processor_perf.h Fri Jun 27 16:16:47 2008 +0100 @@ -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; _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |