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

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

 



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




[Index of Archives]     [Linux Kernel Development]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux