Skip to content

Commit 7cc06e7

Browse files
soyersoyerij-intel
authored andcommitted
platform/x86: ideapad-laptop: add a mutex to synchronize VPC commands
Calling VPC commands consists of several VPCW and VPCR ACPI calls. These calls and their results can get mixed up if they are called simultaneously from different threads, like acpi notify handler, sysfs, debugfs, notification chain. The commit e2ffcda ("ACPI: OSL: Allow Notify () handlers to run on all CPUs") made the race issues much worse than before it but some races were possible even before that commit. Add a mutex to synchronize VPC commands. Fixes: e2ffcda ("ACPI: OSL: Allow Notify () handlers to run on all CPUs") Fixes: e82882c ("platform/x86: Add driver for Yoga Tablet Mode switch") Signed-off-by: Gergo Koteles <[email protected]> Link: https://lore.kernel.org/r/f26782fa1194ad11ed5d9ba121a804e59b58b026.1721898747.git.soyer@irl.hu Reviewed-by: Ilpo Järvinen <[email protected]> Signed-off-by: Ilpo Järvinen <[email protected]>
1 parent cde7886 commit 7cc06e7

File tree

1 file changed

+47
-17
lines changed

1 file changed

+47
-17
lines changed

drivers/platform/x86/ideapad-laptop.c

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ struct ideapad_rfk_priv {
126126

127127
struct ideapad_private {
128128
struct acpi_device *adev;
129+
struct mutex vpc_mutex; /* protects the VPC calls */
129130
struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM];
130131
struct ideapad_rfk_priv rfk_priv[IDEAPAD_RFKILL_DEV_NUM];
131132
struct platform_device *platform_device;
@@ -301,6 +302,8 @@ static int debugfs_status_show(struct seq_file *s, void *data)
301302
struct ideapad_private *priv = s->private;
302303
unsigned long value;
303304

305+
guard(mutex)(&priv->vpc_mutex);
306+
304307
if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &value))
305308
seq_printf(s, "Backlight max: %lu\n", value);
306309
if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL, &value))
@@ -419,7 +422,8 @@ static ssize_t camera_power_show(struct device *dev,
419422
unsigned long result;
420423
int err;
421424

422-
err = read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &result);
425+
scoped_guard(mutex, &priv->vpc_mutex)
426+
err = read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &result);
423427
if (err)
424428
return err;
425429

@@ -438,7 +442,8 @@ static ssize_t camera_power_store(struct device *dev,
438442
if (err)
439443
return err;
440444

441-
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_CAMERA, state);
445+
scoped_guard(mutex, &priv->vpc_mutex)
446+
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_CAMERA, state);
442447
if (err)
443448
return err;
444449

@@ -491,7 +496,8 @@ static ssize_t fan_mode_show(struct device *dev,
491496
unsigned long result;
492497
int err;
493498

494-
err = read_ec_data(priv->adev->handle, VPCCMD_R_FAN, &result);
499+
scoped_guard(mutex, &priv->vpc_mutex)
500+
err = read_ec_data(priv->adev->handle, VPCCMD_R_FAN, &result);
495501
if (err)
496502
return err;
497503

@@ -513,7 +519,8 @@ static ssize_t fan_mode_store(struct device *dev,
513519
if (state > 4 || state == 3)
514520
return -EINVAL;
515521

516-
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_FAN, state);
522+
scoped_guard(mutex, &priv->vpc_mutex)
523+
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_FAN, state);
517524
if (err)
518525
return err;
519526

@@ -598,7 +605,8 @@ static ssize_t touchpad_show(struct device *dev,
598605
unsigned long result;
599606
int err;
600607

601-
err = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &result);
608+
scoped_guard(mutex, &priv->vpc_mutex)
609+
err = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &result);
602610
if (err)
603611
return err;
604612

@@ -619,7 +627,8 @@ static ssize_t touchpad_store(struct device *dev,
619627
if (err)
620628
return err;
621629

622-
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, state);
630+
scoped_guard(mutex, &priv->vpc_mutex)
631+
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, state);
623632
if (err)
624633
return err;
625634

@@ -1012,6 +1021,8 @@ static int ideapad_rfk_set(void *data, bool blocked)
10121021
struct ideapad_rfk_priv *priv = data;
10131022
int opcode = ideapad_rfk_data[priv->dev].opcode;
10141023

1024+
guard(mutex)(&priv->priv->vpc_mutex);
1025+
10151026
return write_ec_cmd(priv->priv->adev->handle, opcode, !blocked);
10161027
}
10171028

@@ -1025,6 +1036,8 @@ static void ideapad_sync_rfk_state(struct ideapad_private *priv)
10251036
int i;
10261037

10271038
if (priv->features.hw_rfkill_switch) {
1039+
guard(mutex)(&priv->vpc_mutex);
1040+
10281041
if (read_ec_data(priv->adev->handle, VPCCMD_R_RF, &hw_blocked))
10291042
return;
10301043
hw_blocked = !hw_blocked;
@@ -1198,8 +1211,9 @@ static void ideapad_input_novokey(struct ideapad_private *priv)
11981211
{
11991212
unsigned long long_pressed;
12001213

1201-
if (read_ec_data(priv->adev->handle, VPCCMD_R_NOVO, &long_pressed))
1202-
return;
1214+
scoped_guard(mutex, &priv->vpc_mutex)
1215+
if (read_ec_data(priv->adev->handle, VPCCMD_R_NOVO, &long_pressed))
1216+
return;
12031217

12041218
if (long_pressed)
12051219
ideapad_input_report(priv, 17);
@@ -1211,8 +1225,9 @@ static void ideapad_check_special_buttons(struct ideapad_private *priv)
12111225
{
12121226
unsigned long bit, value;
12131227

1214-
if (read_ec_data(priv->adev->handle, VPCCMD_R_SPECIAL_BUTTONS, &value))
1215-
return;
1228+
scoped_guard(mutex, &priv->vpc_mutex)
1229+
if (read_ec_data(priv->adev->handle, VPCCMD_R_SPECIAL_BUTTONS, &value))
1230+
return;
12161231

12171232
for_each_set_bit (bit, &value, 16) {
12181233
switch (bit) {
@@ -1245,6 +1260,8 @@ static int ideapad_backlight_get_brightness(struct backlight_device *blightdev)
12451260
unsigned long now;
12461261
int err;
12471262

1263+
guard(mutex)(&priv->vpc_mutex);
1264+
12481265
err = read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now);
12491266
if (err)
12501267
return err;
@@ -1257,6 +1274,8 @@ static int ideapad_backlight_update_status(struct backlight_device *blightdev)
12571274
struct ideapad_private *priv = bl_get_data(blightdev);
12581275
int err;
12591276

1277+
guard(mutex)(&priv->vpc_mutex);
1278+
12601279
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_BL,
12611280
blightdev->props.brightness);
12621281
if (err)
@@ -1334,6 +1353,8 @@ static void ideapad_backlight_notify_power(struct ideapad_private *priv)
13341353
if (!blightdev)
13351354
return;
13361355

1356+
guard(mutex)(&priv->vpc_mutex);
1357+
13371358
if (read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &power))
13381359
return;
13391360

@@ -1346,7 +1367,8 @@ static void ideapad_backlight_notify_brightness(struct ideapad_private *priv)
13461367

13471368
/* if we control brightness via acpi video driver */
13481369
if (!priv->blightdev)
1349-
read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now);
1370+
scoped_guard(mutex, &priv->vpc_mutex)
1371+
read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now);
13501372
else
13511373
backlight_force_update(priv->blightdev, BACKLIGHT_UPDATE_HOTKEY);
13521374
}
@@ -1571,7 +1593,8 @@ static void ideapad_sync_touchpad_state(struct ideapad_private *priv, bool send_
15711593
int ret;
15721594

15731595
/* Without reading from EC touchpad LED doesn't switch state */
1574-
ret = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value);
1596+
scoped_guard(mutex, &priv->vpc_mutex)
1597+
ret = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value);
15751598
if (ret)
15761599
return;
15771600

@@ -1631,7 +1654,8 @@ static void ideapad_laptop_trigger_ec(void)
16311654
if (!priv->features.ymc_ec_trigger)
16321655
return;
16331656

1634-
ret = write_ec_cmd(priv->adev->handle, VPCCMD_W_YMC, 1);
1657+
scoped_guard(mutex, &priv->vpc_mutex)
1658+
ret = write_ec_cmd(priv->adev->handle, VPCCMD_W_YMC, 1);
16351659
if (ret)
16361660
dev_warn(&priv->platform_device->dev, "Could not write YMC: %d\n", ret);
16371661
}
@@ -1677,11 +1701,13 @@ static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
16771701
struct ideapad_private *priv = data;
16781702
unsigned long vpc1, vpc2, bit;
16791703

1680-
if (read_ec_data(handle, VPCCMD_R_VPC1, &vpc1))
1681-
return;
1704+
scoped_guard(mutex, &priv->vpc_mutex) {
1705+
if (read_ec_data(handle, VPCCMD_R_VPC1, &vpc1))
1706+
return;
16821707

1683-
if (read_ec_data(handle, VPCCMD_R_VPC2, &vpc2))
1684-
return;
1708+
if (read_ec_data(handle, VPCCMD_R_VPC2, &vpc2))
1709+
return;
1710+
}
16851711

16861712
vpc1 = (vpc2 << 8) | vpc1;
16871713

@@ -1988,6 +2014,10 @@ static int ideapad_acpi_add(struct platform_device *pdev)
19882014
priv->adev = adev;
19892015
priv->platform_device = pdev;
19902016

2017+
err = devm_mutex_init(&pdev->dev, &priv->vpc_mutex);
2018+
if (err)
2019+
return err;
2020+
19912021
ideapad_check_features(priv);
19922022

19932023
err = ideapad_sysfs_init(priv);

0 commit comments

Comments
 (0)