Skip to content

Commit 5998f0d

Browse files
committed
ASoC: fsl: fsl_qmc_audio: Reduce amount of
Merge series from Christophe Leroy <christophe.leroy@csgroup.eu>: This is a RESEND of v3 sent one month ago, see: https://lore.kernel.org/all/cover.1754993232.git.christophe.leroy@csgroup.eu/ 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
2 parents 309e94a + 2c618f3 commit 5998f0d

2 files changed

Lines changed: 87 additions & 82 deletions

File tree

drivers/soc/fsl/qe/qmc.c

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -461,9 +461,16 @@ int qmc_chan_write_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length,
461461

462462
ctrl = qmc_read16(&bd->cbd_sc);
463463
if (ctrl & (QMC_BD_TX_R | QMC_BD_TX_UB)) {
464-
/* We are full ... */
465-
ret = -EBUSY;
466-
goto end;
464+
if (!(ctrl & (QMC_BD_TX_R | QMC_BD_TX_I)) && bd == chan->txbd_done) {
465+
if (ctrl & QMC_BD_TX_W)
466+
chan->txbd_done = chan->txbds;
467+
else
468+
chan->txbd_done++;
469+
} else {
470+
/* We are full ... */
471+
ret = -EBUSY;
472+
goto end;
473+
}
467474
}
468475

469476
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,
475482

476483
/* Activate the descriptor */
477484
ctrl |= (QMC_BD_TX_R | QMC_BD_TX_UB);
485+
if (complete)
486+
ctrl |= QMC_BD_TX_I;
487+
else
488+
ctrl &= ~QMC_BD_TX_I;
478489
wmb(); /* Be sure to flush the descriptor before control update */
479490
qmc_write16(&bd->cbd_sc, ctrl);
480491

@@ -569,9 +580,16 @@ int qmc_chan_read_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length,
569580

570581
ctrl = qmc_read16(&bd->cbd_sc);
571582
if (ctrl & (QMC_BD_RX_E | QMC_BD_RX_UB)) {
572-
/* We are full ... */
573-
ret = -EBUSY;
574-
goto end;
583+
if (!(ctrl & (QMC_BD_RX_E | QMC_BD_RX_I)) && bd == chan->rxbd_done) {
584+
if (ctrl & QMC_BD_RX_W)
585+
chan->rxbd_done = chan->rxbds;
586+
else
587+
chan->rxbd_done++;
588+
} else {
589+
/* We are full ... */
590+
ret = -EBUSY;
591+
goto end;
592+
}
575593
}
576594

577595
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,
587605

588606
/* Activate the descriptor */
589607
ctrl |= (QMC_BD_RX_E | QMC_BD_RX_UB);
608+
if (complete)
609+
ctrl |= QMC_BD_RX_I;
610+
else
611+
ctrl &= ~QMC_BD_RX_I;
590612
wmb(); /* Be sure to flush data before descriptor activation */
591613
qmc_write16(&bd->cbd_sc, ctrl);
592614

@@ -1482,19 +1504,19 @@ static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan)
14821504

14831505
/* Init Rx BDs and set Wrap bit on last descriptor */
14841506
BUILD_BUG_ON(QMC_NB_RXBDS == 0);
1485-
val = QMC_BD_RX_I;
14861507
for (i = 0; i < QMC_NB_RXBDS; i++) {
14871508
bd = chan->rxbds + i;
1488-
qmc_write16(&bd->cbd_sc, val);
1509+
qmc_write16(&bd->cbd_sc, 0);
14891510
}
14901511
bd = chan->rxbds + QMC_NB_RXBDS - 1;
1491-
qmc_write16(&bd->cbd_sc, val | QMC_BD_RX_W);
1512+
qmc_write16(&bd->cbd_sc, QMC_BD_RX_W);
14921513

14931514
/* Init Tx BDs and set Wrap bit on last descriptor */
14941515
BUILD_BUG_ON(QMC_NB_TXBDS == 0);
1495-
val = QMC_BD_TX_I;
14961516
if (chan->mode == QMC_HDLC)
1497-
val |= QMC_BD_TX_L | QMC_BD_TX_TC;
1517+
val = QMC_BD_TX_L | QMC_BD_TX_TC;
1518+
else
1519+
val = 0;
14981520
for (i = 0; i < QMC_NB_TXBDS; i++) {
14991521
bd = chan->txbds + i;
15001522
qmc_write16(&bd->cbd_sc, val);

sound/soc/fsl/fsl_qmc_audio.c

Lines changed: 54 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,6 @@
1717
#include <sound/pcm_params.h>
1818
#include <sound/soc.h>
1919

20-
struct qmc_dai_chan {
21-
struct qmc_dai_prtd *prtd_tx;
22-
struct qmc_dai_prtd *prtd_rx;
23-
struct qmc_chan *qmc_chan;
24-
};
25-
2620
struct qmc_dai {
2721
char *name;
2822
int id;
@@ -33,7 +27,7 @@ struct qmc_dai {
3327
unsigned int nb_chans_avail;
3428
unsigned int nb_chans_used_tx;
3529
unsigned int nb_chans_used_rx;
36-
struct qmc_dai_chan *chans;
30+
struct qmc_chan **qmc_chans;
3731
};
3832

3933
struct qmc_audio {
@@ -57,7 +51,6 @@ struct qmc_dai_prtd {
5751
size_t ch_dma_offset;
5852

5953
unsigned int channels;
60-
DECLARE_BITMAP(chans_pending, 64);
6154
struct snd_pcm_substream *substream;
6255
};
6356

@@ -126,17 +119,14 @@ static int qmc_audio_pcm_write_submit(struct qmc_dai_prtd *prtd)
126119
int ret;
127120

128121
for (i = 0; i < prtd->channels; i++) {
129-
bitmap_set(prtd->chans_pending, i, 1);
130-
131-
ret = qmc_chan_write_submit(prtd->qmc_dai->chans[i].qmc_chan,
122+
ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chans[i],
132123
prtd->ch_dma_addr_current + i * prtd->ch_dma_offset,
133124
prtd->ch_dma_size,
134-
qmc_audio_pcm_write_complete,
135-
&prtd->qmc_dai->chans[i]);
125+
i == prtd->channels - 1 ? qmc_audio_pcm_write_complete :
126+
NULL, prtd);
136127
if (ret) {
137128
dev_err(prtd->qmc_dai->dev, "write_submit %u failed %d\n",
138129
i, ret);
139-
bitmap_clear(prtd->chans_pending, i, 1);
140130
return ret;
141131
}
142132
}
@@ -146,20 +136,7 @@ static int qmc_audio_pcm_write_submit(struct qmc_dai_prtd *prtd)
146136

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

164141
prtd->buffer_ended += prtd->period_size;
165142
if (prtd->buffer_ended >= prtd->buffer_size)
@@ -182,17 +159,14 @@ static int qmc_audio_pcm_read_submit(struct qmc_dai_prtd *prtd)
182159
int ret;
183160

184161
for (i = 0; i < prtd->channels; i++) {
185-
bitmap_set(prtd->chans_pending, i, 1);
186-
187-
ret = qmc_chan_read_submit(prtd->qmc_dai->chans[i].qmc_chan,
162+
ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chans[i],
188163
prtd->ch_dma_addr_current + i * prtd->ch_dma_offset,
189164
prtd->ch_dma_size,
190-
qmc_audio_pcm_read_complete,
191-
&prtd->qmc_dai->chans[i]);
165+
i == prtd->channels - 1 ? qmc_audio_pcm_read_complete :
166+
NULL, prtd);
192167
if (ret) {
193168
dev_err(prtd->qmc_dai->dev, "read_submit %u failed %d\n",
194169
i, ret);
195-
bitmap_clear(prtd->chans_pending, i, 1);
196170
return ret;
197171
}
198172
}
@@ -202,26 +176,13 @@ static int qmc_audio_pcm_read_submit(struct qmc_dai_prtd *prtd)
202176

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

213181
if (length != prtd->ch_dma_size) {
214182
dev_err(prtd->qmc_dai->dev, "read complete length = %zu, exp %zu\n",
215183
length, prtd->ch_dma_size);
216184
}
217185

218-
/*
219-
* All QMC channels involved must have completed their transfer before
220-
* submitting a new one.
221-
*/
222-
if (!bitmap_empty(prtd->chans_pending, 64))
223-
return;
224-
225186
prtd->buffer_ended += prtd->period_size;
226187
if (prtd->buffer_ended >= prtd->buffer_size)
227188
prtd->buffer_ended = 0;
@@ -239,7 +200,6 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component,
239200
struct snd_pcm_substream *substream, int cmd)
240201
{
241202
struct qmc_dai_prtd *prtd = substream->runtime->private_data;
242-
unsigned int i;
243203
int ret;
244204

245205
if (!prtd->qmc_dai) {
@@ -249,14 +209,10 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component,
249209

250210
switch (cmd) {
251211
case SNDRV_PCM_TRIGGER_START:
252-
bitmap_zero(prtd->chans_pending, 64);
253212
prtd->buffer_ended = 0;
254213
prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;
255214

256215
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
257-
for (i = 0; i < prtd->channels; i++)
258-
prtd->qmc_dai->chans[i].prtd_tx = prtd;
259-
260216
/* Submit first chunk ... */
261217
ret = qmc_audio_pcm_write_submit(prtd);
262218
if (ret)
@@ -272,9 +228,6 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component,
272228
if (ret)
273229
return ret;
274230
} else {
275-
for (i = 0; i < prtd->channels; i++)
276-
prtd->qmc_dai->chans[i].prtd_rx = prtd;
277-
278231
/* Submit first chunk ... */
279232
ret = qmc_audio_pcm_read_submit(prtd);
280233
if (ret)
@@ -644,9 +597,9 @@ static int qmc_dai_hw_params(struct snd_pcm_substream *substream,
644597
chan_param.mode = QMC_TRANSPARENT;
645598
chan_param.transp.max_rx_buf_size = params_period_bytes(params) / nb_chans_used;
646599
for (i = 0; i < nb_chans_used; i++) {
647-
ret = qmc_chan_set_param(qmc_dai->chans[i].qmc_chan, &chan_param);
600+
ret = qmc_chan_set_param(qmc_dai->qmc_chans[i], &chan_param);
648601
if (ret) {
649-
dev_err(dai->dev, "chans[%u], set param failed %d\n",
602+
dev_err(dai->dev, "qmc_chans[%u], set param failed %d\n",
650603
i, ret);
651604
return ret;
652605
}
@@ -688,7 +641,7 @@ static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
688641
case SNDRV_PCM_TRIGGER_RESUME:
689642
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
690643
for (i = 0; i < nb_chans_used; i++) {
691-
ret = qmc_chan_start(qmc_dai->chans[i].qmc_chan, direction);
644+
ret = qmc_chan_start(qmc_dai->qmc_chans[i], direction);
692645
if (ret)
693646
goto err_stop;
694647
}
@@ -697,13 +650,13 @@ static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
697650
case SNDRV_PCM_TRIGGER_STOP:
698651
/* Stop and reset all QMC channels and return the first error encountered */
699652
for (i = 0; i < nb_chans_used; i++) {
700-
ret_tmp = qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction);
653+
ret_tmp = qmc_chan_stop(qmc_dai->qmc_chans[i], direction);
701654
if (!ret)
702655
ret = ret_tmp;
703656
if (ret_tmp)
704657
continue;
705658

706-
ret_tmp = qmc_chan_reset(qmc_dai->chans[i].qmc_chan, direction);
659+
ret_tmp = qmc_chan_reset(qmc_dai->qmc_chans[i], direction);
707660
if (!ret)
708661
ret = ret_tmp;
709662
}
@@ -715,7 +668,7 @@ static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
715668
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
716669
/* Stop all QMC channels and return the first error encountered */
717670
for (i = 0; i < nb_chans_used; i++) {
718-
ret_tmp = qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction);
671+
ret_tmp = qmc_chan_stop(qmc_dai->qmc_chans[i], direction);
719672
if (!ret)
720673
ret = ret_tmp;
721674
}
@@ -731,8 +684,8 @@ static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
731684

732685
err_stop:
733686
while (i--) {
734-
qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction);
735-
qmc_chan_reset(qmc_dai->chans[i].qmc_chan, direction);
687+
qmc_chan_stop(qmc_dai->qmc_chans[i], direction);
688+
qmc_chan_reset(qmc_dai->qmc_chans[i], direction);
736689
}
737690
return ret;
738691
}
@@ -791,12 +744,17 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *
791744
struct qmc_dai *qmc_dai,
792745
struct snd_soc_dai_driver *qmc_soc_dai_driver)
793746
{
747+
struct qmc_chan_ts_info ts_info;
794748
struct qmc_chan_info info;
795749
unsigned long rx_fs_rate;
796750
unsigned long tx_fs_rate;
751+
int prev_last_rx_ts = 0;
752+
int prev_last_tx_ts = 0;
797753
unsigned int nb_tx_ts;
798754
unsigned int nb_rx_ts;
799755
unsigned int i;
756+
int last_rx_ts;
757+
int last_tx_ts;
800758
int count;
801759
u32 val;
802760
int ret;
@@ -823,19 +781,20 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *
823781
return dev_err_probe(qmc_audio->dev, -EINVAL,
824782
"dai %d no QMC channel defined\n", qmc_dai->id);
825783

826-
qmc_dai->chans = devm_kcalloc(qmc_audio->dev, count, sizeof(*qmc_dai->chans), GFP_KERNEL);
827-
if (!qmc_dai->chans)
784+
qmc_dai->qmc_chans = devm_kcalloc(qmc_audio->dev, count, sizeof(*qmc_dai->qmc_chans),
785+
GFP_KERNEL);
786+
if (!qmc_dai->qmc_chans)
828787
return -ENOMEM;
829788

830789
for (i = 0; i < count; i++) {
831-
qmc_dai->chans[i].qmc_chan = devm_qmc_chan_get_byphandles_index(qmc_audio->dev, np,
832-
"fsl,qmc-chan", i);
833-
if (IS_ERR(qmc_dai->chans[i].qmc_chan)) {
834-
return dev_err_probe(qmc_audio->dev, PTR_ERR(qmc_dai->chans[i].qmc_chan),
790+
qmc_dai->qmc_chans[i] = devm_qmc_chan_get_byphandles_index(qmc_audio->dev, np,
791+
"fsl,qmc-chan", i);
792+
if (IS_ERR(qmc_dai->qmc_chans[i])) {
793+
return dev_err_probe(qmc_audio->dev, PTR_ERR(qmc_dai->qmc_chans[i]),
835794
"dai %d get QMC channel %d failed\n", qmc_dai->id, i);
836795
}
837796

838-
ret = qmc_chan_get_info(qmc_dai->chans[i].qmc_chan, &info);
797+
ret = qmc_chan_get_info(qmc_dai->qmc_chans[i], &info);
839798
if (ret) {
840799
dev_err(qmc_audio->dev, "dai %d get QMC %d channel info failed %d\n",
841800
qmc_dai->id, i, ret);
@@ -879,6 +838,30 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *
879838
return -EINVAL;
880839
}
881840
}
841+
842+
ret = qmc_chan_get_ts_info(qmc_dai->qmc_chans[i], &ts_info);
843+
if (ret) {
844+
dev_err(qmc_audio->dev, "dai %d get QMC %d channel TS info failed %d\n",
845+
qmc_dai->id, i, ret);
846+
return ret;
847+
}
848+
849+
last_rx_ts = fls64(ts_info.rx_ts_mask);
850+
last_tx_ts = fls64(ts_info.tx_ts_mask);
851+
852+
if (prev_last_rx_ts > last_rx_ts) {
853+
dev_err(qmc_audio->dev, "dai %d QMC chan %d unordered channels (RX timeslot %d before %d)\n",
854+
qmc_dai->id, i, prev_last_rx_ts, last_rx_ts);
855+
return -EINVAL;
856+
}
857+
if (prev_last_tx_ts > last_tx_ts) {
858+
dev_err(qmc_audio->dev, "dai %d QMC chan %d unordered channels (TX timeslot %d before %d)\n",
859+
qmc_dai->id, i, prev_last_tx_ts, last_tx_ts);
860+
return -EINVAL;
861+
}
862+
863+
prev_last_rx_ts = last_rx_ts;
864+
prev_last_tx_ts = last_tx_ts;
882865
}
883866

884867
qmc_dai->nb_chans_avail = count;

0 commit comments

Comments
 (0)