[PATCH] Add C1 Idle time accounting for powertop/AMD C1E

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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;
 }
 

[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux