regmap: fix page selection for noinc writes
authorDmitry Baryshkov <dmitry.baryshkov@linaro.org>
Thu, 17 Sep 2020 15:34:05 +0000 (18:34 +0300)
committerMark Brown <broonie@kernel.org>
Mon, 21 Sep 2020 19:58:02 +0000 (20:58 +0100)
Non-incrementing writes can fail if register + length crosses page
border. However for non-incrementing writes we should not check for page
border crossing. Fix this by passing additional flag to _regmap_raw_write
and passing length to _regmap_select_page basing on the flag.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Fixes: cdf6b11daa77 ("regmap: Add regmap_noinc_write API")
Link: https://lore.kernel.org/r/20200917153405.3139200-2-dmitry.baryshkov@linaro.org
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/base/regmap/internal.h
drivers/base/regmap/regcache.c
drivers/base/regmap/regmap.c

index e0ff8e9..7be2fcf 100644 (file)
@@ -259,7 +259,7 @@ bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
 int regcache_lookup_reg(struct regmap *map, unsigned int reg);
 
 int _regmap_raw_write(struct regmap *map, unsigned int reg,
-                     const void *val, size_t val_len);
+                     const void *val, size_t val_len, bool noinc);
 
 void regmap_async_complete_cb(struct regmap_async *async, int ret);
 
index a93cafd..7f4b3b6 100644 (file)
@@ -717,7 +717,7 @@ static int regcache_sync_block_raw_flush(struct regmap *map, const void **data,
 
        map->cache_bypass = true;
 
-       ret = _regmap_raw_write(map, base, *data, count * val_bytes);
+       ret = _regmap_raw_write(map, base, *data, count * val_bytes, false);
        if (ret)
                dev_err(map->dev, "Unable to sync registers %#x-%#x. %d\n",
                        base, cur - map->reg_stride, ret);
index e2822dc..b71f9ec 100644 (file)
@@ -1486,7 +1486,7 @@ static void regmap_set_work_buf_flag_mask(struct regmap *map, int max_bytes,
 }
 
 static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg,
-                                 const void *val, size_t val_len)
+                                 const void *val, size_t val_len, bool noinc)
 {
        struct regmap_range_node *range;
        unsigned long flags;
@@ -1545,7 +1545,7 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg,
                                win_residue, val_len / map->format.val_bytes);
                        ret = _regmap_raw_write_impl(map, reg, val,
                                                     win_residue *
-                                                    map->format.val_bytes);
+                                                    map->format.val_bytes, noinc);
                        if (ret != 0)
                                return ret;
 
@@ -1559,7 +1559,7 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg,
                        win_residue = range->window_len - win_offset;
                }
 
-               ret = _regmap_select_page(map, &reg, range, val_num);
+               ret = _regmap_select_page(map, &reg, range, noinc ? 1 : val_num);
                if (ret != 0)
                        return ret;
        }
@@ -1767,7 +1767,8 @@ static int _regmap_bus_raw_write(void *context, unsigned int reg,
                                      map->work_buf +
                                      map->format.reg_bytes +
                                      map->format.pad_bytes,
-                                     map->format.val_bytes);
+                                     map->format.val_bytes,
+                                     false);
 }
 
 static inline void *_regmap_map_get_context(struct regmap *map)
@@ -1861,7 +1862,7 @@ int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val)
 EXPORT_SYMBOL_GPL(regmap_write_async);
 
 int _regmap_raw_write(struct regmap *map, unsigned int reg,
-                     const void *val, size_t val_len)
+                     const void *val, size_t val_len, bool noinc)
 {
        size_t val_bytes = map->format.val_bytes;
        size_t val_count = val_len / val_bytes;
@@ -1882,7 +1883,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
 
        /* Write as many bytes as possible with chunk_size */
        for (i = 0; i < chunk_count; i++) {
-               ret = _regmap_raw_write_impl(map, reg, val, chunk_bytes);
+               ret = _regmap_raw_write_impl(map, reg, val, chunk_bytes, noinc);
                if (ret)
                        return ret;
 
@@ -1893,7 +1894,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
 
        /* Write remaining bytes */
        if (val_len)
-               ret = _regmap_raw_write_impl(map, reg, val, val_len);
+               ret = _regmap_raw_write_impl(map, reg, val, val_len, noinc);
 
        return ret;
 }
@@ -1926,7 +1927,7 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
 
        map->lock(map->lock_arg);
 
-       ret = _regmap_raw_write(map, reg, val, val_len);
+       ret = _regmap_raw_write(map, reg, val, val_len, false);
 
        map->unlock(map->lock_arg);
 
@@ -1984,7 +1985,7 @@ int regmap_noinc_write(struct regmap *map, unsigned int reg,
                        write_len = map->max_raw_write;
                else
                        write_len = val_len;
-               ret = _regmap_raw_write(map, reg, val, write_len);
+               ret = _regmap_raw_write(map, reg, val, write_len, true);
                if (ret)
                        goto out_unlock;
                val = ((u8 *)val) + write_len;
@@ -2461,7 +2462,7 @@ int regmap_raw_write_async(struct regmap *map, unsigned int reg,
 
        map->async = true;
 
-       ret = _regmap_raw_write(map, reg, val, val_len);
+       ret = _regmap_raw_write(map, reg, val, val_len, false);
 
        map->async = false;