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
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é
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
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
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é
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
© 2016 - 2025 Red Hat, Inc.