* [PATCH v3 0/4] ASoC: fsl: fsl_qmc_audio: Reduce amount of interrupts
@ 2025-08-18 8:19 Christophe Leroy
2025-08-18 8:20 ` [PATCH v3 1/4] soc: fsl: qmc: Only set completion interrupt when needed Christophe Leroy
` (3 more replies)
0 siblings, 4 replies; 7+ messages in thread
From: Christophe Leroy @ 2025-08-18 8:19 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
This series reduces significantly the amount of interrupts on
fsl_qmc_audio device.
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(-)
--
2.49.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [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
` (2 subsequent siblings)
3 siblings, 1 reply; 7+ 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] 7+ 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
2025-08-18 8:20 ` [PATCH v3 4/4] ASoc: fsl: fsl_qmc_audio: Drop struct qmc_dai_chan Christophe Leroy
3 siblings, 1 reply; 7+ 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] 7+ 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
3 siblings, 0 replies; 7+ 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] 7+ 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
3 siblings, 0 replies; 7+ 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] 7+ 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; 7+ 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] 7+ 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; 7+ 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] 7+ messages in thread
end of thread, other threads:[~2025-08-21 23:49 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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-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
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
2025-08-18 8:20 ` [PATCH v3 4/4] ASoc: fsl: fsl_qmc_audio: Drop struct qmc_dai_chan Christophe Leroy
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).