summaryrefslogtreecommitdiff
path: root/sound/soc
diff options
context:
space:
mode:
authorShengjiu Wang <shengjiu.wang@freescale.com>2016-06-30 17:45:05 +0800
committerDong Aisheng <aisheng.dong@nxp.com>2019-11-25 15:48:25 +0800
commitd53e77a086745032a11284f7e4a5be148d8cce56 (patch)
treec5313a6ffc344436a324eb8a81d124f57b177372 /sound/soc
parent21859d28ffc44bdbd3ae5163637dae571321f004 (diff)
MLK-12771: ASoC: fsl_asrc: fix dma task timeout issue
The test case is one p2p playback + two m2m converter running simultaneously. There are three root cause for this issue: 1. hw_free() of p2p may be called twice in the end, which cause release twice of one pair, if another pair request is called between this two release, there will be issue. 2. In m2m close(), the asrc_priv->pair[i] will be set NULL twice, which is same issue as 1. 3. when output rate is more than eight multiple of input rate for m2m, the last_period_size should be larger. Signed-off-by: Shengjiu Wang <shengjiu.wang@freescale.com>
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/fsl/fsl_asrc.c9
-rw-r--r--sound/soc/fsl/fsl_asrc.h2
-rw-r--r--sound/soc/fsl/fsl_asrc_m2m.c15
3 files changed, 14 insertions, 12 deletions
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index 817adbfa27fa..26050427b7ff 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -525,6 +525,7 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
return ret;
}
+ asrc_priv->pair_streams |= BIT(substream->stream);
pair->config = &config;
if (width == 16)
@@ -573,11 +574,15 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
static int fsl_asrc_dai_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
+ struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai);
struct snd_pcm_runtime *runtime = substream->runtime;
struct fsl_asrc_pair *pair = runtime->private_data;
- if (pair)
- fsl_asrc_release_pair(pair);
+ if (asrc_priv->pair_streams & BIT(substream->stream)) {
+ if (pair)
+ fsl_asrc_release_pair(pair);
+ asrc_priv->pair_streams &= ~BIT(substream->stream);
+ }
return 0;
}
diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h
index 1fb06410d86f..034d10dc11e9 100644
--- a/sound/soc/fsl/fsl_asrc.h
+++ b/sound/soc/fsl/fsl_asrc.h
@@ -341,6 +341,7 @@ struct fsl_asrc_pair {
* @pair: pair pointers
* @channel_bits: width of ASRCNCR register for each pair
* @channel_avail: non-occupied channel numbers
+ * @pair_streams:indicat which substream is running
* @asrc_rate: default sample rate for ASoC Back-Ends
* @asrc_width: default sample width for ASoC Back-Ends
* @regcache_cfg: store register value of REG_ASRCFG
@@ -360,6 +361,7 @@ struct fsl_asrc {
struct fsl_asrc_pair *pair[ASRC_PAIR_MAX_NUM];
unsigned int channel_bits;
unsigned int channel_avail;
+ unsigned int pair_streams;
int asrc_rate;
int asrc_width;
diff --git a/sound/soc/fsl/fsl_asrc_m2m.c b/sound/soc/fsl/fsl_asrc_m2m.c
index 9ee0f503e8c5..7363dc003aa6 100644
--- a/sound/soc/fsl/fsl_asrc_m2m.c
+++ b/sound/soc/fsl/fsl_asrc_m2m.c
@@ -274,7 +274,8 @@ static int fsl_asrc_prepare_io_buffer(struct fsl_asrc_pair *pair,
word_size = 2;
if (buf_len < word_size * pair->channels * wm ||
- buf_len > ASRC_DMA_BUFFER_SIZE) {
+ buf_len > ASRC_DMA_BUFFER_SIZE ||
+ (dir == OUT && buf_len < word_size * pair->channels * last_period_size)) {
pair_err("%sput buffer size is error: [%d]\n",
DIR_STR(dir), buf_len);
return -EINVAL;
@@ -557,7 +558,9 @@ static long fsl_asrc_ioctl_config_pair(struct fsl_asrc_pair *pair,
m2m->rate[IN] = config.input_sample_rate;
m2m->rate[OUT] = config.output_sample_rate;
- if (m2m->rate[OUT] > m2m->rate[IN])
+ if (m2m->rate[OUT] >= m2m->rate[IN] * 8)
+ m2m->last_period_size = (m2m->rate[OUT] / m2m->rate[IN]) * 5;
+ else if (m2m->rate[OUT] > m2m->rate[IN])
m2m->last_period_size = ASRC_OUTPUT_LAST_SAMPLE_MAX;
else
m2m->last_period_size = ASRC_OUTPUT_LAST_SAMPLE;
@@ -852,14 +855,6 @@ static int fsl_asrc_close(struct inode *inode, struct file *file)
struct fsl_asrc *asrc_priv = pair->asrc_priv;
struct device *dev = &asrc_priv->pdev->dev;
unsigned long lock_flags;
- int i;
-
- /* Make sure we have clear the pointer */
- spin_lock_irqsave(&asrc_priv->lock, lock_flags);
- for (i = 0; i < ASRC_PAIR_MAX_NUM; i++)
- if (asrc_priv->pair[i] == pair)
- asrc_priv->pair[i] = NULL;
- spin_unlock_irqrestore(&asrc_priv->lock, lock_flags);
if (m2m->asrc_active) {
m2m->asrc_active = 0;