* [PATCH v3 1/4] soc: fsl: qmc: Only set completion interrupt when needed
2025-08-18 8:19 [PATCH v3 0/4] ASoC: fsl: fsl_qmc_audio: Reduce amount of interrupts Christophe Leroy
@ 2025-08-18 8:20 ` Christophe Leroy
2025-08-21 16:23 ` Herve Codina
2025-08-18 8:20 ` [PATCH v3 2/4] ASoc: fsl: fsl_qmc_audio: Ensure audio channels are ordered in TDM bus Christophe Leroy
` (3 subsequent siblings)
4 siblings, 1 reply; 9+ messages in thread
From: Christophe Leroy @ 2025-08-18 8:20 UTC (permalink / raw)
To: Herve Codina, Qiang Zhao, Shengjiu Wang, Xiubo Li, Fabio Estevam,
Nicolin Chen, Liam Girdwood, Mark Brown, Jaroslav Kysela,
Takashi Iwai
Cc: Christophe Leroy, linuxppc-dev, linux-arm-kernel, linux-kernel,
linux-sound
When no post-completion processing is expected, don't waste time
handling useless interrupts.
Only set QMC_BD_[R/T]X_I when a completion function is passed in,
and perform seamless completion on submit for interruptless buffers.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
drivers/soc/fsl/qe/qmc.c | 44 ++++++++++++++++++++++++++++++----------
1 file changed, 33 insertions(+), 11 deletions(-)
diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c
index 36c0ccc06151..da5ea6d35618 100644
--- a/drivers/soc/fsl/qe/qmc.c
+++ b/drivers/soc/fsl/qe/qmc.c
@@ -461,9 +461,16 @@ int qmc_chan_write_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length,
ctrl = qmc_read16(&bd->cbd_sc);
if (ctrl & (QMC_BD_TX_R | QMC_BD_TX_UB)) {
- /* We are full ... */
- ret = -EBUSY;
- goto end;
+ if (!(ctrl & (QMC_BD_TX_R | QMC_BD_TX_I)) && bd == chan->txbd_done) {
+ if (ctrl & QMC_BD_TX_W)
+ chan->txbd_done = chan->txbds;
+ else
+ chan->txbd_done++;
+ } else {
+ /* We are full ... */
+ ret = -EBUSY;
+ goto end;
+ }
}
qmc_write16(&bd->cbd_datlen, length);
@@ -475,6 +482,10 @@ int qmc_chan_write_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length,
/* Activate the descriptor */
ctrl |= (QMC_BD_TX_R | QMC_BD_TX_UB);
+ if (complete)
+ ctrl |= QMC_BD_TX_I;
+ else
+ ctrl &= ~QMC_BD_TX_I;
wmb(); /* Be sure to flush the descriptor before control update */
qmc_write16(&bd->cbd_sc, ctrl);
@@ -569,9 +580,16 @@ int qmc_chan_read_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length,
ctrl = qmc_read16(&bd->cbd_sc);
if (ctrl & (QMC_BD_RX_E | QMC_BD_RX_UB)) {
- /* We are full ... */
- ret = -EBUSY;
- goto end;
+ if (!(ctrl & (QMC_BD_RX_E | QMC_BD_RX_I)) && bd == chan->rxbd_done) {
+ if (ctrl & QMC_BD_RX_W)
+ chan->rxbd_done = chan->rxbds;
+ else
+ chan->rxbd_done++;
+ } else {
+ /* We are full ... */
+ ret = -EBUSY;
+ goto end;
+ }
}
qmc_write16(&bd->cbd_datlen, 0); /* data length is updated by the QMC */
@@ -587,6 +605,10 @@ int qmc_chan_read_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length,
/* Activate the descriptor */
ctrl |= (QMC_BD_RX_E | QMC_BD_RX_UB);
+ if (complete)
+ ctrl |= QMC_BD_RX_I;
+ else
+ ctrl &= ~QMC_BD_RX_I;
wmb(); /* Be sure to flush data before descriptor activation */
qmc_write16(&bd->cbd_sc, ctrl);
@@ -1482,19 +1504,19 @@ static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan)
/* Init Rx BDs and set Wrap bit on last descriptor */
BUILD_BUG_ON(QMC_NB_RXBDS == 0);
- val = QMC_BD_RX_I;
for (i = 0; i < QMC_NB_RXBDS; i++) {
bd = chan->rxbds + i;
- qmc_write16(&bd->cbd_sc, val);
+ qmc_write16(&bd->cbd_sc, 0);
}
bd = chan->rxbds + QMC_NB_RXBDS - 1;
- qmc_write16(&bd->cbd_sc, val | QMC_BD_RX_W);
+ qmc_write16(&bd->cbd_sc, QMC_BD_RX_W);
/* Init Tx BDs and set Wrap bit on last descriptor */
BUILD_BUG_ON(QMC_NB_TXBDS == 0);
- val = QMC_BD_TX_I;
if (chan->mode == QMC_HDLC)
- val |= QMC_BD_TX_L | QMC_BD_TX_TC;
+ val = QMC_BD_TX_L | QMC_BD_TX_TC;
+ else
+ val = 0;
for (i = 0; i < QMC_NB_TXBDS; i++) {
bd = chan->txbds + i;
qmc_write16(&bd->cbd_sc, val);
--
2.49.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v3 1/4] soc: fsl: qmc: Only set completion interrupt when needed
2025-08-18 8:20 ` [PATCH v3 1/4] soc: fsl: qmc: Only set completion interrupt when needed Christophe Leroy
@ 2025-08-21 16:23 ` Herve Codina
0 siblings, 0 replies; 9+ messages in thread
From: Herve Codina @ 2025-08-21 16:23 UTC (permalink / raw)
To: Christophe Leroy
Cc: Qiang Zhao, Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen,
Liam Girdwood, Mark Brown, Jaroslav Kysela, Takashi Iwai,
linuxppc-dev, linux-arm-kernel, linux-kernel, linux-sound
Hi Christophe,
On Mon, 18 Aug 2025 10:20:00 +0200
Christophe Leroy <christophe.leroy@csgroup.eu> wrote:
> When no post-completion processing is expected, don't waste time
> handling useless interrupts.
>
> Only set QMC_BD_[R/T]X_I when a completion function is passed in,
> and perform seamless completion on submit for interruptless buffers.
>
> Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
> ---
> drivers/soc/fsl/qe/qmc.c | 44 ++++++++++++++++++++++++++++++----------
> 1 file changed, 33 insertions(+), 11 deletions(-)
>
Acked-by: Herve Codina <herve.codina@bootlin.com>
Best regards,
Hervé
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 2/4] ASoc: fsl: fsl_qmc_audio: Ensure audio channels are ordered in TDM bus
2025-08-18 8:19 [PATCH v3 0/4] ASoC: fsl: fsl_qmc_audio: Reduce amount of interrupts Christophe Leroy
2025-08-18 8:20 ` [PATCH v3 1/4] soc: fsl: qmc: Only set completion interrupt when needed Christophe Leroy
@ 2025-08-18 8:20 ` Christophe Leroy
2025-08-21 16:23 ` Herve Codina
2025-08-18 8:20 ` [PATCH v3 3/4] ASoC: fsl: fsl_qmc_audio: Only request completion on last channel Christophe Leroy
` (2 subsequent siblings)
4 siblings, 1 reply; 9+ messages in thread
From: Christophe Leroy @ 2025-08-18 8:20 UTC (permalink / raw)
To: Herve Codina, Qiang Zhao, Shengjiu Wang, Xiubo Li, Fabio Estevam,
Nicolin Chen, Liam Girdwood, Mark Brown, Jaroslav Kysela,
Takashi Iwai
Cc: Christophe Leroy, linuxppc-dev, linux-arm-kernel, linux-kernel,
linux-sound
To reduce complexity of interrupt handling in following patch, ensure
audio channels are configured in the same order as timeslots on the
TDM bus. If we need a given ordering of audio sources in the audio
frame, it is possible to re-order codecs on the TDM bus, no need to
mix up timeslots in channels.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
sound/soc/fsl/fsl_qmc_audio.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c
index 5614a8b909ed..c0c7ef0a1511 100644
--- a/sound/soc/fsl/fsl_qmc_audio.c
+++ b/sound/soc/fsl/fsl_qmc_audio.c
@@ -791,12 +791,17 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *
struct qmc_dai *qmc_dai,
struct snd_soc_dai_driver *qmc_soc_dai_driver)
{
+ struct qmc_chan_ts_info ts_info;
struct qmc_chan_info info;
unsigned long rx_fs_rate;
unsigned long tx_fs_rate;
+ int prev_last_rx_ts = 0;
+ int prev_last_tx_ts = 0;
unsigned int nb_tx_ts;
unsigned int nb_rx_ts;
unsigned int i;
+ int last_rx_ts;
+ int last_tx_ts;
int count;
u32 val;
int ret;
@@ -879,6 +884,30 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *
return -EINVAL;
}
}
+
+ ret = qmc_chan_get_ts_info(qmc_dai->chans[i].qmc_chan, &ts_info);
+ if (ret) {
+ dev_err(qmc_audio->dev, "dai %d get QMC %d channel TS info failed %d\n",
+ qmc_dai->id, i, ret);
+ return ret;
+ }
+
+ last_rx_ts = fls64(ts_info.rx_ts_mask);
+ last_tx_ts = fls64(ts_info.tx_ts_mask);
+
+ if (prev_last_rx_ts > last_rx_ts) {
+ dev_err(qmc_audio->dev, "dai %d QMC chan %d unordered channels (RX timeslot %d before %d)\n",
+ qmc_dai->id, i, prev_last_rx_ts, last_rx_ts);
+ return -EINVAL;
+ }
+ if (prev_last_tx_ts > last_tx_ts) {
+ dev_err(qmc_audio->dev, "dai %d QMC chan %d unordered channels (TX timeslot %d before %d)\n",
+ qmc_dai->id, i, prev_last_tx_ts, last_tx_ts);
+ return -EINVAL;
+ }
+
+ prev_last_rx_ts = last_rx_ts;
+ prev_last_tx_ts = last_tx_ts;
}
qmc_dai->nb_chans_avail = count;
--
2.49.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v3 2/4] ASoc: fsl: fsl_qmc_audio: Ensure audio channels are ordered in TDM bus
2025-08-18 8:20 ` [PATCH v3 2/4] ASoc: fsl: fsl_qmc_audio: Ensure audio channels are ordered in TDM bus Christophe Leroy
@ 2025-08-21 16:23 ` Herve Codina
0 siblings, 0 replies; 9+ messages in thread
From: Herve Codina @ 2025-08-21 16:23 UTC (permalink / raw)
To: Christophe Leroy
Cc: Qiang Zhao, Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen,
Liam Girdwood, Mark Brown, Jaroslav Kysela, Takashi Iwai,
linuxppc-dev, linux-arm-kernel, linux-kernel, linux-sound
Hi Christophe,
On Mon, 18 Aug 2025 10:20:01 +0200
Christophe Leroy <christophe.leroy@csgroup.eu> wrote:
> To reduce complexity of interrupt handling in following patch, ensure
> audio channels are configured in the same order as timeslots on the
> TDM bus. If we need a given ordering of audio sources in the audio
> frame, it is possible to re-order codecs on the TDM bus, no need to
> mix up timeslots in channels.
>
> Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
> ---
> sound/soc/fsl/fsl_qmc_audio.c | 29 +++++++++++++++++++++++++++++
> 1 file changed, 29 insertions(+)
>
Acked-by: Herve Codina <herve.codina@bootlin.com>
Best regards,
Hervé
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 3/4] ASoC: fsl: fsl_qmc_audio: Only request completion on last channel
2025-08-18 8:19 [PATCH v3 0/4] ASoC: fsl: fsl_qmc_audio: Reduce amount of interrupts Christophe Leroy
2025-08-18 8:20 ` [PATCH v3 1/4] soc: fsl: qmc: Only set completion interrupt when needed Christophe Leroy
2025-08-18 8:20 ` [PATCH v3 2/4] ASoc: fsl: fsl_qmc_audio: Ensure audio channels are ordered in TDM bus Christophe Leroy
@ 2025-08-18 8:20 ` Christophe Leroy
2025-08-18 8:20 ` [PATCH v3 4/4] ASoc: fsl: fsl_qmc_audio: Drop struct qmc_dai_chan Christophe Leroy
2025-09-18 6:12 ` [PATCH v3 0/4] ASoC: fsl: fsl_qmc_audio: Reduce amount of interrupts Christophe Leroy
4 siblings, 0 replies; 9+ messages in thread
From: Christophe Leroy @ 2025-08-18 8:20 UTC (permalink / raw)
To: Herve Codina, Qiang Zhao, Shengjiu Wang, Xiubo Li, Fabio Estevam,
Nicolin Chen, Liam Girdwood, Mark Brown, Jaroslav Kysela,
Takashi Iwai
Cc: Christophe Leroy, linuxppc-dev, linux-arm-kernel, linux-kernel,
linux-sound
In non-interleaved mode, several QMC channels are used in sync.
More details can be found in commit 188d9cae5438 ("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.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Acked-by: Herve Codina <herve.codina@bootlin.com>
---
sound/soc/fsl/fsl_qmc_audio.c | 46 +++++------------------------------
1 file changed, 6 insertions(+), 40 deletions(-)
diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c
index c0c7ef0a1511..2790953543c5 100644
--- a/sound/soc/fsl/fsl_qmc_audio.c
+++ b/sound/soc/fsl/fsl_qmc_audio.c
@@ -57,7 +57,6 @@ struct qmc_dai_prtd {
size_t ch_dma_offset;
unsigned int channels;
- DECLARE_BITMAP(chans_pending, 64);
struct snd_pcm_substream *substream;
};
@@ -126,17 +125,14 @@ static int qmc_audio_pcm_write_submit(struct qmc_dai_prtd *prtd)
int ret;
for (i = 0; i < prtd->channels; i++) {
- bitmap_set(prtd->chans_pending, i, 1);
-
ret = qmc_chan_write_submit(prtd->qmc_dai->chans[i].qmc_chan,
prtd->ch_dma_addr_current + i * prtd->ch_dma_offset,
prtd->ch_dma_size,
- qmc_audio_pcm_write_complete,
- &prtd->qmc_dai->chans[i]);
+ i == prtd->channels - 1 ? qmc_audio_pcm_write_complete :
+ NULL, prtd);
if (ret) {
dev_err(prtd->qmc_dai->dev, "write_submit %u failed %d\n",
i, ret);
- bitmap_clear(prtd->chans_pending, i, 1);
return ret;
}
}
@@ -146,20 +142,7 @@ static int qmc_audio_pcm_write_submit(struct qmc_dai_prtd *prtd)
static void qmc_audio_pcm_write_complete(void *context)
{
- struct qmc_dai_chan *chan = context;
- struct qmc_dai_prtd *prtd;
-
- prtd = chan->prtd_tx;
-
- /* Mark the current channel as completed */
- bitmap_clear(prtd->chans_pending, chan - prtd->qmc_dai->chans, 1);
-
- /*
- * All QMC channels involved must have completed their transfer before
- * submitting a new one.
- */
- if (!bitmap_empty(prtd->chans_pending, 64))
- return;
+ struct qmc_dai_prtd *prtd = context;
prtd->buffer_ended += prtd->period_size;
if (prtd->buffer_ended >= prtd->buffer_size)
@@ -182,17 +165,14 @@ static int qmc_audio_pcm_read_submit(struct qmc_dai_prtd *prtd)
int ret;
for (i = 0; i < prtd->channels; i++) {
- bitmap_set(prtd->chans_pending, i, 1);
-
ret = qmc_chan_read_submit(prtd->qmc_dai->chans[i].qmc_chan,
prtd->ch_dma_addr_current + i * prtd->ch_dma_offset,
prtd->ch_dma_size,
- qmc_audio_pcm_read_complete,
- &prtd->qmc_dai->chans[i]);
+ i == prtd->channels - 1 ? qmc_audio_pcm_read_complete :
+ NULL, prtd);
if (ret) {
dev_err(prtd->qmc_dai->dev, "read_submit %u failed %d\n",
i, ret);
- bitmap_clear(prtd->chans_pending, i, 1);
return ret;
}
}
@@ -202,26 +182,13 @@ static int qmc_audio_pcm_read_submit(struct qmc_dai_prtd *prtd)
static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags)
{
- struct qmc_dai_chan *chan = context;
- struct qmc_dai_prtd *prtd;
-
- prtd = chan->prtd_rx;
-
- /* Mark the current channel as completed */
- bitmap_clear(prtd->chans_pending, chan - prtd->qmc_dai->chans, 1);
+ struct qmc_dai_prtd *prtd = context;
if (length != prtd->ch_dma_size) {
dev_err(prtd->qmc_dai->dev, "read complete length = %zu, exp %zu\n",
length, prtd->ch_dma_size);
}
- /*
- * All QMC channels involved must have completed their transfer before
- * submitting a new one.
- */
- if (!bitmap_empty(prtd->chans_pending, 64))
- return;
-
prtd->buffer_ended += prtd->period_size;
if (prtd->buffer_ended >= prtd->buffer_size)
prtd->buffer_ended = 0;
@@ -249,7 +216,6 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- bitmap_zero(prtd->chans_pending, 64);
prtd->buffer_ended = 0;
prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;
--
2.49.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v3 4/4] ASoc: fsl: fsl_qmc_audio: Drop struct qmc_dai_chan
2025-08-18 8:19 [PATCH v3 0/4] ASoC: fsl: fsl_qmc_audio: Reduce amount of interrupts Christophe Leroy
` (2 preceding siblings ...)
2025-08-18 8:20 ` [PATCH v3 3/4] ASoC: fsl: fsl_qmc_audio: Only request completion on last channel Christophe Leroy
@ 2025-08-18 8:20 ` Christophe Leroy
2025-09-18 6:12 ` [PATCH v3 0/4] ASoC: fsl: fsl_qmc_audio: Reduce amount of interrupts Christophe Leroy
4 siblings, 0 replies; 9+ messages in thread
From: Christophe Leroy @ 2025-08-18 8:20 UTC (permalink / raw)
To: Herve Codina, Qiang Zhao, Shengjiu Wang, Xiubo Li, Fabio Estevam,
Nicolin Chen, Liam Girdwood, Mark Brown, Jaroslav Kysela,
Takashi Iwai
Cc: Christophe Leroy, linuxppc-dev, linux-arm-kernel, linux-kernel,
linux-sound
prtd_tx and prtd_rx members are not used anymore and only qmc_chan
member remains so struct qmc_dai_chan has become pointless.
Use qmc_chan directly and drop struct qmc_dai_chan.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Acked-by: Herve Codina <herve.codina@bootlin.com>
---
sound/soc/fsl/fsl_qmc_audio.c | 52 ++++++++++++++---------------------
1 file changed, 20 insertions(+), 32 deletions(-)
diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c
index 2790953543c5..3de448ef724c 100644
--- a/sound/soc/fsl/fsl_qmc_audio.c
+++ b/sound/soc/fsl/fsl_qmc_audio.c
@@ -17,12 +17,6 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
-struct qmc_dai_chan {
- struct qmc_dai_prtd *prtd_tx;
- struct qmc_dai_prtd *prtd_rx;
- struct qmc_chan *qmc_chan;
-};
-
struct qmc_dai {
char *name;
int id;
@@ -33,7 +27,7 @@ struct qmc_dai {
unsigned int nb_chans_avail;
unsigned int nb_chans_used_tx;
unsigned int nb_chans_used_rx;
- struct qmc_dai_chan *chans;
+ struct qmc_chan **qmc_chans;
};
struct qmc_audio {
@@ -125,7 +119,7 @@ static int qmc_audio_pcm_write_submit(struct qmc_dai_prtd *prtd)
int ret;
for (i = 0; i < prtd->channels; i++) {
- ret = qmc_chan_write_submit(prtd->qmc_dai->chans[i].qmc_chan,
+ ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chans[i],
prtd->ch_dma_addr_current + i * prtd->ch_dma_offset,
prtd->ch_dma_size,
i == prtd->channels - 1 ? qmc_audio_pcm_write_complete :
@@ -165,7 +159,7 @@ static int qmc_audio_pcm_read_submit(struct qmc_dai_prtd *prtd)
int ret;
for (i = 0; i < prtd->channels; i++) {
- ret = qmc_chan_read_submit(prtd->qmc_dai->chans[i].qmc_chan,
+ ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chans[i],
prtd->ch_dma_addr_current + i * prtd->ch_dma_offset,
prtd->ch_dma_size,
i == prtd->channels - 1 ? qmc_audio_pcm_read_complete :
@@ -206,7 +200,6 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component,
struct snd_pcm_substream *substream, int cmd)
{
struct qmc_dai_prtd *prtd = substream->runtime->private_data;
- unsigned int i;
int ret;
if (!prtd->qmc_dai) {
@@ -220,9 +213,6 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component,
prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- for (i = 0; i < prtd->channels; i++)
- prtd->qmc_dai->chans[i].prtd_tx = prtd;
-
/* Submit first chunk ... */
ret = qmc_audio_pcm_write_submit(prtd);
if (ret)
@@ -238,9 +228,6 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component,
if (ret)
return ret;
} else {
- for (i = 0; i < prtd->channels; i++)
- prtd->qmc_dai->chans[i].prtd_rx = prtd;
-
/* Submit first chunk ... */
ret = qmc_audio_pcm_read_submit(prtd);
if (ret)
@@ -610,9 +597,9 @@ static int qmc_dai_hw_params(struct snd_pcm_substream *substream,
chan_param.mode = QMC_TRANSPARENT;
chan_param.transp.max_rx_buf_size = params_period_bytes(params) / nb_chans_used;
for (i = 0; i < nb_chans_used; i++) {
- ret = qmc_chan_set_param(qmc_dai->chans[i].qmc_chan, &chan_param);
+ ret = qmc_chan_set_param(qmc_dai->qmc_chans[i], &chan_param);
if (ret) {
- dev_err(dai->dev, "chans[%u], set param failed %d\n",
+ dev_err(dai->dev, "qmc_chans[%u], set param failed %d\n",
i, ret);
return ret;
}
@@ -654,7 +641,7 @@ static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
for (i = 0; i < nb_chans_used; i++) {
- ret = qmc_chan_start(qmc_dai->chans[i].qmc_chan, direction);
+ ret = qmc_chan_start(qmc_dai->qmc_chans[i], direction);
if (ret)
goto err_stop;
}
@@ -663,13 +650,13 @@ static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_STOP:
/* Stop and reset all QMC channels and return the first error encountered */
for (i = 0; i < nb_chans_used; i++) {
- ret_tmp = qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction);
+ ret_tmp = qmc_chan_stop(qmc_dai->qmc_chans[i], direction);
if (!ret)
ret = ret_tmp;
if (ret_tmp)
continue;
- ret_tmp = qmc_chan_reset(qmc_dai->chans[i].qmc_chan, direction);
+ ret_tmp = qmc_chan_reset(qmc_dai->qmc_chans[i], direction);
if (!ret)
ret = ret_tmp;
}
@@ -681,7 +668,7 @@ static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
/* Stop all QMC channels and return the first error encountered */
for (i = 0; i < nb_chans_used; i++) {
- ret_tmp = qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction);
+ ret_tmp = qmc_chan_stop(qmc_dai->qmc_chans[i], direction);
if (!ret)
ret = ret_tmp;
}
@@ -697,8 +684,8 @@ static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
err_stop:
while (i--) {
- qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction);
- qmc_chan_reset(qmc_dai->chans[i].qmc_chan, direction);
+ qmc_chan_stop(qmc_dai->qmc_chans[i], direction);
+ qmc_chan_reset(qmc_dai->qmc_chans[i], direction);
}
return ret;
}
@@ -794,19 +781,20 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *
return dev_err_probe(qmc_audio->dev, -EINVAL,
"dai %d no QMC channel defined\n", qmc_dai->id);
- qmc_dai->chans = devm_kcalloc(qmc_audio->dev, count, sizeof(*qmc_dai->chans), GFP_KERNEL);
- if (!qmc_dai->chans)
+ qmc_dai->qmc_chans = devm_kcalloc(qmc_audio->dev, count, sizeof(*qmc_dai->qmc_chans),
+ GFP_KERNEL);
+ if (!qmc_dai->qmc_chans)
return -ENOMEM;
for (i = 0; i < count; i++) {
- qmc_dai->chans[i].qmc_chan = devm_qmc_chan_get_byphandles_index(qmc_audio->dev, np,
- "fsl,qmc-chan", i);
- if (IS_ERR(qmc_dai->chans[i].qmc_chan)) {
- return dev_err_probe(qmc_audio->dev, PTR_ERR(qmc_dai->chans[i].qmc_chan),
+ qmc_dai->qmc_chans[i] = devm_qmc_chan_get_byphandles_index(qmc_audio->dev, np,
+ "fsl,qmc-chan", i);
+ if (IS_ERR(qmc_dai->qmc_chans[i])) {
+ return dev_err_probe(qmc_audio->dev, PTR_ERR(qmc_dai->qmc_chans[i]),
"dai %d get QMC channel %d failed\n", qmc_dai->id, i);
}
- ret = qmc_chan_get_info(qmc_dai->chans[i].qmc_chan, &info);
+ ret = qmc_chan_get_info(qmc_dai->qmc_chans[i], &info);
if (ret) {
dev_err(qmc_audio->dev, "dai %d get QMC %d channel info failed %d\n",
qmc_dai->id, i, ret);
@@ -851,7 +839,7 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *
}
}
- ret = qmc_chan_get_ts_info(qmc_dai->chans[i].qmc_chan, &ts_info);
+ ret = qmc_chan_get_ts_info(qmc_dai->qmc_chans[i], &ts_info);
if (ret) {
dev_err(qmc_audio->dev, "dai %d get QMC %d channel TS info failed %d\n",
qmc_dai->id, i, ret);
--
2.49.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v3 0/4] ASoC: fsl: fsl_qmc_audio: Reduce amount of interrupts
2025-08-18 8:19 [PATCH v3 0/4] ASoC: fsl: fsl_qmc_audio: Reduce amount of interrupts Christophe Leroy
` (3 preceding siblings ...)
2025-08-18 8:20 ` [PATCH v3 4/4] ASoc: fsl: fsl_qmc_audio: Drop struct qmc_dai_chan Christophe Leroy
@ 2025-09-18 6:12 ` Christophe Leroy
2025-09-18 11:14 ` Mark Brown
4 siblings, 1 reply; 9+ messages in thread
From: Christophe Leroy @ 2025-09-18 6:12 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood
Cc: Herve Codina, linuxppc-dev, linux-arm-kernel, linux-kernel,
Nicolin Chen, Shengjiu Wang, linux-sound, Qiang Zhao,
Fabio Estevam, Takashi Iwai, Xiubo Li, Jaroslav Kysela
Hi Mark, Liam,
Le 18/08/2025 à 10:19, Christophe Leroy a écrit :
> This series reduces significantly the amount of interrupts on
> fsl_qmc_audio device.
I can't see this series in linux-next.
I see in patchwork [1] that this series still has status 'NEW' but also
state 'archived'.
What is the way forward to get it applied for v6.18 ?
Thanks
Christophe
[1]
https://patchwork.kernel.org/project/alsa-devel/patch/f0c5260651822e8003daf11c7a76921796517152.1755504428.git.christophe.leroy@csgroup.eu/
>
> Patches 1 and 2 are preparatory patches.
> Patch 3 is the main change
> Patch 4 is a cleanup which is enabled by previous patch
>
> Changes in v3:
> - Properly check the buffer descriptor is unused (Patch 1, comment from Herve Codina)
> - Fixed copy/paste error (patch 2, comment from Herve Codina)
> - Fixed build failure (patch 2, comment from Herve Codina and Test robot)
>
> Changes in v2:
> - Don't remove UB bit (Patch 1, comment from Herve Codina)
> - Make sure audio channels are ordered on TDM bus (Patch 2, new patch, comment from Herve Codina)
> - Drop struct qmc_dai_chan (patch 4, new patch)
>
> Backgroup (copied from patch 3):
>
> In non-interleaved mode, several QMC channels are used in sync.
> More details can be found in commit 188d9cae5438 ("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.
>
> Christophe Leroy (4):
> soc: fsl: qmc: Only set completion interrupt when needed
> ASoc: fsl: fsl_qmc_audio: Ensure audio channels are ordered in TDM bus
> ASoC: fsl: fsl_qmc_audio: Only request completion on last channel
> ASoc: fsl: fsl_qmc_audio: Drop struct qmc_dai_chan
>
> drivers/soc/fsl/qe/qmc.c | 44 +++++++++---
> sound/soc/fsl/fsl_qmc_audio.c | 125 +++++++++++++++-------------------
> 2 files changed, 87 insertions(+), 82 deletions(-)
>
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH v3 0/4] ASoC: fsl: fsl_qmc_audio: Reduce amount of interrupts
2025-09-18 6:12 ` [PATCH v3 0/4] ASoC: fsl: fsl_qmc_audio: Reduce amount of interrupts Christophe Leroy
@ 2025-09-18 11:14 ` Mark Brown
0 siblings, 0 replies; 9+ messages in thread
From: Mark Brown @ 2025-09-18 11:14 UTC (permalink / raw)
To: Christophe Leroy
Cc: Liam Girdwood, Herve Codina, linuxppc-dev, linux-arm-kernel,
linux-kernel, Nicolin Chen, Shengjiu Wang, linux-sound,
Qiang Zhao, Fabio Estevam, Takashi Iwai, Xiubo Li,
Jaroslav Kysela
[-- Attachment #1: Type: text/plain, Size: 1208 bytes --]
On Thu, Sep 18, 2025 at 08:12:21AM +0200, Christophe Leroy wrote:
> Hi Mark, Liam,
>
> Le 18/08/2025 à 10:19, Christophe Leroy a écrit :
> > This series reduces significantly the amount of interrupts on
> > fsl_qmc_audio device.
>
> I can't see this series in linux-next.
>
> I see in patchwork [1] that this series still has status 'NEW' but also
> state 'archived'.
>
> What is the way forward to get it applied for v6.18 ?
Please don't send content free pings and please allow a reasonable time
for review. People get busy, go on holiday, attend conferences and so
on so unless there is some reason for urgency (like critical bug fixes)
please allow at least a couple of weeks for review. If there have been
review comments then people may be waiting for those to be addressed.
Sending content free pings adds to the mail volume (if they are seen at
all) which is often the problem and since they can't be reviewed
directly if something has gone wrong you'll have to resend the patches
anyway, so sending again is generally a better approach though there are
some other maintainers who like them - if in doubt look at how patches
for the subsystem are normally handled.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread