ASoC: Intel: sof_sdw: handle errors on card registration
authorPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Mon, 6 Jun 2022 20:37:48 +0000 (15:37 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 21 Jul 2022 19:24:37 +0000 (21:24 +0200)
[ Upstream commit fe154c4ff376bc31041c6441958a08243df09c99 ]

If the card registration fails, typically because of deferred probes,
the device properties added for headset codecs are not removed, which
leads to kernel oopses in driver bind/unbind tests.

We already clean-up the device properties when the card is removed,
this code can be moved as a helper and called upon card registration
errors.

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Rander Wang <rander.wang@intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Link: https://lore.kernel.org/r/20220606203752.144159-4-pierre-louis.bossart@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
sound/soc/intel/boards/sof_sdw.c

index 0bf3e56..abe39a0 100644 (file)
@@ -1323,6 +1323,33 @@ static struct snd_soc_card card_sof_sdw = {
        .late_probe = sof_sdw_card_late_probe,
 };
 
+static void mc_dailink_exit_loop(struct snd_soc_card *card)
+{
+       struct snd_soc_dai_link *link;
+       int ret;
+       int i, j;
+
+       for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
+               if (!codec_info_list[i].exit)
+                       continue;
+               /*
+                * We don't need to call .exit function if there is no matched
+                * dai link found.
+                */
+               for_each_card_prelinks(card, j, link) {
+                       if (!strcmp(link->codecs[0].dai_name,
+                                   codec_info_list[i].dai_name)) {
+                               ret = codec_info_list[i].exit(card, link);
+                               if (ret)
+                                       dev_warn(card->dev,
+                                                "codec exit failed %d\n",
+                                                ret);
+                               break;
+                       }
+               }
+       }
+}
+
 static int mc_probe(struct platform_device *pdev)
 {
        struct snd_soc_card *card = &card_sof_sdw;
@@ -1387,6 +1414,7 @@ static int mc_probe(struct platform_device *pdev)
        ret = devm_snd_soc_register_card(&pdev->dev, card);
        if (ret) {
                dev_err(card->dev, "snd_soc_register_card failed %d\n", ret);
+               mc_dailink_exit_loop(card);
                return ret;
        }
 
@@ -1398,29 +1426,8 @@ static int mc_probe(struct platform_device *pdev)
 static int mc_remove(struct platform_device *pdev)
 {
        struct snd_soc_card *card = platform_get_drvdata(pdev);
-       struct snd_soc_dai_link *link;
-       int ret;
-       int i, j;
 
-       for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
-               if (!codec_info_list[i].exit)
-                       continue;
-               /*
-                * We don't need to call .exit function if there is no matched
-                * dai link found.
-                */
-               for_each_card_prelinks(card, j, link) {
-                       if (!strcmp(link->codecs[0].dai_name,
-                                   codec_info_list[i].dai_name)) {
-                               ret = codec_info_list[i].exit(card, link);
-                               if (ret)
-                                       dev_warn(&pdev->dev,
-                                                "codec exit failed %d\n",
-                                                ret);
-                               break;
-                       }
-               }
-       }
+       mc_dailink_exit_loop(card);
 
        return 0;
 }