mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-17 13:58:46 +00:00
power: supply: cros_charge-control: add mutex for driver data
Concurrent accesses through sysfs may lead to inconsistent state in the priv data. Introduce a mutex to avoid this. Fixes: c6ed48ef5259 ("power: supply: add ChromeOS EC based charge control driver") Cc: stable@vger.kernel.org Signed-off-by: Thomas Weißschuh <linux@weissschuh.net> Link: https://lore.kernel.org/r/20241208-cros_charge-control-v2-v1-1-8d168d0f08a3@weissschuh.net Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
This commit is contained in:
parent
afc6e39e82
commit
e5f84d1cf5
@ -7,8 +7,10 @@
|
||||
#include <acpi/battery.h>
|
||||
#include <linux/container_of.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/lockdep.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
@ -49,6 +51,7 @@ struct cros_chctl_priv {
|
||||
struct attribute *attributes[_CROS_CHCTL_ATTR_COUNT];
|
||||
struct attribute_group group;
|
||||
|
||||
struct mutex lock; /* protects fields below and cros_ec */
|
||||
enum power_supply_charge_behaviour current_behaviour;
|
||||
u8 current_start_threshold, current_end_threshold;
|
||||
};
|
||||
@ -85,6 +88,8 @@ static int cros_chctl_configure_ec(struct cros_chctl_priv *priv)
|
||||
{
|
||||
struct ec_params_charge_control req = {};
|
||||
|
||||
lockdep_assert_held(&priv->lock);
|
||||
|
||||
req.cmd = EC_CHARGE_CONTROL_CMD_SET;
|
||||
|
||||
switch (priv->current_behaviour) {
|
||||
@ -159,6 +164,7 @@ static ssize_t charge_control_start_threshold_show(struct device *dev,
|
||||
struct cros_chctl_priv *priv = cros_chctl_attr_to_priv(&attr->attr,
|
||||
CROS_CHCTL_ATTR_START_THRESHOLD);
|
||||
|
||||
guard(mutex)(&priv->lock);
|
||||
return sysfs_emit(buf, "%u\n", (unsigned int)priv->current_start_threshold);
|
||||
}
|
||||
|
||||
@ -169,6 +175,7 @@ static ssize_t charge_control_start_threshold_store(struct device *dev,
|
||||
struct cros_chctl_priv *priv = cros_chctl_attr_to_priv(&attr->attr,
|
||||
CROS_CHCTL_ATTR_START_THRESHOLD);
|
||||
|
||||
guard(mutex)(&priv->lock);
|
||||
return cros_chctl_store_threshold(dev, priv, 0, buf, count);
|
||||
}
|
||||
|
||||
@ -178,6 +185,7 @@ static ssize_t charge_control_end_threshold_show(struct device *dev, struct devi
|
||||
struct cros_chctl_priv *priv = cros_chctl_attr_to_priv(&attr->attr,
|
||||
CROS_CHCTL_ATTR_END_THRESHOLD);
|
||||
|
||||
guard(mutex)(&priv->lock);
|
||||
return sysfs_emit(buf, "%u\n", (unsigned int)priv->current_end_threshold);
|
||||
}
|
||||
|
||||
@ -187,6 +195,7 @@ static ssize_t charge_control_end_threshold_store(struct device *dev, struct dev
|
||||
struct cros_chctl_priv *priv = cros_chctl_attr_to_priv(&attr->attr,
|
||||
CROS_CHCTL_ATTR_END_THRESHOLD);
|
||||
|
||||
guard(mutex)(&priv->lock);
|
||||
return cros_chctl_store_threshold(dev, priv, 1, buf, count);
|
||||
}
|
||||
|
||||
@ -195,6 +204,7 @@ static ssize_t charge_behaviour_show(struct device *dev, struct device_attribute
|
||||
struct cros_chctl_priv *priv = cros_chctl_attr_to_priv(&attr->attr,
|
||||
CROS_CHCTL_ATTR_CHARGE_BEHAVIOUR);
|
||||
|
||||
guard(mutex)(&priv->lock);
|
||||
return power_supply_charge_behaviour_show(dev, EC_CHARGE_CONTROL_BEHAVIOURS,
|
||||
priv->current_behaviour, buf);
|
||||
}
|
||||
@ -210,6 +220,7 @@ static ssize_t charge_behaviour_store(struct device *dev, struct device_attribut
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
guard(mutex)(&priv->lock);
|
||||
priv->current_behaviour = ret;
|
||||
|
||||
ret = cros_chctl_configure_ec(priv);
|
||||
@ -290,6 +301,10 @@ static int cros_chctl_probe(struct platform_device *pdev)
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = devm_mutex_init(dev, &priv->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = cros_ec_get_cmd_versions(cros_ec, EC_CMD_CHARGE_CONTROL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -327,7 +342,8 @@ static int cros_chctl_probe(struct platform_device *pdev)
|
||||
priv->current_end_threshold = 100;
|
||||
|
||||
/* Bring EC into well-known state */
|
||||
ret = cros_chctl_configure_ec(priv);
|
||||
scoped_guard(mutex, &priv->lock)
|
||||
ret = cros_chctl_configure_ec(priv);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user