ASoC: soc-cache: Introduce the cache_bypass option
PATCH 1/2 ASoC: soc-cache: Introduce the cache_bypass option
This is primarily needed to avoid writing back to the cache whenever we are syncing the cache with the hardware. This gives a performance benefit especially for large register maps.
--- include/sound/soc.h | 1 + sound/soc/soc-cache.c | 36 ++++++++++++++++++++++++------------ 2 files changed, 25 insertions(+), 12 deletions(-)
include/sound/soc.h +1 -0
@@ -463,6 +463,7 @@ struct snd_soc_codec {/* runtime */ struct snd_ac97 *ac97;/* for ad-hoc ac97 devices */ unsigned int active; + unsigned int cache_bypass:1; /* Suppress access to the cache */ unsigned int cache_only:1; /* Suppress writes to hardware */ unsigned int cache_sync:1; /* Cache needs to be synced to hardware */ unsigned int suspended:1; /* Codec is in suspend PM state */
sound/soc/soc-cache.c +24 -12
@@ -25,7 +25,8 @@ static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,unsigned int val;if (reg >= codec->driver->reg_cache_size || -snd_soc_codec_volatile_register (codec, reg)) { +snd_soc_codec_volatile_register (codec, reg) || + codec->cache_bypass) {if (codec->cache_only)return -1 ;
@@ -49,7 +50,8 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, data[1 ] = value &0x00ff ;if (!snd_soc_codec_volatile_register (codec, reg) && - reg < codec->driver->reg_cache_size) { + reg < codec->driver->reg_cache_size && + !codec->cache_bypass) { ret =snd_soc_cache_write (codec, reg, value);if (ret <0 )return -1 ;
@@ -106,7 +108,8 @@ static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,unsigned int val;if (reg >= codec->driver->reg_cache_size || -snd_soc_codec_volatile_register (codec, reg)) { +snd_soc_codec_volatile_register (codec, reg) || + codec->cache_bypass) {if (codec->cache_only)return -1 ;
@@ -130,7 +133,8 @@ static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, data[1 ] = value &0x00ff ;if (!snd_soc_codec_volatile_register (codec, reg) && - reg < codec->driver->reg_cache_size) { + reg < codec->driver->reg_cache_size && + !codec->cache_bypass) { ret =snd_soc_cache_write (codec, reg, value);if (ret <0 )return -1 ;
@@ -191,7 +195,8 @@ static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg, data[1 ] = value &0xff ;if (!snd_soc_codec_volatile_register (codec, reg) && - reg < codec->driver->reg_cache_size) { + reg < codec->driver->reg_cache_size && + !codec->cache_bypass) { ret =snd_soc_cache_write (codec, reg, value);if (ret <0 )return -1 ;
@@ -216,7 +221,8 @@ static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec, reg &=0xff ;if (reg >= codec->driver->reg_cache_size || -snd_soc_codec_volatile_register (codec, reg)) { +snd_soc_codec_volatile_register (codec, reg) || + codec->cache_bypass) {if (codec->cache_only)return -1 ;
@@ -271,7 +277,8 @@ static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, data[2 ] = value &0xff ;if (!snd_soc_codec_volatile_register (codec, reg) && - reg < codec->driver->reg_cache_size) { + reg < codec->driver->reg_cache_size && + !codec->cache_bypass) { ret =snd_soc_cache_write (codec, reg, value);if (ret <0 )return -1 ;
@@ -295,7 +302,8 @@ static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,unsigned int val;if (reg >= codec->driver->reg_cache_size || -snd_soc_codec_volatile_register (codec, reg)) { +snd_soc_codec_volatile_register (codec, reg) || + codec->cache_bypass) {if (codec->cache_only)return -1 ;
@@ -450,7 +458,8 @@ static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec, reg &=0xff ;if (reg >= codec->driver->reg_cache_size || -snd_soc_codec_volatile_register (codec, reg)) { +snd_soc_codec_volatile_register (codec, reg) || + codec->cache_bypass) {if (codec->cache_only)return -1 ;
@@ -476,7 +485,8 @@ static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, reg &=0xff ;if (!snd_soc_codec_volatile_register (codec, reg) && - reg < codec->driver->reg_cache_size) { + reg < codec->driver->reg_cache_size && + !codec->cache_bypass) { ret =snd_soc_cache_write (codec, reg, value);if (ret <0 )return -1 ;
@@ -568,7 +578,8 @@ static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,unsigned int val;if (reg >= codec->driver->reg_cache_size || -snd_soc_codec_volatile_register (codec, reg)) { +snd_soc_codec_volatile_register (codec, reg) || + codec->cache_bypass) {if (codec->cache_only)return -1 ;
@@ -595,7 +606,8 @@ static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg, data[3 ] = value &0xff ;if (!snd_soc_codec_volatile_register (codec, reg) && - reg < codec->driver->reg_cache_size) { + reg < codec->driver->reg_cache_size && + !codec->cache_bypass) { ret =snd_soc_cache_write (codec, reg, value);if (ret <0 )return -1 ;
Signature · 1 line
1.7.4
PATCH 2/2 ASoC: soc-cache: Apply the cache_bypass option
Incorporate the use of the cache_bypass functionality in the syncing functions. The snd_soc_flat_cache_sync() need not be hooked as there is no performance benefit from using the cache_bypass option.
--- sound/soc/soc-cache.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-)
sound/soc/soc-cache.c +4 -0
@@ -847,7 +847,9 @@ static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec) ret =snd_soc_cache_read (codec, rbnode->reg, &val);if (ret)return ret; + codec->cache_bypass =1 ; ret =snd_soc_write (codec, rbnode->reg, val); + codec->cache_bypass =0 ;if (ret)return ret; dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
@@ -1134,7 +1136,9 @@ static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec) ret =snd_soc_cache_read (codec, i, &val);if (ret)return ret; + codec->cache_bypass =1 ; ret =snd_soc_write (codec, i, val); + codec->cache_bypass =0 ;if (ret)return ret; dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
Signature · 1 line
1.7.4
Quoted 3 lines · Dimitris Papastamos
This is primarily needed to avoid writing back to the cache whenever we are syncing the cache with the hardware. This gives a performance benefit especially for large register maps.
Hrm, this is a rather large and invasive patch to be applying as part of a bug fix for a specific driver this late in the release process. Can we do something driver specific for the 2.6.38 release?
Quoted 8 lines · Mark Brown
Quoted 3 lines · Dimitris Papastamos
This is primarily needed to avoid writing back to the cache whenever we are syncing the cache with the hardware. This gives a performance benefit especially for large register maps.
Hrm, this is a rather large and invasive patch to be applying as part of a bug fix for a specific driver this late in the release process. Can we do something driver specific for the 2.6.38 release?
Em, make WM8994_POWER_MANAGEMENT_5 a volatile register? That is sort of a hack but I can't think of anything else.
Thanks,
Dimitris
Quoted 6 lines · Dimitris Papastamos
Quoted 5 lines · Mark Brown
Quoted 3 lines · Dimitris Papastamos
This is primarily needed to avoid writing back to the cache whenever we are syncing the cache with the hardware. This gives a performance benefit especially for large register maps.
Quoted 6 lines
Quoted 3 lines
Hrm, this is a rather large and invasive patch to be applying as part of a bug fix for a specific driver this late in the release process. Can we do something driver specific for the 2.6.38 release?
Em, make
WM8994_POWER_MANAGEMENT_5a volatile register? That is sort of a hack but I can't think of anything else.
Now that I think about it, that won't work. We still need to be able to sync the other bitfields in that register on resume.
Thanks,
Dimitris
Quoted 8 lines · Mark Brown
Quoted 3 lines · Dimitris Papastamos
This is primarily needed to avoid writing back to the cache whenever we are syncing the cache with the hardware. This gives a performance benefit especially for large register maps.
Hrm, this is a rather large and invasive patch to be applying as part of a bug fix for a specific driver this late in the release process. Can we do something driver specific for the 2.6.38 release?
Would this be acceptable? In wm8994_resume():
/* force a HW read */
val = wm8994_reg_read(codec->control_data, WM8994_POWER_MANAGEMENT_5);
instead of the call to snd_soc_read().
Thanks,
Dimitris
Quoted 6 lines · Dimitris Papastamos
Would this be acceptable? In
wm8994_resume():/* force a HW read */
val =wm8994_reg_read(codec->control_data, WM8994_POWER_MANAGEMENT_5);instead of the call to
snd_soc_read().
Yes, that looks good. We can then update to use the APIs more normally in 2.6.39.