Skip to content

Commit b5a3163

Browse files
Rongronggg9popcornmix
authored andcommitted
platform/x86: ideapad-laptop: use usleep_range() for EC polling
commit 5808c34 upstream. It was reported that ideapad-laptop sometimes causes some recent (since 2024) Lenovo ThinkBook models shut down when: - suspending/resuming - closing/opening the lid - (dis)connecting a charger - reading/writing some sysfs properties, e.g., fan_mode, touchpad - pressing down some Fn keys, e.g., Brightness Up/Down (Fn+F5/F6) - (seldom) loading the kmod The issue has existed since the launch day of such models, and there have been some out-of-tree workarounds (see Link:) for the issue. One disables some functionalities, while another one simply shortens IDEAPAD_EC_TIMEOUT. The disabled functionalities have read_ec_data() in their call chains, which calls schedule() between each poll. It turns out that these models suffer from the indeterminacy of schedule() because of their low tolerance for being polled too frequently. Sometimes schedule() returns too soon due to the lack of ready tasks, causing the margin between two polls to be too short. In this case, the command is somehow aborted, and too many subsequent polls (they poll for "nothing!") may eventually break the state machine in the EC, resulting in a hard shutdown. This explains why shortening IDEAPAD_EC_TIMEOUT works around the issue - it reduces the total number of polls sent to the EC. Even when it doesn't lead to a shutdown, frequent polls may also disturb the ongoing operation and notably delay (+ 10-20ms) the availability of EC response. This phenomenon is unlikely to be exclusive to the models mentioned above, so dropping the schedule() manner should also slightly improve the responsiveness of various models. Fix these issues by migrating to usleep_range(150, 300). The interval is chosen to add some margin to the minimal 50us and considering EC responses are usually available after 150-2500us based on my test. It should be enough to fix these issues on all models subject to the EC bug without introducing latency on other models. Tested on ThinkBook 14 G7+ ASP and solved both issues. No regression was introduced in the test on a model without the EC bug (ThinkBook X IMH, thanks Eric). Link: ty2/ideapad-laptop-tb2024g6plus@6c5db18 Link: ferstar/ideapad-laptop-tb@42d1e68 Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218771 Fixes: 6a09f21 ("ideapad: add ACPI helpers") Cc: stable@vger.kernel.org Tested-by: Felix Yan <felixonmars@archlinux.org> Tested-by: Eric Long <i@hack3r.moe> Tested-by: Jianfei Zhang <zhangjianfei3@gmail.com> Tested-by: Mingcong Bai <jeffbai@aosc.io> Tested-by: Minh Le <minhld139@gmail.com> Tested-by: Sicheng Zhu <Emmet_Z@outlook.com> Signed-off-by: Rong Zhang <i@rong.moe> Link: https://lore.kernel.org/r/20250525201833.37939-1-i@rong.moe Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 2d39d3c commit b5a3163

File tree

1 file changed

+17
-2
lines changed

1 file changed

+17
-2
lines changed

drivers/platform/x86/ideapad-laptop.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <linux/bug.h>
1616
#include <linux/cleanup.h>
1717
#include <linux/debugfs.h>
18+
#include <linux/delay.h>
1819
#include <linux/device.h>
1920
#include <linux/dmi.h>
2021
#include <linux/i8042.h>
@@ -267,6 +268,20 @@ static void ideapad_shared_exit(struct ideapad_private *priv)
267268
*/
268269
#define IDEAPAD_EC_TIMEOUT 200 /* in ms */
269270

271+
/*
272+
* Some models (e.g., ThinkBook since 2024) have a low tolerance for being
273+
* polled too frequently. Doing so may break the state machine in the EC,
274+
* resulting in a hard shutdown.
275+
*
276+
* It is also observed that frequent polls may disturb the ongoing operation
277+
* and notably delay the availability of EC response.
278+
*
279+
* These values are used as the delay before the first poll and the interval
280+
* between subsequent polls to solve the above issues.
281+
*/
282+
#define IDEAPAD_EC_POLL_MIN_US 150
283+
#define IDEAPAD_EC_POLL_MAX_US 300
284+
270285
static int eval_int(acpi_handle handle, const char *name, unsigned long *res)
271286
{
272287
unsigned long long result;
@@ -383,7 +398,7 @@ static int read_ec_data(acpi_handle handle, unsigned long cmd, unsigned long *da
383398
end_jiffies = jiffies + msecs_to_jiffies(IDEAPAD_EC_TIMEOUT) + 1;
384399

385400
while (time_before(jiffies, end_jiffies)) {
386-
schedule();
401+
usleep_range(IDEAPAD_EC_POLL_MIN_US, IDEAPAD_EC_POLL_MAX_US);
387402

388403
err = eval_vpcr(handle, 1, &val);
389404
if (err)
@@ -414,7 +429,7 @@ static int write_ec_cmd(acpi_handle handle, unsigned long cmd, unsigned long dat
414429
end_jiffies = jiffies + msecs_to_jiffies(IDEAPAD_EC_TIMEOUT) + 1;
415430

416431
while (time_before(jiffies, end_jiffies)) {
417-
schedule();
432+
usleep_range(IDEAPAD_EC_POLL_MIN_US, IDEAPAD_EC_POLL_MAX_US);
418433

419434
err = eval_vpcr(handle, 1, &val);
420435
if (err)

0 commit comments

Comments
 (0)