https://bugzilla.novell.com/show_bug.cgi?id=432809 Summary: C1 state unsupported on modern AMD mobile CPUs Product: openSUSE 11.0 Version: Final Platform: Other OS/Version: openSUSE 11.0 Status: NEW Severity: Normal Priority: P5 - None Component: Kernel AssignedTo: bnc-team-screening@forge.provo.novell.com ReportedBy: jakub007@go2.pl QAContact: qa@suse.de Found By: Corporate Interoperability Test Newer laptops with AMD Turion X2 and AMD Athlon X2 mobile processors (which are C1E capable) are overheating and have very degraded battery life due to bugs in /usr/src/linux/drivers/acpi/processor_idle.c (not properly implemented C1 support). C1E replaces C2 and C3 states, so BIOS usually doesn't have definitions for _CST and PBLK in FADT - it is valid according to ACPI specification. Here is MS info about PPM in Vista: http://download.microsoft.com/download/0/0/b/00bba048-35e6-4e5b-a3dc-36da83c... Below is patch which fixes C1 visibility, but doesn't increase battery life to Vista level. --- cut here -- --- kernels/linux-2.6.27-rc8/drivers/acpi/processor_idle.c 2008-09-30 00:24:02.000000000 +0200 +++ linux/drivers/acpi/processor_idle.c 2008-10-06 00:24:19.000000000 +0200 @@ -501,7 +501,7 @@ * ------ * Invoke the current Cx state to put the processor to sleep. */ - if (cx->type == ACPI_STATE_C2 || cx->type == ACPI_STATE_C3) { + if (cx->type >= ACPI_STATE_C1) { current_thread_info()->status &= ~TS_POLLING; /* * TS_POLLING-cleared state must be visible before we @@ -523,12 +523,17 @@ * Use the appropriate idle routine, the one that would * be used without acpi C-states. */ + + t1 = jiffies; + if (pm_idle_save) { pm_idle_save(); /* enables IRQs */ } else { acpi_safe_halt(); local_irq_enable(); } + + t2 = jiffies; /* * TBD: Can't get time duration while in C1, as resumes @@ -538,8 +543,7 @@ * Note: the TSC better not stop in C1, sched_clock() will * skew otherwise. */ - sleep_ticks = 0xFFFFFFFF; - + sleep_ticks = ticks_elapsed(t1, t2); break; case ACPI_STATE_C2: @@ -642,12 +646,13 @@ return; } cx->usage++; - if ((cx->type != ACPI_STATE_C1) && (sleep_ticks > 0)) + if (cx->type != ACPI_STATE_C1 && sleep_ticks > 0) cx->time += sleep_ticks; next_state = pr->power.state; #ifdef CONFIG_HOTPLUG_CPU + /* Don't do promotion/demotion */ if ((cx->type == ACPI_STATE_C1) && (num_online_cpus() > 1) && !pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) { @@ -811,8 +816,11 @@ if (!pr) return -EINVAL; + /* Newer dual-core CPUs use C1E instead of C2 and C3 and + * usually do not have _CST definitions or PBLK entries. + * ACPI specification allows for that so return zero here */ if (!pr->pblk) - return -ENODEV; + return 0; /* if info is obtained from pblk/fadt, type equals state */ pr->power.states[ACPI_STATE_C2].type = ACPI_STATE_C2; @@ -852,6 +860,11 @@ pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1; pr->power.states[ACPI_STATE_C1].valid = 1; pr->power.states[ACPI_STATE_C1].entry_method = ACPI_CSTATE_HALT; + snprintf(pr->power.states[ACPI_STATE_C1].desc, ACPI_CX_DESC_LEN, "ACPI HLT"); + if (!pr->power.states[ACPI_STATE_C1].latency) + pr->power.states[ACPI_STATE_C1].latency = 1; + if (!pr->power.states[ACPI_STATE_C1].power) + pr->power.states[ACPI_STATE_C1].power = 1000; } /* the C0 state only exists as a filler in our array */ pr->power.states[ACPI_STATE_C0].valid = 1; @@ -1191,12 +1204,11 @@ memset(pr->power.states, 0, sizeof(pr->power.states)); result = acpi_processor_get_power_info_cst(pr); - if (result == -ENODEV) - result = acpi_processor_get_power_info_fadt(pr); - if (result) - return result; + result = acpi_processor_get_power_info_fadt(pr); + /* No valid _CST and FADT, but C1 must be supported, + * so here we go */ acpi_processor_get_power_info_default(pr); pr->power.count = acpi_processor_power_verify(pr); @@ -1216,13 +1228,13 @@ #endif /* - * if one state of type C2 or C3 is available, mark this + * if one state of type C1(e), C2 or C3 is available, mark this * CPU as being "idle manageable" */ for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) { if (pr->power.states[i].valid) { pr->power.count = i; - if (pr->power.states[i].type >= ACPI_STATE_C2) + if (pr->power.states[i].type >= ACPI_STATE_C1) pr->flags.power = 1; } } @@ -1455,7 +1467,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, struct cpuidle_state *state) { - u32 t1, t2; + u32 t1, t2, elapsed; struct acpi_processor *pr; struct acpi_processor_cx *cx = cpuidle_get_statedata(state); @@ -1482,7 +1494,10 @@ local_irq_enable(); cx->usage++; - + elapsed = ticks_elapsed(t1, t2); + if (elapsed > 0) + cx->time += elapsed; + return ticks_elapsed_in_us(t1, t2); } -- cut here -- -- Configure bugmail: https://bugzilla.novell.com/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are on the CC list for the bug.