Re: [PATCH v4 4/4] platform/x86: ideapad-laptop: add a mutex to synchronize VPC commands

From: Ilpo Järvinen
Date: Tue Jul 30 2024 - 09:38:03 EST


On Thu, 25 Jul 2024, Gergo Koteles wrote:

> 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.
>
> Add a mutex to synchronize VPC commands.
>
> Signed-off-by: Gergo Koteles <soyer@xxxxxx>

What commit does this fix? I was going to add a Fixes tag myself while
applying this but wasn't sure if it should be the ACPI concurrency commit
e2ffcda16290 or the change introducing lenovo-ymc driver?

Also, I'd prefer to not take the move patch (PATCH 3/4) now so I could
take this through fixes branch since it causes a real issue if I remember
the earlier discussions right? Do you think there's any issue if I take
only patches 1, 2, and 4? They seemed to apply without conflicts when I
tried to apply the entire series and then cherrypicked the last patch
dropping the third patch.

The code movement patch could go through for-next fixes branch is then
merged into it (or after one kernel cycle).


--
i.


> ---
> drivers/platform/x86/ideapad-laptop.c | 64 ++++++++++++++++++++-------
> 1 file changed, 47 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
> index 8398774cdfe2..3c24e3d99cd2 100644
> --- a/drivers/platform/x86/ideapad-laptop.c
> +++ b/drivers/platform/x86/ideapad-laptop.c
> @@ -155,6 +155,7 @@ struct ideapad_rfk_priv {
>
> struct ideapad_private {
> struct acpi_device *adev;
> + struct mutex vpc_mutex; /* protects the VPC calls */
> struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM];
> struct ideapad_rfk_priv rfk_priv[IDEAPAD_RFKILL_DEV_NUM];
> struct platform_device *platform_device;
> @@ -437,6 +438,8 @@ static int debugfs_status_show(struct seq_file *s, void *data)
> struct ideapad_private *priv = s->private;
> unsigned long value;
>
> + guard(mutex)(&priv->vpc_mutex);
> +
> if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &value))
> seq_printf(s, "Backlight max: %lu\n", value);
> if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL, &value))
> @@ -555,7 +558,8 @@ static ssize_t camera_power_show(struct device *dev,
> unsigned long result;
> int err;
>
> - err = read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &result);
> + scoped_guard(mutex, &priv->vpc_mutex)
> + err = read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &result);
> if (err)
> return err;
>
> @@ -574,7 +578,8 @@ static ssize_t camera_power_store(struct device *dev,
> if (err)
> return err;
>
> - err = write_ec_cmd(priv->adev->handle, VPCCMD_W_CAMERA, state);
> + scoped_guard(mutex, &priv->vpc_mutex)
> + err = write_ec_cmd(priv->adev->handle, VPCCMD_W_CAMERA, state);
> if (err)
> return err;
>
> @@ -627,7 +632,8 @@ static ssize_t fan_mode_show(struct device *dev,
> unsigned long result;
> int err;
>
> - err = read_ec_data(priv->adev->handle, VPCCMD_R_FAN, &result);
> + scoped_guard(mutex, &priv->vpc_mutex)
> + err = read_ec_data(priv->adev->handle, VPCCMD_R_FAN, &result);
> if (err)
> return err;
>
> @@ -649,7 +655,8 @@ static ssize_t fan_mode_store(struct device *dev,
> if (state > 4 || state == 3)
> return -EINVAL;
>
> - err = write_ec_cmd(priv->adev->handle, VPCCMD_W_FAN, state);
> + scoped_guard(mutex, &priv->vpc_mutex)
> + err = write_ec_cmd(priv->adev->handle, VPCCMD_W_FAN, state);
> if (err)
> return err;
>
> @@ -734,7 +741,8 @@ static ssize_t touchpad_show(struct device *dev,
> unsigned long result;
> int err;
>
> - err = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &result);
> + scoped_guard(mutex, &priv->vpc_mutex)
> + err = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &result);
> if (err)
> return err;
>
> @@ -755,7 +763,8 @@ static ssize_t touchpad_store(struct device *dev,
> if (err)
> return err;
>
> - err = write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, state);
> + scoped_guard(mutex, &priv->vpc_mutex)
> + err = write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, state);
> if (err)
> return err;
>
> @@ -1148,6 +1157,8 @@ static int ideapad_rfk_set(void *data, bool blocked)
> struct ideapad_rfk_priv *priv = data;
> int opcode = ideapad_rfk_data[priv->dev].opcode;
>
> + guard(mutex)(&priv->priv->vpc_mutex);
> +
> return write_ec_cmd(priv->priv->adev->handle, opcode, !blocked);
> }
>
> @@ -1161,6 +1172,8 @@ static void ideapad_sync_rfk_state(struct ideapad_private *priv)
> int i;
>
> if (priv->features.hw_rfkill_switch) {
> + guard(mutex)(&priv->vpc_mutex);
> +
> if (read_ec_data(priv->adev->handle, VPCCMD_R_RF, &hw_blocked))
> return;
> hw_blocked = !hw_blocked;
> @@ -1334,8 +1347,9 @@ static void ideapad_input_novokey(struct ideapad_private *priv)
> {
> unsigned long long_pressed;
>
> - if (read_ec_data(priv->adev->handle, VPCCMD_R_NOVO, &long_pressed))
> - return;
> + scoped_guard(mutex, &priv->vpc_mutex)
> + if (read_ec_data(priv->adev->handle, VPCCMD_R_NOVO, &long_pressed))
> + return;
>
> if (long_pressed)
> ideapad_input_report(priv, 17);
> @@ -1347,8 +1361,9 @@ static void ideapad_check_special_buttons(struct ideapad_private *priv)
> {
> unsigned long bit, value;
>
> - if (read_ec_data(priv->adev->handle, VPCCMD_R_SPECIAL_BUTTONS, &value))
> - return;
> + scoped_guard(mutex, &priv->vpc_mutex)
> + if (read_ec_data(priv->adev->handle, VPCCMD_R_SPECIAL_BUTTONS, &value))
> + return;
>
> for_each_set_bit (bit, &value, 16) {
> switch (bit) {
> @@ -1381,6 +1396,8 @@ static int ideapad_backlight_get_brightness(struct backlight_device *blightdev)
> unsigned long now;
> int err;
>
> + guard(mutex)(&priv->vpc_mutex);
> +
> err = read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now);
> if (err)
> return err;
> @@ -1393,6 +1410,8 @@ static int ideapad_backlight_update_status(struct backlight_device *blightdev)
> struct ideapad_private *priv = bl_get_data(blightdev);
> int err;
>
> + guard(mutex)(&priv->vpc_mutex);
> +
> err = write_ec_cmd(priv->adev->handle, VPCCMD_W_BL,
> blightdev->props.brightness);
> if (err)
> @@ -1470,6 +1489,8 @@ static void ideapad_backlight_notify_power(struct ideapad_private *priv)
> if (!blightdev)
> return;
>
> + guard(mutex)(&priv->vpc_mutex);
> +
> if (read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &power))
> return;
>
> @@ -1482,7 +1503,8 @@ static void ideapad_backlight_notify_brightness(struct ideapad_private *priv)
>
> /* if we control brightness via acpi video driver */
> if (!priv->blightdev)
> - read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now);
> + scoped_guard(mutex, &priv->vpc_mutex)
> + read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now);
> else
> backlight_force_update(priv->blightdev, BACKLIGHT_UPDATE_HOTKEY);
> }
> @@ -1707,7 +1729,8 @@ static void ideapad_sync_touchpad_state(struct ideapad_private *priv, bool send_
> int ret;
>
> /* Without reading from EC touchpad LED doesn't switch state */
> - ret = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value);
> + scoped_guard(mutex, &priv->vpc_mutex)
> + ret = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value);
> if (ret)
> return;
>
> @@ -1767,7 +1790,8 @@ static void ideapad_laptop_trigger_ec(void)
> if (!priv->features.ymc_ec_trigger)
> return;
>
> - ret = write_ec_cmd(priv->adev->handle, VPCCMD_W_YMC, 1);
> + scoped_guard(mutex, &priv->vpc_mutex)
> + ret = write_ec_cmd(priv->adev->handle, VPCCMD_W_YMC, 1);
> if (ret)
> dev_warn(&priv->platform_device->dev, "Could not write YMC: %d\n", ret);
> }
> @@ -1813,11 +1837,13 @@ static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
> struct ideapad_private *priv = data;
> unsigned long vpc1, vpc2, bit;
>
> - if (read_ec_data(handle, VPCCMD_R_VPC1, &vpc1))
> - return;
> + scoped_guard(mutex, &priv->vpc_mutex) {
> + if (read_ec_data(handle, VPCCMD_R_VPC1, &vpc1))
> + return;
>
> - if (read_ec_data(handle, VPCCMD_R_VPC2, &vpc2))
> - return;
> + if (read_ec_data(handle, VPCCMD_R_VPC2, &vpc2))
> + return;
> + }
>
> vpc1 = (vpc2 << 8) | vpc1;
>
> @@ -2124,6 +2150,10 @@ static int ideapad_acpi_add(struct platform_device *pdev)
> priv->adev = adev;
> priv->platform_device = pdev;
>
> + err = devm_mutex_init(&pdev->dev, &priv->vpc_mutex);
> + if (err)
> + return err;
> +
> ideapad_check_features(priv);
>
> err = ideapad_sysfs_init(priv);
>