From patchwork Wed Jul 15 20:10:04 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Gaarenstroom X-Patchwork-Id: 35743 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n6FKAIgw012144 for ; Wed, 15 Jul 2009 20:10:18 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756219AbZGOUKI (ORCPT ); Wed, 15 Jul 2009 16:10:08 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1755980AbZGOUKI (ORCPT ); Wed, 15 Jul 2009 16:10:08 -0400 Received: from qw-out-2122.google.com ([74.125.92.25]:39828 "EHLO qw-out-2122.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756027AbZGOUKG (ORCPT ); Wed, 15 Jul 2009 16:10:06 -0400 Received: by qw-out-2122.google.com with SMTP id 8so746065qwh.37 for ; Wed, 15 Jul 2009 13:10:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:received:date:message-id:subject :from:to:content-type; bh=6B1pygT4WPLby2MbpedepYr2qh0AwpFy623p3RUZyzw=; b=w9oMzksL9F4WCQjse9qRRIXvVELeiIIAr6TewYEycIFS7xd8T9hGO5Zt+h9NGYSIiR V4pj7ri+0SucedL8QrL42CUzqrDvCc2ra0puPWFQ02oAKczfCopnWueUFFfJ5xETHE+3 TyQOthKaiK5s5udO89ifqqfeHngIb5dEBEHPo= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:date:message-id:subject:from:to:content-type; b=Ks7lfiqpLN/zn19eUtDJI/HV3hPrTq6zZ3q6r4owxzGPs8ydKOkUmKY9Zx+6eoV6SY rt7eLpk86qki/tq5onCjWlu5/OvwPdKQECdm9kLcWsoFn21ppHIe7BH47cPXHPflCt+U paG9M3grhsgE42VdKiHJ3yDMVFoFQxhbJW3Ig= MIME-Version: 1.0 Received: by 10.224.74.75 with SMTP id t11mr5152815qaj.31.1247688605095; Wed, 15 Jul 2009 13:10:05 -0700 (PDT) Date: Wed, 15 Jul 2009 22:10:04 +0200 Message-ID: <9783dadb0907151310w5debaa67t8660b2bc81b0ffc6@mail.gmail.com> Subject: [PATCH] Add C1 Idle time accounting for powertop/AMD C1E From: David Gaarenstroom To: lenb@kernel.org, linux-acpi@vger.kernel.org Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org 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; }