fix sysfs showing the correct C-states after AC->DC and DC->AC transitions
Subsystems (2)
PATCH 1/1 fix sysfs showing the correct C-states after AC->DC and DC->AC transitions
Hello,
I do have a Samsung NC20 netbook which provides the C-states C1 and C2 to the OS when connected to AC, and additionally provides the C3 C-state when disconnected from AC. With the current kernels I have these two problems (regressions):
1. The number of C-states shown in sysfs is fixed to the number of C-states present at boot.
If I boot with AC connected, I always only see the C-states up to C2 even if I disconnect AC.
The reason is commit 130a5f692425e6237229598a8624da0a247f33d5 "ACPI / cpuidle: remove dev->state_count setting". It removes the update of dev->state_count, but sysfs uses exactly this variable to show the C-states.
The fix is to use drv->state_count in sysfs. As this is currently the last user of dev->state_count, this variable can be completely removed. And this is exactly what Bartlomiej Zolnierkiewicz's not yet applied patch "[PATCH v2 9/9] cpuidle: remove state_count field from struct cpuidle_device"
http://marc.info/?m=138756533317836 does.
Long story short: That patch fixes problem 1 for me.
2. After a AC->DC or DC->AC transition, the name and description of the POLLING C-state become "<null>".
Here, the reason is commit d7c7f103262bc2248548ed0e113e916e843c4eeb "cpuidle: don't call poll_idle_init() for every cpu". It only calls poll_idle_init() during cpuidle_register_driver() instead of cpuidle_enable_device() and thus does not re-initialize the fields of drv->states[0] after acpi_processor_setup_cpuidle_states() cleared them.
Here, the fix is to _not_ clear drv->states[0] in acpi_processor_setup_cpuidle_states(). For this purpose I created a small patch.
For your convenience, both of the fixing patches are attached to this mail. The first one is necessary for all kernels since 3.14, the second one for all kernels since 3.13. So I'd propose to push both of them also to the necessary stable kernels.
Kind regards,
Thomas
Quoted 1 line
From
cce99e1975a03b15e374dcd42099448a22390c65Mon Sep 17 00:00:00 2001
From: Bartlomiej Zolnierkiewicz <[email protected]>
Date: Tue, 31 Mar 2015 20:15:09 +0200
Subject: [PATCH 1/2] cpuidle: remove state_count field from struct
cpuidle_device
dev->state_count is now always equal to drv->state_count so it can be removed.
--- drivers/cpuidle/cpuidle.c | 3 --- drivers/cpuidle/sysfs.c | 5 +++-- include/linux/cpuidle.h | 1 - 3 files changed, 3 insertions(+), 6 deletions(-)
drivers/cpuidle/cpuidle.c +0 -3
@@ -330,9 +330,6 @@ int cpuidle_enable_device(struct cpuidle_device *dev)if (!dev->registered)return -EINVAL ; -if (!dev->state_count) - dev->state_count = drv->state_count; - ret =cpuidle_add_device_sysfs (dev);if (ret)return ret;
drivers/cpuidle/sysfs.c +3 -2
@@ -401,7 +401,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device)struct cpuidle_driver *drv =cpuidle_get_cpu_driver (device);/* state statistics */ -for (i =0 ; i < device->state_count; i++) { +for (i =0 ; i < drv->state_count; i++) { kobj =kzalloc (sizeof (struct cpuidle_state_kobj ),GFP_KERNEL );if (!kobj) goto error_state;
@@ -433,9 +433,10 @@ error_state:*/ static void cpuidle_remove_state_sysfs (struct cpuidle_device *device) { +struct cpuidle_driver *drv =cpuidle_get_cpu_driver (device);int i; -for (i =0 ; i < device->state_count; i++) +for (i =0 ; i < drv->state_count; i++)cpuidle_free_state_kobj (device, i); }
include/linux/cpuidle.h +0 -1
@@ -77,7 +77,6 @@ struct cpuidle_device {unsigned int cpu;int last_residency; -int state_count;struct cpuidle_state_usage states_usage[CPUIDLE_STATE_MAX ];struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX ];struct cpuidle_driver_kobj *kobj_driver;
Signature · 1 line
2.1.0
Quoted 1 line
From
d8357a73b8bf4e23a4b5ac4499224b39d0079ddbMon Sep 17 00:00:00 2001
From: Thomas Schlichter <[email protected]>
Date: Tue, 31 Mar 2015 20:24:39 +0200
Subject: [PATCH 2/2] ACPI / cpuidle: do not overwrite name and description of
C0
This fixes a bug that leads to showing name and description of C-state C0 as "<null>" in sysfs after the ACPI C-states changed (e.g. after AC->DC or DC->AC transition).
The function poll_idle_init() in drivers/cpuidle/driver.c initializes the state 0 during cpuidle_register_driver(). So we better do not overwrite it again with '\0' during acpi_processor_cst_has_changed().
--- drivers/acpi/processor_idle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/acpi/processor_idle.c +1 -1
@@ -922,7 +922,7 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)return -EINVAL ; drv->safe_state_index =-1 ; -for (i =0 ; i <CPUIDLE_STATE_MAX ; i++) { +for (i =CPUIDLE_DRIVER_STATE_START ; i <CPUIDLE_STATE_MAX ; i++) { drv->states[i].name[0 ] ='\0' ; drv->states[i].desc[0 ] ='\0' ; }
Signature · 1 line
2.1.0
Quoted 1 line · Thomas Schlichter
Hello,
Hi,
Quoted 15 lines
I do have a Samsung NC20 netbook which provides the C-states C1 and C2 to the OS when connected to AC, and additionally provides the C3 C-state when disconnected from AC. With the current kernels I have these two problems (regressions):
1. The number of C-states shown in sysfs is fixed to the number of C-states present at boot.
If I boot with AC connected, I always only see the C-states up to C2 even if I disconnect AC.The reason is commit
130a5f692425e6237229598a8624da0a247f33d5"ACPI / cpuidle: removedev->state_countsetting". It removes the update ofdev->state_count, but sysfs uses exactly this variable to show the C-states.
Quoted 7 lines
The fix is to use
drv->state_countin sysfs. As this is currently the last user ofdev->state_count, this variable can be completely removed. And this is exactly what Bartlomiej Zolnierkiewicz's not yet applied patch "[PATCH v2 9/9] cpuidle: removestate_countfield from structcpuidle_device"
http://marc.info/?m=138756533317836 does.Long story short: That patch fixes problem 1 for me.
Rafael, please apply that patch (as Thomas has noticed it is required to fix issue with dynamic dev/drv->state_count updates, sorry for not catching it earlier).
[ Originally the whole series was dropped when patch #8 ("[PATCH v2 8/9]
intel_idle: use the common cpuidle_[un]register() routines") turned out to introduce some problems. Patches #1-7 were later re-merged but not patch #9 (which is independent of patch #8). ]
Quoted 9 lines
2. After a
AC->DCorDC->ACtransition, the name and description of the POLLING C-state become "<null>".Here, the reason is commit
d7c7f103262bc2248548ed0e113e916e843c4eeb"cpuidle: don't callpoll_idle_init()for every cpu". It only callspoll_idle_init()duringcpuidle_register_driver()instead ofcpuidle_enable_device()and thus does not re-initialize the fields of drv->states[0] afteracpi_processor_setup_cpuidle_states()cleared them.
Quoted 3 lines
Here, the fix is to _not_ clear drv->states[0] in
acpi_processor_setup_cpuidle_states(). For this purpose I created a small patch.
This patch looks fine to me. FWIW:
Quoted 4 lines
For your convenience, both of the fixing patches are attached to this mail. The first one is necessary for all kernels since 3.14, the second one for all kernels since 3.13. So I'd propose to push both of them also to the necessary stable kernels.
Sounds good to me. Thank you for working on this.
Best regards,
--
Bartlomiej Zolnierkiewicz
Samsung R&D Institute Poland
Samsung Electronics