regmap: cache: Fix possible ZERO_SIZE_PTR pointer dereferencing error.
[firefly-linux-kernel-4.4.55.git] / drivers / base / regmap / regcache.c
index 726d956f6a298ae3500c55f207fc3594a7daf211..d815929ba745409ff0a87365ec0b5b97d8f3001b 100644 (file)
@@ -36,6 +36,23 @@ static int regcache_hw_init(struct regmap *map)
        if (!map->num_reg_defaults_raw)
                return -EINVAL;
 
+       /* calculate the size of reg_defaults */
+       for (count = 0, i = 0; i < map->num_reg_defaults_raw; i++)
+               if (!regmap_volatile(map, i * map->reg_stride))
+                       count++;
+
+       /* all registers are volatile, so just bypass */
+       if (!count) {
+               map->cache_bypass = true;
+               return 0;
+       }
+
+       map->num_reg_defaults = count;
+       map->reg_defaults = kmalloc_array(count, sizeof(struct reg_default),
+                                         GFP_KERNEL);
+       if (!map->reg_defaults)
+               return -ENOMEM;
+
        if (!map->reg_defaults_raw) {
                u32 cache_bypass = map->cache_bypass;
                dev_warn(map->dev, "No cache defaults, reading back from HW\n");
@@ -43,33 +60,21 @@ static int regcache_hw_init(struct regmap *map)
                /* Bypass the cache access till data read from HW*/
                map->cache_bypass = 1;
                tmp_buf = kmalloc(map->cache_size_raw, GFP_KERNEL);
-               if (!tmp_buf)
-                       return -ENOMEM;
+               if (!tmp_buf) {
+                       ret = -ENOMEM;
+                       goto err_free;
+               }
                ret = regmap_raw_read(map, 0, tmp_buf,
                                      map->num_reg_defaults_raw);
                map->cache_bypass = cache_bypass;
-               if (ret < 0) {
-                       kfree(tmp_buf);
-                       return ret;
-               }
+               if (ret < 0)
+                       goto err_cache_free;
+
                map->reg_defaults_raw = tmp_buf;
                map->cache_free = 1;
        }
 
-       /* calculate the size of reg_defaults */
-       for (count = 0, i = 0; i < map->num_reg_defaults_raw; i++)
-               if (!regmap_volatile(map, i * map->reg_stride))
-                       count++;
-
-       map->reg_defaults = kmalloc_array(count, sizeof(struct reg_default),
-                                         GFP_KERNEL);
-       if (!map->reg_defaults) {
-               ret = -ENOMEM;
-               goto err_free;
-       }
-
        /* fill the reg_defaults */
-       map->num_reg_defaults = count;
        for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) {
                if (regmap_volatile(map, i * map->reg_stride))
                        continue;
@@ -81,9 +86,10 @@ static int regcache_hw_init(struct regmap *map)
 
        return 0;
 
+err_cache_free:
+       kfree(tmp_buf);
 err_free:
-       if (map->cache_free)
-               kfree(map->reg_defaults_raw);
+       kfree(map->reg_defaults);
 
        return ret;
 }
@@ -147,6 +153,8 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
                ret = regcache_hw_init(map);
                if (ret < 0)
                        return ret;
+               if (map->cache_bypass)
+                       return 0;
        }
 
        if (!map->max_register)