ASoC: soc-cache: Use reg_def_copy instead of reg_cache_default
Dimitris Papastamos [Thu, 2 Dec 2010 16:11:05 +0000 (16:11 +0000)]
Make sure to use codec->reg_def_copy instead of codec_drv->reg_cache_default
wherever necessary.  This change is necessary because in the next patch we
move the cache initialization code outside snd_soc_register_codec() and by that
time any data marked as __devinitconst such as the original reg_cache_default
array might have already been freed by the kernel.

Signed-off-by: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>

include/sound/soc.h
sound/soc/soc-cache.c
sound/soc/soc-core.c

index cf76021..0179861 100644 (file)
@@ -480,6 +480,7 @@ struct snd_soc_codec {
        unsigned int (*read)(struct snd_soc_codec *, unsigned int);
        int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
        void *reg_cache;
+       const void *reg_def_copy;
        const struct snd_soc_cache_ops *cache_ops;
        struct mutex cache_rw_mutex;
 
index cb58b11..6c6ced7 100644 (file)
@@ -933,7 +933,7 @@ static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
        rbtree_ctx = codec->reg_cache;
        rbtree_ctx->root = RB_ROOT;
 
-       if (!codec->driver->reg_cache_default)
+       if (!codec->reg_def_copy)
                return 0;
 
 /*
@@ -951,7 +951,7 @@ static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
        struct snd_soc_rbtree_node *rbtree_node;                        \
                                                                        \
        ret = 0;                                                        \
-       cache = codec->driver->reg_cache_default;                       \
+       cache = codec->reg_def_copy;                                    \
        for (i = 0; i < codec->driver->reg_cache_size; ++i) {           \
                if (!cache[i])                                          \
                        continue;                                       \
@@ -1316,13 +1316,13 @@ static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec)
         * and remember to free it afterwards.
         */
        tofree = 0;
-       if (!codec_drv->reg_cache_default)
+       if (!codec->reg_def_copy)
                tofree = 1;
 
-       if (!codec_drv->reg_cache_default) {
-               codec_drv->reg_cache_default = kzalloc(reg_size,
+       if (!codec->reg_def_copy) {
+               codec->reg_def_copy = kzalloc(reg_size,
                                                       GFP_KERNEL);
-               if (!codec_drv->reg_cache_default)
+               if (!codec->reg_def_copy)
                        return -ENOMEM;
        }
 
@@ -1368,8 +1368,8 @@ static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec)
        }
 
        blksize = snd_soc_lzo_get_blksize(codec);
-       p = codec_drv->reg_cache_default;
-       end = codec_drv->reg_cache_default + reg_size;
+       p = codec->reg_def_copy;
+       end = codec->reg_def_copy + reg_size;
        /* compress the register map and fill the lzo blocks */
        for (i = 0; i < blkcount; ++i, p += blksize) {
                lzo_blocks[i]->src = p;
@@ -1385,14 +1385,18 @@ static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec)
                        lzo_blocks[i]->src_len;
        }
 
-       if (tofree)
-               kfree(codec_drv->reg_cache_default);
+       if (tofree) {
+               kfree(codec->reg_def_copy);
+               codec->reg_def_copy = NULL;
+       }
        return 0;
 err:
        snd_soc_cache_exit(codec);
 err_tofree:
-       if (tofree)
-               kfree(codec_drv->reg_cache_default);
+       if (tofree) {
+               kfree(codec->reg_def_copy);
+               codec->reg_def_copy = NULL;
+       }
        return ret;
 }
 
@@ -1506,6 +1510,14 @@ static int snd_soc_flat_cache_init(struct snd_soc_codec *codec)
        codec_drv = codec->driver;
        reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
 
+       /*
+        * for flat compression, we don't need to keep a copy of the
+        * original defaults register cache as it will definitely not
+        * be marked as __devinitconst
+        */
+       kfree(codec->reg_def_copy);
+       codec->reg_def_copy = NULL;
+
        if (codec_drv->reg_cache_default)
                codec->reg_cache = kmemdup(codec_drv->reg_cache_default,
                                           reg_size, GFP_KERNEL);
index 4649db6..a95d111 100644 (file)
@@ -3434,6 +3434,7 @@ int snd_soc_register_codec(struct device *dev,
                struct snd_soc_codec_driver *codec_drv,
                struct snd_soc_dai_driver *dai_drv, int num_dai)
 {
+       size_t reg_size;
        struct snd_soc_codec *codec;
        int ret, i;
 
@@ -3469,6 +3470,19 @@ int snd_soc_register_codec(struct device *dev,
 
        /* allocate CODEC register cache */
        if (codec_drv->reg_cache_size && codec_drv->reg_word_size) {
+               reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
+               /* it is necessary to make a copy of the default register cache
+                * because in the case of using a compression type that requires
+                * the default register cache to be marked as __devinitconst the
+                * kernel might have freed the array by the time we initialize
+                * the cache.
+                */
+               codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default,
+                                             reg_size, GFP_KERNEL);
+               if (!codec->reg_def_copy) {
+                       ret = -ENOMEM;
+                       goto error_cache;
+               }
                ret = snd_soc_cache_init(codec);
                if (ret < 0) {
                        dev_err(codec->dev, "Failed to set cache compression type: %d\n",
@@ -3500,6 +3514,8 @@ int snd_soc_register_codec(struct device *dev,
 error_dais:
        snd_soc_cache_exit(codec);
 error_cache:
+       kfree(codec->reg_def_copy);
+       codec->reg_def_copy = NULL;
        kfree(codec->name);
        kfree(codec);
        return ret;
@@ -3534,6 +3550,7 @@ found:
        pr_debug("Unregistered codec '%s'\n", codec->name);
 
        snd_soc_cache_exit(codec);
+       kfree(codec->reg_def_copy);
        kfree(codec->name);
        kfree(codec);
 }