Commit fb70067e authored by Xiubo Li's avatar Xiubo Li Committed by Mark Brown

regmap: cache: Fix possible ZERO_SIZE_PTR pointer dereferencing error.

When all the registers are volatile(unlikely, but logically and mostly
will happen for some 'device' who has very few registers), then the
count will be euqal to 0, then kmalloc() will return ZERO_SIZE_PTR,
which equals to ((void *)16).

So this patch fix this with just doing the zero check before calling
kmalloc(). If the count == 0, so we can make sure that all the registers
are volatile, so no cache is need.
Signed-off-by: default avatarXiubo Li <Li.Xiubo@freescale.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 06f9c24e
...@@ -36,6 +36,23 @@ static int regcache_hw_init(struct regmap *map) ...@@ -36,6 +36,23 @@ static int regcache_hw_init(struct regmap *map)
if (!map->num_reg_defaults_raw) if (!map->num_reg_defaults_raw)
return -EINVAL; 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) { if (!map->reg_defaults_raw) {
u32 cache_bypass = map->cache_bypass; u32 cache_bypass = map->cache_bypass;
dev_warn(map->dev, "No cache defaults, reading back from HW\n"); dev_warn(map->dev, "No cache defaults, reading back from HW\n");
...@@ -43,33 +60,21 @@ static int regcache_hw_init(struct regmap *map) ...@@ -43,33 +60,21 @@ static int regcache_hw_init(struct regmap *map)
/* Bypass the cache access till data read from HW*/ /* Bypass the cache access till data read from HW*/
map->cache_bypass = 1; map->cache_bypass = 1;
tmp_buf = kmalloc(map->cache_size_raw, GFP_KERNEL); tmp_buf = kmalloc(map->cache_size_raw, GFP_KERNEL);
if (!tmp_buf) if (!tmp_buf) {
return -ENOMEM; ret = -ENOMEM;
goto err_free;
}
ret = regmap_raw_read(map, 0, tmp_buf, ret = regmap_raw_read(map, 0, tmp_buf,
map->num_reg_defaults_raw); map->num_reg_defaults_raw);
map->cache_bypass = cache_bypass; map->cache_bypass = cache_bypass;
if (ret < 0) { if (ret < 0)
kfree(tmp_buf); goto err_cache_free;
return ret;
}
map->reg_defaults_raw = tmp_buf; map->reg_defaults_raw = tmp_buf;
map->cache_free = 1; 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 */ /* fill the reg_defaults */
map->num_reg_defaults = count;
for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) { for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) {
if (regmap_volatile(map, i * map->reg_stride)) if (regmap_volatile(map, i * map->reg_stride))
continue; continue;
...@@ -81,9 +86,10 @@ static int regcache_hw_init(struct regmap *map) ...@@ -81,9 +86,10 @@ static int regcache_hw_init(struct regmap *map)
return 0; return 0;
err_cache_free:
kfree(tmp_buf);
err_free: err_free:
if (map->cache_free) kfree(map->reg_defaults);
kfree(map->reg_defaults_raw);
return ret; return ret;
} }
...@@ -147,6 +153,8 @@ int regcache_init(struct regmap *map, const struct regmap_config *config) ...@@ -147,6 +153,8 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
ret = regcache_hw_init(map); ret = regcache_hw_init(map);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (map->cache_bypass)
return 0;
} }
if (!map->max_register) if (!map->max_register)
......
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