ASoC: Intel: Skylake: Correct the handling of fmt_config flexible array
authorPeter Ujfalusi <peter.ujfalusi@linux.intel.com>
Thu, 30 Jun 2022 06:56:38 +0000 (09:56 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 21 Jul 2022 19:24:19 +0000 (21:24 +0200)
[ Upstream commit fc976f5629afb4160ee77798b14a693eac903ffd ]

The struct nhlt_format's fmt_config is a flexible array, it must not be
used as normal array.
When moving to the next nhlt_fmt_cfg we need to take into account the data
behind the ->config.caps (indicated by ->config.size).

The logic of the code also changed: it is no longer saves the _last_
fmt_cfg for all found rates.

Fixes: bc2bd45b1f7f3 ("ASoC: Intel: Skylake: Parse nhlt and register clock device")
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Cezary Rojewski <cezary.rojewski@intel.com>
Link: https://lore.kernel.org/r/20220630065638.11183-3-peter.ujfalusi@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
sound/soc/intel/skylake/skl-nhlt.c

index cb02ec2..74f60f5 100644 (file)
@@ -213,11 +213,12 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
        if (fmt->fmt_count == 0)
                return;
 
+       fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config;
        for (i = 0; i < fmt->fmt_count; i++) {
+               struct nhlt_fmt_cfg *saved_fmt_cfg = fmt_cfg;
                bool present = false;
 
-               fmt_cfg = &fmt->fmt_config[i];
-               wav_fmt = &fmt_cfg->fmt_ext;
+               wav_fmt = &saved_fmt_cfg->fmt_ext;
 
                channels = wav_fmt->fmt.channels;
                bps = wav_fmt->fmt.bits_per_sample;
@@ -235,12 +236,18 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
                 * derive the rate.
                 */
                for (j = i; j < fmt->fmt_count; j++) {
-                       fmt_cfg = &fmt->fmt_config[j];
-                       wav_fmt = &fmt_cfg->fmt_ext;
+                       struct nhlt_fmt_cfg *tmp_fmt_cfg = fmt_cfg;
+
+                       wav_fmt = &tmp_fmt_cfg->fmt_ext;
                        if ((fs == wav_fmt->fmt.samples_per_sec) &&
-                          (bps == wav_fmt->fmt.bits_per_sample))
+                          (bps == wav_fmt->fmt.bits_per_sample)) {
                                channels = max_t(u16, channels,
                                                wav_fmt->fmt.channels);
+                               saved_fmt_cfg = tmp_fmt_cfg;
+                       }
+                       /* Move to the next nhlt_fmt_cfg */
+                       tmp_fmt_cfg = (struct nhlt_fmt_cfg *)(tmp_fmt_cfg->config.caps +
+                                                             tmp_fmt_cfg->config.size);
                }
 
                rate = channels * bps * fs;
@@ -256,8 +263,11 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
 
                /* Fill rate and parent for sclk/sclkfs */
                if (!present) {
+                       struct nhlt_fmt_cfg *first_fmt_cfg;
+
+                       first_fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config;
                        i2s_config_ext = (struct skl_i2s_config_blob_ext *)
-                                               fmt->fmt_config[0].config.caps;
+                                               first_fmt_cfg->config.caps;
 
                        /* MCLK Divider Source Select */
                        if (is_legacy_blob(i2s_config_ext->hdr.sig)) {
@@ -271,6 +281,9 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
 
                        parent = skl_get_parent_clk(clk_src);
 
+                       /* Move to the next nhlt_fmt_cfg */
+                       fmt_cfg = (struct nhlt_fmt_cfg *)(fmt_cfg->config.caps +
+                                                         fmt_cfg->config.size);
                        /*
                         * Do not copy the config data if there is no parent
                         * clock available for this clock source select
@@ -279,9 +292,9 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
                                continue;
 
                        sclk[id].rate_cfg[rate_index].rate = rate;
-                       sclk[id].rate_cfg[rate_index].config = fmt_cfg;
+                       sclk[id].rate_cfg[rate_index].config = saved_fmt_cfg;
                        sclkfs[id].rate_cfg[rate_index].rate = rate;
-                       sclkfs[id].rate_cfg[rate_index].config = fmt_cfg;
+                       sclkfs[id].rate_cfg[rate_index].config = saved_fmt_cfg;
                        sclk[id].parent_name = parent->name;
                        sclkfs[id].parent_name = parent->name;
 
@@ -295,13 +308,13 @@ static void skl_get_mclk(struct skl_dev *skl, struct skl_ssp_clk *mclk,
 {
        struct skl_i2s_config_blob_ext *i2s_config_ext;
        struct skl_i2s_config_blob_legacy *i2s_config;
-       struct nhlt_specific_cfg *fmt_cfg;
+       struct nhlt_fmt_cfg *fmt_cfg;
        struct skl_clk_parent_src *parent;
        u32 clkdiv, div_ratio;
        u8 clk_src;
 
-       fmt_cfg = &fmt->fmt_config[0].config;
-       i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->caps;
+       fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config;
+       i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->config.caps;
 
        /* MCLK Divider Source Select and divider */
        if (is_legacy_blob(i2s_config_ext->hdr.sig)) {
@@ -330,7 +343,7 @@ static void skl_get_mclk(struct skl_dev *skl, struct skl_ssp_clk *mclk,
                return;
 
        mclk[id].rate_cfg[0].rate = parent->rate/div_ratio;
-       mclk[id].rate_cfg[0].config = &fmt->fmt_config[0];
+       mclk[id].rate_cfg[0].config = fmt_cfg;
        mclk[id].parent_name = parent->name;
 }