diff options
author | Takashi Iwai <tiwai@suse.de> | 2014-03-18 07:58:33 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2014-03-18 08:37:25 -0400 |
commit | 4999e9621a58fa03fe18aa2ea55838bd2e755190 (patch) | |
tree | 60746ff9efb1582daa7ed1ab5c80c9d23617fbc6 /drivers/base | |
parent | 56fb1c74f3bda1c0100fc3e9a7888c229174f9a4 (diff) |
regmap: Fix possible sleep-in-atomic in regmap_bulk_write()
regmap deploys the spinlock for the protection when set up in fast_io
mode. This may lead to sleep-in-atomic by memory allocation with
GFP_KERNEL in regmap_bulk_write(). This patch fixes it by moving the
allocation out of the lock.
[Fix excessively large locked region -- broonie]
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/regmap/regmap.c | 11 |
1 files changed, 6 insertions, 5 deletions
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index e5a5509160fe..35077374f38b 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
@@ -1520,12 +1520,12 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, | |||
1520 | if (reg % map->reg_stride) | 1520 | if (reg % map->reg_stride) |
1521 | return -EINVAL; | 1521 | return -EINVAL; |
1522 | 1522 | ||
1523 | map->lock(map->lock_arg); | ||
1524 | /* | 1523 | /* |
1525 | * Some devices don't support bulk write, for | 1524 | * Some devices don't support bulk write, for |
1526 | * them we have a series of single write operations. | 1525 | * them we have a series of single write operations. |
1527 | */ | 1526 | */ |
1528 | if (!map->bus || map->use_single_rw) { | 1527 | if (!map->bus || map->use_single_rw) { |
1528 | map->lock(map->lock_arg); | ||
1529 | for (i = 0; i < val_count; i++) { | 1529 | for (i = 0; i < val_count; i++) { |
1530 | unsigned int ival; | 1530 | unsigned int ival; |
1531 | 1531 | ||
@@ -1554,24 +1554,25 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, | |||
1554 | if (ret != 0) | 1554 | if (ret != 0) |
1555 | goto out; | 1555 | goto out; |
1556 | } | 1556 | } |
1557 | out: | ||
1558 | map->unlock(map->lock_arg); | ||
1557 | } else { | 1559 | } else { |
1558 | void *wval; | 1560 | void *wval; |
1559 | 1561 | ||
1560 | wval = kmemdup(val, val_count * val_bytes, GFP_KERNEL); | 1562 | wval = kmemdup(val, val_count * val_bytes, GFP_KERNEL); |
1561 | if (!wval) { | 1563 | if (!wval) { |
1562 | ret = -ENOMEM; | ||
1563 | dev_err(map->dev, "Error in memory allocation\n"); | 1564 | dev_err(map->dev, "Error in memory allocation\n"); |
1564 | goto out; | 1565 | return -ENOMEM; |
1565 | } | 1566 | } |
1566 | for (i = 0; i < val_count * val_bytes; i += val_bytes) | 1567 | for (i = 0; i < val_count * val_bytes; i += val_bytes) |
1567 | map->format.parse_inplace(wval + i); | 1568 | map->format.parse_inplace(wval + i); |
1568 | 1569 | ||
1570 | map->lock(map->lock_arg); | ||
1569 | ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count); | 1571 | ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count); |
1572 | map->unlock(map->lock_arg); | ||
1570 | 1573 | ||
1571 | kfree(wval); | 1574 | kfree(wval); |
1572 | } | 1575 | } |
1573 | out: | ||
1574 | map->unlock(map->lock_arg); | ||
1575 | return ret; | 1576 | return ret; |
1576 | } | 1577 | } |
1577 | EXPORT_SYMBOL_GPL(regmap_bulk_write); | 1578 | EXPORT_SYMBOL_GPL(regmap_bulk_write); |