# 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
|