ASoC: soc-cache: Use reg_def_copy instead of reg_cache_default

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>
This commit is contained in:
Dimitris Papastamos 2010-12-02 16:11:05 +00:00 committed by Mark Brown
parent ff819b8357
commit 3335ddca93
3 changed files with 42 additions and 12 deletions

View File

@ -480,6 +480,7 @@ struct snd_soc_codec {
unsigned int (*read)(struct snd_soc_codec *, unsigned int); unsigned int (*read)(struct snd_soc_codec *, unsigned int);
int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
void *reg_cache; void *reg_cache;
const void *reg_def_copy;
const struct snd_soc_cache_ops *cache_ops; const struct snd_soc_cache_ops *cache_ops;
struct mutex cache_rw_mutex; struct mutex cache_rw_mutex;

View File

@ -933,7 +933,7 @@ static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
rbtree_ctx = codec->reg_cache; rbtree_ctx = codec->reg_cache;
rbtree_ctx->root = RB_ROOT; rbtree_ctx->root = RB_ROOT;
if (!codec->driver->reg_cache_default) if (!codec->reg_def_copy)
return 0; 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; \ struct snd_soc_rbtree_node *rbtree_node; \
\ \
ret = 0; \ ret = 0; \
cache = codec->driver->reg_cache_default; \ cache = codec->reg_def_copy; \
for (i = 0; i < codec->driver->reg_cache_size; ++i) { \ for (i = 0; i < codec->driver->reg_cache_size; ++i) { \
if (!cache[i]) \ if (!cache[i]) \
continue; \ continue; \
@ -1316,13 +1316,13 @@ static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec)
* and remember to free it afterwards. * and remember to free it afterwards.
*/ */
tofree = 0; tofree = 0;
if (!codec_drv->reg_cache_default) if (!codec->reg_def_copy)
tofree = 1; tofree = 1;
if (!codec_drv->reg_cache_default) { if (!codec->reg_def_copy) {
codec_drv->reg_cache_default = kzalloc(reg_size, codec->reg_def_copy = kzalloc(reg_size,
GFP_KERNEL); GFP_KERNEL);
if (!codec_drv->reg_cache_default) if (!codec->reg_def_copy)
return -ENOMEM; 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); blksize = snd_soc_lzo_get_blksize(codec);
p = codec_drv->reg_cache_default; p = codec->reg_def_copy;
end = codec_drv->reg_cache_default + reg_size; end = codec->reg_def_copy + reg_size;
/* compress the register map and fill the lzo blocks */ /* compress the register map and fill the lzo blocks */
for (i = 0; i < blkcount; ++i, p += blksize) { for (i = 0; i < blkcount; ++i, p += blksize) {
lzo_blocks[i]->src = p; 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; lzo_blocks[i]->src_len;
} }
if (tofree) if (tofree) {
kfree(codec_drv->reg_cache_default); kfree(codec->reg_def_copy);
codec->reg_def_copy = NULL;
}
return 0; return 0;
err: err:
snd_soc_cache_exit(codec); snd_soc_cache_exit(codec);
err_tofree: err_tofree:
if (tofree) if (tofree) {
kfree(codec_drv->reg_cache_default); kfree(codec->reg_def_copy);
codec->reg_def_copy = NULL;
}
return ret; return ret;
} }
@ -1506,6 +1510,14 @@ static int snd_soc_flat_cache_init(struct snd_soc_codec *codec)
codec_drv = codec->driver; codec_drv = codec->driver;
reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size; 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) if (codec_drv->reg_cache_default)
codec->reg_cache = kmemdup(codec_drv->reg_cache_default, codec->reg_cache = kmemdup(codec_drv->reg_cache_default,
reg_size, GFP_KERNEL); reg_size, GFP_KERNEL);

View File

@ -3434,6 +3434,7 @@ int snd_soc_register_codec(struct device *dev,
struct snd_soc_codec_driver *codec_drv, struct snd_soc_codec_driver *codec_drv,
struct snd_soc_dai_driver *dai_drv, int num_dai) struct snd_soc_dai_driver *dai_drv, int num_dai)
{ {
size_t reg_size;
struct snd_soc_codec *codec; struct snd_soc_codec *codec;
int ret, i; int ret, i;
@ -3469,6 +3470,19 @@ int snd_soc_register_codec(struct device *dev,
/* allocate CODEC register cache */ /* allocate CODEC register cache */
if (codec_drv->reg_cache_size && codec_drv->reg_word_size) { 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); ret = snd_soc_cache_init(codec);
if (ret < 0) { if (ret < 0) {
dev_err(codec->dev, "Failed to set cache compression type: %d\n", 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: error_dais:
snd_soc_cache_exit(codec); snd_soc_cache_exit(codec);
error_cache: error_cache:
kfree(codec->reg_def_copy);
codec->reg_def_copy = NULL;
kfree(codec->name); kfree(codec->name);
kfree(codec); kfree(codec);
return ret; return ret;
@ -3534,6 +3550,7 @@ found:
pr_debug("Unregistered codec '%s'\n", codec->name); pr_debug("Unregistered codec '%s'\n", codec->name);
snd_soc_cache_exit(codec); snd_soc_cache_exit(codec);
kfree(codec->reg_def_copy);
kfree(codec->name); kfree(codec->name);
kfree(codec); kfree(codec);
} }