regmap: Use _regmap_read in regmap_bulk_read
authorCharles Keepax <ckeepax@opensource.cirrus.com>
Thu, 15 Feb 2018 17:52:18 +0000 (17:52 +0000)
committerMark Brown <broonie@kernel.org>
Fri, 16 Feb 2018 12:03:30 +0000 (12:03 +0000)
Bulk reads may potentially read a lot of registers and regmap_read will
take and release the regmap lock for each register. Avoid bouncing
the lock so frequently by holding the lock locally and calling
_regmap_read instead. This also has the nice side-effect that all the
reads will be done atomically so no other threads can sneak a write in
during the regmap_bulk_read.

Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/base/regmap/regmap.c

index ff30a91..258a40e 100644 (file)
@@ -2674,6 +2674,8 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
 
        if (!IS_ALIGNED(reg, map->reg_stride))
                return -EINVAL;
+       if (val_count == 0)
+               return -EINVAL;
 
        if (map->bus && map->format.parse_inplace && (vol || map->cache_type == REGCACHE_NONE)) {
                ret = regmap_raw_read(map, reg, val, val_bytes * val_count);
@@ -2690,13 +2692,15 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
                u16 *u16 = val;
                u8 *u8 = val;
 
+               map->lock(map->lock_arg);
+
                for (i = 0; i < val_count; i++) {
                        unsigned int ival;
 
-                       ret = regmap_read(map, reg + regmap_get_offset(map, i),
-                                         &ival);
+                       ret = _regmap_read(map, reg + regmap_get_offset(map, i),
+                                          &ival);
                        if (ret != 0)
-                               return ret;
+                               goto out;
 
                        switch (map->format.val_bytes) {
 #ifdef CONFIG_64BIT
@@ -2714,12 +2718,16 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
                                u8[i] = ival;
                                break;
                        default:
-                               return -EINVAL;
+                               ret = -EINVAL;
+                               goto out;
                        }
                }
+
+out:
+               map->unlock(map->lock_arg);
        }
 
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(regmap_bulk_read);