summaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorXiubo Li <Li.Xiubo@freescale.com>2014-10-09 17:02:57 +0800
committerMark Brown <broonie@kernel.org>2014-10-20 12:25:02 +0100
commitfb70067e4a2cc45d273864f071fd6cf62143137a (patch)
tree853f7f6971a9d336adb2d32a6a9ac12feb4bc753 /drivers/base
parent06f9c24e55075e50ebc8b249a7853ad31bc1b3d1 (diff)
downloadop-kernel-dev-fb70067e4a2cc45d273864f071fd6cf62143137a.zip
op-kernel-dev-fb70067e4a2cc45d273864f071fd6cf62143137a.tar.gz
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: Xiubo Li <Li.Xiubo@freescale.com> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/regmap/regcache.c50
1 files changed, 29 insertions, 21 deletions
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 726d956..d815929 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -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)
OpenPOWER on IntegriCloud