Commit fbac0812 authored by Samu Onkalo's avatar Samu Onkalo Committed by Linus Torvalds

leds: lp5523: fix circular locking

Driver contained possibility for circular locking.

One lock is held by sysfs-core and another one by the driver itself.  This
happened when the driver created or removed sysfs entries dynamically.
There is no real need to do those operations.  Now all the sysfs entries
are created at probe and removed at removal.  Engine load and mux
configuration sysfs entries are now visible all the time.  However, access
to the entries fails if the engine is disabled or running.
Signed-off-by: default avatarSamu Onkalo <samu.p.onkalo@nokia.com>
Cc: Arun Murthy <arun.murthy@stericsson.com>
Reviewed-by: default avatarIlkka Koskinen <ilkka.koskinen@nokia.com>
Cc: Richard Purdie <rpurdie@rpsys.net>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 278ad4fd
...@@ -105,7 +105,6 @@ ...@@ -105,7 +105,6 @@
#define SHIFT_MASK(id) (((id) - 1) * 2) #define SHIFT_MASK(id) (((id) - 1) * 2)
struct lp5523_engine { struct lp5523_engine {
const struct attribute_group *attributes;
int id; int id;
u8 mode; u8 mode;
u8 prog_page; u8 prog_page;
...@@ -403,14 +402,23 @@ static ssize_t store_engine_leds(struct device *dev, ...@@ -403,14 +402,23 @@ static ssize_t store_engine_leds(struct device *dev,
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
struct lp5523_chip *chip = i2c_get_clientdata(client); struct lp5523_chip *chip = i2c_get_clientdata(client);
u16 mux = 0; u16 mux = 0;
ssize_t ret;
if (lp5523_mux_parse(buf, &mux, len)) if (lp5523_mux_parse(buf, &mux, len))
return -EINVAL; return -EINVAL;
mutex_lock(&chip->lock);
ret = -EINVAL;
if (chip->engines[nr - 1].mode != LP5523_CMD_LOAD)
goto leave;
if (lp5523_load_mux(&chip->engines[nr - 1], mux)) if (lp5523_load_mux(&chip->engines[nr - 1], mux))
return -EINVAL; goto leave;
return len; ret = len;
leave:
mutex_unlock(&chip->lock);
return ret;
} }
#define store_leds(nr) \ #define store_leds(nr) \
...@@ -556,7 +564,11 @@ static int lp5523_do_store_load(struct lp5523_engine *engine, ...@@ -556,7 +564,11 @@ static int lp5523_do_store_load(struct lp5523_engine *engine,
mutex_lock(&chip->lock); mutex_lock(&chip->lock);
ret = lp5523_load_program(engine, pattern); if (engine->mode == LP5523_CMD_LOAD)
ret = lp5523_load_program(engine, pattern);
else
ret = -EINVAL;
mutex_unlock(&chip->lock); mutex_unlock(&chip->lock);
if (ret) { if (ret) {
...@@ -737,37 +749,18 @@ static struct attribute *lp5523_attributes[] = { ...@@ -737,37 +749,18 @@ static struct attribute *lp5523_attributes[] = {
&dev_attr_engine2_mode.attr, &dev_attr_engine2_mode.attr,
&dev_attr_engine3_mode.attr, &dev_attr_engine3_mode.attr,
&dev_attr_selftest.attr, &dev_attr_selftest.attr,
NULL
};
static struct attribute *lp5523_engine1_attributes[] = {
&dev_attr_engine1_load.attr, &dev_attr_engine1_load.attr,
&dev_attr_engine1_leds.attr, &dev_attr_engine1_leds.attr,
NULL
};
static struct attribute *lp5523_engine2_attributes[] = {
&dev_attr_engine2_load.attr, &dev_attr_engine2_load.attr,
&dev_attr_engine2_leds.attr, &dev_attr_engine2_leds.attr,
NULL
};
static struct attribute *lp5523_engine3_attributes[] = {
&dev_attr_engine3_load.attr, &dev_attr_engine3_load.attr,
&dev_attr_engine3_leds.attr, &dev_attr_engine3_leds.attr,
NULL
}; };
static const struct attribute_group lp5523_group = { static const struct attribute_group lp5523_group = {
.attrs = lp5523_attributes, .attrs = lp5523_attributes,
}; };
static const struct attribute_group lp5523_engine_group[] = {
{.attrs = lp5523_engine1_attributes },
{.attrs = lp5523_engine2_attributes },
{.attrs = lp5523_engine3_attributes },
};
static int lp5523_register_sysfs(struct i2c_client *client) static int lp5523_register_sysfs(struct i2c_client *client)
{ {
struct device *dev = &client->dev; struct device *dev = &client->dev;
...@@ -788,10 +781,6 @@ static void lp5523_unregister_sysfs(struct i2c_client *client) ...@@ -788,10 +781,6 @@ static void lp5523_unregister_sysfs(struct i2c_client *client)
sysfs_remove_group(&dev->kobj, &lp5523_group); sysfs_remove_group(&dev->kobj, &lp5523_group);
for (i = 0; i < ARRAY_SIZE(chip->engines); i++)
if (chip->engines[i].mode == LP5523_CMD_LOAD)
sysfs_remove_group(&dev->kobj, &lp5523_engine_group[i]);
for (i = 0; i < chip->num_leds; i++) for (i = 0; i < chip->num_leds; i++)
sysfs_remove_group(&chip->leds[i].cdev.dev->kobj, sysfs_remove_group(&chip->leds[i].cdev.dev->kobj,
&lp5523_led_attribute_group); &lp5523_led_attribute_group);
...@@ -802,10 +791,6 @@ static void lp5523_unregister_sysfs(struct i2c_client *client) ...@@ -802,10 +791,6 @@ static void lp5523_unregister_sysfs(struct i2c_client *client)
/*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/
static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode) static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode)
{ {
/* engine to chip */
struct lp5523_chip *chip = engine_to_lp5523(engine);
struct i2c_client *client = chip->client;
struct device *dev = &client->dev;
int ret = 0; int ret = 0;
/* if in that mode already do nothing, except for run */ /* if in that mode already do nothing, except for run */
...@@ -817,18 +802,10 @@ static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode) ...@@ -817,18 +802,10 @@ static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode)
} else if (mode == LP5523_CMD_LOAD) { } else if (mode == LP5523_CMD_LOAD) {
lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED); lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED);
lp5523_set_engine_mode(engine, LP5523_CMD_LOAD); lp5523_set_engine_mode(engine, LP5523_CMD_LOAD);
ret = sysfs_create_group(&dev->kobj, engine->attributes);
if (ret)
return ret;
} else if (mode == LP5523_CMD_DISABLED) { } else if (mode == LP5523_CMD_DISABLED) {
lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED); lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED);
} }
/* remove load attribute from sysfs if not in load mode */
if (engine->mode == LP5523_CMD_LOAD && mode != LP5523_CMD_LOAD)
sysfs_remove_group(&dev->kobj, engine->attributes);
engine->mode = mode; engine->mode = mode;
return ret; return ret;
...@@ -845,7 +822,6 @@ static int __init lp5523_init_engine(struct lp5523_engine *engine, int id) ...@@ -845,7 +822,6 @@ static int __init lp5523_init_engine(struct lp5523_engine *engine, int id)
engine->engine_mask = LP5523_ENG_MASK_BASE >> SHIFT_MASK(id); engine->engine_mask = LP5523_ENG_MASK_BASE >> SHIFT_MASK(id);
engine->prog_page = id - 1; engine->prog_page = id - 1;
engine->mux_page = id + 2; engine->mux_page = id + 2;
engine->attributes = &lp5523_engine_group[id - 1];
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment