From patchwork Mon Aug 1 11:38:10 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aisheng Dong X-Patchwork-Id: 1025822 Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by demeter1.kernel.org (8.14.4/8.14.4) with ESMTP id p71BVbiv026490 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Mon, 1 Aug 2011 11:31:58 GMT Received: from canuck.infradead.org ([2001:4978:20e::1]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QnqiS-0006dp-AH; Mon, 01 Aug 2011 11:31:24 +0000 Received: from localhost ([127.0.0.1] helo=canuck.infradead.org) by canuck.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1QnqiR-0000v1-QW; Mon, 01 Aug 2011 11:31:23 +0000 Received: from ch1ehsobe006.messaging.microsoft.com ([216.32.181.186] helo=ch1outboundpool.messaging.microsoft.com) by canuck.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QnqiN-0000ui-90 for linux-arm-kernel@lists.infradead.org; Mon, 01 Aug 2011 11:31:21 +0000 Received: from mail171-ch1-R.bigfish.com (216.32.181.173) by CH1EHSOBE014.bigfish.com (10.43.70.64) with Microsoft SMTP Server id 14.1.225.22; Mon, 1 Aug 2011 11:31:17 +0000 Received: from mail171-ch1 (localhost.localdomain [127.0.0.1]) by mail171-ch1-R.bigfish.com (Postfix) with ESMTP id 3F4C1478333; Mon, 1 Aug 2011 11:31:17 +0000 (UTC) X-SpamScore: 3 X-BigFish: VS3(zzzz1202h1082kzz8275bhz2dh2a8h668h839h61h) X-Spam-TCS-SCL: 0:0 X-Forefront-Antispam-Report: CIP:70.37.183.190; KIP:(null); UIP:(null); IPVD:NLI; H:mail.freescale.net; RD:none; EFVD:NLI Received: from mail171-ch1 (localhost.localdomain [127.0.0.1]) by mail171-ch1 (MessageSwitch) id 1312198276641780_8715; Mon, 1 Aug 2011 11:31:16 +0000 (UTC) Received: from CH1EHSMHS010.bigfish.com (snatpool1.int.messaging.microsoft.com [10.43.68.243]) by mail171-ch1.bigfish.com (Postfix) with ESMTP id 92C21E2004B; Mon, 1 Aug 2011 11:31:16 +0000 (UTC) Received: from mail.freescale.net (70.37.183.190) by CH1EHSMHS010.bigfish.com (10.43.70.10) with Microsoft SMTP Server (TLS) id 14.1.225.22; Mon, 1 Aug 2011 11:31:14 +0000 Received: from az33smr02.freescale.net (10.64.34.200) by 039-SN1MMR1-002.039d.mgd.msft.net (10.84.1.15) with Microsoft SMTP Server id 14.1.289.8; Mon, 1 Aug 2011 06:31:13 -0500 Received: from localhost.localdomain (shlinux2.ap.freescale.net [10.192.224.44]) by az33smr02.freescale.net (8.13.1/8.13.0) with ESMTP id p71BV96v028161; Mon, 1 Aug 2011 06:31:10 -0500 (CDT) From: Dong Aisheng To: Subject: [PATCH 1/1] ASoC: core: cache index fix Date: Mon, 1 Aug 2011 19:38:10 +0800 Message-ID: <1312198690-13237-1-git-send-email-b29396@freescale.com> X-Mailer: git-send-email 1.7.0.4 MIME-Version: 1.0 X-OriginatorOrg: freescale.com X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20110801_073119_540953_23E421BE X-CRM114-Status: GOOD ( 26.48 ) X-Spam-Score: -0.7 (/) X-Spam-Report: SpamAssassin version 3.3.1 on canuck.infradead.org summary: Content analysis details: (-0.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [216.32.181.186 listed in list.dnswl.org] Cc: s.hauer@pengutronix.de, broonie@opensource.wolfsonmicro.com, lrg@ti.com, linux-arm-kernel@lists.infradead.org, w.sang@pengutronix.de X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Mon, 01 Aug 2011 11:31:59 +0000 (UTC) For codecs whose reg_cache_step is not 1, the original cache io code may fetch a wrong value since it does not check the reg_cache_step and remainly use the reg as index to fetch value from cache. This patch provides help functions for conversion between cache index and register index and the cache io functions will use them in right place to ensure to fetch a correct register value. Signed-off-by: Dong Aisheng Cc: Mark Brown Cc: Liam Girdwood Cc: Sascha Hauer Cc: Wolfram Sang --- include/sound/soc.h | 4 ++ sound/soc/soc-cache.c | 117 +++++++++++++++++++++++++++++++++++++------------ sound/soc/soc-core.c | 15 +++--- sound/soc/soc-io.c | 10 +++- 4 files changed, 107 insertions(+), 39 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index aa19f5a..b70789d 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -306,6 +306,10 @@ int snd_soc_cache_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value); int snd_soc_cache_read(struct snd_soc_codec *codec, unsigned int reg, unsigned int *value); +int snd_soc_cache_reg_to_idx(struct snd_soc_codec *codec, + unsigned int reg); +int snd_soc_cache_idx_to_reg(struct snd_soc_codec *codec, + unsigned int idx); int snd_soc_default_volatile_register(struct snd_soc_codec *codec, unsigned int reg); int snd_soc_default_readable_register(struct snd_soc_codec *codec, diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index d9f8ade..1a08bcf 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -66,6 +66,38 @@ static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx, return -1; } +int snd_soc_cache_reg_to_idx(struct snd_soc_codec *codec, + unsigned int reg) +{ + const struct snd_soc_codec_driver *codec_drv; + unsigned int idx = 0; + + codec_drv = codec->driver; + + if (codec_drv->reg_cache_step > 0) + idx = reg / codec_drv->reg_cache_step; + else + idx = reg; + + return idx; +} + +int snd_soc_cache_idx_to_reg(struct snd_soc_codec *codec, + unsigned int idx) +{ + const struct snd_soc_codec_driver *codec_drv; + unsigned int reg = 0; + + codec_drv = codec->driver; + + if (codec_drv->reg_cache_step > 0) + reg = idx * codec_drv->reg_cache_step; + else + reg = idx; + + return reg; +} + struct snd_soc_rbtree_node { struct rb_node node; /* the actual rbtree node holding this block */ unsigned int base_reg; /* base register handled by this block */ @@ -262,14 +294,17 @@ static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec, unsigned int pos; int i; int ret; + unsigned int idx; + + idx = snd_soc_cache_reg_to_idx(codec, reg); rbtree_ctx = codec->reg_cache; /* look up the required register in the cached rbnode */ rbnode = rbtree_ctx->cached_rbnode; if (rbnode) { snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg); - if (reg >= base_reg && reg <= top_reg) { - reg_tmp = reg - base_reg; + if (idx >= base_reg && idx <= top_reg) { + reg_tmp = idx - base_reg; val = snd_soc_rbtree_get_register(rbnode, reg_tmp); if (val == value) return 0; @@ -280,9 +315,9 @@ static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec, /* if we can't locate it in the cached rbnode we'll have * to traverse the rbtree looking for it. */ - rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg); + rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, idx); if (rbnode) { - reg_tmp = reg - rbnode->base_reg; + reg_tmp = idx - rbnode->base_reg; val = snd_soc_rbtree_get_register(rbnode, reg_tmp); if (val == value) return 0; @@ -298,15 +333,15 @@ static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec, rbnode_tmp = rb_entry(node, struct snd_soc_rbtree_node, node); for (i = 0; i < rbnode_tmp->blklen; ++i) { reg_tmp = rbnode_tmp->base_reg + i; - if (abs(reg_tmp - reg) != 1) + if (abs(reg_tmp - idx) != 1) continue; /* decide where in the block to place our register */ - if (reg_tmp + 1 == reg) + if (reg_tmp + 1 == idx) pos = i + 1; else pos = i; ret = snd_soc_rbtree_insert_to_block(rbnode_tmp, pos, - reg, value); + idx, value); if (ret) return ret; rbtree_ctx->cached_rbnode = rbnode_tmp; @@ -322,7 +357,7 @@ static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec, if (!rbnode) return -ENOMEM; rbnode->blklen = 1; - rbnode->base_reg = reg; + rbnode->base_reg = idx; rbnode->word_size = codec->driver->reg_word_size; rbnode->block = kmalloc(rbnode->blklen * rbnode->word_size, GFP_KERNEL); @@ -345,14 +380,17 @@ static int snd_soc_rbtree_cache_read(struct snd_soc_codec *codec, struct snd_soc_rbtree_node *rbnode; unsigned int base_reg, top_reg; unsigned int reg_tmp; + unsigned int idx; + + idx = snd_soc_cache_reg_to_idx(codec, reg); rbtree_ctx = codec->reg_cache; /* look up the required register in the cached rbnode */ rbnode = rbtree_ctx->cached_rbnode; if (rbnode) { snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg); - if (reg >= base_reg && reg <= top_reg) { - reg_tmp = reg - base_reg; + if (idx >= base_reg && reg <= top_reg) { + reg_tmp = idx - base_reg; *value = snd_soc_rbtree_get_register(rbnode, reg_tmp); return 0; } @@ -360,9 +398,9 @@ static int snd_soc_rbtree_cache_read(struct snd_soc_codec *codec, /* if we can't locate it in the cached rbnode we'll have * to traverse the rbtree looking for it. */ - rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg); + rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, idx); if (rbnode) { - reg_tmp = reg - rbnode->base_reg; + reg_tmp = idx - rbnode->base_reg; *value = snd_soc_rbtree_get_register(rbnode, reg_tmp); rbtree_ctx->cached_rbnode = rbnode; } else { @@ -408,6 +446,7 @@ static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec) unsigned int val; int i; int ret; + unsigned int reg; codec->reg_cache = kmalloc(sizeof *rbtree_ctx, GFP_KERNEL); if (!codec->reg_cache) @@ -426,7 +465,8 @@ static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec) word_size); if (!val) continue; - ret = snd_soc_rbtree_cache_write(codec, i, val); + reg = snd_soc_cache_idx_to_reg(codec, i); + ret = snd_soc_rbtree_cache_write(codec, reg, val); if (ret) goto err; } @@ -560,21 +600,23 @@ static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec) unsigned int val; int i; int ret; + unsigned int reg; lzo_blocks = codec->reg_cache; for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) { + reg = snd_soc_cache_idx_to_reg(codec, i); WARN_ON(codec->writable_register && - codec->writable_register(codec, i)); - ret = snd_soc_cache_read(codec, i, &val); + codec->writable_register(codec, reg)); + ret = snd_soc_cache_read(codec, reg, &val); if (ret) return ret; codec->cache_bypass = 1; - ret = snd_soc_write(codec, i, val); + ret = snd_soc_write(codec, reg, val); codec->cache_bypass = 0; if (ret) return ret; dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", - i, val); + reg, val); } return 0; @@ -587,11 +629,14 @@ static int snd_soc_lzo_cache_write(struct snd_soc_codec *codec, int ret, blkindex, blkpos; size_t blksize, tmp_dst_len; void *tmp_dst; + unsigned int idx; + + idx = snd_soc_cache_reg_to_idx(codec, reg); /* index of the compressed lzo block */ - blkindex = snd_soc_lzo_get_blkindex(codec, reg); + blkindex = snd_soc_lzo_get_blkindex(codec, idx); /* register index within the decompressed block */ - blkpos = snd_soc_lzo_get_blkpos(codec, reg); + blkpos = snd_soc_lzo_get_blkpos(codec, idx); /* size of the compressed block */ blksize = snd_soc_lzo_get_blksize(codec); lzo_blocks = codec->reg_cache; @@ -632,7 +677,7 @@ static int snd_soc_lzo_cache_write(struct snd_soc_codec *codec, } /* set the bit so we know we have to sync this register */ - set_bit(reg, lzo_block->sync_bmp); + set_bit(idx, lzo_block->sync_bmp); kfree(tmp_dst); kfree(lzo_block->src); return 0; @@ -649,12 +694,15 @@ static int snd_soc_lzo_cache_read(struct snd_soc_codec *codec, int ret, blkindex, blkpos; size_t blksize, tmp_dst_len; void *tmp_dst; + unsigned int idx; + + idx = snd_soc_cache_reg_to_idx(codec, reg); *value = 0; /* index of the compressed lzo block */ - blkindex = snd_soc_lzo_get_blkindex(codec, reg); + blkindex = snd_soc_lzo_get_blkindex(codec, idx); /* register index within the decompressed block */ - blkpos = snd_soc_lzo_get_blkpos(codec, reg); + blkpos = snd_soc_lzo_get_blkpos(codec, idx); /* size of the compressed block */ blksize = snd_soc_lzo_get_blksize(codec); lzo_blocks = codec->reg_cache; @@ -820,23 +868,25 @@ static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) int ret; const struct snd_soc_codec_driver *codec_drv; unsigned int val; + unsigned int reg; codec_drv = codec->driver; for (i = 0; i < codec_drv->reg_cache_size; ++i) { + reg = snd_soc_cache_idx_to_reg(codec, i); WARN_ON(codec->writable_register && - codec->writable_register(codec, i)); - ret = snd_soc_cache_read(codec, i, &val); + codec->writable_register(codec, reg)); + ret = snd_soc_cache_read(codec, reg, &val); if (ret) return ret; if (codec->reg_def_copy) if (snd_soc_get_cache_val(codec->reg_def_copy, - i, codec_drv->reg_word_size) == val) + reg, codec_drv->reg_word_size) == val) continue; - ret = snd_soc_write(codec, i, val); + ret = snd_soc_write(codec, reg, val); if (ret) return ret; dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", - i, val); + reg, val); } return 0; } @@ -844,15 +894,24 @@ static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) static int snd_soc_flat_cache_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { - snd_soc_set_cache_val(codec->reg_cache, reg, value, + unsigned int idx; + + idx = snd_soc_cache_reg_to_idx(codec, reg); + + snd_soc_set_cache_val(codec->reg_cache, idx, value, codec->driver->reg_word_size); + return 0; } static int snd_soc_flat_cache_read(struct snd_soc_codec *codec, unsigned int reg, unsigned int *value) { - *value = snd_soc_get_cache_val(codec->reg_cache, reg, + unsigned int idx; + + idx = snd_soc_cache_reg_to_idx(codec, reg); + + *value = snd_soc_get_cache_val(codec->reg_cache, idx, codec->driver->reg_word_size); return 0; } diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 83ad8ca..a23971e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -125,11 +125,12 @@ static int format_register_str(struct snd_soc_codec *codec, static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf, size_t count, loff_t pos) { - int i, step = 1; + int i; int wordsize, regsize; int len; size_t total = 0; loff_t p = 0; + unsigned int reg; wordsize = min_bytes_needed(codec->driver->reg_cache_size) * 2; regsize = codec->driver->reg_word_size * 2; @@ -139,22 +140,20 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf, if (!codec->driver->reg_cache_size) return 0; - if (codec->driver->reg_cache_step) - step = codec->driver->reg_cache_step; - - for (i = 0; i < codec->driver->reg_cache_size; i += step) { - if (codec->readable_register && !codec->readable_register(codec, i)) + for (i = 0; i <= codec->driver->reg_cache_size; i++) { + reg = snd_soc_cache_idx_to_reg(codec, i); + if (codec->readable_register && !codec->readable_register(codec, reg)) continue; if (codec->driver->display_register) { count += codec->driver->display_register(codec, buf + count, - PAGE_SIZE - count, i); + PAGE_SIZE - count, reg); } else { /* only support larger than PAGE_SIZE bytes debugfs * entries for the default case */ if (p >= pos) { if (total + len >= count - 1) break; - format_register_str(codec, i, buf + total, len); + format_register_str(codec, reg, buf + total, len); total += len; } p += len; diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c index cca490c..e5c15d3 100644 --- a/sound/soc/soc-io.c +++ b/sound/soc/soc-io.c @@ -35,9 +35,12 @@ static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value, const void *data, int len) { int ret; + unsigned int idx; + + idx = snd_soc_cache_reg_to_idx(codec, reg); if (!snd_soc_codec_volatile_register(codec, reg) && - reg < codec->driver->reg_cache_size && + idx < codec->driver->reg_cache_size && !codec->cache_bypass) { ret = snd_soc_cache_write(codec, reg, value); if (ret < 0) @@ -62,8 +65,11 @@ static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg) { int ret; unsigned int val; + unsigned int idx; + + idx = snd_soc_cache_reg_to_idx(codec, reg); - if (reg >= codec->driver->reg_cache_size || + if (idx >= codec->driver->reg_cache_size || snd_soc_codec_volatile_register(codec, reg) || codec->cache_bypass) { if (codec->cache_only)