# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1225373620 0
# Node ID 112e81ae5824e213b181a65f944b729ba270d658
# Parent 1137464400a81bbfe7a5093a07102b2ded7a4684
CPUIDLE: Support C1 FFH entry
Add support for C1 FFH (mwait) entry. Meanwhile add timing for C1. The
timing for C1 should be accurate for FFH case, but may not for halt case.
Signed-off-by: Wei Gang <gang.wei@xxxxxxxxx>
---
xen/arch/x86/acpi/cpu_idle.c | 84 ++++++++++++++++++---------------------
xen/arch/x86/acpi/cpuidle_menu.c | 14 ------
xen/include/xen/cpuidle.h | 7 ++-
3 files changed, 48 insertions(+), 57 deletions(-)
diff -r 1137464400a8 -r 112e81ae5824 xen/arch/x86/acpi/cpu_idle.c
--- a/xen/arch/x86/acpi/cpu_idle.c Thu Oct 30 13:33:17 2008 +0000
+++ b/xen/arch/x86/acpi/cpu_idle.c Thu Oct 30 13:33:40 2008 +0000
@@ -140,20 +140,26 @@ static void acpi_processor_ffh_cstate_en
static void acpi_idle_do_entry(struct acpi_processor_cx *cx)
{
- if ( cx->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE )
- {
+ int unused;
+
+ switch ( cx->entry_method )
+ {
+ case ACPI_CSTATE_EM_FFH:
/* Call into architectural FFH based C-state */
acpi_processor_ffh_cstate_enter(cx);
- }
- else
- {
- int unused;
+ return;
+ case ACPI_CSTATE_EM_SYSIO:
/* IO port based C-state */
inb(cx->address);
/* Dummy wait op - must do something useless after P_LVL2 read
because chipsets cannot guarantee that STPCLK# signal
gets asserted in time to freeze execution properly. */
unused = inl(pmtmr_ioport);
+ return;
+ case ACPI_CSTATE_EM_HALT:
+ acpi_safe_halt();
+ local_irq_disable();
+ return;
}
}
@@ -253,35 +259,11 @@ static void acpi_processor_idle(void)
switch ( cx->type )
{
case ACPI_STATE_C1:
- /* Trace cpu idle entry */
- TRACE_1D(TRC_PM_IDLE_ENTRY, 1);
-
- /*
- * Invoke C1.
- * Use the appropriate idle routine, the one that would
- * be used without acpi C-states.
- */
- if ( pm_idle_save )
- pm_idle_save();
- else
- acpi_safe_halt();
-
- /* Trace cpu idle exit */
- TRACE_1D(TRC_PM_IDLE_EXIT, 1);
-
- /*
- * TBD: Can't get time duration while in C1, as resumes
- * go to an ISR rather than here. Need to instrument
- * base interrupt handler.
- */
- sleep_ticks = 0xFFFFFFFF;
- break;
-
case ACPI_STATE_C2:
- if ( local_apic_timer_c2_ok )
+ if ( cx->type == ACPI_STATE_C1 || local_apic_timer_c2_ok )
{
/* Trace cpu idle entry */
- TRACE_1D(TRC_PM_IDLE_ENTRY, 2);
+ TRACE_1D(TRC_PM_IDLE_ENTRY, cx->idx);
/* Get start time (ticks) */
t1 = inl(pmtmr_ioport);
/* Invoke C2 */
@@ -289,7 +271,7 @@ static void acpi_processor_idle(void)
/* Get end time (ticks) */
t2 = inl(pmtmr_ioport);
/* Trace cpu idle exit */
- TRACE_1D(TRC_PM_IDLE_EXIT, 2);
+ TRACE_1D(TRC_PM_IDLE_EXIT, cx->idx);
/* Re-enable interrupts */
local_irq_enable();
@@ -396,6 +378,7 @@ static int init_cx_pminfo(struct acpi_pr
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;
@@ -492,16 +475,13 @@ static int check_cx(struct acpi_processo
break;
case ACPI_ADR_SPACE_FIXED_HARDWARE:
- if ( cx->type > ACPI_STATE_C1 )
- {
- if ( cx->reg.bit_width != VENDOR_INTEL ||
- cx->reg.bit_offset != NATIVE_CSTATE_BEYOND_HALT )
- return -EINVAL;
-
- /* assume all logical cpu has the same support for mwait */
- if ( acpi_processor_ffh_cstate_probe(cx) )
- return -EINVAL;
- }
+ if ( cx->reg.bit_width != VENDOR_INTEL ||
+ cx->reg.bit_offset != NATIVE_CSTATE_BEYOND_HALT )
+ return -EINVAL;
+
+ /* assume all logical cpu has the same support for mwait */
+ if ( acpi_processor_ffh_cstate_probe(cx) )
+ return -EINVAL;
break;
default:
@@ -605,7 +585,23 @@ static void set_cx(
cx->valid = 1;
cx->type = xen_cx->type;
cx->address = xen_cx->reg.address;
- cx->space_id = xen_cx->reg.space_id;
+
+ switch ( xen_cx->reg.space_id )
+ {
+ case ACPI_ADR_SPACE_FIXED_HARDWARE:
+ if ( xen_cx->reg.bit_width == VENDOR_INTEL &&
+ xen_cx->reg.bit_offset == NATIVE_CSTATE_BEYOND_HALT )
+ cx->entry_method = ACPI_CSTATE_EM_FFH;
+ else
+ cx->entry_method = ACPI_CSTATE_EM_HALT;
+ break;
+ case ACPI_ADR_SPACE_SYSTEM_IO:
+ cx->entry_method = ACPI_CSTATE_EM_SYSIO;
+ break;
+ default:
+ cx->entry_method = ACPI_CSTATE_EM_NONE;
+ }
+
cx->latency = xen_cx->latency;
cx->power = xen_cx->power;
diff -r 1137464400a8 -r 112e81ae5824 xen/arch/x86/acpi/cpuidle_menu.c
--- a/xen/arch/x86/acpi/cpuidle_menu.c Thu Oct 30 13:33:17 2008 +0000
+++ b/xen/arch/x86/acpi/cpuidle_menu.c Thu Oct 30 13:33:40 2008 +0000
@@ -59,7 +59,7 @@ static int menu_select(struct acpi_proce
data->expected_us = (u32) get_sleep_length_ns() / 1000;
/* find the deepest idle state that satisfies our constraints */
- for ( i = 1; i < power->count; i++ )
+ for ( i = 2; i < power->count; i++ )
{
struct acpi_processor_cx *s = &power->states[i];
@@ -81,17 +81,7 @@ static void menu_reflect(struct acpi_pro
unsigned int last_residency;
unsigned int measured_us;
- /*
- * Ugh, this idle state doesn't support residency measurements, so we
- * are basically lost in the dark. As a compromise, assume we slept
- * for one full standard timer tick. However, be aware that this
- * could potentially result in a suboptimal state transition.
- */
- if ( target->type == ACPI_STATE_C1 )
- last_residency = USEC_PER_SEC / HZ;
- else
- last_residency = power->last_residency;
-
+ last_residency = power->last_residency;
measured_us = last_residency + data->elapsed_us;
/* if wrapping, set to max uint (-1) */
diff -r 1137464400a8 -r 112e81ae5824 xen/include/xen/cpuidle.h
--- a/xen/include/xen/cpuidle.h Thu Oct 30 13:33:17 2008 +0000
+++ b/xen/include/xen/cpuidle.h Thu Oct 30 13:33:40 2008 +0000
@@ -30,13 +30,18 @@
#define ACPI_PROCESSOR_MAX_POWER 8
#define CPUIDLE_NAME_LEN 16
+#define ACPI_CSTATE_EM_NONE 0
+#define ACPI_CSTATE_EM_SYSIO 1
+#define ACPI_CSTATE_EM_FFH 2
+#define ACPI_CSTATE_EM_HALT 3
+
struct acpi_processor_cx
{
u8 idx;
u8 valid;
u8 type;
u32 address;
- u8 space_id;
+ u8 entry_method; /* ACPI_CSTATE_EM_xxx */
u32 latency;
u32 latency_ticks;
u32 power;
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|