* [PATCH v2 0/4] ASoC: fsl: fsl_qmc_audio: Reduce amount of interrupts
@ 2025-08-12 10:50 Christophe Leroy
2025-08-12 10:50 ` [PATCH v2 1/4] soc: fsl: qmc: Only set completion interrupt when needed Christophe Leroy
` (3 more replies)
0 siblings, 4 replies; 15+ messages in thread
From: Christophe Leroy @ 2025-08-12 10:50 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 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] 15+ messages in thread
* [PATCH v2 1/4] soc: fsl: qmc: Only set completion interrupt when needed
2025-08-12 10:50 [PATCH v2 0/4] ASoC: fsl: fsl_qmc_audio: Reduce amount of interrupts Christophe Leroy
@ 2025-08-12 10:50 ` Christophe Leroy
2025-08-13 10:06 ` Herve Codina
2025-08-12 10:50 ` [PATCH v2 2/4] ASoc: fsl: fsl_qmc_audio: Ensure audio channels are ordered in TDM bus Christophe Leroy
` (2 subsequent siblings)
3 siblings, 1 reply; 15+ messages in thread
From: Christophe Leroy @ 2025-08-12 10:50 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>
---
v2: Keep the UB flag to mark not completed buffers and seamlessly flag them as completed during next submit.
---
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 36c0ccc06151f..8f76b9a5e385d 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_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_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] 15+ messages in thread
* [PATCH v2 2/4] ASoc: fsl: fsl_qmc_audio: Ensure audio channels are ordered in TDM bus
2025-08-12 10:50 [PATCH v2 0/4] ASoC: fsl: fsl_qmc_audio: Reduce amount of interrupts Christophe Leroy
2025-08-12 10:50 ` [PATCH v2 1/4] soc: fsl: qmc: Only set completion interrupt when needed Christophe Leroy
@ 2025-08-12 10:50 ` Christophe Leroy
2025-08-13 10:06 ` Herve Codina
` (2 more replies)
2025-08-12 10:50 ` [PATCH v2 3/4] ASoC: fsl: fsl_qmc_audio: Only request completion on last channel Christophe Leroy
2025-08-12 10:50 ` [PATCH v2 4/4] ASoc: fsl: fsl_qmc_audio: Drop struct qmc_dai_chan Christophe Leroy
3 siblings, 3 replies; 15+ messages in thread
From: Christophe Leroy @ 2025-08-12 10:50 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>
---
v2: New
---
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 5614a8b909edf..0be29ccc1ff7b 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->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);
+ return ret;
+ }
+
+ last_rx_ts = fls64(ts_info.rx_ts_mask);
+ last_tx_ts = fls64(ts_info.rx_ts_mask);
+
+ if (prev_last_rx_ts > last_rx_ts) {
+ dev_err(qmc_audio->dev, "dai %d QMC chan %d unordered channels (RX timeslot %lu before %lu)\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 %lu before %lu)\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] 15+ messages in thread
* [PATCH v2 3/4] ASoC: fsl: fsl_qmc_audio: Only request completion on last channel
2025-08-12 10:50 [PATCH v2 0/4] ASoC: fsl: fsl_qmc_audio: Reduce amount of interrupts Christophe Leroy
2025-08-12 10:50 ` [PATCH v2 1/4] soc: fsl: qmc: Only set completion interrupt when needed Christophe Leroy
2025-08-12 10:50 ` [PATCH v2 2/4] ASoc: fsl: fsl_qmc_audio: Ensure audio channels are ordered in TDM bus Christophe Leroy
@ 2025-08-12 10:50 ` Christophe Leroy
2025-08-13 10:07 ` Herve Codina
2025-08-12 10:50 ` [PATCH v2 4/4] ASoc: fsl: fsl_qmc_audio: Drop struct qmc_dai_chan Christophe Leroy
3 siblings, 1 reply; 15+ messages in thread
From: Christophe Leroy @ 2025-08-12 10:50 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>
---
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 0be29ccc1ff7b..92aa813aa3bee 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] 15+ messages in thread
* [PATCH v2 4/4] ASoc: fsl: fsl_qmc_audio: Drop struct qmc_dai_chan
2025-08-12 10:50 [PATCH v2 0/4] ASoC: fsl: fsl_qmc_audio: Reduce amount of interrupts Christophe Leroy
` (2 preceding siblings ...)
2025-08-12 10:50 ` [PATCH v2 3/4] ASoC: fsl: fsl_qmc_audio: Only request completion on last channel Christophe Leroy
@ 2025-08-12 10:50 ` Christophe Leroy
2025-08-13 10:07 ` Herve Codina
3 siblings, 1 reply; 15+ messages in thread
From: Christophe Leroy @ 2025-08-12 10:50 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>
---
v2: New
---
sound/soc/fsl/fsl_qmc_audio.c | 50 +++++++++++++----------------------
1 file changed, 19 insertions(+), 31 deletions(-)
diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c
index 92aa813aa3bee..6719da1c81f1d 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);
--
2.49.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v2 1/4] soc: fsl: qmc: Only set completion interrupt when needed
2025-08-12 10:50 ` [PATCH v2 1/4] soc: fsl: qmc: Only set completion interrupt when needed Christophe Leroy
@ 2025-08-13 10:06 ` Herve Codina
2025-08-14 7:34 ` Herve Codina
0 siblings, 1 reply; 15+ messages in thread
From: Herve Codina @ 2025-08-13 10:06 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 Tue, 12 Aug 2025 12:50:55 +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>
> ---
> v2: Keep the UB flag to mark not completed buffers and seamlessly flag them as completed during next submit.
> ---
> 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 36c0ccc06151f..8f76b9a5e385d 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_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);
>
You try to purge one descriptor for which the transfer is done but you do that
when you have no more free descriptors.
You end up with all descriptor "used". I think a better way to do that is
to purge all "done" descriptor configured to work without interrupts until a
descriptor with interrupt is found.
What do you think about the following (draft code not compiled and not tested) ?
/* must be called with tx_lock taken */
static void qmc_chan_write_purge(struct qmc_chan *chan)
{
cbd_t __iomem *bd;
u16 ctrl;
/*
* Purge descriptors configured to work without interrupts
* (I bit == 0) those descriptors have no completion
* callbacks.
*
* R bit UB bit
* 0 0 : The BD is free
* 1 1 : The BD is in used, waiting for transfer
* 0 1 : The BD is in used, waiting for completion
* 1 0 : Should not append
*
* We purge those descriptors which are in the state "waiting for
* completion" up to the first one configured to work with an interrupt.
*
*/
bd = chan->txbd_done;
ctrl = qmc_read16(&bd->cbd_sc);
while (!(ctrl & (QMC_BD_TX_R | QMC_BD_TX_I)) {
if (!(ctrl & QMC_BD_TX_UB))
return;
qmc_write16(&bd->cbd_sc, ctrl & ~QMC_BD_TX_UB);
if (ctrl & QMC_BD_TX_W)
chan->txbd_done = chan->txbds;
else
chan->txbd_done++;
bd = chan->txbd_done;
ctrl = qmc_read16(&bd->cbd_sc);
}
}
Then, qmc_chan_write_submit() calls the purge function as a first operation.
This will look to something like the following:
int qmc_chan_write_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length,
void (*complete)(void *context), void *context)
{
struct qmc_xfer_desc *xfer_desc;
unsigned long flags;
cbd_t __iomem *bd;
u16 ctrl;
int ret;
/*
* R bit UB bit
* 0 0 : The BD is free
* 1 1 : The BD is in used, waiting for transfer
* 0 1 : The BD is in used, waiting for completion
* 1 0 : Should not append
*/
spin_lock_irqsave(&chan->tx_lock, flags);
qmc_chan_write_purge(chan);
bd = chan->txbd_free;
...
if (complete)
ctrl |= QMC_BD_TX_I;
else
ctrl &= ~QMC_BD_TX_I;
...
}
> @@ -569,9 +580,16 @@ int qmc_chan_read_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length,
>
...
Exact same comment and proposal for read part.
>
> @@ -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);
Ok for modifications in qmc_setup_chan().
Best regards,
Hervé
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 2/4] ASoc: fsl: fsl_qmc_audio: Ensure audio channels are ordered in TDM bus
2025-08-12 10:50 ` [PATCH v2 2/4] ASoc: fsl: fsl_qmc_audio: Ensure audio channels are ordered in TDM bus Christophe Leroy
@ 2025-08-13 10:06 ` Herve Codina
2025-08-18 8:18 ` Christophe Leroy
2025-08-13 17:16 ` kernel test robot
2025-08-14 7:45 ` Herve Codina
2 siblings, 1 reply; 15+ messages in thread
From: Herve Codina @ 2025-08-13 10:06 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 Tue, 12 Aug 2025 12:50:56 +0200
Christophe Leroy <christophe.leroy@csgroup.eu> wrote:
...
> @@ -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->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);
> + return ret;
> + }
> +
> + last_rx_ts = fls64(ts_info.rx_ts_mask);
> + last_tx_ts = fls64(ts_info.rx_ts_mask);
tx_ts_mask instead of rx_ts_mask for last_tx_ts.
Best regards,
Hervé
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 3/4] ASoC: fsl: fsl_qmc_audio: Only request completion on last channel
2025-08-12 10:50 ` [PATCH v2 3/4] ASoC: fsl: fsl_qmc_audio: Only request completion on last channel Christophe Leroy
@ 2025-08-13 10:07 ` Herve Codina
0 siblings, 0 replies; 15+ messages in thread
From: Herve Codina @ 2025-08-13 10:07 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
On Tue, 12 Aug 2025 12:50:57 +0200
Christophe Leroy <christophe.leroy@csgroup.eu> wrote:
> 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>
> ---
> sound/soc/fsl/fsl_qmc_audio.c | 46 +++++------------------------------
> 1 file changed, 6 insertions(+), 40 deletions(-)
>
Acked-by: Herve Codina <herve.codina@bootlin.com>
Best regards,
Hervé
--
Hervé Codina, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 4/4] ASoc: fsl: fsl_qmc_audio: Drop struct qmc_dai_chan
2025-08-12 10:50 ` [PATCH v2 4/4] ASoc: fsl: fsl_qmc_audio: Drop struct qmc_dai_chan Christophe Leroy
@ 2025-08-13 10:07 ` Herve Codina
0 siblings, 0 replies; 15+ messages in thread
From: Herve Codina @ 2025-08-13 10:07 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 Tue, 12 Aug 2025 12:50:58 +0200
Christophe Leroy <christophe.leroy@csgroup.eu> wrote:
> 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>
> ---
> v2: New
> ---
> sound/soc/fsl/fsl_qmc_audio.c | 50 +++++++++++++----------------------
> 1 file changed, 19 insertions(+), 31 deletions(-)
Acked-by: Herve Codina <herve.codina@bootlin.com>
Best regards,
Hervé
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 2/4] ASoc: fsl: fsl_qmc_audio: Ensure audio channels are ordered in TDM bus
2025-08-12 10:50 ` [PATCH v2 2/4] ASoc: fsl: fsl_qmc_audio: Ensure audio channels are ordered in TDM bus Christophe Leroy
2025-08-13 10:06 ` Herve Codina
@ 2025-08-13 17:16 ` kernel test robot
2025-08-14 7:45 ` Herve Codina
2 siblings, 0 replies; 15+ messages in thread
From: kernel test robot @ 2025-08-13 17:16 UTC (permalink / raw)
To: Christophe Leroy, Herve Codina, Qiang Zhao, Shengjiu Wang,
Xiubo Li, Fabio Estevam, Nicolin Chen, Liam Girdwood, Mark Brown,
Jaroslav Kysela, Takashi Iwai
Cc: oe-kbuild-all, Christophe Leroy, linuxppc-dev, linux-arm-kernel,
linux-kernel, linux-sound
Hi Christophe,
kernel test robot noticed the following build warnings:
[auto build test WARNING on broonie-sound/for-next]
[also build test WARNING on linus/master v6.17-rc1 next-20250813]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Christophe-Leroy/soc-fsl-qmc-Only-set-completion-interrupt-when-needed/20250812-193812
base: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
patch link: https://lore.kernel.org/r/8d01cf4599664188c92a515922d68c9834263384.1754993232.git.christophe.leroy%40csgroup.eu
patch subject: [PATCH v2 2/4] ASoc: fsl: fsl_qmc_audio: Ensure audio channels are ordered in TDM bus
config: powerpc64-randconfig-r073-20250813 (https://download.01.org/0day-ci/archive/20250814/202508140002.NBrWOZJL-lkp@intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 3769ce013be2879bf0b329c14a16f5cb766f26ce)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250814/202508140002.NBrWOZJL-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202508140002.NBrWOZJL-lkp@intel.com/
All warnings (new ones prefixed by >>):
sound/soc/fsl/fsl_qmc_audio.c:888:39: error: no member named 'qmc_chans' in 'struct qmc_dai'
888 | ret = qmc_chan_get_ts_info(qmc_dai->qmc_chans[i], &ts_info);
| ~~~~~~~ ^
>> sound/soc/fsl/fsl_qmc_audio.c:900:21: warning: format specifies type 'unsigned long' but the argument has type 'int' [-Wformat]
899 | dev_err(qmc_audio->dev, "dai %d QMC chan %d unordered channels (RX timeslot %lu before %lu)\n",
| ~~~
| %d
900 | qmc_dai->id, i, prev_last_rx_ts, last_rx_ts);
| ^~~~~~~~~~~~~~~
include/linux/dev_printk.h:154:65: note: expanded from macro 'dev_err'
154 | dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
| ~~~ ^~~~~~~~~~~
include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap'
110 | _p_func(dev, fmt, ##__VA_ARGS__); \
| ~~~ ^~~~~~~~~~~
sound/soc/fsl/fsl_qmc_audio.c:900:38: warning: format specifies type 'unsigned long' but the argument has type 'int' [-Wformat]
899 | dev_err(qmc_audio->dev, "dai %d QMC chan %d unordered channels (RX timeslot %lu before %lu)\n",
| ~~~
| %d
900 | qmc_dai->id, i, prev_last_rx_ts, last_rx_ts);
| ^~~~~~~~~~
include/linux/dev_printk.h:154:65: note: expanded from macro 'dev_err'
154 | dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
| ~~~ ^~~~~~~~~~~
include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap'
110 | _p_func(dev, fmt, ##__VA_ARGS__); \
| ~~~ ^~~~~~~~~~~
sound/soc/fsl/fsl_qmc_audio.c:905:21: warning: format specifies type 'unsigned long' but the argument has type 'int' [-Wformat]
904 | dev_err(qmc_audio->dev, "dai %d QMC chan %d unordered channels (TX timeslot %lu before %lu)\n",
| ~~~
| %d
905 | qmc_dai->id, i, prev_last_tx_ts, last_tx_ts);
| ^~~~~~~~~~~~~~~
include/linux/dev_printk.h:154:65: note: expanded from macro 'dev_err'
154 | dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
| ~~~ ^~~~~~~~~~~
include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap'
110 | _p_func(dev, fmt, ##__VA_ARGS__); \
| ~~~ ^~~~~~~~~~~
sound/soc/fsl/fsl_qmc_audio.c:905:38: warning: format specifies type 'unsigned long' but the argument has type 'int' [-Wformat]
904 | dev_err(qmc_audio->dev, "dai %d QMC chan %d unordered channels (TX timeslot %lu before %lu)\n",
| ~~~
| %d
905 | qmc_dai->id, i, prev_last_tx_ts, last_tx_ts);
| ^~~~~~~~~~
include/linux/dev_printk.h:154:65: note: expanded from macro 'dev_err'
154 | dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
| ~~~ ^~~~~~~~~~~
include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap'
110 | _p_func(dev, fmt, ##__VA_ARGS__); \
| ~~~ ^~~~~~~~~~~
4 warnings and 1 error generated.
vim +900 sound/soc/fsl/fsl_qmc_audio.c
789
790 static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *np,
791 struct qmc_dai *qmc_dai,
792 struct snd_soc_dai_driver *qmc_soc_dai_driver)
793 {
794 struct qmc_chan_ts_info ts_info;
795 struct qmc_chan_info info;
796 unsigned long rx_fs_rate;
797 unsigned long tx_fs_rate;
798 int prev_last_rx_ts = 0;
799 int prev_last_tx_ts = 0;
800 unsigned int nb_tx_ts;
801 unsigned int nb_rx_ts;
802 unsigned int i;
803 int last_rx_ts;
804 int last_tx_ts;
805 int count;
806 u32 val;
807 int ret;
808
809 qmc_dai->dev = qmc_audio->dev;
810
811 ret = of_property_read_u32(np, "reg", &val);
812 if (ret) {
813 dev_err(qmc_audio->dev, "%pOF: failed to read reg\n", np);
814 return ret;
815 }
816 qmc_dai->id = val;
817
818 qmc_dai->name = devm_kasprintf(qmc_audio->dev, GFP_KERNEL, "%s.%d",
819 np->parent->name, qmc_dai->id);
820 if (!qmc_dai->name)
821 return -ENOMEM;
822
823 count = qmc_chan_count_phandles(np, "fsl,qmc-chan");
824 if (count < 0)
825 return dev_err_probe(qmc_audio->dev, count,
826 "dai %d get number of QMC channel failed\n", qmc_dai->id);
827 if (!count)
828 return dev_err_probe(qmc_audio->dev, -EINVAL,
829 "dai %d no QMC channel defined\n", qmc_dai->id);
830
831 qmc_dai->chans = devm_kcalloc(qmc_audio->dev, count, sizeof(*qmc_dai->chans), GFP_KERNEL);
832 if (!qmc_dai->chans)
833 return -ENOMEM;
834
835 for (i = 0; i < count; i++) {
836 qmc_dai->chans[i].qmc_chan = devm_qmc_chan_get_byphandles_index(qmc_audio->dev, np,
837 "fsl,qmc-chan", i);
838 if (IS_ERR(qmc_dai->chans[i].qmc_chan)) {
839 return dev_err_probe(qmc_audio->dev, PTR_ERR(qmc_dai->chans[i].qmc_chan),
840 "dai %d get QMC channel %d failed\n", qmc_dai->id, i);
841 }
842
843 ret = qmc_chan_get_info(qmc_dai->chans[i].qmc_chan, &info);
844 if (ret) {
845 dev_err(qmc_audio->dev, "dai %d get QMC %d channel info failed %d\n",
846 qmc_dai->id, i, ret);
847 return ret;
848 }
849
850 if (info.mode != QMC_TRANSPARENT) {
851 dev_err(qmc_audio->dev, "dai %d QMC chan %d mode %d is not QMC_TRANSPARENT\n",
852 qmc_dai->id, i, info.mode);
853 return -EINVAL;
854 }
855
856 /*
857 * All channels must have the same number of Tx slots and the
858 * same numbers of Rx slots.
859 */
860 if (i == 0) {
861 nb_tx_ts = info.nb_tx_ts;
862 nb_rx_ts = info.nb_rx_ts;
863 tx_fs_rate = info.tx_fs_rate;
864 rx_fs_rate = info.rx_fs_rate;
865 } else {
866 if (nb_tx_ts != info.nb_tx_ts) {
867 dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent number of Tx timeslots (%u instead of %u)\n",
868 qmc_dai->id, i, info.nb_tx_ts, nb_tx_ts);
869 return -EINVAL;
870 }
871 if (nb_rx_ts != info.nb_rx_ts) {
872 dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent number of Rx timeslots (%u instead of %u)\n",
873 qmc_dai->id, i, info.nb_rx_ts, nb_rx_ts);
874 return -EINVAL;
875 }
876 if (tx_fs_rate != info.tx_fs_rate) {
877 dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent Tx frame sample rate (%lu instead of %lu)\n",
878 qmc_dai->id, i, info.tx_fs_rate, tx_fs_rate);
879 return -EINVAL;
880 }
881 if (rx_fs_rate != info.rx_fs_rate) {
882 dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent Rx frame sample rate (%lu instead of %lu)\n",
883 qmc_dai->id, i, info.rx_fs_rate, rx_fs_rate);
884 return -EINVAL;
885 }
886 }
887
> 888 ret = qmc_chan_get_ts_info(qmc_dai->qmc_chans[i], &ts_info);
889 if (ret) {
890 dev_err(qmc_audio->dev, "dai %d get QMC %d channel TS info failed %d\n",
891 qmc_dai->id, i, ret);
892 return ret;
893 }
894
895 last_rx_ts = fls64(ts_info.rx_ts_mask);
896 last_tx_ts = fls64(ts_info.rx_ts_mask);
897
898 if (prev_last_rx_ts > last_rx_ts) {
899 dev_err(qmc_audio->dev, "dai %d QMC chan %d unordered channels (RX timeslot %lu before %lu)\n",
> 900 qmc_dai->id, i, prev_last_rx_ts, last_rx_ts);
901 return -EINVAL;
902 }
903 if (prev_last_tx_ts > last_tx_ts) {
904 dev_err(qmc_audio->dev, "dai %d QMC chan %d unordered channels (TX timeslot %lu before %lu)\n",
905 qmc_dai->id, i, prev_last_tx_ts, last_tx_ts);
906 return -EINVAL;
907 }
908
909 prev_last_rx_ts = last_rx_ts;
910 prev_last_tx_ts = last_tx_ts;
911 }
912
913 qmc_dai->nb_chans_avail = count;
914 qmc_dai->nb_tx_ts = nb_tx_ts * count;
915 qmc_dai->nb_rx_ts = nb_rx_ts * count;
916
917 qmc_soc_dai_driver->id = qmc_dai->id;
918 qmc_soc_dai_driver->name = qmc_dai->name;
919
920 qmc_soc_dai_driver->playback.channels_min = 0;
921 qmc_soc_dai_driver->playback.channels_max = 0;
922 if (nb_tx_ts) {
923 qmc_soc_dai_driver->playback.channels_min = 1;
924 qmc_soc_dai_driver->playback.channels_max = count > 1 ? count : nb_tx_ts;
925 }
926 qmc_soc_dai_driver->playback.formats = qmc_audio_formats(nb_tx_ts,
927 count > 1);
928
929 qmc_soc_dai_driver->capture.channels_min = 0;
930 qmc_soc_dai_driver->capture.channels_max = 0;
931 if (nb_rx_ts) {
932 qmc_soc_dai_driver->capture.channels_min = 1;
933 qmc_soc_dai_driver->capture.channels_max = count > 1 ? count : nb_rx_ts;
934 }
935 qmc_soc_dai_driver->capture.formats = qmc_audio_formats(nb_rx_ts,
936 count > 1);
937
938 qmc_soc_dai_driver->playback.rates = snd_pcm_rate_to_rate_bit(tx_fs_rate);
939 qmc_soc_dai_driver->playback.rate_min = tx_fs_rate;
940 qmc_soc_dai_driver->playback.rate_max = tx_fs_rate;
941 qmc_soc_dai_driver->capture.rates = snd_pcm_rate_to_rate_bit(rx_fs_rate);
942 qmc_soc_dai_driver->capture.rate_min = rx_fs_rate;
943 qmc_soc_dai_driver->capture.rate_max = rx_fs_rate;
944
945 qmc_soc_dai_driver->ops = &qmc_dai_ops;
946
947 return 0;
948 }
949
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 1/4] soc: fsl: qmc: Only set completion interrupt when needed
2025-08-13 10:06 ` Herve Codina
@ 2025-08-14 7:34 ` Herve Codina
2025-08-18 8:16 ` Christophe Leroy
0 siblings, 1 reply; 15+ messages in thread
From: Herve Codina @ 2025-08-14 7:34 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 Wed, 13 Aug 2025 12:06:51 +0200
Herve Codina <herve.codina@bootlin.com> wrote:
> Hi Christophe,
>
> On Tue, 12 Aug 2025 12:50:55 +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>
> > ---
> > v2: Keep the UB flag to mark not completed buffers and seamlessly flag them as completed during next submit.
> > ---
> > 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 36c0ccc06151f..8f76b9a5e385d 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_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);
> >
>
> You try to purge one descriptor for which the transfer is done but you do that
> when you have no more free descriptors.
>
> You end up with all descriptor "used". I think a better way to do that is
> to purge all "done" descriptor configured to work without interrupts until a
> descriptor with interrupt is found.
I have looked again at your code and looking for a free descriptor only when it
is needed is sufficient. You can forget my previous proposal.
Back to your code, I think you need to be sure that the descriptor you want to
re-use is really available and so you need to check the 'R' bit to be sure
that we are not with 'R' = 1 and 'UB' = 1 which means "BD is used, waiting for
a transfer".
For instance:
if (ctrl & (QMC_BD_TX_R | QMC_BD_TX_UB)) {
if (!(ctrl & (QMC_BD_TX_I | QMC_BD_TX_R) &&
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;
}
}
Best regards,
Hervé
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 2/4] ASoc: fsl: fsl_qmc_audio: Ensure audio channels are ordered in TDM bus
2025-08-12 10:50 ` [PATCH v2 2/4] ASoc: fsl: fsl_qmc_audio: Ensure audio channels are ordered in TDM bus Christophe Leroy
2025-08-13 10:06 ` Herve Codina
2025-08-13 17:16 ` kernel test robot
@ 2025-08-14 7:45 ` Herve Codina
2025-08-18 8:18 ` Christophe Leroy
2 siblings, 1 reply; 15+ messages in thread
From: Herve Codina @ 2025-08-14 7:45 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
On Tue, 12 Aug 2025 12:50:56 +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>
> ---
> v2: New
> ---
> 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 5614a8b909edf..0be29ccc1ff7b 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->qmc_chans[i], &ts_info);
qmc_chan_get_ts_info() need a struct qmc_chan as first parameter
qmc_dai->qmc_chans[i].qmc_chan instead of qmc_dai->qmc_chans[i].
The use of qmc_dai->qmc_chans[i] without .qmc_chan have to be done on patch 4 (cleanup patch).
Best regards,
Hervé
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 1/4] soc: fsl: qmc: Only set completion interrupt when needed
2025-08-14 7:34 ` Herve Codina
@ 2025-08-18 8:16 ` Christophe Leroy
0 siblings, 0 replies; 15+ messages in thread
From: Christophe Leroy @ 2025-08-18 8:16 UTC (permalink / raw)
To: Herve Codina
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 Hervé,
Le 14/08/2025 à 09:34, Herve Codina a écrit :
> Hi Christophe,
>
> On Wed, 13 Aug 2025 12:06:51 +0200
> Herve Codina <herve.codina@bootlin.com> wrote:
>
>> Hi Christophe,
>>
>> On Tue, 12 Aug 2025 12:50:55 +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>
>>> ---
>>> v2: Keep the UB flag to mark not completed buffers and seamlessly flag them as completed during next submit.
>>> ---
>>> 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 36c0ccc06151f..8f76b9a5e385d 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_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);
>>>
>>
>> You try to purge one descriptor for which the transfer is done but you do that
>> when you have no more free descriptors.
>>
>> You end up with all descriptor "used". I think a better way to do that is
>> to purge all "done" descriptor configured to work without interrupts until a
>> descriptor with interrupt is found.
>
> I have looked again at your code and looking for a free descriptor only when it
> is needed is sufficient. You can forget my previous proposal.
>
> Back to your code, I think you need to be sure that the descriptor you want to
> re-use is really available and so you need to check the 'R' bit to be sure
> that we are not with 'R' = 1 and 'UB' = 1 which means "BD is used, waiting for
> a transfer".
>
Fixed in v3.
Thanks
Christophe
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 2/4] ASoc: fsl: fsl_qmc_audio: Ensure audio channels are ordered in TDM bus
2025-08-14 7:45 ` Herve Codina
@ 2025-08-18 8:18 ` Christophe Leroy
0 siblings, 0 replies; 15+ messages in thread
From: Christophe Leroy @ 2025-08-18 8:18 UTC (permalink / raw)
To: Herve Codina
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
Le 14/08/2025 à 09:45, Herve Codina a écrit :
> On Tue, 12 Aug 2025 12:50:56 +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>
>> ---
>> v2: New
>> ---
>> 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 5614a8b909edf..0be29ccc1ff7b 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->qmc_chans[i], &ts_info);
>
> qmc_chan_get_ts_info() need a struct qmc_chan as first parameter
>
> qmc_dai->qmc_chans[i].qmc_chan instead of qmc_dai->qmc_chans[i].
>
> The use of qmc_dai->qmc_chans[i] without .qmc_chan have to be done on patch 4 (cleanup patch).
Fixed in v3
Thanks
Christophe
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 2/4] ASoc: fsl: fsl_qmc_audio: Ensure audio channels are ordered in TDM bus
2025-08-13 10:06 ` Herve Codina
@ 2025-08-18 8:18 ` Christophe Leroy
0 siblings, 0 replies; 15+ messages in thread
From: Christophe Leroy @ 2025-08-18 8:18 UTC (permalink / raw)
To: Herve Codina
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
Le 13/08/2025 à 12:06, Herve Codina a écrit :
> Hi Christophe,
>
> On Tue, 12 Aug 2025 12:50:56 +0200
> Christophe Leroy <christophe.leroy@csgroup.eu> wrote:
>
> ...
>
>> @@ -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->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);
>> + return ret;
>> + }
>> +
>> + last_rx_ts = fls64(ts_info.rx_ts_mask);
>> + last_tx_ts = fls64(ts_info.rx_ts_mask);
>
> tx_ts_mask instead of rx_ts_mask for last_tx_ts.
>
Fixed in v3
Thanks
Christophe
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2025-08-18 13:39 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-12 10:50 [PATCH v2 0/4] ASoC: fsl: fsl_qmc_audio: Reduce amount of interrupts Christophe Leroy
2025-08-12 10:50 ` [PATCH v2 1/4] soc: fsl: qmc: Only set completion interrupt when needed Christophe Leroy
2025-08-13 10:06 ` Herve Codina
2025-08-14 7:34 ` Herve Codina
2025-08-18 8:16 ` Christophe Leroy
2025-08-12 10:50 ` [PATCH v2 2/4] ASoc: fsl: fsl_qmc_audio: Ensure audio channels are ordered in TDM bus Christophe Leroy
2025-08-13 10:06 ` Herve Codina
2025-08-18 8:18 ` Christophe Leroy
2025-08-13 17:16 ` kernel test robot
2025-08-14 7:45 ` Herve Codina
2025-08-18 8:18 ` Christophe Leroy
2025-08-12 10:50 ` [PATCH v2 3/4] ASoC: fsl: fsl_qmc_audio: Only request completion on last channel Christophe Leroy
2025-08-13 10:07 ` Herve Codina
2025-08-12 10:50 ` [PATCH v2 4/4] ASoc: fsl: fsl_qmc_audio: Drop struct qmc_dai_chan Christophe Leroy
2025-08-13 10:07 ` Herve Codina
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).