Skip to content

Commit 4c5f8c2

Browse files
chleroybroonie
authored andcommitted
ASoC: fsl: fsl_qmc_audio: Only request completion on last channel
In non-interleaved mode, several QMC channels are used in sync. More details can be found in commit 188d9ca ("ASoC: fsl: fsl_qmc_audio: Add support for non-interleaved mode.") At the time being, an interrupt is requested on each channel to perform capture/playback completion, allthough the completion is really performed only once all channels have completed their work. This leads to a lot more interrupts than really needed. Looking at /proc/interrupts shows ~3800 interrupts per second when using 4 capture and 4 playback devices with 5ms periods while only 1600 (200 x 4 + 200 x 4) periods are processed during one second. The QMC channels work in sync, the one started first is the one finishing first and the one started last is the one finishing last, so when the last one finishes it is guaranteed that the other ones are finished as well. Therefore only request completion processing on the last QMC channel. On my board with the above exemple, on a kernel started with 'threadirqs' option, the QMC irq thread uses 16% CPU time with this patch while it uses 26% CPU time without this patch. Acked-by: Herve Codina <herve.codina@bootlin.com> Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu> Link: https://patch.msgid.link/bbd5167d190bbb45c3a4cd6ef2dece8817e0cc1e.1758209158.git.christophe.leroy@csgroup.eu Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent fb418fe commit 4c5f8c2

1 file changed

Lines changed: 6 additions & 40 deletions

File tree

sound/soc/fsl/fsl_qmc_audio.c

Lines changed: 6 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ struct qmc_dai_prtd {
5757
size_t ch_dma_offset;
5858

5959
unsigned int channels;
60-
DECLARE_BITMAP(chans_pending, 64);
6160
struct snd_pcm_substream *substream;
6261
};
6362

@@ -126,17 +125,14 @@ static int qmc_audio_pcm_write_submit(struct qmc_dai_prtd *prtd)
126125
int ret;
127126

128127
for (i = 0; i < prtd->channels; i++) {
129-
bitmap_set(prtd->chans_pending, i, 1);
130-
131128
ret = qmc_chan_write_submit(prtd->qmc_dai->chans[i].qmc_chan,
132129
prtd->ch_dma_addr_current + i * prtd->ch_dma_offset,
133130
prtd->ch_dma_size,
134-
qmc_audio_pcm_write_complete,
135-
&prtd->qmc_dai->chans[i]);
131+
i == prtd->channels - 1 ? qmc_audio_pcm_write_complete :
132+
NULL, prtd);
136133
if (ret) {
137134
dev_err(prtd->qmc_dai->dev, "write_submit %u failed %d\n",
138135
i, ret);
139-
bitmap_clear(prtd->chans_pending, i, 1);
140136
return ret;
141137
}
142138
}
@@ -146,20 +142,7 @@ static int qmc_audio_pcm_write_submit(struct qmc_dai_prtd *prtd)
146142

147143
static void qmc_audio_pcm_write_complete(void *context)
148144
{
149-
struct qmc_dai_chan *chan = context;
150-
struct qmc_dai_prtd *prtd;
151-
152-
prtd = chan->prtd_tx;
153-
154-
/* Mark the current channel as completed */
155-
bitmap_clear(prtd->chans_pending, chan - prtd->qmc_dai->chans, 1);
156-
157-
/*
158-
* All QMC channels involved must have completed their transfer before
159-
* submitting a new one.
160-
*/
161-
if (!bitmap_empty(prtd->chans_pending, 64))
162-
return;
145+
struct qmc_dai_prtd *prtd = context;
163146

164147
prtd->buffer_ended += prtd->period_size;
165148
if (prtd->buffer_ended >= prtd->buffer_size)
@@ -182,17 +165,14 @@ static int qmc_audio_pcm_read_submit(struct qmc_dai_prtd *prtd)
182165
int ret;
183166

184167
for (i = 0; i < prtd->channels; i++) {
185-
bitmap_set(prtd->chans_pending, i, 1);
186-
187168
ret = qmc_chan_read_submit(prtd->qmc_dai->chans[i].qmc_chan,
188169
prtd->ch_dma_addr_current + i * prtd->ch_dma_offset,
189170
prtd->ch_dma_size,
190-
qmc_audio_pcm_read_complete,
191-
&prtd->qmc_dai->chans[i]);
171+
i == prtd->channels - 1 ? qmc_audio_pcm_read_complete :
172+
NULL, prtd);
192173
if (ret) {
193174
dev_err(prtd->qmc_dai->dev, "read_submit %u failed %d\n",
194175
i, ret);
195-
bitmap_clear(prtd->chans_pending, i, 1);
196176
return ret;
197177
}
198178
}
@@ -202,26 +182,13 @@ static int qmc_audio_pcm_read_submit(struct qmc_dai_prtd *prtd)
202182

203183
static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags)
204184
{
205-
struct qmc_dai_chan *chan = context;
206-
struct qmc_dai_prtd *prtd;
207-
208-
prtd = chan->prtd_rx;
209-
210-
/* Mark the current channel as completed */
211-
bitmap_clear(prtd->chans_pending, chan - prtd->qmc_dai->chans, 1);
185+
struct qmc_dai_prtd *prtd = context;
212186

213187
if (length != prtd->ch_dma_size) {
214188
dev_err(prtd->qmc_dai->dev, "read complete length = %zu, exp %zu\n",
215189
length, prtd->ch_dma_size);
216190
}
217191

218-
/*
219-
* All QMC channels involved must have completed their transfer before
220-
* submitting a new one.
221-
*/
222-
if (!bitmap_empty(prtd->chans_pending, 64))
223-
return;
224-
225192
prtd->buffer_ended += prtd->period_size;
226193
if (prtd->buffer_ended >= prtd->buffer_size)
227194
prtd->buffer_ended = 0;
@@ -249,7 +216,6 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component,
249216

250217
switch (cmd) {
251218
case SNDRV_PCM_TRIGGER_START:
252-
bitmap_zero(prtd->chans_pending, 64);
253219
prtd->buffer_ended = 0;
254220
prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;
255221

0 commit comments

Comments
 (0)