According to MAINTAINERS I should send this here... Quite a while ago, after I bought my AMD notebook, I found out powertop did not fully work on newer AMD processors, because these processors only support C1E idling and not C2/C3. After a some digging, I came across a patch that adds C1E idle state accounting, in order to get Intels' "powertop" working. I am unsure about who originally wrote it, nor could I find out whether this patch has been send to a Linux mailing list previously and how it was received (forgive me if I overlooked it). I have been using/syncing the patch ever since, up to the latest git. (I must admit I did it a bit blindly however, because I am still unsure about the necessity of the first two changes in "acpi_processor_get_power_info" at all...) Since I haven't found any post mentioning the original patch, I hereby send my most recent version of it. Hopefully this patch or its intention can be reviewed and get submitted, because I really like using powertop and know others do too... Greetings, David G
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 0efa59e..356eecb 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -271,8 +271,11 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr) 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; @@ -312,6 +315,11 @@ static int acpi_processor_get_power_info_default(struct acpi_processor *pr) 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; @@ -653,24 +661,23 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr) 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); /* - * 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; } } @@ -821,6 +828,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, { ktime_t kt1, kt2; s64 idle_time; + s64 sleep_ticks = 0; struct acpi_processor *pr; struct acpi_processor_cx *cx = cpuidle_get_statedata(state); @@ -844,10 +852,14 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, kt2 = ktime_get_real(); idle_time = ktime_to_us(ktime_sub(kt2, kt1)); + sleep_ticks = us_to_pm_timer_ticks(idle_time); + local_irq_enable(); + cx->usage++; - lapic_timer_state_broadcast(pr, cx, 0); + lapic_timer_state_broadcast(pr, cx, 0); + cx->time += sleep_ticks; return idle_time; }