History

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

Mark Brown committed 1 year ago

Commit 5998f0d2 parents 309e94a 2c618f32 files · +87 −82Browse files

Unified · Split

2 files
  1. drivers/soc/fsl/qe/qmc.c +33 −11
  2. sound/soc/fsl/fsl_qmc_audio.c +54 −71
drivers/soc/fsl/qe/qmc.c+33−11
@@ -461,9 +461,16 @@ int qmc_chan_write_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length, · 460 unmodified lines
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, · 5 unmodified lines
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, · 88 unmodified lines
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, · 9 unmodified lines
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) · 889 unmodified lines
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+54−71
@@ -17,12 +17,6 @@ · 16 unmodified lines
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 { · 4 unmodified lines
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 { · 17 unmodified lines
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) · 62 unmodified lines
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) · 3 unmodified lines
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) · 16 unmodified lines
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) · 3 unmodified lines
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, · 11 unmodified lines
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, · 3 unmodified lines
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, · 9 unmodified lines
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, · 363 unmodified lines
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, · 35 unmodified lines
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, · 2 unmodified lines
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, · 5 unmodified lines
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, · 9 unmodified lines
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 * · 52 unmodified lines
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 * · 20 unmodified lines
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 * · 37 unmodified lines
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;